Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-17 14:33:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-17 14:33:21 +0300
commit7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 (patch)
tree5bdc2229f5198d516781f8d24eace62fc7e589e9 /app/assets/javascripts/sidebar
parent185b095e93520f96e9cfc31d9c3e69b498cdab7c (diff)
Add latest changes from gitlab-org/gitlab@15-6-stable-eev15.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/sidebar')
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_title.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue115
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue35
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue34
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown.vue252
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue185
-rw-r--r--app/assets/javascripts/sidebar/constants.js11
-rw-r--r--app/assets/javascripts/sidebar/mount_milestone_sidebar.js2
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js344
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js4
13 files changed, 657 insertions, 330 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
index 6e18cf36690..2a9100f0cb5 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
@@ -55,6 +55,7 @@ export default {
class="js-sidebar-dropdown-toggle edit-link btn gl-text-gray-900! gl-ml-auto hide-collapsed btn-default btn-sm gl-button btn-default-tertiary float-right"
href="#"
data-test-id="edit-link"
+ data-qa-selector="edit_link"
data-track-action="click_edit_button"
data-track-label="right_sidebar"
data-track-property="assignee"
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index 29ea390a81d..cf07752a0b8 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -56,6 +56,7 @@ export default {
type="button"
class="gl-button btn-link gl-reset-color!"
data-testid="assign-yourself"
+ data-qa-selector="assign_yourself_button"
@click="assignSelf"
>
{{ __('assign yourself') }}
diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
index 0e4d4c74160..d83ae782e26 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -91,6 +91,7 @@ export default {
<div
class="gl-ml-3 gl-line-height-normal gl-display-grid gl-align-items-center"
data-testid="username"
+ data-qa-selector="username"
>
<user-name-with-status :name="user.name" :availability="userAvailability(user)" />
</div>
diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
index 98468583992..c262d65f6ce 100644
--- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
+++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
@@ -170,7 +170,7 @@ export default {
this.$emit('closeForm');
},
openDatePicker() {
- this.$refs.datePicker.calendar.show();
+ this.$refs.datePicker.show();
},
setFixedDate(isFixed) {
const date = this.issuable[dateFields[this.dateType].dateFixed];
diff --git a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
new file mode 100644
index 00000000000..1fff089eab4
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
@@ -0,0 +1,115 @@
+<script>
+import { GlDropdownItem } from '@gitlab/ui';
+import { TYPE_MILESTONE } from '~/graphql_shared/constants';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import { IssuableAttributeType } from '../../constants';
+import SidebarDropdown from '../sidebar_dropdown.vue';
+
+const noMilestone = {
+ id: 0,
+ title: __('No milestone'),
+};
+
+const placeholderMilestone = {
+ id: -1,
+ title: __('Select milestone'),
+};
+
+export default {
+ issuableAttribute: IssuableAttributeType.Milestone,
+ components: {
+ GlDropdownItem,
+ SidebarDropdown,
+ },
+ props: {
+ attrWorkspacePath: {
+ required: true,
+ type: String,
+ },
+ canAdminMilestone: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ issuableType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
+ },
+ },
+ inputName: {
+ type: String,
+ required: false,
+ default: 'update[milestone_id]',
+ },
+ milestoneId: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ milestoneTitle: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ projectMilestonesPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ workspaceType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ },
+ },
+ },
+ data() {
+ return {
+ milestone: this.milestoneId
+ ? { id: convertToGraphQLId(TYPE_MILESTONE, this.milestoneId), title: this.milestoneTitle }
+ : placeholderMilestone,
+ };
+ },
+ computed: {
+ footerItemText() {
+ return this.canAdminMilestone ? __('Manage milestones') : __('View milestones');
+ },
+ value() {
+ return this.milestone.id === placeholderMilestone.id
+ ? undefined
+ : getIdFromGraphQLId(this.milestone.id);
+ },
+ },
+ methods: {
+ handleChange(milestone) {
+ this.milestone = milestone.id === null ? noMilestone : milestone;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <input type="hidden" :name="inputName" :value="value" />
+ <sidebar-dropdown
+ :attr-workspace-path="attrWorkspacePath"
+ :current-attribute="milestone"
+ :issuable-attribute="$options.issuableAttribute"
+ :issuable-type="issuableType"
+ :workspace-type="workspaceType"
+ data-qa-selector="issuable_milestone_dropdown"
+ @change="handleChange"
+ >
+ <template #footer>
+ <gl-dropdown-item v-if="projectMilestonesPath" :href="projectMilestonesPath">
+ {{ footerItemText }}
+ </gl-dropdown-item>
+ </template>
+ </sidebar-dropdown>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index ad061dd2e6b..5f1350690eb 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -9,6 +9,8 @@ import eventHub from '~/sidebar/event_hub';
import Store from '~/sidebar/stores/sidebar_store';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getMergeRequestReviewersQuery from '~/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql';
+import mergeRequestReviewersUpdatedSubscription from '~/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import ReviewerTitle from './reviewer_title.vue';
import Reviewers from './reviewers.vue';
@@ -66,6 +68,36 @@ export default {
error() {
createAlert({ message: __('An error occurred while fetching reviewers.') });
},
+ subscribeToMore: {
+ document() {
+ return mergeRequestReviewersUpdatedSubscription;
+ },
+ variables() {
+ return {
+ issuableId: this.issuable?.id,
+ };
+ },
+ skip() {
+ return !this.issuable?.id || !this.isRealtimeEnabled;
+ },
+ updateQuery(
+ _,
+ {
+ subscriptionData: {
+ data: { mergeRequestReviewersUpdated },
+ },
+ },
+ ) {
+ if (mergeRequestReviewersUpdated) {
+ this.store.setReviewersFromRealtime(
+ mergeRequestReviewersUpdated.reviewers.nodes.map((r) => ({
+ ...r,
+ id: getIdFromGraphQLId(r.id),
+ })),
+ );
+ }
+ },
+ },
},
},
data() {
@@ -87,6 +119,9 @@ export default {
canUpdate() {
return this.issuable.userPermissions?.adminMergeRequest || false;
},
+ isRealtimeEnabled() {
+ return this.glFeatures.realtimeReviewers;
+ },
},
created() {
this.store = new Store();
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue
new file mode 100644
index 00000000000..a135dfdca72
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue
@@ -0,0 +1,34 @@
+<script>
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { state } from './sidebar_reviewers.vue';
+
+export default {
+ data() {
+ return state;
+ },
+ computed: {
+ reviewers() {
+ return this.issuable?.reviewers?.nodes || [];
+ },
+ },
+ methods: {
+ getIdFromGraphQLId,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <input
+ v-for="reviewer in reviewers"
+ :key="reviewer.id"
+ type="hidden"
+ name="merge_request[reviewer_ids][]"
+ :value="getIdFromGraphQLId(reviewer.id)"
+ :data-avatar-url="reviewer.avatarUrl"
+ :data-name="reviewer.name"
+ :data-username="reviewer.username"
+ :data-can-merge="reviewer.mergeRequestInteraction.canMerge"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
new file mode 100644
index 00000000000..26e2bc96f54
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
@@ -0,0 +1,252 @@
+<script>
+import {
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlDropdownText,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import { kebabCase, snakeCase } from 'lodash';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import {
+ defaultEpicSort,
+ dropdowni18nText,
+ epicIidPattern,
+ issuableAttributesQueries,
+ IssuableAttributeState,
+ IssuableAttributeType,
+ IssuableAttributeTypeKeyMap,
+ LocalizedIssuableAttributeType,
+ noAttributeId,
+} from 'ee_else_ce/sidebar/constants';
+import { createAlert } from '~/flash';
+import { PathIdSeparator } from '~/related_issues/constants';
+
+export default {
+ noAttributeId,
+ i18n: {
+ expired: __('(expired)'),
+ },
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlDropdownDivider,
+ GlSearchBoxByType,
+ GlLoadingIcon,
+ },
+ inject: {
+ issuableAttributesQueries: {
+ default: issuableAttributesQueries,
+ },
+ issuableAttributesState: {
+ default: IssuableAttributeState,
+ },
+ widgetTitleText: {
+ default: {
+ [IssuableAttributeType.Milestone]: __('Milestone'),
+ expired: __('(expired)'),
+ none: __('None'),
+ },
+ },
+ },
+ props: {
+ attrWorkspacePath: {
+ required: true,
+ type: String,
+ },
+ currentAttribute: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ issuableAttribute: {
+ type: String,
+ required: true,
+ },
+ issuableType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
+ },
+ },
+ workspaceType: {
+ type: String,
+ required: false,
+ default: WorkspaceType.project,
+ validator(value) {
+ return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ },
+ },
+ },
+ data() {
+ return {
+ attributesList: [],
+ searchTerm: '',
+ skipQuery: true,
+ };
+ },
+ apollo: {
+ attributesList: {
+ query() {
+ const { list } = this.issuableAttributeQuery;
+ const { query } = list[this.issuableType];
+ return query[this.workspaceType] || query;
+ },
+ variables() {
+ if (!this.isEpic) {
+ return {
+ fullPath: this.attrWorkspacePath,
+ title: this.searchTerm,
+ state: this.issuableAttributesState[this.issuableAttribute],
+ };
+ }
+
+ const variables = {
+ fullPath: this.attrWorkspacePath,
+ state: this.issuableAttributesState[this.issuableAttribute],
+ sort: defaultEpicSort,
+ };
+
+ if (epicIidPattern.test(this.searchTerm)) {
+ const matches = this.searchTerm.match(epicIidPattern);
+ variables.iidStartsWith = matches.groups.iid;
+ } else if (this.searchTerm !== '') {
+ variables.in = 'TITLE';
+ variables.title = this.searchTerm;
+ }
+
+ return variables;
+ },
+ update: (data) => data?.workspace?.attributes?.nodes ?? [],
+ error(error) {
+ createAlert({ message: this.i18n.listFetchError, captureError: true, error });
+ },
+ skip() {
+ if (
+ this.isEpic &&
+ this.searchTerm.startsWith(PathIdSeparator.Epic) &&
+ this.searchTerm.length < 2
+ ) {
+ return true;
+ }
+ return this.skipQuery;
+ },
+ debounce: 250,
+ },
+ },
+ computed: {
+ attributeTypeTitle() {
+ return this.widgetTitleText[this.issuableAttribute];
+ },
+ dropdownText() {
+ return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
+ },
+ emptyPropsList() {
+ return this.attributesList.length === 0;
+ },
+ i18n() {
+ const localizedAttribute =
+ LocalizedIssuableAttributeType[IssuableAttributeTypeKeyMap[this.issuableAttribute]];
+ return dropdowni18nText(localizedAttribute, this.issuableType);
+ },
+ isEpic() {
+ // MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311
+ return this.issuableAttribute === IssuableType.Epic;
+ },
+ issuableAttributeQuery() {
+ return this.issuableAttributesQueries[this.issuableAttribute];
+ },
+ formatIssuableAttribute() {
+ return {
+ kebab: kebabCase(this.issuableAttribute),
+ snake: snakeCase(this.issuableAttribute),
+ };
+ },
+ },
+ methods: {
+ isAttributeChecked(attributeId) {
+ return (
+ attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
+ );
+ },
+ isAttributeOverdue(attribute) {
+ return this.issuableAttribute === IssuableAttributeType.Milestone
+ ? attribute?.expired
+ : false;
+ },
+ handleShow() {
+ this.skipQuery = false;
+ },
+ setFocus() {
+ this.$refs.search.focusInput();
+ },
+ show() {
+ this.$refs.dropdown.show();
+ },
+ updateAttribute(attribute) {
+ this.$emit('change', attribute);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="dropdown"
+ block
+ :header-text="i18n.assignAttribute"
+ lazy
+ :text="dropdownText"
+ toggle-class="gl-m-0"
+ @show="handleShow"
+ @shown="setFocus"
+ >
+ <gl-search-box-by-type ref="search" v-model="searchTerm" :placeholder="__('Search')" />
+ <gl-dropdown-item
+ :data-testid="`no-${formatIssuableAttribute.kebab}-item`"
+ is-check-item
+ :is-checked="isAttributeChecked($options.noAttributeId)"
+ @click="$emit('change', { id: $options.noAttributeId })"
+ >
+ {{ i18n.noAttribute }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ <gl-loading-icon
+ v-if="$apollo.queries.attributesList.loading"
+ size="sm"
+ class="gl-py-4"
+ data-testid="loading-icon-dropdown"
+ />
+ <template v-else>
+ <gl-dropdown-text v-if="emptyPropsList">
+ {{ i18n.noAttributesFound }}
+ </gl-dropdown-text>
+ <slot
+ v-else
+ name="list"
+ :attributes-list="attributesList"
+ :is-attribute-checked="isAttributeChecked"
+ :update-attribute="updateAttribute"
+ >
+ <gl-dropdown-item
+ v-for="attrItem in attributesList"
+ :key="attrItem.id"
+ is-check-item
+ :is-checked="isAttributeChecked(attrItem.id)"
+ :data-testid="`${formatIssuableAttribute.kebab}-items`"
+ @click="updateAttribute(attrItem)"
+ >
+ {{ attrItem.title }}
+ <template v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</template>
+ </gl-dropdown-item>
+ </slot>
+ </template>
+ <template #footer>
+ <slot name="footer"></slot>
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
index c33b1468ca4..a685929cdea 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
@@ -1,17 +1,5 @@
<script>
-import {
- GlLink,
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlSearchBoxByType,
- GlDropdownDivider,
- GlLoadingIcon,
- GlIcon,
- GlTooltipDirective,
- GlPopover,
- GlButton,
-} from '@gitlab/ui';
+import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
import { kebabCase, snakeCase } from 'lodash';
import { createAlert } from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -22,19 +10,15 @@ import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
dropdowni18nText,
- Tracking,
- IssuableAttributeState,
- IssuableAttributeType,
LocalizedIssuableAttributeType,
IssuableAttributeTypeKeyMap,
issuableAttributesQueries,
- noAttributeId,
- defaultEpicSort,
- epicIidPattern,
+ IssuableAttributeType,
+ Tracking,
} from 'ee_else_ce/sidebar/constants';
+import SidebarDropdown from './sidebar_dropdown.vue';
export default {
- noAttributeId,
i18n: {
expired: __('(expired)'),
none: __('None'),
@@ -43,17 +27,12 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
- SidebarEditableItem,
GlLink,
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlDropdownDivider,
- GlSearchBoxByType,
GlIcon,
- GlLoadingIcon,
GlPopover,
GlButton,
+ SidebarDropdown,
+ SidebarEditableItem,
},
mixins: [glFeatureFlagMixin()],
inject: {
@@ -63,9 +42,6 @@ export default {
issuableAttributesQueries: {
default: issuableAttributesQueries,
},
- issuableAttributesState: {
- default: IssuableAttributeState,
- },
widgetTitleText: {
default: {
[IssuableAttributeType.Milestone]: __('Milestone'),
@@ -74,7 +50,6 @@ export default {
},
},
},
-
props: {
issuableAttribute: {
type: String,
@@ -134,67 +109,14 @@ export default {
});
},
},
- attributesList: {
- query() {
- const { list } = this.issuableAttributeQuery;
- const { query } = list[this.issuableType];
-
- return query;
- },
- skip() {
- if (this.isEpic && this.searchTerm.startsWith('&') && this.searchTerm.length < 2) {
- return true;
- }
-
- return !this.editing;
- },
- debounce: 250,
- variables() {
- if (!this.isEpic) {
- return {
- fullPath: this.attrWorkspacePath,
- title: this.searchTerm,
- state: this.issuableAttributesState[this.issuableAttribute],
- };
- }
-
- const variables = {
- fullPath: this.attrWorkspacePath,
- state: this.issuableAttributesState[this.issuableAttribute],
- sort: defaultEpicSort,
- };
-
- if (epicIidPattern.test(this.searchTerm)) {
- const matches = this.searchTerm.match(epicIidPattern);
- variables.iidStartsWith = matches.groups.iid;
- } else if (this.searchTerm !== '') {
- variables.in = 'TITLE';
- variables.title = this.searchTerm;
- }
-
- return variables;
- },
- update(data) {
- if (data?.workspace) {
- return data?.workspace?.attributes.nodes;
- }
- return [];
- },
- error(error) {
- createAlert({ message: this.i18n.listFetchError, captureError: true, error });
- },
- },
},
data() {
return {
- searchTerm: '',
- editing: false,
updating: false,
selectedTitle: null,
currentAttribute: null,
hasCurrentAttribute: false,
editConfirmation: false,
- attributesList: [],
tracking: {
event: Tracking.editEvent,
label: Tracking.rightSidebarLabel,
@@ -212,15 +134,9 @@ export default {
attributeUrl() {
return this.currentAttribute?.webUrl;
},
- dropdownText() {
- return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
- },
loading() {
return this.$apollo.queries.currentAttribute.loading;
},
- emptyPropsList() {
- return this.attributesList.length === 0;
- },
attributeTypeTitle() {
return this.widgetTitleText[this.issuableAttribute];
},
@@ -256,16 +172,12 @@ export default {
},
},
methods: {
- updateAttribute(attributeId) {
- if (this.currentAttribute === null && attributeId === null) return;
- if (attributeId === this.currentAttribute?.id) return;
+ updateAttribute({ id }) {
+ if (this.currentAttribute === null && id === null) return;
+ if (id === this.currentAttribute?.id) return;
this.updating = true;
- const selectedAttribute =
- Boolean(attributeId) && this.attributesList.find((p) => p.id === attributeId);
- this.selectedTitle = selectedAttribute ? selectedAttribute.title : this.widgetTitleText.none;
-
const { current } = this.issuableAttributeQuery;
const { mutation } = current[this.issuableType];
@@ -277,8 +189,8 @@ export default {
attributeId:
this.issuableAttribute === IssuableAttributeType.Milestone &&
this.issuableType === IssuableType.Issue
- ? getIdFromGraphQLId(attributeId)
- : attributeId,
+ ? getIdFromGraphQLId(id)
+ : id,
iid: this.iid,
},
})
@@ -298,32 +210,16 @@ export default {
})
.finally(() => {
this.updating = false;
- this.searchTerm = '';
this.selectedTitle = null;
});
},
- isAttributeChecked(attributeId = undefined) {
- return (
- attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
- );
- },
isAttributeOverdue(attribute) {
return this.issuableAttribute === IssuableAttributeType.Milestone
? attribute?.expired
: false;
},
showDropdown() {
- this.$refs.newDropdown.show();
- },
- handleOpen() {
- this.editing = true;
- this.showDropdown();
- },
- handleClose() {
- this.editing = false;
- },
- setFocus() {
- this.$refs.search.focusInput();
+ this.$refs.dropdown.show();
},
handlePopoverClose() {
this.$refs.popover.$emit('close');
@@ -349,8 +245,7 @@ export default {
:tracking="tracking"
:should-show-confirmation-popover="shouldShowConfirmationPopover"
:loading="updating || loading"
- @open="handleOpen"
- @close="handleClose"
+ @open="showDropdown"
@edit-confirm="handleEditConfirmation"
>
<template #collapsed>
@@ -432,58 +327,24 @@ export default {
</gl-popover>
</template>
<template v-else #default>
- <gl-dropdown
- ref="newDropdown"
- lazy
- :header-text="i18n.assignAttribute"
- :text="dropdownText"
- :loading="loading"
- class="gl-w-full"
- toggle-class="gl-max-w-100"
- block
- @shown="setFocus"
+ <sidebar-dropdown
+ ref="dropdown"
+ :attr-workspace-path="attrWorkspacePath"
+ :current-attribute="currentAttribute"
+ :issuable-attribute="issuableAttribute"
+ :issuable-type="issuableType"
+ @change="updateAttribute"
>
- <gl-search-box-by-type ref="search" v-model="searchTerm" />
- <gl-dropdown-item
- :data-testid="`no-${formatIssuableAttribute.kebab}-item`"
- is-check-item
- :is-checked="isAttributeChecked($options.noAttributeId)"
- @click="updateAttribute($options.noAttributeId)"
- >
- {{ i18n.noAttribute }}
- </gl-dropdown-item>
- <gl-dropdown-divider />
- <gl-loading-icon
- v-if="$apollo.queries.attributesList.loading"
- size="sm"
- class="gl-py-4"
- data-testid="loading-icon-dropdown"
- />
- <template v-else>
- <gl-dropdown-text v-if="emptyPropsList">
- {{ i18n.noAttributesFound }}
- </gl-dropdown-text>
+ <template #list="{ attributesList, isAttributeChecked, updateAttribute: update }">
<slot
- v-else
name="list"
:attributes-list="attributesList"
:is-attribute-checked="isAttributeChecked"
- :update-attribute="updateAttribute"
+ :update-attribute="update"
>
- <gl-dropdown-item
- v-for="attrItem in attributesList"
- :key="attrItem.id"
- is-check-item
- :is-checked="isAttributeChecked(attrItem.id)"
- :data-testid="`${formatIssuableAttribute.kebab}-items`"
- @click="updateAttribute(attrItem.id)"
- >
- {{ attrItem.title }}
- <span v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</span>
- </gl-dropdown-item>
</slot>
</template>
- </gl-dropdown>
+ </sidebar-dropdown>
</template>
</sidebar-editable-item>
</template>
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 6248bcb8e2d..67b9b540e91 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -53,6 +53,7 @@ import updateIssueAssigneesMutation from '~/vue_shared/components/sidebar/querie
import updateMergeRequestAssigneesMutation from '~/vue_shared/components/sidebar/queries/update_mr_assignees.mutation.graphql';
import getEscalationStatusQuery from '~/sidebar/queries/escalation_status.query.graphql';
import updateEscalationStatusMutation from '~/sidebar/queries/update_escalation_status.mutation.graphql';
+import groupMilestonesQuery from './queries/group_milestones.query.graphql';
import projectIssueMilestoneMutation from './queries/project_issue_milestone.mutation.graphql';
import projectIssueMilestoneQuery from './queries/project_issue_milestone.query.graphql';
import projectMilestonesQuery from './queries/project_milestones.query.graphql';
@@ -241,10 +242,16 @@ export const issuableMilestoneQueries = {
export const milestonesQueries = {
[IssuableType.Issue]: {
- query: projectMilestonesQuery,
+ query: {
+ [WorkspaceType.group]: groupMilestonesQuery,
+ [WorkspaceType.project]: projectMilestonesQuery,
+ },
},
[IssuableType.MergeRequest]: {
- query: projectMilestonesQuery,
+ query: {
+ [WorkspaceType.group]: groupMilestonesQuery,
+ [WorkspaceType.project]: projectMilestonesQuery,
+ },
},
};
diff --git a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
index cc5de5e4083..afce59d304f 100644
--- a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
@@ -5,7 +5,7 @@ import TimeTracker from './components/time_tracking/time_tracker.vue';
export default class SidebarMilestone {
constructor() {
- const el = document.getElementById('issuable-time-tracker');
+ const el = document.querySelector('.js-sidebar-time-tracking-root');
if (!el) return;
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 9b5bad710dd..b37486283ca 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -18,6 +18,7 @@ import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assi
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import SidebarDueDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
+import MilestoneDropdown from '~/sidebar/components/milestone/milestone_dropdown.vue';
import SidebarParticipantsWidget from '~/sidebar/components/participants/sidebar_participants_widget.vue';
import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
@@ -33,6 +34,7 @@ import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue';
import SidebarEscalationStatus from './components/incidents/sidebar_escalation_status.vue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue';
+import SidebarReviewersInputs from './components/reviewers/sidebar_reviewers_inputs.vue';
import SidebarSeverity from './components/severity/sidebar_severity.vue';
import SidebarSubscriptionsWidget from './components/subscriptions/sidebar_subscriptions_widget.vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
@@ -47,27 +49,24 @@ function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-op
return JSON.parse(sidebarOptEl.innerHTML);
}
-function mountSidebarToDoWidget() {
- const el = document.querySelector('.js-issuable-todo');
+function mountSidebarTodoWidget() {
+ const el = document.querySelector('.js-sidebar-todo-widget-root');
if (!el) {
- return false;
+ return null;
}
const { projectPath, iid, id } = el.dataset;
return new Vue({
el,
- name: 'SidebarTodoRoot',
+ name: 'SidebarTodoWidgetRoot',
apolloProvider,
- components: {
- SidebarTodoWidget,
- },
provide: {
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('sidebar-todo-widget', {
+ createElement(SidebarTodoWidget, {
props: {
fullPath: projectPath,
issuableId:
@@ -97,23 +96,22 @@ function getSidebarAssigneeAvailabilityData() {
);
}
-function mountAssigneesComponentDeprecated(mediator) {
- const el = document.getElementById('js-vue-sidebar-assignees');
+function mountSidebarAssigneesDeprecated(mediator) {
+ const el = document.querySelector('.js-sidebar-assignees-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { id, iid, fullPath } = getSidebarOptions();
const assigneeAvailabilityStatus = getSidebarAssigneeAvailabilityData();
- // eslint-disable-next-line no-new
- new Vue({
+
+ return new Vue({
el,
name: 'SidebarAssigneesRoot',
apolloProvider,
- components: {
- SidebarAssignees,
- },
render: (createElement) =>
- createElement('sidebar-assignees', {
+ createElement(SidebarAssignees, {
props: {
mediator,
issuableIid: String(iid),
@@ -131,10 +129,12 @@ function mountAssigneesComponentDeprecated(mediator) {
});
}
-function mountAssigneesComponent() {
- const el = document.getElementById('js-vue-sidebar-assignees');
+function mountSidebarAssigneesWidget() {
+ const el = document.querySelector('.js-sidebar-assignees-root');
- if (!el) return;
+ if (!el) {
+ return;
+ }
const { id, iid, fullPath, editable } = getSidebarOptions();
const isIssuablePage = isInIssuePage() || isInIncidentPage() || isInDesignPage();
@@ -144,9 +144,6 @@ function mountAssigneesComponent() {
el,
name: 'SidebarAssigneesRoot',
apolloProvider,
- components: {
- SidebarAssigneesWidget,
- },
provide: {
canUpdate: editable,
directlyInviteMembers: Object.prototype.hasOwnProperty.call(
@@ -155,7 +152,7 @@ function mountAssigneesComponent() {
),
},
render: (createElement) =>
- createElement('sidebar-assignees-widget', {
+ createElement(SidebarAssigneesWidget, {
props: {
iid: String(iid),
fullPath,
@@ -183,10 +180,12 @@ function mountAssigneesComponent() {
}
}
-function mountReviewersComponent(mediator) {
- const el = document.getElementById('js-vue-sidebar-reviewers');
+function mountSidebarReviewers(mediator) {
+ const el = document.querySelector('.js-sidebar-reviewers-root');
- if (!el) return;
+ if (!el) {
+ return;
+ }
const { iid, fullPath } = getSidebarOptions();
// eslint-disable-next-line no-new
@@ -194,11 +193,8 @@ function mountReviewersComponent(mediator) {
el,
name: 'SidebarReviewersRoot',
apolloProvider,
- components: {
- SidebarReviewers,
- },
render: (createElement) =>
- createElement('sidebar-reviewers', {
+ createElement(SidebarReviewers, {
props: {
mediator,
issuableIid: String(iid),
@@ -210,6 +206,18 @@ function mountReviewersComponent(mediator) {
}),
});
+ const reviewersInputEl = document.querySelector('.js-reviewers-inputs');
+
+ if (reviewersInputEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: reviewersInputEl,
+ render(createElement) {
+ return createElement(SidebarReviewersInputs);
+ },
+ });
+ }
+
const reviewerDropdown = document.querySelector('.js-sidebar-reviewer-dropdown');
if (reviewerDropdown) {
@@ -217,22 +225,21 @@ function mountReviewersComponent(mediator) {
}
}
-function mountCrmContactsComponent() {
- const el = document.getElementById('js-issue-crm-contacts');
+function mountSidebarCrmContacts() {
+ const el = document.querySelector('.js-sidebar-crm-contacts-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { issueId, groupIssuesPath } = el.dataset;
- // eslint-disable-next-line no-new
- new Vue({
+
+ return new Vue({
el,
name: 'SidebarCrmContactsRoot',
apolloProvider,
- components: {
- CrmContacts,
- },
render: (createElement) =>
- createElement('crm-contacts', {
+ createElement(CrmContacts, {
props: {
issueId,
groupIssuesPath,
@@ -241,28 +248,25 @@ function mountCrmContactsComponent() {
});
}
-function mountMilestoneSelect() {
- const el = document.querySelector('.js-milestone-select');
+function mountSidebarMilestoneWidget() {
+ const el = document.querySelector('.js-sidebar-milestone-widget-root');
if (!el) {
- return false;
+ return null;
}
const { canEdit, projectPath, issueIid } = el.dataset;
return new Vue({
el,
- name: 'SidebarMilestoneRoot',
+ name: 'SidebarMilestoneWidgetRoot',
apolloProvider,
- components: {
- SidebarDropdownWidget,
- },
provide: {
canUpdate: parseBoolean(canEdit),
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('sidebar-dropdown-widget', {
+ createElement(SidebarDropdownWidget, {
props: {
attrWorkspacePath: projectPath,
workspacePath: projectPath,
@@ -276,21 +280,57 @@ function mountMilestoneSelect() {
});
}
-export function mountSidebarLabels() {
- const el = document.querySelector('.js-sidebar-labels');
+export function mountMilestoneDropdown() {
+ const el = document.querySelector('.js-milestone-dropdown-root');
if (!el) {
- return false;
+ return null;
}
+ Vue.use(VueApollo);
+
+ const {
+ canAdminMilestone,
+ fullPath,
+ inputName,
+ milestoneId,
+ milestoneTitle,
+ projectMilestonesPath,
+ workspaceType,
+ } = el.dataset;
+
return new Vue({
el,
- name: 'SidebarLabelsRoot',
+ name: 'MilestoneDropdownRoot',
apolloProvider,
-
- components: {
- LabelsSelectWidget,
+ render(createElement) {
+ return createElement(MilestoneDropdown, {
+ props: {
+ attrWorkspacePath: fullPath,
+ canAdminMilestone,
+ inputName,
+ issuableType: isInIssuePage() ? IssuableType.Issue : IssuableType.MergeRequest,
+ milestoneId,
+ milestoneTitle,
+ projectMilestonesPath,
+ workspaceType,
+ },
+ });
},
+ });
+}
+
+export function mountSidebarLabelsWidget() {
+ const el = document.querySelector('.js-sidebar-labels-widget-root');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ name: 'SidebarLabelsWidgetRoot',
+ apolloProvider,
provide: {
...el.dataset,
canUpdate: parseBoolean(el.dataset.canEdit),
@@ -300,7 +340,7 @@ export function mountSidebarLabels() {
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('labels-select-widget', {
+ createElement(LabelsSelectWidget, {
props: {
iid: String(el.dataset.iid),
fullPath: el.dataset.projectPath,
@@ -327,31 +367,27 @@ export function mountSidebarLabels() {
});
}
-function mountConfidentialComponent() {
- const el = document.getElementById('js-confidential-entry-point');
+function mountSidebarConfidentialityWidget() {
+ const el = document.querySelector('.js-sidebar-confidential-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid } = getSidebarOptions();
const dataNode = document.getElementById('js-confidential-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarConfidentialRoot',
+ name: 'SidebarConfidentialityWidgetRoot',
apolloProvider,
- components: {
- SidebarConfidentialityWidget,
- },
provide: {
canUpdate: initialData.is_editable,
isClassicSidebar: true,
},
-
render: (createElement) =>
- createElement('sidebar-confidentiality-widget', {
+ createElement(SidebarConfidentialityWidget, {
props: {
iid: String(iid),
fullPath,
@@ -364,28 +400,24 @@ function mountConfidentialComponent() {
});
}
-function mountDueDateComponent() {
- const el = document.getElementById('js-due-date-entry-point');
+function mountSidebarDueDateWidget() {
+ const el = document.querySelector('.js-sidebar-due-date-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarDueDateRoot',
+ name: 'SidebarDueDateWidgetRoot',
apolloProvider,
- components: {
- SidebarDueDateWidget,
- },
provide: {
canUpdate: editable,
},
-
render: (createElement) =>
- createElement('sidebar-due-date-widget', {
+ createElement(SidebarDueDateWidget, {
props: {
iid: String(iid),
fullPath,
@@ -395,29 +427,25 @@ function mountDueDateComponent() {
});
}
-function mountReferenceComponent() {
- const el = document.getElementById('js-reference-entry-point');
+function mountSidebarReferenceWidget() {
+ const el = document.querySelector('.js-sidebar-reference-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarReferenceRoot',
+ name: 'SidebarReferenceWidgetRoot',
apolloProvider,
- components: {
- SidebarReferenceWidget,
- },
provide: {
iid: String(iid),
fullPath,
},
-
render: (createElement) =>
- createElement('sidebar-reference-widget', {
+ createElement(SidebarReferenceWidget, {
props: {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
@@ -428,17 +456,16 @@ function mountReferenceComponent() {
});
}
-function mountLockComponent(store) {
- const el = document.getElementById('js-lock-entry-point');
+function mountIssuableLockForm(store) {
+ const el = document.querySelector('.js-sidebar-lock-root');
if (!el || !store) {
- return;
+ return null;
}
const { fullPath, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarLockRoot',
store,
@@ -454,23 +481,21 @@ function mountLockComponent(store) {
});
}
-function mountParticipantsComponent() {
- const el = document.querySelector('.js-sidebar-participants-entry-point');
+function mountSidebarParticipantsWidget() {
+ const el = document.querySelector('.js-sidebar-participants-widget-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { fullPath, iid } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarParticipantsRoot',
+ name: 'SidebarParticipantsWidgetRoot',
apolloProvider,
- components: {
- SidebarParticipantsWidget,
- },
render: (createElement) =>
- createElement('sidebar-participants-widget', {
+ createElement(SidebarParticipantsWidget, {
props: {
iid: String(iid),
fullPath,
@@ -483,26 +508,24 @@ function mountParticipantsComponent() {
});
}
-function mountSubscriptionsComponent() {
- const el = document.querySelector('.js-sidebar-subscriptions-entry-point');
+function mountSidebarSubscriptionsWidget() {
+ const el = document.querySelector('.js-sidebar-subscriptions-widget-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { fullPath, iid, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarSubscriptionsRoot',
+ name: 'SidebarSubscriptionsWidgetRoot',
apolloProvider,
- components: {
- SidebarSubscriptionsWidget,
- },
provide: {
canUpdate: editable,
},
render: (createElement) =>
- createElement('sidebar-subscriptions-widget', {
+ createElement(SidebarSubscriptionsWidget, {
props: {
iid: String(iid),
fullPath,
@@ -515,14 +538,15 @@ function mountSubscriptionsComponent() {
});
}
-function mountTimeTrackingComponent() {
- const el = document.getElementById('issuable-time-tracker');
+function mountSidebarTimeTracking() {
+ const el = document.querySelector('.js-sidebar-time-tracking-root');
const { id, iid, fullPath, issuableType, timeTrackingLimitToHours } = getSidebarOptions();
- if (!el) return;
+ if (!el) {
+ return null;
+ }
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarTimeTrackingRoot',
apolloProvider,
@@ -539,27 +563,24 @@ function mountTimeTrackingComponent() {
});
}
-function mountSeverityComponent() {
- const severityContainerEl = document.querySelector('#js-severity');
+function mountSidebarSeverity() {
+ const el = document.querySelector('.js-sidebar-severity-root');
- if (!severityContainerEl) {
- return false;
+ if (!el) {
+ return null;
}
const { fullPath, iid, severity, editable } = getSidebarOptions();
return new Vue({
- el: severityContainerEl,
+ el,
name: 'SidebarSeverityRoot',
apolloProvider,
- components: {
- SidebarSeverity,
- },
provide: {
canUpdate: editable,
},
render: (createElement) =>
- createElement('sidebar-severity', {
+ createElement(SidebarSeverity, {
props: {
projectPath: fullPath,
iid: String(iid),
@@ -569,27 +590,25 @@ function mountSeverityComponent() {
});
}
-function mountEscalationStatusComponent() {
- const statusContainerEl = document.querySelector('#js-escalation-status');
+function mountSidebarEscalationStatus() {
+ const el = document.querySelector('.js-sidebar-escalation-status-root');
- if (!statusContainerEl) {
- return false;
+ if (!el) {
+ return null;
}
const { issuableType } = getSidebarOptions();
- const { canUpdate, issueIid, projectPath } = statusContainerEl.dataset;
+ const { canUpdate, issueIid, projectPath } = el.dataset;
return new Vue({
- el: statusContainerEl,
+ el,
+ name: 'SidebarEscalationStatusRoot',
apolloProvider,
- components: {
- SidebarEscalationStatus,
- },
provide: {
canUpdate: parseBoolean(canUpdate),
},
render: (createElement) =>
- createElement('sidebar-escalation-status', {
+ createElement(SidebarEscalationStatus, {
props: {
iid: issueIid,
issuableType,
@@ -599,15 +618,16 @@ function mountEscalationStatusComponent() {
});
}
-function mountCopyEmailComponent() {
- const el = document.getElementById('issuable-copy-email');
+function mountCopyEmailToClipboard() {
+ const el = document.querySelector('.js-sidebar-copy-email-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { createNoteEmail } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarCopyEmailRoot',
render: (createElement) =>
@@ -621,36 +641,32 @@ const isAssigneesWidgetShown =
export function mountSidebar(mediator, store) {
initInviteMembersModal();
initInviteMembersTrigger();
-
- mountSidebarToDoWidget();
+ mountSidebarTodoWidget();
if (isAssigneesWidgetShown) {
- mountAssigneesComponent();
+ mountSidebarAssigneesWidget();
} else {
- mountAssigneesComponentDeprecated(mediator);
+ mountSidebarAssigneesDeprecated(mediator);
}
- mountReviewersComponent(mediator);
- mountCrmContactsComponent();
- mountSidebarLabels();
- mountMilestoneSelect();
- mountConfidentialComponent(mediator);
- mountDueDateComponent(mediator);
- mountReferenceComponent(mediator);
- mountLockComponent(store);
- mountParticipantsComponent();
- mountSubscriptionsComponent();
- mountCopyEmailComponent();
+ mountSidebarReviewers(mediator);
+ mountSidebarCrmContacts();
+ mountSidebarLabelsWidget();
+ mountSidebarMilestoneWidget();
+ mountSidebarConfidentialityWidget();
+ mountSidebarDueDateWidget();
+ mountSidebarReferenceWidget();
+ mountIssuableLockForm(store);
+ mountSidebarParticipantsWidget();
+ mountSidebarSubscriptionsWidget();
+ mountCopyEmailToClipboard();
+ mountSidebarTimeTracking();
+ mountSidebarSeverity();
+ mountSidebarEscalationStatus();
new SidebarMoveIssue(
mediator,
$('.js-move-issue'),
$('.js-move-issue-confirmation-button'),
).init();
-
- mountTimeTrackingComponent();
-
- mountSeverityComponent();
-
- mountEscalationStatusComponent();
}
export { getSidebarOptions };
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index e2581a8f30e..baf906bb96c 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -138,6 +138,10 @@ export default class SidebarStore {
this.assignees = data;
}
+ setReviewersFromRealtime(data) {
+ this.reviewers = data;
+ }
+
setAutocompleteProjects(projects) {
this.autocompleteProjects = projects;
}