summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/work_items/components/work_item_todos.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/work_items/components/work_item_todos.vue')
-rw-r--r--app/assets/javascripts/work_items/components/work_item_todos.vue116
1 files changed, 116 insertions, 0 deletions
diff --git a/app/assets/javascripts/work_items/components/work_item_todos.vue b/app/assets/javascripts/work_items/components/work_item_todos.vue
new file mode 100644
index 00000000000..4e787720a42
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_todos.vue
@@ -0,0 +1,116 @@
+<script>
+import { GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { updateGlobalTodoCount } from '~/sidebar/utils';
+import { getWorkItemTodoOptimisticResponse } from '../utils';
+import { ADD, MARK_AS_DONE, TODO_ADD_ICON, TODO_DONE_ICON } from '../constants';
+import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
+
+export default {
+ i18n: {
+ addATodo: s__('WorkItem|Add a to do'),
+ markAsDone: s__('WorkItem|Mark as done'),
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlIcon,
+ GlButton,
+ },
+ props: {
+ workItem: {
+ type: Object,
+ required: true,
+ },
+ currentUserTodos: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ data() {
+ return {
+ isLoading: false,
+ buttonLabel:
+ this.currentUserTodos.length > 0
+ ? this.$options.i18n.markAsDone
+ : this.$options.i18n.addATodo,
+ };
+ },
+ computed: {
+ pendingTodo() {
+ return this.currentUserTodos.length > 0;
+ },
+ buttonIcon() {
+ return this.pendingTodo ? TODO_DONE_ICON : TODO_ADD_ICON;
+ },
+ },
+ methods: {
+ onToggle() {
+ this.isLoading = true;
+ this.buttonLabel = '';
+ const action = this.pendingTodo ? MARK_AS_DONE : ADD;
+ const inputVariables = {
+ id: this.workItem.id,
+ currentUserTodosWidget: {
+ action,
+ },
+ };
+ this.$apollo
+ .mutate({
+ mutation: updateWorkItemMutation,
+ variables: {
+ input: inputVariables,
+ },
+ optimisticResponse: getWorkItemTodoOptimisticResponse({
+ workItem: this.workItem,
+ pendingTodo: this.pendingTodo,
+ }),
+ })
+ .then(
+ ({
+ data: {
+ workItemUpdate: { errors },
+ },
+ }) => {
+ if (errors?.length) {
+ throw new Error(errors[0]);
+ }
+ if (this.pendingTodo) {
+ updateGlobalTodoCount(1);
+ this.buttonLabel = this.$options.i18n.markAsDone;
+ } else {
+ updateGlobalTodoCount(-1);
+ this.buttonLabel = this.$options.i18n.addATodo;
+ }
+ },
+ )
+ .catch((error) => {
+ this.$emit('error', error.message);
+ })
+ .finally(() => {
+ this.isLoading = false;
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-button
+ v-gl-tooltip.hover
+ data-testid="work-item-todos-action"
+ :loading="isLoading"
+ :title="buttonLabel"
+ category="tertiary"
+ :aria-label="buttonLabel"
+ @click="onToggle"
+ >
+ <gl-icon
+ data-testid="work-item-todos-icon"
+ :class="{ 'gl-fill-blue-500': pendingTodo }"
+ :name="buttonIcon"
+ />
+ </gl-button>
+</template>