import $ from 'jquery'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createFlash from '~/flash'; import createDefaultClient from '~/lib/graphql'; import { isInIssuePage, isInDesignPage, isInIncidentPage, parseBoolean, } from '~/lib/utils/common_utils'; import { __ } from '~/locale'; import Translate from '../vue_shared/translate'; import SidebarAssignees from './components/assignees/sidebar_assignees.vue'; import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue'; import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue'; import SidebarLabels from './components/labels/sidebar_labels.vue'; import IssuableLockForm from './components/lock/issuable_lock_form.vue'; import sidebarParticipants from './components/participants/sidebar_participants.vue'; import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue'; import SidebarSeverity from './components/severity/sidebar_severity.vue'; import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue'; import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue'; import SidebarMoveIssue from './lib/sidebar_move_issue'; Vue.use(Translate); Vue.use(VueApollo); function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-options')) { return JSON.parse(sidebarOptEl.innerHTML); } /** * Extracts the list of assignees with availability information from a hidden input * field and converts to a key:value pair for use in the sidebar assignees component. * The assignee username is used as the key and their busy status is the value * * e.g { root: 'busy', admin: '' } * * @returns {Object} */ function getSidebarAssigneeAvailabilityData() { const sidebarAssigneeEl = document.querySelectorAll('.js-sidebar-assignee-data input'); return Array.from(sidebarAssigneeEl) .map((el) => el.dataset) .reduce( (acc, { username, availability = '' }) => ({ ...acc, [username]: availability, }), {}, ); } function mountAssigneesComponent(mediator) { const el = document.getElementById('js-vue-sidebar-assignees'); const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), }); if (!el) return; const { iid, fullPath } = getSidebarOptions(); const assigneeAvailabilityStatus = getSidebarAssigneeAvailabilityData(); // eslint-disable-next-line no-new new Vue({ el, apolloProvider, components: { SidebarAssignees, }, render: (createElement) => createElement('sidebar-assignees', { props: { mediator, issuableIid: String(iid), projectPath: fullPath, field: el.dataset.field, signedIn: el.hasAttribute('data-signed-in'), issuableType: isInIssuePage() || isInIncidentPage() || isInDesignPage() ? 'issue' : 'merge_request', assigneeAvailabilityStatus, }, }), }); } function mountReviewersComponent(mediator) { const el = document.getElementById('js-vue-sidebar-reviewers'); const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), }); if (!el) return; const { iid, fullPath } = getSidebarOptions(); // eslint-disable-next-line no-new new Vue({ el, apolloProvider, components: { SidebarReviewers, }, render: (createElement) => createElement('sidebar-reviewers', { props: { mediator, issuableIid: String(iid), projectPath: fullPath, field: el.dataset.field, issuableType: isInIssuePage() || isInDesignPage() ? 'issue' : 'merge_request', }, }), }); } export function mountSidebarLabels() { const el = document.querySelector('.js-sidebar-labels'); if (!el) { return false; } const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), }); return new Vue({ el, apolloProvider, provide: { ...el.dataset, allowLabelCreate: parseBoolean(el.dataset.allowLabelCreate), allowLabelEdit: parseBoolean(el.dataset.canEdit), allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels), initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels), }, render: (createElement) => createElement(SidebarLabels), }); } function mountConfidentialComponent(mediator) { const el = document.getElementById('js-confidential-entry-point'); const { fullPath, iid } = getSidebarOptions(); if (!el) return; const dataNode = document.getElementById('js-confidential-issue-data'); const initialData = JSON.parse(dataNode.innerHTML); import(/* webpackChunkName: 'notesStore' */ '~/notes/stores') .then( ({ store }) => new Vue({ el, store, components: { ConfidentialIssueSidebar, }, render: (createElement) => createElement('confidential-issue-sidebar', { props: { iid: String(iid), fullPath, isEditable: initialData.is_editable, service: mediator.service, }, }), }), ) .catch(() => { createFlash({ message: __('Failed to load sidebar confidential toggle') }); }); } function mountLockComponent() { const el = document.getElementById('js-lock-entry-point'); if (!el) { return; } const { fullPath } = getSidebarOptions(); const dataNode = document.getElementById('js-lock-issue-data'); const initialData = JSON.parse(dataNode.innerHTML); let importStore; if (isInIssuePage() || isInIncidentPage()) { importStore = import(/* webpackChunkName: 'notesStore' */ '~/notes/stores').then( ({ store }) => store, ); } else { importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then( (store) => store.default, ); } importStore .then( (store) => new Vue({ el, store, provide: { fullPath, }, render: (createElement) => createElement(IssuableLockForm, { props: { isEditable: initialData.is_editable, }, }), }), ) .catch(() => { createFlash({ message: __('Failed to load sidebar lock status') }); }); } function mountParticipantsComponent(mediator) { const el = document.querySelector('.js-sidebar-participants-entry-point'); if (!el) return; // eslint-disable-next-line no-new new Vue({ el, components: { sidebarParticipants, }, render: (createElement) => createElement('sidebar-participants', { props: { mediator, }, }), }); } function mountSubscriptionsComponent(mediator) { const el = document.querySelector('.js-sidebar-subscriptions-entry-point'); if (!el) return; // eslint-disable-next-line no-new new Vue({ el, components: { sidebarSubscriptions, }, render: (createElement) => createElement('sidebar-subscriptions', { props: { mediator, }, }), }); } function mountTimeTrackingComponent() { const el = document.getElementById('issuable-time-tracker'); if (!el) return; // eslint-disable-next-line no-new new Vue({ el, components: { SidebarTimeTracking, }, render: (createElement) => createElement('sidebar-time-tracking', {}), }); } function mountSeverityComponent() { const severityContainerEl = document.querySelector('#js-severity'); if (!severityContainerEl) { return false; } const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), }); const { fullPath, iid, severity } = getSidebarOptions(); return new Vue({ el: severityContainerEl, apolloProvider, components: { SidebarSeverity, }, render: (createElement) => createElement('sidebar-severity', { props: { projectPath: fullPath, iid: String(iid), initialSeverity: severity.toUpperCase(), }, }), }); } function mountCopyEmailComponent() { const el = document.getElementById('issuable-copy-email'); if (!el) return; const { createNoteEmail } = getSidebarOptions(); // eslint-disable-next-line no-new new Vue({ el, render: (createElement) => createElement(CopyEmailToClipboard, { props: { copyText: createNoteEmail } }), }); } export function mountSidebar(mediator) { mountAssigneesComponent(mediator); mountReviewersComponent(mediator); mountConfidentialComponent(mediator); mountLockComponent(); mountParticipantsComponent(mediator); mountSubscriptionsComponent(mediator); mountCopyEmailComponent(); new SidebarMoveIssue( mediator, $('.js-move-issue'), $('.js-move-issue-confirmation-button'), ).init(); mountTimeTrackingComponent(); mountSeverityComponent(); } export { getSidebarOptions };