diff options
Diffstat (limited to 'app/assets/javascripts/design_management/components/design_todo_button.vue')
-rw-r--r-- | app/assets/javascripts/design_management/components/design_todo_button.vue | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/app/assets/javascripts/design_management/components/design_todo_button.vue b/app/assets/javascripts/design_management/components/design_todo_button.vue new file mode 100644 index 00000000000..aff4f348d15 --- /dev/null +++ b/app/assets/javascripts/design_management/components/design_todo_button.vue @@ -0,0 +1,168 @@ +<script> +import todoMarkDoneMutation from '~/graphql_shared/mutations/todo_mark_done.mutation.graphql'; +import getDesignQuery from '../graphql/queries/get_design.query.graphql'; +import createDesignTodoMutation from '../graphql/mutations/create_design_todo.mutation.graphql'; +import TodoButton from '~/vue_shared/components/todo_button.vue'; +import allVersionsMixin from '../mixins/all_versions'; +import { updateStoreAfterDeleteDesignTodo } from '../utils/cache_update'; +import { findIssueId, findDesignId } from '../utils/design_management_utils'; +import { CREATE_DESIGN_TODO_ERROR, DELETE_DESIGN_TODO_ERROR } from '../utils/error_messages'; + +export default { + components: { + TodoButton, + }, + mixins: [allVersionsMixin], + props: { + design: { + type: Object, + required: true, + }, + }, + inject: { + projectPath: { + default: '', + }, + issueIid: { + default: '', + }, + }, + data() { + return { + todoLoading: false, + }; + }, + computed: { + designVariables() { + return { + fullPath: this.projectPath, + iid: this.issueIid, + filenames: [this.$route.params.id], + atVersion: this.designsVersion, + }; + }, + designTodoVariables() { + return { + projectPath: this.projectPath, + issueId: findIssueId(this.design.issue.id), + designId: findDesignId(this.design.id), + issueIid: this.issueIid, + filenames: [this.$route.params.id], + atVersion: this.designsVersion, + }; + }, + pendingTodo() { + // TODO data structure pending BE MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40555#note_405732940 + return this.design.currentUserTodos?.nodes[0]; + }, + hasPendingTodo() { + return Boolean(this.pendingTodo); + }, + }, + methods: { + updateGlobalTodoCount(additionalTodoCount) { + const currentCount = parseInt(document.querySelector('.js-todos-count').innerText, 10); + const todoToggleEvent = new CustomEvent('todo:toggle', { + detail: { + count: Math.max(currentCount + additionalTodoCount, 0), + }, + }); + + document.dispatchEvent(todoToggleEvent); + }, + incrementGlobalTodoCount() { + this.updateGlobalTodoCount(1); + }, + decrementGlobalTodoCount() { + this.updateGlobalTodoCount(-1); + }, + createTodo() { + this.todoLoading = true; + return this.$apollo + .mutate({ + mutation: createDesignTodoMutation, + variables: this.designTodoVariables, + update: (store, { data: { createDesignTodo } }) => { + // because this is a @client mutation, + // we control what is in errors, and therefore + // we are certain that there is at most 1 item in the array + const createDesignTodoError = (createDesignTodo.errors || [])[0]; + if (createDesignTodoError) { + this.$emit('error', Error(createDesignTodoError.message)); + } + }, + }) + .then(() => { + this.incrementGlobalTodoCount(); + }) + .catch(err => { + this.$emit('error', Error(CREATE_DESIGN_TODO_ERROR)); + throw err; + }) + .finally(() => { + this.todoLoading = false; + }); + }, + deleteTodo() { + if (!this.hasPendingTodo) return Promise.reject(); + + const { id } = this.pendingTodo; + const { designVariables } = this; + + this.todoLoading = true; + return this.$apollo + .mutate({ + mutation: todoMarkDoneMutation, + variables: { + id, + }, + update( + store, + { + data: { todoMarkDone }, + }, + ) { + const todoMarkDoneFirstError = (todoMarkDone.errors || [])[0]; + if (todoMarkDoneFirstError) { + this.$emit('error', Error(todoMarkDoneFirstError)); + } else { + updateStoreAfterDeleteDesignTodo( + store, + todoMarkDone, + getDesignQuery, + designVariables, + ); + } + }, + }) + .then(() => { + this.decrementGlobalTodoCount(); + }) + .catch(err => { + this.$emit('error', Error(DELETE_DESIGN_TODO_ERROR)); + throw err; + }) + .finally(() => { + this.todoLoading = false; + }); + }, + toggleTodo() { + if (this.hasPendingTodo) { + return this.deleteTodo(); + } + + return this.createTodo(); + }, + }, +}; +</script> + +<template> + <todo-button + issuable-type="design" + :issuable-id="design.iid" + :is-todo="hasPendingTodo" + :loading="todoLoading" + @click.stop.prevent="toggleTodo" + /> +</template> |