Commit 30540a98 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '342970-labels-widget-architecture-consolidation' into 'master'

Consolidate labels widget architecture

See merge request gitlab-org/gitlab!72356
parents a42a6d5e 7f13bc9e
......@@ -15,6 +15,7 @@ import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue
import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue';
import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import SidebarLabelsWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
......@@ -63,7 +64,7 @@ export default {
'groupPathForActiveIssue',
'projectPathForActiveIssue',
]),
...mapState(['sidebarType', 'issuableType', 'isSettingLabels']),
...mapState(['sidebarType', 'issuableType']),
isIssuableSidebar() {
return this.sidebarType === ISSUABLE;
},
......@@ -84,7 +85,10 @@ export default {
});
},
attrWorkspacePath() {
return this.isGroupBoard ? this.groupPathForActiveIssue : undefined;
return this.isGroupBoard ? this.groupPathForActiveIssue : this.projectPathForActiveIssue;
},
labelType() {
return this.isGroupBoard ? LabelType.group : LabelType.project;
},
},
methods: {
......@@ -98,21 +102,19 @@ export default {
handleClose() {
this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType });
},
handleUpdateSelectedLabels(input) {
handleUpdateSelectedLabels({ labels, id }) {
this.setActiveBoardItemLabels({
iid: this.activeBoardItem.iid,
id,
projectPath: this.projectPathForActiveIssue,
addLabelIds: input.map((label) => getIdFromGraphQLId(label.id)),
removeLabelIds: this.activeBoardItem.labels
.filter((label) => !input.find((selected) => selected.id === label.id))
.map((label) => label.id),
labelIds: labels.map((label) => getIdFromGraphQLId(label.id)),
labels,
});
},
handleLabelRemove(input) {
handleLabelRemove(removeLabelId) {
this.setActiveBoardItemLabels({
iid: this.activeBoardItem.iid,
projectPath: this.projectPathForActiveIssue,
removeLabelIds: [input],
removeLabelIds: [removeLabelId],
});
},
},
......@@ -207,14 +209,13 @@ export default {
:full-path="projectPathForActiveIssue"
:allow-label-remove="allowLabelEdit"
:allow-multiselect="true"
:selected-labels="activeBoardItem.labels"
:labels-select-in-progress="isSettingLabels"
:footer-create-label-title="createLabelTitle"
:footer-manage-label-title="manageLabelTitle"
:labels-create-title="createLabelTitle"
:labels-filter-base-path="projectPathForActiveIssue"
:attr-workspace-path="attrWorkspacePath"
:issuable-type="issuableType"
:label-type="labelType"
@onLabelRemove="handleLabelRemove"
@updateSelectedLabels="handleUpdateSelectedLabels"
>
......
......@@ -91,9 +91,7 @@ export default {
try {
const addLabelIds = payload.filter((label) => label.set).map((label) => label.id);
const removeLabelIds = this.selectedLabels
.filter((label) => !payload.find((selected) => selected.id === label.id))
.map((label) => label.id);
const removeLabelIds = payload.filter((label) => !label.set).map((label) => label.id);
const input = {
addLabelIds,
......@@ -164,7 +162,7 @@ export default {
:labels-list-title="__('Select label')"
:dropdown-button-text="__('Choose labels')"
:is-editing="edit"
variant="embedded"
variant="sidebar"
class="gl-display-block labels gl-w-full"
@updateSelectedLabels="setLabels"
>
......
......@@ -656,30 +656,45 @@ export default {
},
setActiveIssueLabels: async ({ commit, getters }, input) => {
commit(types.SET_LABELS_LOADING, true);
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetLabelsMutation,
variables: {
input: {
iid: input.iid || String(activeBoardItem.iid),
addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [],
projectPath: input.projectPath,
if (!gon.features?.labelsWidget) {
const { data } = await gqlClient.mutate({
mutation: issueSetLabelsMutation,
variables: {
input: {
iid: input.iid || String(activeBoardItem.iid),
labelIds: input.labelsId ?? undefined,
addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [],
projectPath: input.projectPath,
},
},
},
});
});
if (data.updateIssue?.errors?.length > 0) {
throw new Error(data.updateIssue.errors);
}
commit(types.SET_LABELS_LOADING, false);
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: data.updateIssue?.issue?.id || activeBoardItem.id,
prop: 'labels',
value: data.updateIssue?.issue?.labels.nodes,
});
if (data.updateIssue?.errors?.length > 0) {
throw new Error(data.updateIssue.errors);
return;
}
let labels = input?.labels || [];
if (input.removeLabelIds) {
labels = activeBoardItem.labels.filter(
(label) => input.removeLabelIds[0] !== getIdFromGraphQLId(label.id),
);
}
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: data.updateIssue?.issue?.id || activeBoardItem.id,
itemId: input.id || activeBoardItem.id,
prop: 'labels',
value: data.updateIssue.issue.labels.nodes,
value: labels,
});
},
......
......@@ -28,7 +28,6 @@ export const ADD_BOARD_ITEM_TO_LIST = 'ADD_BOARD_ITEM_TO_LIST';
export const REMOVE_BOARD_ITEM_FROM_LIST = 'REMOVE_BOARD_ITEM_FROM_LIST';
export const SET_ACTIVE_ID = 'SET_ACTIVE_ID';
export const UPDATE_BOARD_ITEM_BY_ID = 'UPDATE_BOARD_ITEM_BY_ID';
export const SET_LABELS_LOADING = 'SET_LABELS_LOADING';
export const SET_ASSIGNEE_LOADING = 'SET_ASSIGNEE_LOADING';
export const RESET_ISSUES = 'RESET_ISSUES';
export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS';
......
......@@ -195,10 +195,6 @@ export default {
Vue.set(state.boardItems[itemId], prop, value);
},
[mutationTypes.SET_LABELS_LOADING](state, isLoading) {
state.isSettingLabels = isLoading;
},
[mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) {
state.isSettingAssignees = isLoading;
},
......
......@@ -12,7 +12,6 @@ export default () => ({
listsFlags: {},
boardItemsByListId: {},
backupItemsList: [],
isSettingLabels: false,
isSettingAssignees: false,
pageInfoByListId: {},
boardItems: {},
......
......@@ -11,6 +11,7 @@ import { toLabelGid } from '~/sidebar/utils';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_vue/constants';
import LabelsSelect from '~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue';
import LabelsSelectWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const mutationMap = {
......@@ -48,6 +49,7 @@ export default {
return {
isLabelsSelectInProgress: false,
selectedLabels: this.initiallySelectedLabels,
LabelType,
};
},
methods: {
......@@ -154,13 +156,11 @@ export default {
:footer-manage-label-title="__('Manage project labels')"
:labels-create-title="__('Create project label')"
:labels-filter-base-path="projectIssuesPath"
:labels-select-in-progress="isLabelsSelectInProgress"
:selected-labels="selectedLabels"
:variant="$options.variant"
:issuable-type="issuableType"
:attr-workspace-path="fullPath"
:label-type="LabelType.project"
data-qa-selector="labels_block"
@onLabelRemove="handleLabelRemove"
@updateSelectedLabels="handleUpdateSelectedLabels"
>
{{ __('None') }}
</labels-select-widget>
......
import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
import { IssuableType } from '~/issue_show/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import epicConfidentialQuery from '~/sidebar/queries/epic_confidential.query.graphql';
......@@ -29,6 +30,7 @@ import updateIssueConfidentialMutation from '~/sidebar/queries/update_issue_conf
import updateIssueDueDateMutation from '~/sidebar/queries/update_issue_due_date.mutation.graphql';
import updateIssueSubscriptionMutation from '~/sidebar/queries/update_issue_subscription.mutation.graphql';
import mergeRequestMilestoneMutation from '~/sidebar/queries/update_merge_request_milestone.mutation.graphql';
import updateMergeRequestLabelsMutation from '~/sidebar/queries/update_merge_request_labels.mutation.graphql';
import updateMergeRequestSubscriptionMutation from '~/sidebar/queries/update_merge_request_subscription.mutation.graphql';
import updateAlertAssigneesMutation from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql';
import epicLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql';
......@@ -120,6 +122,17 @@ export const labelsQueries = {
},
};
export const labelsMutations = {
[IssuableType.Issue]: {
mutation: updateIssueLabelsMutation,
mutationName: 'updateIssue',
},
[IssuableType.MergeRequest]: {
mutation: updateMergeRequestLabelsMutation,
mutationName: 'mergeRequestSetLabels',
},
};
export const dateTypes = {
start: 'startDate',
due: 'dueDate',
......
......@@ -5,3 +5,8 @@ export const DropdownVariant = {
Standalone: 'standalone',
Embedded: 'embedded',
};
export const LabelType = {
group: 'GroupLabel',
project: 'ProjectLabel',
};
......@@ -68,8 +68,11 @@ export default {
},
attrWorkspacePath: {
type: String,
required: false,
default: undefined,
required: true,
},
labelType: {
type: String,
required: true,
},
},
data() {
......@@ -119,13 +122,16 @@ export default {
if (newVal) {
this.$refs.dropdown.show();
this.isDirty = false;
this.localSelectedLabels = this.selectedLabels;
} else {
this.$refs.dropdown.hide();
this.setLabels();
}
},
selectedLabels(newVal) {
this.localSelectedLabels = newVal;
if (!this.isDirty) {
this.localSelectedLabels = newVal;
}
},
},
created() {
......@@ -193,11 +199,11 @@ export default {
:is="dropdownContentsView"
v-model="localSelectedLabels"
:search-key="searchKey"
:selected-labels="selectedLabels"
:allow-multiselect="allowMultiselect"
:issuable-type="issuableType"
:full-path="fullPath"
:attr-workspace-path="attrWorkspacePath"
:label-type="labelType"
@hideCreateView="toggleDropdownContentsCreateView"
/>
</template>
......
......@@ -2,10 +2,10 @@
import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
import produce from 'immer';
import createFlash from '~/flash';
import { IssuableType } from '~/issue_show/constants';
import { __ } from '~/locale';
import { labelsQueries } from '~/sidebar/constants';
import createLabelMutation from './graphql/create_label.mutation.graphql';
import { LabelType } from './constants';
const errorMessage = __('Error creating label.');
......@@ -30,8 +30,11 @@ export default {
},
attrWorkspacePath: {
type: String,
required: false,
default: undefined,
required: true,
},
labelType: {
type: String,
required: true,
},
},
data() {
......@@ -50,25 +53,13 @@ export default {
return Object.keys(colorsMap).map((color) => ({ [color]: colorsMap[color] }));
},
mutationVariables() {
if (this.issuableType === IssuableType.Epic) {
return {
title: this.labelTitle,
color: this.selectedColor,
groupPath: this.fullPath,
};
}
const attributePath = this.labelType === LabelType.group ? 'groupPath' : 'projectPath';
return this.attrWorkspacePath !== undefined
? {
title: this.labelTitle,
color: this.selectedColor,
groupPath: this.attrWorkspacePath,
}
: {
title: this.labelTitle,
color: this.selectedColor,
projectPath: this.fullPath,
};
return {
title: this.labelTitle,
color: this.selectedColor,
[attributePath]: this.attrWorkspacePath,
};
},
},
methods: {
......
......@@ -19,10 +19,6 @@ export default {
prop: 'localSelectedLabels',
},
props: {
selectedLabels: {
type: Array,
required: true,
},
allowMultiselect: {
type: Boolean,
required: true,
......
<script>
import { MutationOperationMode } from '~/graphql_shared/utils';
import createFlash from '~/flash';
import { IssuableType } from '~/issue_show/constants';
import { __ } from '~/locale';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { labelsQueries } from '~/sidebar/constants';
import { labelsQueries, labelsMutations } from '~/sidebar/constants';
import { DropdownVariant } from './constants';
import DropdownContents from './dropdown_contents.vue';
import DropdownValue from './dropdown_value.vue';
......@@ -50,16 +52,6 @@ export default {
required: false,
default: DropdownVariant.Sidebar,
},
selectedLabels: {
type: Array,
required: false,
default: () => [],
},
labelsSelectInProgress: {
type: Boolean,
required: false,
default: false,
},
labelsFilterBasePath: {
type: String,
required: false,
......@@ -95,25 +87,25 @@ export default {
required: false,
default: __('Manage group labels'),
},
isEditing: {
type: Boolean,
required: false,
default: false,
},
issuableType: {
type: String,
required: true,
},
attrWorkspacePath: {
type: String,
required: false,
default: undefined,
required: true,
},
labelType: {
type: String,
required: true,
},
},
data() {
return {
contentIsOnViewport: true,
issuableLabels: [],
labelsSelectInProgress: false,
oldIid: null,
};
},
computed: {
......@@ -143,9 +135,19 @@ export default {
},
},
},
watch: {
iid(_, oldVal) {
this.oldIid = oldVal;
},
},
methods: {
handleDropdownClose(labels) {
this.$emit('updateSelectedLabels', labels);
if (this.iid !== '') {
this.updateSelectedLabels(this.getUpdateVariables(labels));
} else {
this.$emit('updateSelectedLabels', { labels });
}
this.collapseEditableItem();
},
collapseEditableItem() {
......@@ -154,6 +156,85 @@ export default {
handleCollapsedValueClick() {
this.$emit('toggleCollapse');
},
getUpdateVariables(labels) {
let labelIds = [];
labelIds = labels.map(({ id }) => id);
const currentIid = this.oldIid || this.iid;
const updateVariables = {
iid: currentIid,
projectPath: this.fullPath,
labelIds,
};
switch (this.issuableType) {
case IssuableType.Issue:
return updateVariables;
case IssuableType.MergeRequest:
updateVariables.operationMode = MutationOperationMode.Replace;
return updateVariables;
default:
return {};
}
},
updateSelectedLabels(inputVariables) {
this.labelsSelectInProgress = true;
this.$apollo
.mutate({
mutation: labelsMutations[this.issuableType].mutation,
variables: { input: inputVariables },
})
.then(({ data }) => {
const { mutationName } = labelsMutations[this.issuableType];
if (data[mutationName]?.errors?.length) {
throw new Error();
}
this.$emit('updateSelectedLabels', {
id: data[mutationName]?.[this.issuableType].id,
labels: data[mutationName]?.[this.issuableType].labels?.nodes,
});
})
.catch((error) =>
createFlash({
message: __('An error occurred while updating labels.'),
captureError: true,
error,
}),
)
.finally(() => {
this.labelsSelectInProgress = false;
});
},
getRemoveVariables(labelId) {
const removeVariables = {
iid: this.iid,
projectPath: this.fullPath,
};
switch (this.issuableType) {
case IssuableType.Issue:
return {
...removeVariables,
removeLabelIds: [labelId],
};
case IssuableType.MergeRequest:
return {
...removeVariables,
labelIds: [labelId],
operationMode: MutationOperationMode.Remove,
};
default:
return {};
}
},
handleLabelRemove(labelId) {
this.updateSelectedLabels(this.getRemoveVariables(labelId));
this.$emit('onLabelRemove', labelId);
},
isDropdownVariantSidebar,
isDropdownVariantStandalone,
isDropdownVariantEmbedded,
......@@ -180,6 +261,7 @@ export default {
:title="__('Labels')"
:loading="isLoading"
:can-edit="allowLabelEdit"
@open="oldIid = null"
>
<template #collapsed>
<dropdown-value
......@@ -188,7 +270,7 @@ export default {
:allow-label-remove="allowLabelRemove"
:labels-filter-base-path="labelsFilterBasePath"
:labels-filter-param="labelsFilterParam"
@onLabelRemove="$emit('onLabelRemove', $event)"
@onLabelRemove="handleLabelRemove"
>
<slot></slot>
</dropdown-value>
......@@ -201,7 +283,7 @@ export default {
:labels-filter-base-path="labelsFilterBasePath"
:labels-filter-param="labelsFilterParam"
class="gl-mb-2"
@onLabelRemove="$emit('onLabelRemove', $event)"
@onLabelRemove="handleLabelRemove"
>
<slot></slot>
</dropdown-value>
......@@ -212,12 +294,13 @@ export default {
:footer-create-label-title="footerCreateLabelTitle"
:footer-manage-label-title="footerManageLabelTitle"
:labels-create-title="labelsCreateTitle"
:selected-labels="selectedLabels"
:selected-labels="issuableLabels"
:variant="variant"
:issuable-type="issuableType"
:is-visible="edit"
:full-path="fullPath"
:attr-workspace-path="attrWorkspacePath"
:label-type="labelType"
@setLabels="handleDropdownClose"
@closeDropdown="collapseEditableItem"
/>
......@@ -233,10 +316,12 @@ export default {
:footer-create-label-title="footerCreateLabelTitle"
:footer-manage-label-title="footerManageLabelTitle"
:labels-create-title="labelsCreateTitle"
:selected-labels="selectedLabels"
:selected-labels="issuableLabels"
:variant="variant"
:issuable-type="issuableType"
:full-path="fullPath"
:attr-workspace-path="attrWorkspacePath"
:label-type="labelType"
@setLabels="handleDropdownClose"
/>
</div>
......
......@@ -14,6 +14,7 @@ import { s__ } from '~/locale';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import LabelsSelectVue from '~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue';
import LabelsSelectWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import createEpic from '../queries/createEpic.mutation.graphql';
......@@ -31,7 +32,6 @@ export default {
},
mixins: [glFeatureFlagMixin()],
inject: [
'iid',
'groupPath',
'groupEpicsPath',
'labelsFetchPath',
......@@ -48,6 +48,7 @@ export default {
startDateFixed: null,
dueDateFixed: null,
loading: false,
LabelType,
};
},
computed: {
......@@ -190,17 +191,17 @@ export default {
<labels-select-widget
v-if="glFeatures.labelsWidget"
class="block labels js-labels-block"
:iid="iid"
:full-path="groupPath"
:allow-label-create="true"
:allow-multiselect="true"
:allow-scoped-labels="false"
:labels-filter-base-path="groupEpicsPath"
:selected-labels="labels"
:attr-workspace-path="groupPath"
:label-type="LabelType.group"
issuable-type="epic"
variant="embedded"
data-qa-selector="labels_block"
@updateSelectedLabels="handleUpdateSelectedLabels"
@updateSelectedLabels="handleUpdateSelectedLabels($event.labels)"
>
{{ __('None') }}
</labels-select-widget>
......
......@@ -11,12 +11,11 @@ RSpec.describe 'Labels Hierarchy', :js do
let!(:grandparent_group_label) { create(:group_label, group: grandparent, title: 'Label_1') }
let!(:parent_group_label) { create(:group_label, group: parent, title: 'Label_2') }
let!(:child_group_label) { create(:group_label, group: child, title: 'Label_3') }
let!(:project_label_1) { create(:label, project: project_1, title: 'Label_4') }
let!(:project_label_1) { create(:label, project: project_1, title: 'Label_3') }
let!(:labeled_issue_1) { create(:labeled_issue, project: project_1, labels: [grandparent_group_label, parent_group_label, child_group_label]) }
let!(:labeled_issue_1) { create(:labeled_issue, project: project_1, labels: [grandparent_group_label, parent_group_label]) }
let!(:labeled_issue_2) { create(:labeled_issue, project: project_1, labels: [grandparent_group_label, parent_group_label]) }
let!(:labeled_issue_3) { create(:labeled_issue, project: project_1, labels: [grandparent_group_label, parent_group_label, child_group_label, project_label_1]) }
let!(:labeled_issue_3) { create(:labeled_issue, project: project_1, labels: [grandparent_group_label, parent_group_label, project_label_1]) }
let!(:not_labeled) { create(:issue, project: project_1) }
before do
......@@ -26,8 +25,8 @@ RSpec.describe 'Labels Hierarchy', :js do
end
shared_examples 'filter for scoped boards' do |project = false|
it 'scopes board to ancestor and descendant labels' do
labels = [grandparent_group_label, parent_group_label, child_group_label]
it 'scopes board to ancestor and current group labels' do
labels = [grandparent_group_label, parent_group_label]
labels.push(project_label_1) if project
labels.each do |label|
......
......@@ -105,6 +105,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
describe('when labels are updated over existing labels', () => {
const testLabelsPayload = [
{ id: 5, set: true },
{ id: 6, set: false },
{ id: 7, set: true },
];
const expectedLabels = [{ id: 5 }, { id: 7 }];
......
......@@ -27,6 +27,7 @@ import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql'
import actions from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import mutations from '~/boards/stores/mutations';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import {
mockLists,
......@@ -1572,12 +1573,13 @@ describe('setActiveIssueLabels', () => {
const getters = { activeBoardItem: mockIssue };
const testLabelIds = labels.map((label) => label.id);
const input = {
addLabelIds: testLabelIds,
labelIds: testLabelIds,
removeLabelIds: [],
projectPath: 'h/b',
labels,
};
it('should assign labels on success, and sets loading state for labels', (done) => {
it('should assign labels on success', (done) => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } });
......@@ -1593,14 +1595,6 @@ describe('setActiveIssueLabels', () => {
input,
{ ...state, ...getters },
[
{
type: types.SET_LABELS_LOADING,
payload: true,
},
{
type: types.SET_LABELS_LOADING,
payload: false,
},
{
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
......@@ -1618,6 +1612,64 @@ describe('setActiveIssueLabels', () => {
await expect(actions.setActiveIssueLabels({ getters }, input)).rejects.toThrow(Error);
});
describe('labels_widget FF on', () => {
beforeEach(() => {
window.gon = {
features: { labelsWidget: true },
};
getters.activeBoardItem = { ...mockIssue, labels };
});
afterEach(() => {
window.gon = {
features: {},
};
});
it('should assign labels', () => {
const payload = {
itemId: getters.activeBoardItem.id,
prop: 'labels',
value: labels,
};
testAction(
actions.setActiveIssueLabels,
input,
{ ...state, ...getters },
[
{
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
[],
);
});
it('should remove label', () => {
const payload = {
itemId: getters.activeBoardItem.id,
prop: 'labels',
value: [labels[1]],
};
testAction(
actions.setActiveIssueLabels,
{ ...input, removeLabelIds: [getIdFromGraphQLId(labels[0].id)] },
{ ...state, ...getters },
[
{
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
[],
);
});
});
});
describe('setActiveItemSubscribed', () => {
......
......@@ -51,6 +51,7 @@ describe('DropdownContentsCreateView', () => {
const createComponent = ({
mutationHandler = createLabelSuccessHandler,
issuableType = IssuableType.Issue,
labelType = 'ProjectLabel',
} = {}) => {
const mockApollo = createMockApollo([[createLabelMutation, mutationHandler]]);
mockApollo.clients.defaultClient.cache.writeQuery({
......@@ -68,6 +69,8 @@ describe('DropdownContentsCreateView', () => {
propsData: {
issuableType,
fullPath: '',
attrWorkspacePath: '',
labelType,
},
});
};
......@@ -174,7 +177,7 @@ describe('DropdownContentsCreateView', () => {
});
it('calls a mutation with `groupPath` variable on the epic', () => {
createComponent({ issuableType: IssuableType.Epic });
createComponent({ issuableType: IssuableType.Epic, labelType: 'GroupLabel' });
fillLabelAttributes();
findCreateButton().vm.$emit('click');
......
......@@ -41,6 +41,8 @@ describe('DropdownContent', () => {
variant: 'sidebar',
issuableType: 'issue',
fullPath: 'test',
labelType: 'ProjectLabel',
attrWorkspacePath: 'path',
...props,
},
data() {
......
......@@ -41,6 +41,7 @@ describe('LabelsSelectRoot', () => {
propsData: {
...config,
issuableType: IssuableType.Issue,
labelType: 'ProjectLabel',
},
stubs: {
SidebarEditableItem,
......@@ -121,11 +122,11 @@ describe('LabelsSelectRoot', () => {
});
});
it('emits `updateSelectedLabels` event on dropdown contents `setLabels` event', async () => {
it('emits `updateSelectedLabels` event on dropdown contents `setLabels` event if iid is not set', async () => {
const label = { id: 'gid://gitlab/ProjectLabel/1' };
createComponent();
createComponent({ config: { ...mockConfig, iid: undefined } });
findDropdownContents().vm.$emit('setLabels', [label]);
expect(wrapper.emitted('updateSelectedLabels')).toEqual([[[label]]]);
expect(wrapper.emitted('updateSelectedLabels')).toEqual([[{ labels: [label] }]]);
});
});
......@@ -40,12 +40,12 @@ export const mockConfig = {
labelsListTitle: 'Assign labels',
labelsCreateTitle: 'Create label',
variant: 'sidebar',
selectedLabels: [mockRegularLabel, mockScopedLabel],
labelsSelectInProgress: false,
labelsFilterBasePath: '/gitlab-org/my-project/issues',
labelsFilterParam: 'label_name',
footerCreateLabelTitle: 'create',
footerManageLabelTitle: 'manage',
attrWorkspacePath: 'test',
};
export const mockSuggestedColors = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment