diff options
Diffstat (limited to 'app/assets/javascripts')
17 files changed, 141 insertions, 27 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue index d9cd4f3acf1..2581c3e9928 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue @@ -70,7 +70,7 @@ export default { :title="$options.currentBranchPermissionsTooltip" > <span - class="ide-radio-label" + class="ide-option-label" data-qa-selector="commit_to_current_branch_radio" v-html="commitToCurrentBranchText" ></span> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue b/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue index daa44a42765..0812599c25c 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/new_merge_request_option.vue @@ -1,16 +1,27 @@ <script> import { createNamespacedHelpers } from 'vuex'; +import { GlTooltipDirective } from '@gitlab/ui'; +import { s__ } from '~/locale'; -const { - mapState: mapCommitState, - mapActions: mapCommitActions, - mapGetters: mapCommitGetters, -} = createNamespacedHelpers('commit'); +const { mapActions: mapCommitActions, mapGetters: mapCommitGetters } = createNamespacedHelpers( + 'commit', +); export default { + directives: { + GlTooltip: GlTooltipDirective, + }, computed: { - ...mapCommitState(['shouldCreateMR']), - ...mapCommitGetters(['shouldHideNewMrOption']), + ...mapCommitGetters(['shouldHideNewMrOption', 'shouldDisableNewMrOption', 'shouldCreateMR']), + tooltipText() { + if (this.shouldDisableNewMrOption) { + return s__( + 'IDE|This option is disabled because you are not allowed to create merge requests in this project.', + ); + } + + return ''; + }, }, methods: { ...mapCommitActions(['toggleShouldCreateMR']), @@ -21,14 +32,19 @@ export default { <template> <fieldset v-if="!shouldHideNewMrOption"> <hr class="my-2" /> - <label class="mb-0 js-ide-commit-new-mr"> + <label + v-gl-tooltip="tooltipText" + class="mb-0 js-ide-commit-new-mr" + :class="{ 'is-disabled': shouldDisableNewMrOption }" + > <input + :disabled="shouldDisableNewMrOption" :checked="shouldCreateMR" type="checkbox" data-qa-selector="start_new_mr_checkbox" @change="toggleShouldCreateMR" /> - <span class="prepend-left-10"> + <span class="prepend-left-10 ide-option-label"> {{ __('Start a new merge request') }} </span> </label> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue index 07073f5f879..a9591805261 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue @@ -67,7 +67,7 @@ export default { @change="updateCommitAction($event.target.value)" /> <span class="prepend-left-10"> - <span v-if="label" class="ide-radio-label"> {{ label }} </span> <slot v-else></slot> + <span v-if="label" class="ide-option-label"> {{ label }} </span> <slot v-else></slot> </span> </label> <div v-if="commitAction === value && showInput" class="ide-commit-new-branch"> diff --git a/app/assets/javascripts/ide/components/nav_dropdown.vue b/app/assets/javascripts/ide/components/nav_dropdown.vue index 2e290de0943..2307efd1d24 100644 --- a/app/assets/javascripts/ide/components/nav_dropdown.vue +++ b/app/assets/javascripts/ide/components/nav_dropdown.vue @@ -1,5 +1,6 @@ <script> import $ from 'jquery'; +import { mapGetters } from 'vuex'; import NavForm from './nav_form.vue'; import NavDropdownButton from './nav_dropdown_button.vue'; @@ -13,6 +14,9 @@ export default { isVisibleDropdown: false, }; }, + computed: { + ...mapGetters(['canReadMergeRequests']), + }, mounted() { this.addDropdownListeners(); }, @@ -42,7 +46,9 @@ export default { <template> <div ref="dropdown" class="btn-group ide-nav-dropdown dropdown"> - <nav-dropdown-button /> - <div class="dropdown-menu dropdown-menu-left p-0"><nav-form v-if="isVisibleDropdown" /></div> + <nav-dropdown-button :show-merge-requests="canReadMergeRequests" /> + <div class="dropdown-menu dropdown-menu-left p-0"> + <nav-form v-if="isVisibleDropdown" :show-merge-requests="canReadMergeRequests" /> + </div> </div> </template> diff --git a/app/assets/javascripts/ide/components/nav_dropdown_button.vue b/app/assets/javascripts/ide/components/nav_dropdown_button.vue index f1d44443125..4cd320d5d66 100644 --- a/app/assets/javascripts/ide/components/nav_dropdown_button.vue +++ b/app/assets/javascripts/ide/components/nav_dropdown_button.vue @@ -10,6 +10,13 @@ export default { Icon, DropdownButton, }, + props: { + showMergeRequests: { + type: Boolean, + required: false, + default: true, + }, + }, computed: { ...mapState(['currentBranchId', 'currentMergeRequestId']), mergeRequestLabel() { @@ -25,10 +32,10 @@ export default { <template> <dropdown-button> <span class="row"> - <span class="col-7 text-truncate"> + <span class="col-auto text-truncate" :class="{ 'col-7': showMergeRequests }"> <icon :size="16" :aria-label="__('Current Branch')" name="branch" /> {{ branchLabel }} </span> - <span class="col-5 pl-0 text-truncate"> + <span v-if="showMergeRequests" class="col-5 pl-0 text-truncate"> <icon :size="16" :aria-label="__('Merge Request')" name="merge-request" /> {{ mergeRequestLabel }} </span> diff --git a/app/assets/javascripts/ide/components/nav_form.vue b/app/assets/javascripts/ide/components/nav_form.vue index 2ccc84ea5d5..195504a6861 100644 --- a/app/assets/javascripts/ide/components/nav_form.vue +++ b/app/assets/javascripts/ide/components/nav_form.vue @@ -11,12 +11,19 @@ export default { BranchesSearchList, MergeRequestSearchList, }, + props: { + showMergeRequests: { + type: Boolean, + required: false, + default: true, + }, + }, }; </script> <template> <div class="ide-nav-form p-0"> - <tabs stop-propagation> + <tabs v-if="showMergeRequests" stop-propagation> <tab active> <template slot="title"> {{ __('Branches') }} @@ -30,5 +37,6 @@ export default { <merge-request-search-list /> </tab> </tabs> + <branches-search-list v-else /> </div> </template> diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index 673ac1bfa9a..54d3e79411f 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -8,6 +8,9 @@ export const MAX_BODY_LENGTH = 72; export const FILE_VIEW_MODE_EDITOR = 'editor'; export const FILE_VIEW_MODE_PREVIEW = 'preview'; +export const PERMISSION_CREATE_MR = 'createMergeRequestIn'; +export const PERMISSION_READ_MR = 'readMergeRequest'; + export const activityBarViews = { edit: 'ide-tree', commit: 'commit-section', diff --git a/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql b/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql new file mode 100644 index 00000000000..48f63995f44 --- /dev/null +++ b/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql @@ -0,0 +1,8 @@ +query getUserPermissions($projectPath: ID!) { + project(fullPath: $projectPath) { + userPermissions { + createMergeRequestIn, + readMergeRequest + } + } +} diff --git a/app/assets/javascripts/ide/services/gql.js b/app/assets/javascripts/ide/services/gql.js new file mode 100644 index 00000000000..8a7f27328ba --- /dev/null +++ b/app/assets/javascripts/ide/services/gql.js @@ -0,0 +1,8 @@ +import createGqClient, { fetchPolicies } from '~/lib/graphql'; + +export default createGqClient( + {}, + { + fetchPolicy: fetchPolicies.NO_CACHE, + }, +); diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index a5134c64705..84a2b2bd58e 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -1,6 +1,18 @@ import axios from '~/lib/utils/axios_utils'; import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; import Api from '~/api'; +import getUserPermissions from '../queries/getUserPermissions.query.graphql'; +import gqClient from './gql'; + +const fetchApiProjectData = projectPath => Api.project(projectPath).then(({ data }) => data); + +const fetchGqlProjectData = projectPath => + gqClient + .query({ + query: getUserPermissions, + variables: { projectPath }, + }) + .then(({ data }) => data.project); export default { getFileData(endpoint) { @@ -47,7 +59,16 @@ export default { .then(({ data }) => data); }, getProjectData(namespace, project) { - return Api.project(`${namespace}/${project}`); + const projectPath = `${namespace}/${project}`; + + return Promise.all([fetchApiProjectData(projectPath), fetchGqlProjectData(projectPath)]).then( + ([apiProjectData, gqlProjectData]) => ({ + data: { + ...apiProjectData, + ...gqlProjectData, + }, + }), + ); }, getProjectMergeRequests(projectId, params = {}) { return Api.projectMergeRequests(projectId, params); diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index aa44067edf8..9e9c6fc42b3 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -2,10 +2,17 @@ import flash from '~/flash'; import { __ } from '~/locale'; import service from '../../services'; import * as types from '../mutation_types'; -import { activityBarViews } from '../../constants'; +import { activityBarViews, PERMISSION_READ_MR } from '../../constants'; -export const getMergeRequestsForBranch = ({ commit, state }, { projectId, branchId } = {}) => - service +export const getMergeRequestsForBranch = ( + { commit, state, getters }, + { projectId, branchId } = {}, +) => { + if (!getters.findProjectPermissions(projectId)[PERMISSION_READ_MR]) { + return Promise.resolve(); + } + + return service .getProjectMergeRequests(`${projectId}`, { source_branch: branchId, source_project_id: state.projects[projectId].id, @@ -36,6 +43,7 @@ export const getMergeRequestsForBranch = ({ commit, state }, { projectId, branch ); throw e; }); +}; export const getMergeRequestData = ( { commit, dispatch, state }, diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index 2fc574cd343..257062d118c 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -1,5 +1,10 @@ import { getChangesCountForFiles, filePathMatches } from './utils'; -import { activityBarViews, packageJsonPath } from '../constants'; +import { + activityBarViews, + packageJsonPath, + PERMISSION_READ_MR, + PERMISSION_CREATE_MR, +} from '../constants'; export const activeFile = state => state.openFiles.find(file => file.active) || null; @@ -141,5 +146,14 @@ export const getDiffInfo = (state, getters) => path => { }; }; +export const findProjectPermissions = (state, getters) => projectId => + getters.findProject(projectId)?.userPermissions || {}; + +export const canReadMergeRequests = (state, getters) => + Boolean(getters.findProjectPermissions(state.currentProjectId)[PERMISSION_READ_MR]); + +export const canCreateMergeRequests = (state, getters) => + Boolean(getters.findProjectPermissions(state.currentProjectId)[PERMISSION_CREATE_MR]); + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index 0740e0523a9..3be350db3da 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -158,7 +158,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true }); }, 5000); - if (state.shouldCreateMR) { + if (getters.shouldCreateMR) { const { currentProject } = rootGetters; const targetBranch = getters.isCreatingNewBranch ? rootState.currentBranchId diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js index de289e27199..e421d44b6de 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/getters.js +++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js @@ -54,5 +54,11 @@ export const shouldHideNewMrOption = (_state, getters, _rootState, rootGetters) (!rootGetters.hasMergeRequest && rootGetters.isOnDefaultBranch)) && rootGetters.canPushToBranch; +export const shouldDisableNewMrOption = (state, getters, rootState, rootGetters) => + !rootGetters.canCreateMergeRequests; + +export const shouldCreateMR = (state, getters) => + state.shouldCreateMR && !getters.shouldDisableNewMrOption; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js index 089dedd14cb..78b7e29ae53 100644 --- a/app/assets/javascripts/pages/admin/application_settings/index.js +++ b/app/assets/javascripts/pages/admin/application_settings/index.js @@ -3,9 +3,7 @@ import projectSelect from '~/project_select'; import selfMonitor from '~/self_monitor'; document.addEventListener('DOMContentLoaded', () => { - if (gon.features && gon.features.selfMonitoringProject) { - selfMonitor(); - } + selfMonitor(); // Initialize expandable settings panels initSettingsPanels(); projectSelect(); diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue index 29a3340b83d..2ba170998e8 100644 --- a/app/assets/javascripts/repository/components/table/index.vue +++ b/app/assets/javascripts/repository/components/table/index.vue @@ -71,7 +71,12 @@ export default { <template> <div class="tree-content-holder"> <div class="table-holder bordered-box"> - <table :aria-label="tableCaption" class="table tree-table qa-file-tree" aria-live="polite"> + <table + :aria-label="tableCaption" + class="table tree-table" + aria-live="polite" + data-qa-selector="file_tree_table" + > <table-header v-once /> <tbody> <parent-row diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index 8703796b116..c905c39bbba 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -139,7 +139,13 @@ export default { class="d-inline-block align-text-bottom fa-fw" /> <i v-else :aria-label="type" role="img" :class="iconName" class="fa fa-fw"></i> - <component :is="linkComponent" :to="routerLinkTo" :href="url" class="str-truncated"> + <component + :is="linkComponent" + :to="routerLinkTo" + :href="url" + class="str-truncated" + data-qa-selector="file_name_link" + > {{ fullPath }} </component> <!-- eslint-disable-next-line @gitlab/vue-i18n/no-bare-strings --> |