diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-16 12:09:18 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-16 12:09:18 +0300 |
commit | 14cb5b3d793c1f41c7d36e2e899d3e5e9eca148f (patch) | |
tree | 235f19919bf2a070c337f0336443fb05eacf52b2 /app/assets/javascripts/boards | |
parent | 0ab17699c88587c5872f9517b29be5f43224a8ea (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/boards')
6 files changed, 115 insertions, 15 deletions
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 19e6f8a2269..6935ead2706 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 @@ -18,7 +18,7 @@ export default { }; }, computed: { - ...mapGetters({ issue: 'activeIssue' }), + ...mapGetters({ issue: 'activeIssue', projectPathForActiveIssue: 'projectPathForActiveIssue' }), hasDueDate() { return this.issue.dueDate != null; }, @@ -36,10 +36,6 @@ export default { return dateInWords(this.parsedDueDate, true); }, - projectPath() { - const referencePath = this.issue.referencePath || ''; - return referencePath.slice(0, referencePath.indexOf('#')); - }, }, methods: { ...mapActions(['setActiveIssueDueDate']), @@ -53,7 +49,7 @@ export default { try { const dueDate = date ? formatDate(date, 'yyyy-mm-dd') : null; - await this.setActiveIssueDueDate({ dueDate, projectPath: this.projectPath }); + await this.setActiveIssueDueDate({ dueDate, projectPath: this.projectPathForActiveIssue }); } catch (e) { createFlash({ message: this.$options.i18n.updateDueDateError }); } finally { diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue index 31094939733..9d537a4ef2c 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue @@ -21,9 +21,9 @@ export default { }, inject: ['labelsFetchPath', 'labelsManagePath', 'labelsFilterBasePath'], computed: { - ...mapGetters({ issue: 'activeIssue' }), + ...mapGetters(['activeIssue', 'projectPathForActiveIssue']), selectedLabels() { - const { labels = [] } = this.issue; + const { labels = [] } = this.activeIssue; return labels.map(label => ({ ...label, @@ -31,17 +31,13 @@ export default { })); }, issueLabels() { - const { labels = [] } = this.issue; + const { labels = [] } = this.activeIssue; return labels.map(label => ({ ...label, scoped: isScopedLabel(label), })); }, - projectPath() { - const { referencePath = '' } = this.issue; - return referencePath.slice(0, referencePath.indexOf('#')); - }, }, methods: { ...mapActions(['setActiveIssueLabels']), @@ -55,7 +51,7 @@ export default { .filter(label => !payload.find(selected => selected.id === label.id)) .map(label => label.id); - const input = { addLabelIds, removeLabelIds, projectPath: this.projectPath }; + const input = { addLabelIds, removeLabelIds, projectPath: this.projectPathForActiveIssue }; await this.setActiveIssueLabels(input); } catch (e) { createFlash({ message: __('An error occurred while updating labels.') }); @@ -68,7 +64,7 @@ export default { try { const removeLabelIds = [getIdFromGraphQLId(id)]; - const input = { removeLabelIds, projectPath: this.projectPath }; + const input = { removeLabelIds, projectPath: this.projectPathForActiveIssue }; await this.setActiveIssueLabels(input); } catch (e) { createFlash({ message: __('An error occurred when removing the label.') }); diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_subscription.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_subscription.vue new file mode 100644 index 00000000000..ed069cea630 --- /dev/null +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_subscription.vue @@ -0,0 +1,71 @@ +<script> +import { mapGetters, mapActions } from 'vuex'; +import { GlToggle } from '@gitlab/ui'; +import createFlash from '~/flash'; +import { __, s__ } from '~/locale'; + +export default { + i18n: { + header: { + title: __('Notifications'), + /* Any change to subscribeDisabledDescription + must be reflected in app/helpers/notifications_helper.rb */ + subscribeDisabledDescription: __( + 'Notifications have been disabled by the project or group owner', + ), + }, + updateSubscribedErrorMessage: s__( + 'IssueBoards|An error occurred while setting notifications status.', + ), + }, + components: { + GlToggle, + }, + data() { + return { + loading: false, + }; + }, + computed: { + ...mapGetters(['activeIssue', 'projectPathForActiveIssue']), + notificationText() { + return this.activeIssue.emailsDisabled + ? this.$options.i18n.header.subscribeDisabledDescription + : this.$options.i18n.header.title; + }, + }, + methods: { + ...mapActions(['setActiveIssueSubscribed']), + async handleToggleSubscription() { + this.loading = true; + + try { + await this.setActiveIssueSubscribed({ + subscribed: !this.activeIssue.subscribed, + projectPath: this.projectPathForActiveIssue, + }); + } catch (error) { + createFlash({ message: this.$options.i18n.updateSubscribedErrorMessage }); + } finally { + this.loading = false; + } + }, + }, +}; +</script> + +<template> + <div + class="gl-display-flex gl-align-items-center gl-justify-content-space-between" + data-testid="sidebar-notifications" + > + <span data-testid="notification-header-text"> {{ notificationText }} </span> + <gl-toggle + v-if="!activeIssue.emailsDisabled" + :value="activeIssue.subscribed" + :is-loading="loading" + data-testid="notification-subscribe-toggle" + @change="handleToggleSubscription" + /> + </div> +</template> diff --git a/app/assets/javascripts/boards/graphql/mutations/issue_set_subscription.mutation.graphql b/app/assets/javascripts/boards/graphql/mutations/issue_set_subscription.mutation.graphql new file mode 100644 index 00000000000..1f383245ac2 --- /dev/null +++ b/app/assets/javascripts/boards/graphql/mutations/issue_set_subscription.mutation.graphql @@ -0,0 +1,8 @@ +mutation issueSetSubscription($input: IssueSetSubscriptionInput!) { + issueSetSubscription(input: $input) { + issue { + subscribed + } + errors + } +} diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 2552a3a4113..dd950a45076 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -24,6 +24,7 @@ import destroyBoardListMutation from '../queries/board_list_destroy.mutation.gra 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'; const notImplemented = () => { /* eslint-disable-next-line @gitlab/require-i18n-strings */ @@ -423,6 +424,29 @@ export default { }); }, + setActiveIssueSubscribed: async ({ commit, getters }, input) => { + const { data } = await gqlClient.mutate({ + mutation: issueSetSubscriptionMutation, + variables: { + input: { + iid: String(getters.activeIssue.iid), + projectPath: input.projectPath, + subscribedState: input.subscribed, + }, + }, + }); + + if (data.issueSetSubscription?.errors?.length > 0) { + throw new Error(data.issueSetSubscription.errors); + } + + commit(types.UPDATE_ISSUE_BY_ID, { + issueId: getters.activeIssue.id, + prop: 'subscribed', + value: data.issueSetSubscription.issue.subscribed, + }); + }, + fetchBacklog: () => { notImplemented(); }, diff --git a/app/assets/javascripts/boards/stores/getters.js b/app/assets/javascripts/boards/stores/getters.js index f717b4101ab..cd28b4a0ff7 100644 --- a/app/assets/javascripts/boards/stores/getters.js +++ b/app/assets/javascripts/boards/stores/getters.js @@ -24,6 +24,11 @@ export default { return state.issues[state.activeId] || {}; }, + projectPathForActiveIssue: (_, getters) => { + const referencePath = getters.activeIssue.referencePath || ''; + return referencePath.slice(0, referencePath.indexOf('#')); + }, + getListByLabelId: state => labelId => { return find(state.boardLists, l => l.label?.id === labelId); }, |