diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-12 21:09:26 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-12 21:09:26 +0300 |
commit | f4182abcb628e20978f011376811bbf8e644eff5 (patch) | |
tree | bb7886935855da9f69571b4970cfc5519dd40f2a /app/assets/javascripts | |
parent | 6cf30e964d54d536b0ff861916745f0a4bb31ebb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
15 files changed, 227 insertions, 51 deletions
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index 2d426ee663a..f84e39baa53 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -8,11 +8,40 @@ import initPopover from '~/blob/suggest_gitlab_ci_yml'; import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils'; import Tracking from '~/tracking'; +const initPopovers = () => { + const suggestEl = document.querySelector('.js-suggest-gitlab-ci-yml'); + + if (suggestEl) { + const commitButton = document.querySelector('#commit-changes'); + + initPopover(suggestEl); + + if (commitButton) { + const { dismissKey, humanAccess } = suggestEl.dataset; + const urlParams = new URLSearchParams(window.location.search); + const mergeRequestPath = urlParams.get('mr_path') || true; + + const commitCookieName = `suggest_gitlab_ci_yml_commit_${dismissKey}`; + const commitTrackLabel = 'suggest_gitlab_ci_yml_commit_changes'; + const commitTrackValue = '20'; + + commitButton.addEventListener('click', () => { + setCookie(commitCookieName, mergeRequestPath); + + Tracking.event(undefined, 'click_button', { + label: commitTrackLabel, + property: humanAccess, + value: commitTrackValue, + }); + }); + } + } +}; + export default () => { const editBlobForm = $('.js-edit-blob-form'); const uploadBlobForm = $('.js-upload-blob-form'); const deleteBlobForm = $('.js-delete-blob-form'); - const suggestEl = document.querySelector('.js-suggest-gitlab-ci-yml'); if (editBlobForm.length) { const urlRoot = editBlobForm.data('relativeUrlRoot'); @@ -33,6 +62,7 @@ export default () => { projectId, isMarkdown, }); + initPopovers(); }) .catch(e => createFlash(e)); @@ -62,30 +92,4 @@ export default () => { if (deleteBlobForm.length) { new NewCommitForm(deleteBlobForm); } - - if (suggestEl) { - const commitButton = document.querySelector('#commit-changes'); - - initPopover(suggestEl); - - if (commitButton) { - const { dismissKey, humanAccess } = suggestEl.dataset; - const urlParams = new URLSearchParams(window.location.search); - const mergeRequestPath = urlParams.get('mr_path') || true; - - const commitCookieName = `suggest_gitlab_ci_yml_commit_${dismissKey}`; - const commitTrackLabel = 'suggest_gitlab_ci_yml_commit_changes'; - const commitTrackValue = '20'; - - commitButton.addEventListener('click', () => { - setCookie(commitCookieName, mergeRequestPath); - - Tracking.event(undefined, 'click_button', { - label: commitTrackLabel, - property: humanAccess, - value: commitTrackValue, - }); - }); - } - } }; diff --git a/app/assets/javascripts/boards/components/board_assignee_dropdown.vue b/app/assets/javascripts/boards/components/board_assignee_dropdown.vue index 2245c0d0f44..c81f171af2b 100644 --- a/app/assets/javascripts/boards/components/board_assignee_dropdown.vue +++ b/app/assets/javascripts/boards/components/board_assignee_dropdown.vue @@ -1,13 +1,22 @@ <script> import { mapActions, mapGetters } from 'vuex'; -import { GlDropdownItem, GlDropdownDivider, GlAvatarLabeled, GlAvatarLink } from '@gitlab/ui'; +import { + GlDropdownItem, + GlDropdownDivider, + GlAvatarLabeled, + GlAvatarLink, + GlSearchBoxByType, +} from '@gitlab/ui'; import { __, n__ } from '~/locale'; import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue'; import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue'; import getIssueParticipants from '~/vue_shared/components/sidebar/queries/getIssueParticipants.query.graphql'; +import searchUsers from '~/boards/queries/users_search.query.graphql'; export default { + noSearchDelay: 0, + searchDelay: 250, i18n: { unassigned: __('Unassigned'), assignee: __('Assignee'), @@ -22,23 +31,42 @@ export default { GlDropdownDivider, GlAvatarLabeled, GlAvatarLink, + GlSearchBoxByType, }, data() { return { + search: '', participants: [], selected: this.$store.getters.activeIssue.assignees, }; }, apollo: { participants: { - query: getIssueParticipants, + query() { + return this.isSearchEmpty ? getIssueParticipants : searchUsers; + }, variables() { + if (this.isSearchEmpty) { + return { + id: `gid://gitlab/Issue/${this.activeIssue.iid}`, + }; + } + return { - id: `gid://gitlab/Issue/${this.activeIssue.iid}`, + search: this.search, }; }, update(data) { - return data.issue?.participants?.nodes || []; + if (this.isSearchEmpty) { + return data.issue?.participants?.nodes || []; + } + + return data.users?.nodes || []; + }, + debounce() { + const { noSearchDelay, searchDelay } = this.$options; + + return this.isSearchEmpty ? noSearchDelay : searchDelay; }, }, }, @@ -58,6 +86,9 @@ export default { selectedUserNames() { return this.selected.map(({ username }) => username); }, + isSearchEmpty() { + return this.search === ''; + }, }, methods: { ...mapActions(['setAssignees']), @@ -97,6 +128,9 @@ export default { :text="$options.i18n.assignees" :header-text="$options.i18n.assignTo" > + <template #search> + <gl-search-box-by-type v-model.trim="search" /> + </template> <template #items> <gl-dropdown-item :is-checked="selectedIsEmpty" diff --git a/app/assets/javascripts/boards/queries/users_search.query.graphql b/app/assets/javascripts/boards/queries/users_search.query.graphql new file mode 100644 index 00000000000..ca016495d79 --- /dev/null +++ b/app/assets/javascripts/boards/queries/users_search.query.graphql @@ -0,0 +1,11 @@ +query usersSearch($search: String!) { + users(search: $search) { + nodes { + username + name + webUrl + avatarUrl + id + } + } +} diff --git a/app/assets/javascripts/pages/projects/pipelines/show/index.js b/app/assets/javascripts/pages/projects/pipelines/show/index.js index 7a57e417b41..d3f46b7e025 100644 --- a/app/assets/javascripts/pages/projects/pipelines/show/index.js +++ b/app/assets/javascripts/pages/projects/pipelines/show/index.js @@ -1,7 +1,5 @@ import initPipelineDetails from '~/pipelines/pipeline_details_bundle'; import initPipelines from '../init_pipelines'; -document.addEventListener('DOMContentLoaded', () => { - initPipelines(); - initPipelineDetails(); -}); +initPipelines(); +initPipelineDetails(); diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index 67aec12655a..51d8bbeaef0 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -6,12 +6,10 @@ import { setUrlFragment, redirectTo } from '~/lib/utils/url_utility'; import pipelineGraph from './components/graph/graph_component.vue'; import createDagApp from './pipeline_details_dag'; import GraphBundleMixin from './mixins/graph_pipeline_bundle_mixin'; -import PipelinesMediator from './pipeline_details_mediator'; import legacyPipelineHeader from './components/legacy_header_component.vue'; import eventHub from './event_hub'; import TestReports from './components/test_reports/test_reports.vue'; import createTestReportsStore from './stores/test_reports'; -import { createPipelineHeaderApp } from './pipeline_details_header'; Vue.use(Translate); @@ -22,7 +20,7 @@ const SELECTORS = { PIPELINE_TESTS: '#js-pipeline-tests-detail', }; -const createPipelinesDetailApp = mediator => { +const createLegacyPipelinesDetailApp = mediator => { if (!document.querySelector(SELECTORS.PIPELINE_GRAPH)) { return; } @@ -127,18 +125,48 @@ const createTestDetails = () => { }); }; -export default () => { +export default async function() { + createTestDetails(); + createDagApp(); + const { dataset } = document.querySelector(SELECTORS.PIPELINE_DETAILS); - const mediator = new PipelinesMediator({ endpoint: dataset.endpoint }); - mediator.fetchPipeline(); + let mediator; + + if (!gon.features.graphqlPipelineHeader || !gon.features.graphqlPipelineDetails) { + try { + const { default: PipelinesMediator } = await import( + /* webpackChunkName: 'PipelinesMediator' */ './pipeline_details_mediator' + ); + mediator = new PipelinesMediator({ endpoint: dataset.endpoint }); + mediator.fetchPipeline(); + } catch { + Flash(__('An error occurred while loading the pipeline.')); + } + } - createPipelinesDetailApp(mediator); + if (gon.features.graphqlPipelineDetails) { + try { + const { createPipelinesDetailApp } = await import( + /* webpackChunkName: 'createPipelinesDetailApp' */ './pipeline_details_graph' + ); + createPipelinesDetailApp(); + } catch { + Flash(__('An error occurred while loading the pipeline.')); + } + } else { + createLegacyPipelinesDetailApp(mediator); + } if (gon.features.graphqlPipelineHeader) { - createPipelineHeaderApp(SELECTORS.PIPELINE_HEADER); + try { + const { createPipelineHeaderApp } = await import( + /* webpackChunkName: 'createPipelineHeaderApp' */ './pipeline_details_header' + ); + createPipelineHeaderApp(SELECTORS.PIPELINE_HEADER); + } catch { + Flash(__('An error occurred while loading a section of this page.')); + } } else { createLegacyPipelineHeaderApp(mediator); } - createTestDetails(); - createDagApp(); -}; +} diff --git a/app/assets/javascripts/pipelines/pipeline_details_dag.js b/app/assets/javascripts/pipelines/pipeline_details_dag.js index dc03b457265..3e9bdae96dd 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_dag.js +++ b/app/assets/javascripts/pipelines/pipeline_details_dag.js @@ -10,11 +10,12 @@ const apolloProvider = new VueApollo({ }); const createDagApp = () => { - if (!window.gon?.features?.dagPipelineTab) { + const el = document.querySelector('#js-pipeline-dag-vue'); + + if (!window.gon?.features?.dagPipelineTab || !el) { return; } - const el = document.querySelector('#js-pipeline-dag-vue'); const { pipelineProjectPath, pipelineIid, emptySvgPath, dagDocPath } = el?.dataset; // eslint-disable-next-line no-new diff --git a/app/assets/javascripts/pipelines/pipeline_details_graph.js b/app/assets/javascripts/pipelines/pipeline_details_graph.js new file mode 100644 index 00000000000..880855cf21d --- /dev/null +++ b/app/assets/javascripts/pipelines/pipeline_details_graph.js @@ -0,0 +1,7 @@ +const createPipelinesDetailApp = () => { + // Placeholder. See: https://gitlab.com/gitlab-org/gitlab/-/issues/223262 + // eslint-disable-next-line no-useless-return + return; +}; + +export { createPipelinesDetailApp }; diff --git a/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue b/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue index 68c97ed13d7..c5bbe1b33fb 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue @@ -21,6 +21,7 @@ export default { <template> <gl-dropdown class="show" :text="text" :header-text="headerText"> + <slot name="search"></slot> <gl-dropdown-form> <slot name="items"></slot> </gl-dropdown-form> diff --git a/app/assets/javascripts/vue_shared/security_reports/constants.js b/app/assets/javascripts/vue_shared/security_reports/constants.js new file mode 100644 index 00000000000..2f87c4e7878 --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/constants.js @@ -0,0 +1,3 @@ +export const FEEDBACK_TYPE_DISMISSAL = 'dismissal'; +export const FEEDBACK_TYPE_ISSUE = 'issue'; +export const FEEDBACK_TYPE_MERGE_REQUEST = 'merge_request'; diff --git a/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/actions.js b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/actions.js new file mode 100644 index 00000000000..c9da824613d --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/actions.js @@ -0,0 +1,24 @@ +import { fetchDiffData } from '../../utils'; +import * as types from './mutation_types'; + +export const setDiffEndpoint = ({ commit }, path) => commit(types.SET_DIFF_ENDPOINT, path); + +export const requestDiff = ({ commit }) => commit(types.REQUEST_DIFF); + +export const receiveDiffSuccess = ({ commit }, response) => + commit(types.RECEIVE_DIFF_SUCCESS, response); + +export const receiveDiffError = ({ commit }, response) => + commit(types.RECEIVE_DIFF_ERROR, response); + +export const fetchDiff = ({ state, rootState, dispatch }) => { + dispatch('requestDiff'); + + return fetchDiffData(rootState, state.paths.diffEndpoint, 'secret_detection') + .then(data => { + dispatch('receiveDiffSuccess', data); + }) + .catch(() => { + dispatch('receiveDiffError'); + }); +}; diff --git a/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/index.js b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/index.js new file mode 100644 index 00000000000..68c81bb4509 --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/index.js @@ -0,0 +1,10 @@ +import state from './state'; +import mutations from './mutations'; +import * as actions from './actions'; + +export default { + namespaced: true, + state, + mutations, + actions, +}; diff --git a/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutation_types.js b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutation_types.js new file mode 100644 index 00000000000..aacec0fb679 --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutation_types.js @@ -0,0 +1,4 @@ +export const RECEIVE_DIFF_SUCCESS = 'RECEIVE_DIFF_SUCCESS'; +export const RECEIVE_DIFF_ERROR = 'RECEIVE_DIFF_ERROR'; +export const REQUEST_DIFF = 'REQUEST_DIFF'; +export const SET_DIFF_ENDPOINT = 'SET_DIFF_ENDPOINT'; diff --git a/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutations.js b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutations.js new file mode 100644 index 00000000000..ee943b0621c --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/mutations.js @@ -0,0 +1,30 @@ +import { parseDiff } from '~/vue_shared/security_reports/store/utils'; +import * as types from './mutation_types'; + +export default { + [types.SET_DIFF_ENDPOINT](state, path) { + state.paths.diffEndpoint = path; + }, + + [types.REQUEST_DIFF](state) { + state.isLoading = true; + }, + + [types.RECEIVE_DIFF_SUCCESS](state, { diff, enrichData }) { + const { added, fixed, existing } = parseDiff(diff, enrichData); + const baseReportOutofDate = diff.base_report_out_of_date || false; + const hasBaseReport = Boolean(diff.base_report_created_at); + + state.isLoading = false; + state.newIssues = added; + state.resolvedIssues = fixed; + state.allIssues = existing; + state.baseReportOutofDate = baseReportOutofDate; + state.hasBaseReport = hasBaseReport; + }, + + [types.RECEIVE_DIFF_ERROR](state) { + state.isLoading = false; + state.hasError = true; + }, +}; diff --git a/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/state.js b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/state.js new file mode 100644 index 00000000000..e860e3af924 --- /dev/null +++ b/app/assets/javascripts/vue_shared/security_reports/store/modules/secret_detection/state.js @@ -0,0 +1,16 @@ +export default () => ({ + paths: { + head: null, + base: null, + diffEndpoint: null, + }, + + isLoading: false, + hasError: false, + + newIssues: [], + resolvedIssues: [], + allIssues: [], + baseReportOutofDate: false, + hasBaseReport: false, +}); diff --git a/app/assets/javascripts/vue_shared/security_reports/store/utils.js b/app/assets/javascripts/vue_shared/security_reports/store/utils.js index 9a3581e276e..6e50efae741 100644 --- a/app/assets/javascripts/vue_shared/security_reports/store/utils.js +++ b/app/assets/javascripts/vue_shared/security_reports/store/utils.js @@ -1,5 +1,10 @@ import pollUntilComplete from '~/lib/utils/poll_until_complete'; import axios from '~/lib/utils/axios_utils'; +import { + FEEDBACK_TYPE_DISMISSAL, + FEEDBACK_TYPE_ISSUE, + FEEDBACK_TYPE_MERGE_REQUEST, +} from '../constants'; export const fetchDiffData = (state, endpoint, category) => { const requests = [pollUntilComplete(endpoint)]; @@ -24,21 +29,21 @@ export const enrichVulnerabilityWithFeedback = (vulnerability, feedback = []) => feedback .filter(fb => fb.project_fingerprint === vulnerability.project_fingerprint) .reduce((vuln, fb) => { - if (fb.feedback_type === 'dismissal') { + if (fb.feedback_type === FEEDBACK_TYPE_DISMISSAL) { return { ...vuln, isDismissed: true, dismissalFeedback: fb, }; } - if (fb.feedback_type === 'issue' && fb.issue_iid) { + if (fb.feedback_type === FEEDBACK_TYPE_ISSUE && fb.issue_iid) { return { ...vuln, hasIssue: true, issue_feedback: fb, }; } - if (fb.feedback_type === 'merge_request' && fb.merge_request_iid) { + if (fb.feedback_type === FEEDBACK_TYPE_MERGE_REQUEST && fb.merge_request_iid) { return { ...vuln, hasMergeRequest: true, |