Skip to content
Snippets Groups Projects
Commit bc8c209c authored by Natalia Tepluhina's avatar Natalia Tepluhina
Browse files

Merge branch '346132-delete-a-task' into 'master'

Add delete work item button

See merge request !85589
parents 8da66777 9405b69b
No related branches found
No related tags found
1 merge request!85589Add delete work item button
Pipeline #526711412 failed
Pipeline: GitLab

#526734075

    Showing
    with 85 additions and 71 deletions
    ......@@ -21,7 +21,7 @@ export default {
    required: false,
    default: null,
    },
    canUpdate: {
    canDelete: {
    type: Boolean,
    required: false,
    default: false,
    ......@@ -63,7 +63,7 @@ export default {
    </script>
    <template>
    <div v-if="canUpdate">
    <div v-if="canDelete">
    <gl-dropdown
    icon="ellipsis_v"
    text-sr-only
    ......
    ......@@ -3,6 +3,7 @@ import { GlAlert } from '@gitlab/ui';
    import { i18n } from '../constants';
    import workItemQuery from '../graphql/work_item.query.graphql';
    import workItemTitleSubscription from '../graphql/work_item_title.subscription.graphql';
    import WorkItemActions from './work_item_actions.vue';
    import WorkItemState from './work_item_state.vue';
    import WorkItemTitle from './work_item_title.vue';
    ......@@ -10,6 +11,7 @@ export default {
    i18n,
    components: {
    GlAlert,
    WorkItemActions,
    WorkItemTitle,
    WorkItemState,
    },
    ......@@ -57,6 +59,17 @@ export default {
    workItemType() {
    return this.workItem.workItemType?.name;
    },
    canUpdate() {
    return this.workItem?.userPermissions?.updateWorkItem;
    },
    canDelete() {
    return this.workItem?.userPermissions?.deleteWorkItem;
    },
    },
    methods: {
    handleWorkItemDeleted() {
    this.$emit('workItemDeleted');
    },
    },
    };
    </script>
    ......@@ -67,13 +80,23 @@ export default {
    {{ error }}
    </gl-alert>
    <work-item-title
    :loading="workItemLoading"
    :work-item-id="workItem.id"
    :work-item-title="workItem.title"
    :work-item-type="workItemType"
    @error="error = $event"
    />
    <div class="gl-display-flex">
    <work-item-title
    :loading="workItemLoading"
    :work-item-id="workItem.id"
    :work-item-title="workItem.title"
    :work-item-type="workItemType"
    class="gl-mr-5"
    @error="error = $event"
    />
    <work-item-actions
    :work-item-id="workItem.id"
    :can-delete="canDelete"
    class="gl-ml-auto gl-mt-5"
    @workItemDeleted="handleWorkItemDeleted"
    @error="error = $event"
    />
    </div>
    <work-item-state :loading="workItemLoading" :work-item="workItem" @error="error = $event" />
    </section>
    </template>
    <script>
    import { GlAlert, GlButton, GlModal } from '@gitlab/ui';
    import WorkItemActions from './work_item_actions.vue';
    import { GlAlert, GlModal } from '@gitlab/ui';
    import WorkItemDetail from './work_item_detail.vue';
    export default {
    components: {
    GlAlert,
    GlButton,
    GlModal,
    WorkItemDetail,
    WorkItemActions,
    },
    props: {
    canUpdate: {
    type: Boolean,
    required: false,
    default: false,
    },
    visible: {
    type: Boolean,
    required: true,
    ......@@ -50,32 +42,25 @@ export default {
    </script>
    <template>
    <gl-modal hide-footer modal-id="work-item-detail-modal" :visible="visible" @hide="closeModal">
    <template #modal-header>
    <div class="gl-w-full gl-display-flex gl-align-items-center gl-justify-content-end">
    <h2 class="modal-title gl-mr-auto">{{ s__('WorkItem|Work Item') }}</h2>
    <work-item-actions
    :work-item-id="workItemId"
    :can-update="canUpdate"
    @workItemDeleted="handleWorkItemDeleted"
    @error="setErrorMessage"
    />
    <gl-button category="tertiary" icon="close" :aria-label="__('Close')" @click="closeModal" />
    </div>
    </template>
    <gl-modal
    hide-footer
    size="lg"
    modal-id="work-item-detail-modal"
    :visible="visible"
    @hide="closeModal"
    >
    <gl-alert v-if="error" variant="danger" @dismiss="error = false">
    {{ error }}
    </gl-alert>
    <work-item-detail :work-item-id="workItemId" />
    <work-item-detail :work-item-id="workItemId" @workItemDeleted="handleWorkItemDeleted" />
    </gl-modal>
    </template>
    <style>
    /* hide the existing close button until we can do it
    * with https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2710
    /* hide the existing modal header
    */
    #work-item-detail-modal .modal-header > .gl-button {
    #work-item-detail-modal .modal-header {
    display: none;
    }
    </style>
    ......@@ -6,4 +6,8 @@ fragment WorkItem on WorkItem {
    id
    name
    }
    userPermissions {
    deleteWorkItem
    updateWorkItem
    }
    }
    ......@@ -115,21 +115,15 @@ export default {
    },
    },
    update(store, { data: { workItemCreate } }) {
    const { id, title, workItemType, state } = workItemCreate.workItem;
    const { workItem } = workItemCreate;
    store.writeQuery({
    query: workItemQuery,
    variables: {
    id,
    id: workItem.id,
    },
    data: {
    workItem: {
    __typename: 'WorkItem',
    id,
    title,
    state,
    workItemType,
    },
    workItem,
    },
    });
    },
    ......
    <script>
    import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
    import { convertToGraphQLId } from '~/graphql_shared/utils';
    import { s__ } from '~/locale';
    import WorkItemDetail from '../components/work_item_detail.vue';
    export default {
    ......@@ -18,9 +19,15 @@ export default {
    return convertToGraphQLId(TYPE_WORK_ITEM, this.id);
    },
    },
    methods: {
    handleWorkItemDeleted() {
    this.$root.$toast.show(s__('WorkItem|Work item deleted'));
    this.$router.push('/');
    },
    },
    };
    </script>
    <template>
    <work-item-detail :work-item-id="gid" />
    <work-item-detail :work-item-id="gid" @workItemDeleted="handleWorkItemDeleted" />
    </template>
    import { GlToast } from '@gitlab/ui';
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    import { joinPaths } from '~/lib/utils/url_utility';
    import { routes } from './routes';
    Vue.use(GlToast);
    Vue.use(VueRouter);
    export function createRouter(fullPath) {
    ......
    ......@@ -42826,9 +42826,6 @@ msgstr ""
    msgid "WorkItem|Type"
    msgstr ""
     
    msgid "WorkItem|Work Item"
    msgstr ""
    msgid "WorkItem|Work Items"
    msgstr ""
     
    ......
    ......@@ -18,13 +18,13 @@ describe('WorkItemActions component', () => {
    const findDeleteButton = () => wrapper.findComponent(GlDropdownItem);
    const createComponent = ({
    canUpdate = true,
    canDelete = true,
    deleteWorkItemHandler = jest.fn().mockResolvedValue(deleteWorkItemResponse),
    } = {}) => {
    glModalDirective = jest.fn();
    wrapper = shallowMount(WorkItemActions, {
    apolloProvider: createMockApollo([[deleteWorkItem, deleteWorkItemHandler]]),
    propsData: { workItemId: '123', canUpdate },
    propsData: { workItemId: '123', canDelete },
    directives: {
    glModal: {
    bind(_, { value }) {
    ......@@ -93,9 +93,9 @@ describe('WorkItemActions component', () => {
    expect(wrapper.emitted('workItemDeleted')).toBeUndefined();
    });
    it('does not render when canUpdate is false', () => {
    it('does not render when canDelete is false', () => {
    createComponent({
    canUpdate: false,
    canDelete: false,
    });
    expect(wrapper.html()).toBe('');
    ......
    ......@@ -4,7 +4,6 @@ import Vue from 'vue';
    import VueApollo from 'vue-apollo';
    import WorkItemDetail from '~/work_items/components/work_item_detail.vue';
    import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
    import WorkItemActions from '~/work_items/components/work_item_actions.vue';
    describe('WorkItemDetailModal component', () => {
    let wrapper;
    ......@@ -12,12 +11,11 @@ describe('WorkItemDetailModal component', () => {
    Vue.use(VueApollo);
    const findModal = () => wrapper.findComponent(GlModal);
    const findWorkItemActions = () => wrapper.findComponent(WorkItemActions);
    const findWorkItemDetail = () => wrapper.findComponent(WorkItemDetail);
    const createComponent = ({ visible = true, workItemId = '1', canUpdate = false } = {}) => {
    const createComponent = ({ visible = true, workItemId = '1' } = {}) => {
    wrapper = shallowMount(WorkItemDetailModal, {
    propsData: { visible, workItemId, canUpdate },
    propsData: { visible, workItemId },
    stubs: {
    GlModal,
    },
    ......@@ -36,23 +34,9 @@ describe('WorkItemDetailModal component', () => {
    });
    });
    it('renders heading', () => {
    createComponent();
    expect(wrapper.find('h2').text()).toBe('Work Item');
    });
    it('renders WorkItemDetail', () => {
    createComponent();
    expect(findWorkItemDetail().props()).toEqual({ workItemId: '1' });
    });
    it('shows work item actions', () => {
    createComponent({
    canUpdate: true,
    });
    expect(findWorkItemActions().exists()).toBe(true);
    });
    });
    ......@@ -10,6 +10,10 @@ export const workItemQueryResponse = {
    id: 'gid://gitlab/WorkItems::Type/5',
    name: 'Task',
    },
    userPermissions: {
    deleteWorkItem: false,
    updateWorkItem: false,
    },
    },
    },
    };
    ......@@ -28,6 +32,10 @@ export const updateWorkItemMutationResponse = {
    id: 'gid://gitlab/WorkItems::Type/5',
    name: 'Task',
    },
    userPermissions: {
    deleteWorkItem: false,
    updateWorkItem: false,
    },
    },
    },
    },
    ......@@ -61,6 +69,10 @@ export const createWorkItemMutationResponse = {
    id: 'gid://gitlab/WorkItems::Type/5',
    name: 'Task',
    },
    userPermissions: {
    deleteWorkItem: false,
    updateWorkItem: false,
    },
    },
    },
    },
    ......@@ -75,6 +87,10 @@ export const createWorkItemFromTaskMutationResponse = {
    descriptionHtml: '<p>New description</p>',
    id: 'gid://gitlab/WorkItem/13',
    __typename: 'WorkItem',
    userPermissions: {
    deleteWorkItem: false,
    updateWorkItem: false,
    },
    },
    },
    },
    ......
    ......@@ -26,6 +26,8 @@ describe('Work items root component', () => {
    it('renders WorkItemDetail', () => {
    createComponent();
    expect(findWorkItemDetail().props()).toEqual({ workItemId: 'gid://gitlab/WorkItem/1' });
    expect(findWorkItemDetail().props()).toEqual({
    workItemId: 'gid://gitlab/WorkItem/1',
    });
    });
    });
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment