1<script> 2import { GlDrawer } from '@gitlab/ui'; 3import { MountingPortal } from 'portal-vue'; 4import { mapState, mapActions, mapGetters } from 'vuex'; 5import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdown_widget.vue'; 6import { __, sprintf } from '~/locale'; 7import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue'; 8import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue'; 9import { ISSUABLE } from '~/boards/constants'; 10import { getIdFromGraphQLId } from '~/graphql_shared/utils'; 11import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; 12import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue'; 13import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue'; 14import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue'; 15import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue'; 16import SidebarLabelsWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue'; 17import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants'; 18import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; 19 20export default { 21 components: { 22 GlDrawer, 23 BoardSidebarTitle, 24 SidebarAssigneesWidget, 25 SidebarDateWidget, 26 SidebarConfidentialityWidget, 27 BoardSidebarTimeTracker, 28 SidebarLabelsWidget, 29 SidebarSubscriptionsWidget, 30 SidebarDropdownWidget, 31 SidebarTodoWidget, 32 MountingPortal, 33 SidebarWeightWidget: () => 34 import('ee_component/sidebar/components/weight/sidebar_weight_widget.vue'), 35 IterationSidebarDropdownWidget: () => 36 import('ee_component/sidebar/components/iteration_sidebar_dropdown_widget.vue'), 37 }, 38 mixins: [glFeatureFlagMixin()], 39 inject: { 40 multipleAssigneesFeatureAvailable: { 41 default: false, 42 }, 43 epicFeatureAvailable: { 44 default: false, 45 }, 46 iterationFeatureAvailable: { 47 default: false, 48 }, 49 weightFeatureAvailable: { 50 default: false, 51 }, 52 allowLabelEdit: { 53 default: false, 54 }, 55 labelsFilterBasePath: { 56 default: '', 57 }, 58 }, 59 inheritAttrs: false, 60 computed: { 61 ...mapGetters([ 62 'isGroupBoard', 63 'isSidebarOpen', 64 'activeBoardItem', 65 'groupPathForActiveIssue', 66 'projectPathForActiveIssue', 67 ]), 68 ...mapState(['sidebarType', 'issuableType']), 69 isIssuableSidebar() { 70 return this.sidebarType === ISSUABLE; 71 }, 72 showSidebar() { 73 return this.isIssuableSidebar && this.isSidebarOpen; 74 }, 75 fullPath() { 76 return this.activeBoardItem?.referencePath?.split('#')[0] || ''; 77 }, 78 createLabelTitle() { 79 return sprintf(__('Create %{workspace} label'), { 80 workspace: this.isGroupBoard ? 'group' : 'project', 81 }); 82 }, 83 manageLabelTitle() { 84 return sprintf(__('Manage %{workspace} labels'), { 85 workspace: this.isGroupBoard ? 'group' : 'project', 86 }); 87 }, 88 attrWorkspacePath() { 89 return this.isGroupBoard ? this.groupPathForActiveIssue : this.projectPathForActiveIssue; 90 }, 91 labelType() { 92 return this.isGroupBoard ? LabelType.group : LabelType.project; 93 }, 94 labelsFilterPath() { 95 return this.isGroupBoard 96 ? this.labelsFilterBasePath.replace(':project_path', this.projectPathForActiveIssue) 97 : this.labelsFilterBasePath; 98 }, 99 }, 100 methods: { 101 ...mapActions([ 102 'toggleBoardItem', 103 'setAssignees', 104 'setActiveItemConfidential', 105 'setActiveBoardItemLabels', 106 'setActiveItemWeight', 107 ]), 108 handleClose() { 109 this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType }); 110 }, 111 handleUpdateSelectedLabels({ labels, id }) { 112 this.setActiveBoardItemLabels({ 113 id, 114 projectPath: this.projectPathForActiveIssue, 115 labelIds: labels.map((label) => getIdFromGraphQLId(label.id)), 116 labels, 117 }); 118 }, 119 handleLabelRemove(removeLabelId) { 120 this.setActiveBoardItemLabels({ 121 iid: this.activeBoardItem.iid, 122 projectPath: this.projectPathForActiveIssue, 123 removeLabelIds: [removeLabelId], 124 }); 125 }, 126 }, 127}; 128</script> 129 130<template> 131 <mounting-portal mount-to="#js-right-sidebar-portal" name="board-content-sidebar" append> 132 <gl-drawer 133 v-if="showSidebar" 134 v-bind="$attrs" 135 :open="isSidebarOpen" 136 class="boards-sidebar gl-absolute" 137 variant="sidebar" 138 @close="handleClose" 139 > 140 <template #title> 141 <h2 class="gl-my-0 gl-font-size-h2 gl-line-height-24">{{ __('Issue details') }}</h2> 142 </template> 143 <template #header> 144 <sidebar-todo-widget 145 class="gl-mt-3" 146 :issuable-id="activeBoardItem.id" 147 :issuable-iid="activeBoardItem.iid" 148 :full-path="fullPath" 149 :issuable-type="issuableType" 150 /> 151 </template> 152 <template #default> 153 <board-sidebar-title /> 154 <sidebar-assignees-widget 155 :iid="activeBoardItem.iid" 156 :full-path="fullPath" 157 :initial-assignees="activeBoardItem.assignees" 158 :allow-multiple-assignees="multipleAssigneesFeatureAvailable" 159 @assignees-updated="setAssignees" 160 /> 161 <sidebar-dropdown-widget 162 v-if="epicFeatureAvailable" 163 :iid="activeBoardItem.iid" 164 issuable-attribute="epic" 165 :workspace-path="projectPathForActiveIssue" 166 :attr-workspace-path="groupPathForActiveIssue" 167 :issuable-type="issuableType" 168 data-testid="sidebar-epic" 169 /> 170 <div> 171 <sidebar-dropdown-widget 172 :iid="activeBoardItem.iid" 173 issuable-attribute="milestone" 174 :workspace-path="projectPathForActiveIssue" 175 :attr-workspace-path="projectPathForActiveIssue" 176 :issuable-type="issuableType" 177 data-testid="sidebar-milestones" 178 /> 179 <template v-if="!glFeatures.iterationCadences"> 180 <sidebar-dropdown-widget 181 v-if="iterationFeatureAvailable" 182 :iid="activeBoardItem.iid" 183 issuable-attribute="iteration" 184 :workspace-path="projectPathForActiveIssue" 185 :attr-workspace-path="groupPathForActiveIssue" 186 :issuable-type="issuableType" 187 class="gl-mt-5" 188 data-testid="iteration-edit" 189 /> 190 </template> 191 <template v-else> 192 <iteration-sidebar-dropdown-widget 193 v-if="iterationFeatureAvailable" 194 :iid="activeBoardItem.iid" 195 :workspace-path="projectPathForActiveIssue" 196 :attr-workspace-path="groupPathForActiveIssue" 197 :issuable-type="issuableType" 198 class="gl-mt-5" 199 data-testid="iteration-edit" 200 /> 201 </template> 202 </div> 203 <board-sidebar-time-tracker class="swimlanes-sidebar-time-tracker" /> 204 <sidebar-date-widget 205 :iid="activeBoardItem.iid" 206 :full-path="fullPath" 207 :issuable-type="issuableType" 208 data-testid="sidebar-due-date" 209 /> 210 <sidebar-labels-widget 211 class="block labels" 212 data-testid="sidebar-labels" 213 :iid="activeBoardItem.iid" 214 :full-path="projectPathForActiveIssue" 215 :allow-label-remove="allowLabelEdit" 216 :allow-multiselect="true" 217 :footer-create-label-title="createLabelTitle" 218 :footer-manage-label-title="manageLabelTitle" 219 :labels-create-title="createLabelTitle" 220 :labels-filter-base-path="labelsFilterPath" 221 :attr-workspace-path="attrWorkspacePath" 222 workspace-type="project" 223 :issuable-type="issuableType" 224 :label-create-type="labelType" 225 @onLabelRemove="handleLabelRemove" 226 @updateSelectedLabels="handleUpdateSelectedLabels" 227 > 228 {{ __('None') }} 229 </sidebar-labels-widget> 230 <sidebar-weight-widget 231 v-if="weightFeatureAvailable" 232 :iid="activeBoardItem.iid" 233 :full-path="fullPath" 234 :issuable-type="issuableType" 235 @weightUpdated="setActiveItemWeight($event)" 236 /> 237 <sidebar-confidentiality-widget 238 :iid="activeBoardItem.iid" 239 :full-path="fullPath" 240 :issuable-type="issuableType" 241 @confidentialityUpdated="setActiveItemConfidential($event)" 242 /> 243 <sidebar-subscriptions-widget 244 :iid="activeBoardItem.iid" 245 :full-path="fullPath" 246 :issuable-type="issuableType" 247 data-testid="sidebar-notifications" 248 /> 249 </template> 250 </gl-drawer> 251 </mounting-portal> 252</template> 253