diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-23 15:09:37 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-23 15:09:37 +0000 |
commit | 33827e3a534757eead42e6c17460564c49ff1c3a (patch) | |
tree | cd84507420eedb869a3ebfd39458b07cb68cc0c5 /app/assets/javascripts | |
parent | 15ea3fec22d1efd1945d390b21ff65461290dfc1 (diff) | |
download | gitlab-ce-33827e3a534757eead42e6c17460564c49ff1c3a.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
9 files changed, 265 insertions, 45 deletions
diff --git a/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue b/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue index e1f5c7717bb..ce267be6d45 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue @@ -50,6 +50,13 @@ export default { } window.removeEventListener('click', this.collapseWhenOffClick); }, + toggle({ emitEvent = true } = {}) { + if (this.edit) { + this.collapse({ emitEvent }); + } else { + this.expand(); + } + }, }, }; </script> @@ -66,12 +73,12 @@ export default { variant="link" class="gl-text-gray-900! js-sidebar-dropdown-toggle" data-testid="edit-button" - @click="expand" + @click="toggle" > {{ __('Edit') }} </gl-button> </div> - <div v-show="!edit" class="gl-text-gray-400" data-testid="collapsed-content"> + <div v-show="!edit" class="gl-text-gray-500" data-testid="collapsed-content"> <slot name="collapsed">{{ __('None') }}</slot> </div> <div v-show="edit" data-testid="expanded-content"> diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue index 6935ead2706..904ceaed1b3 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue @@ -79,7 +79,7 @@ export default { <span class="gl-mx-2">-</span> <gl-button variant="link" - class="gl-text-gray-400!" + class="gl-text-gray-500!" data-testid="reset-button" :disabled="loading" @click="setDueDate(null)" diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue new file mode 100644 index 00000000000..f7b7fd3f61f --- /dev/null +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue @@ -0,0 +1,161 @@ +<script> +import { mapGetters, mapActions } from 'vuex'; +import { + GlDropdown, + GlDropdownItem, + GlDropdownText, + GlSearchBoxByType, + GlDropdownDivider, + GlLoadingIcon, +} from '@gitlab/ui'; +import { fetchPolicies } from '~/lib/graphql'; +import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; +import groupMilestones from '../../queries/group_milestones.query.graphql'; +import createFlash from '~/flash'; +import { __, s__ } from '~/locale'; + +export default { + components: { + BoardEditableItem, + GlDropdown, + GlLoadingIcon, + GlDropdownItem, + GlDropdownText, + GlSearchBoxByType, + GlDropdownDivider, + }, + data() { + return { + milestones: [], + searchTitle: '', + loading: false, + edit: false, + }; + }, + apollo: { + milestones: { + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, + query: groupMilestones, + debounce: 250, + skip() { + return !this.edit; + }, + variables() { + return { + fullPath: this.groupFullPath, + searchTitle: this.searchTitle, + state: 'active', + includeDescendants: true, + }; + }, + update(data) { + const edges = data?.group?.milestones?.edges ?? []; + return edges.map(item => item.node); + }, + error() { + createFlash({ message: this.$options.i18n.fetchMilestonesError }); + }, + }, + }, + computed: { + ...mapGetters({ issue: 'activeIssue' }), + hasMilestone() { + return this.issue.milestone !== null; + }, + groupFullPath() { + const { referencePath = '' } = this.issue; + return referencePath.slice(0, referencePath.indexOf('/')); + }, + projectPath() { + const { referencePath = '' } = this.issue; + return referencePath.slice(0, referencePath.indexOf('#')); + }, + dropdownText() { + return this.issue.milestone?.title ?? this.$options.i18n.noMilestone; + }, + }, + mounted() { + this.$root.$on('bv::dropdown::hide', () => { + this.$refs.sidebarItem.collapse(); + }); + }, + methods: { + ...mapActions(['setActiveIssueMilestone']), + handleOpen() { + this.edit = true; + this.$refs.dropdown.show(); + }, + async setMilestone(milestoneId) { + this.loading = true; + this.searchTitle = ''; + this.$refs.sidebarItem.collapse(); + + try { + const input = { milestoneId, projectPath: this.projectPath }; + await this.setActiveIssueMilestone(input); + } catch (e) { + createFlash({ message: this.$options.i18n.updateMilestoneError }); + } finally { + this.loading = false; + } + }, + }, + i18n: { + milestone: __('Milestone'), + noMilestone: __('No milestone'), + assignMilestone: __('Assign milestone'), + noMilestonesFound: s__('Milestones|No milestones found'), + fetchMilestonesError: __('There was a problem fetching milestones.'), + updateMilestoneError: __('An error occurred while updating the milestone.'), + }, +}; +</script> + +<template> + <board-editable-item + ref="sidebarItem" + :title="$options.i18n.milestone" + :loading="loading" + @open="handleOpen()" + @close="edit = false" + > + <template v-if="hasMilestone" #collapsed> + <strong class="gl-text-gray-900">{{ issue.milestone.title }}</strong> + </template> + <template> + <gl-dropdown + ref="dropdown" + :text="dropdownText" + :header-text="$options.i18n.assignMilestone" + block + > + <gl-search-box-by-type ref="search" v-model.trim="searchTitle" class="gl-m-3" /> + <gl-dropdown-item + data-testid="no-milestone-item" + :is-check-item="true" + :is-checked="!issue.milestone" + @click="setMilestone(null)" + > + {{ $options.i18n.noMilestone }} + </gl-dropdown-item> + <gl-dropdown-divider /> + <gl-loading-icon v-if="$apollo.loading" class="gl-py-4" /> + <template v-else-if="milestones.length > 0"> + <gl-dropdown-item + v-for="milestone in milestones" + :key="milestone.id" + :is-check-item="true" + :is-checked="issue.milestone && milestone.id === issue.milestone.id" + data-testid="milestone-item" + @click="setMilestone(milestone.id)" + > + {{ milestone.title }} + </gl-dropdown-item> + </template> + <gl-dropdown-text v-else data-testid="no-milestones-found"> + {{ $options.i18n.noMilestonesFound }} + </gl-dropdown-text> + </gl-dropdown> + </template> + </board-editable-item> +</template> diff --git a/app/assets/javascripts/boards/queries/group_milestones.query.graphql b/app/assets/javascripts/boards/queries/group_milestones.query.graphql new file mode 100644 index 00000000000..f2ab12ef4a7 --- /dev/null +++ b/app/assets/javascripts/boards/queries/group_milestones.query.graphql @@ -0,0 +1,17 @@ +query groupMilestones( + $fullPath: ID! + $state: MilestoneStateEnum + $includeDescendants: Boolean + $searchTitle: String +) { + group(fullPath: $fullPath) { + milestones(state: $state, includeDescendants: $includeDescendants, searchTitle: $searchTitle) { + edges { + node { + id + title + } + } + } + } +} diff --git a/app/assets/javascripts/boards/queries/issue.fragment.graphql b/app/assets/javascripts/boards/queries/issue.fragment.graphql index 4b429f875a6..1395bef39ed 100644 --- a/app/assets/javascripts/boards/queries/issue.fragment.graphql +++ b/app/assets/javascripts/boards/queries/issue.fragment.graphql @@ -11,6 +11,10 @@ fragment IssueNode on Issue { webUrl subscribed relativePosition + milestone { + id + title + } assignees { nodes { ...User diff --git a/app/assets/javascripts/boards/queries/issue_set_milestone.mutation.graphql b/app/assets/javascripts/boards/queries/issue_set_milestone.mutation.graphql new file mode 100644 index 00000000000..5dc78a03a06 --- /dev/null +++ b/app/assets/javascripts/boards/queries/issue_set_milestone.mutation.graphql @@ -0,0 +1,12 @@ +mutation issueSetMilestone($input: UpdateIssueInput!) { + updateIssue(input: $input) { + issue { + milestone { + id + title + description + } + } + errors + } +} diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 4e9b11cd7d1..00c64bff74e 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -25,6 +25,7 @@ import issueCreateMutation from '../queries/issue_create.mutation.graphql'; import issueSetLabels from '../queries/issue_set_labels.mutation.graphql'; import issueSetDueDate from '../queries/issue_set_due_date.mutation.graphql'; import issueSetSubscriptionMutation from '../graphql/mutations/issue_set_subscription.mutation.graphql'; +import issueSetMilestone from '../queries/issue_set_milestone.mutation.graphql'; const notImplemented = () => { /* eslint-disable-next-line @gitlab/require-i18n-strings */ @@ -337,6 +338,30 @@ export default { }); }, + setActiveIssueMilestone: async ({ commit, getters }, input) => { + const { activeIssue } = getters; + const { data } = await gqlClient.mutate({ + mutation: issueSetMilestone, + variables: { + input: { + iid: String(activeIssue.iid), + milestoneId: getIdFromGraphQLId(input.milestoneId), + projectPath: input.projectPath, + }, + }, + }); + + if (data.updateIssue.errors?.length > 0) { + throw new Error(data.updateIssue.errors); + } + + commit(types.UPDATE_ISSUE_BY_ID, { + issueId: activeIssue.id, + prop: 'milestone', + value: data.updateIssue.issue.milestone, + }); + }, + createNewIssue: ({ commit, state }, issueInput) => { const input = issueInput; const { boardType, endpoints } = state; diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index 1b747fb7f20..a548354f257 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -136,7 +136,12 @@ export default { class="d-inline-flex mb-2" /> <gl-button-group class="gl-ml-4 gl-mb-4" data-testid="commit-sha-group"> - <gl-button label class="gl-font-monospace" v-text="commit.short_id" /> + <gl-button + label + class="gl-font-monospace" + data-testid="commit-sha-short-id" + v-text="commit.short_id" + /> <clipboard-button :text="commit.id" :title="__('Copy commit SHA')" diff --git a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue index dec8aa61838..52593aabfea 100644 --- a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue +++ b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue @@ -1,11 +1,12 @@ <script> -import { GlButton } from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import { viewerTypes } from '../constants'; export default { components: { - GlButton, + GlDropdown, + GlDropdownItem, }, props: { viewer: { @@ -18,10 +19,21 @@ export default { }, }, computed: { - mergeReviewLine() { - return sprintf(__('Reviewing (merge request !%{mergeRequestId})'), { - mergeRequestId: this.mergeRequestId, - }); + modeDropdownItems() { + return [ + { + viewerType: this.$options.viewerTypes.mr, + title: sprintf(__('Reviewing (merge request !%{mergeRequestId})'), { + mergeRequestId: this.mergeRequestId, + }), + content: __('Compare changes with the merge request target branch'), + }, + { + viewerType: this.$options.viewerTypes.diff, + title: __('Reviewing'), + content: __('Compare changes with the last commit'), + }, + ]; }, }, methods: { @@ -34,39 +46,16 @@ export default { </script> <template> - <div class="dropdown"> - <gl-button variant="link" data-toggle="dropdown">{{ __('Edit') }}</gl-button> - <div class="dropdown-menu dropdown-menu-selectable dropdown-open-left"> - <ul> - <li> - <a - :class="{ - 'is-active': viewer === $options.viewerTypes.mr, - }" - href="#" - @click.prevent="changeMode($options.viewerTypes.mr)" - > - <strong class="dropdown-menu-inner-title"> {{ mergeReviewLine }} </strong> - <span class="dropdown-menu-inner-content"> - {{ __('Compare changes with the merge request target branch') }} - </span> - </a> - </li> - <li> - <a - :class="{ - 'is-active': viewer === $options.viewerTypes.diff, - }" - href="#" - @click.prevent="changeMode($options.viewerTypes.diff)" - > - <strong class="dropdown-menu-inner-title">{{ __('Reviewing') }}</strong> - <span class="dropdown-menu-inner-content"> - {{ __('Compare changes with the last commit') }} - </span> - </a> - </li> - </ul> - </div> - </div> + <gl-dropdown :text="__('Edit')" size="small"> + <gl-dropdown-item + v-for="mode in modeDropdownItems" + :key="mode.viewerType" + :is-check-item="true" + :is-checked="viewer === mode.viewerType" + @click="changeMode(mode.viewerType)" + > + <strong class="dropdown-menu-inner-title"> {{ mode.title }} </strong> + <span class="dropdown-menu-inner-content"> {{ mode.content }} </span> + </gl-dropdown-item> + </gl-dropdown> </template> |