diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 01:45:44 +0000 |
commit | 85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch) | |
tree | 9160f299afd8c80c038f08e1545be119f5e3f1e1 /app/assets/javascripts/sidebar | |
parent | 15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff) | |
download | gitlab-ce-85dc423f7090da0a52c73eb66faf22ddb20efff9.tar.gz |
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'app/assets/javascripts/sidebar')
24 files changed, 512 insertions, 54 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue index 9a60172db2e..878b331fb3c 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue @@ -59,7 +59,7 @@ export default { }; }, assigneeUrl() { - return this.user.web_url; + return this.user.web_url || this.user.webUrl; }, }, }; diff --git a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue index 7375855f899..eabd4d88d52 100644 --- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue +++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective } from '@gitlab/ui'; +import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import CollapsedAssignee from './collapsed_assignee.vue'; @@ -12,6 +12,7 @@ export default { }, components: { CollapsedAssignee, + GlIcon, }, props: { users: { @@ -102,7 +103,7 @@ export default { :title="tooltipTitle" class="sidebar-collapsed-icon sidebar-collapsed-user" > - <i v-if="hasNoUsers" :aria-label="__('None')" class="fa fa-user"> </i> + <gl-icon v-if="hasNoUsers" name="user" :aria-label="__('None')" /> <collapsed-assignee v-for="user in collapsedUsers" :key="user.id" diff --git a/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue new file mode 100644 index 00000000000..4697d85472b --- /dev/null +++ b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue @@ -0,0 +1,37 @@ +<script> +import { n__ } from '~/locale'; +import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue'; + +export default { + components: { + UncollapsedAssigneeList, + }, + inject: ['rootPath'], + props: { + users: { + type: Array, + required: true, + }, + }, + computed: { + assigneesText() { + return n__('Assignee', '%d Assignees', this.users.length); + }, + emptyUsers() { + return this.users.length === 0; + }, + }, +}; +</script> + +<template> + <div class="gl-display-flex gl-flex-direction-column"> + <label data-testid="assigneeLabel">{{ assigneesText }}</label> + <div v-if="emptyUsers" data-testid="none"> + <span> + {{ __('None') }} + </span> + </div> + <uncollapsed-assignee-list v-else :users="users" :root-path="rootPath" /> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue index 14c14d0bad1..2f714ac3847 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue @@ -62,7 +62,7 @@ export default { this.addAssignee = this.store.addAssignee.bind(this.store); this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store); - // Get events from glDropdown + // Get events from deprecatedJQueryDropdown eventHub.$on('sidebar.removeAssignee', this.removeAssignee); eventHub.$on('sidebar.addAssignee', this.addAssignee); eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees); 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 fed9e5886c0..95934c0ef2a 100644 --- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue +++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue @@ -73,9 +73,9 @@ export default { :root-path="rootPath" :issuable-type="issuableType" > - <div class="ml-2"> - <span class="author"> {{ user.name }} </span> - <span class="username"> {{ username }} </span> + <div class="ml-2 gl-line-height-normal"> + <div>{{ user.name }}</div> + <div>{{ username }}</div> </div> </assignee-avatar-link> <div v-else> diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue index c6f7d5e44ad..2530cb77acd 100644 --- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue +++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue @@ -1,18 +1,17 @@ <script> import { mapState } from 'vuex'; +import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; -import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '~/sidebar/event_hub'; import EditForm from './edit_form.vue'; export default { components: { EditForm, - Icon, + GlIcon, }, directives: { - tooltip, + GlTooltip: GlTooltipDirective, }, props: { fullPath: { @@ -73,15 +72,12 @@ export default { <div class="block issuable-sidebar-item confidentiality"> <div ref="collapseIcon" - v-tooltip + v-gl-tooltip.viewport.left :title="tooltipLabel" class="sidebar-collapsed-icon" - data-container="body" - data-placement="left" - data-boundary="viewport" @click="toggleForm" > - <icon :name="confidentialityIcon" aria-hidden="true" /> + <gl-icon :name="confidentialityIcon" aria-hidden="true" /> </div> <div class="title hide-collapsed"> {{ __('Confidentiality') }} @@ -105,11 +101,11 @@ export default { :issuable-type="issuableType" /> <div v-if="!confidential" class="no-value sidebar-item-value" data-testid="not-confidential"> - <icon :size="16" name="eye" aria-hidden="true" class="sidebar-item-icon inline" /> + <gl-icon :size="16" name="eye" aria-hidden="true" class="sidebar-item-icon inline" /> {{ __('Not confidential') }} </div> <div v-else class="value sidebar-item-value hide-collapsed"> - <icon + <gl-icon :size="16" name="eye-slash" aria-hidden="true" diff --git a/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue new file mode 100644 index 00000000000..d7be8927c29 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue @@ -0,0 +1,97 @@ +<script> +import $ from 'jquery'; +import { difference, union } from 'lodash'; +import { mapState, mapActions } from 'vuex'; +import flash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; +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'; + +export default { + components: { + LabelsSelect, + }, + variant: DropdownVariant.Sidebar, + inject: [ + 'allowLabelCreate', + 'allowLabelEdit', + 'allowScopedLabels', + 'iid', + 'initiallySelectedLabels', + 'issuableType', + 'labelsFetchPath', + 'labelsManagePath', + 'labelsUpdatePath', + 'projectIssuesPath', + 'projectPath', + ], + data: () => ({ + labelsSelectInProgress: false, + }), + computed: { + ...mapState(['selectedLabels']), + }, + mounted() { + this.setInitialState({ + selectedLabels: this.initiallySelectedLabels, + }); + }, + methods: { + ...mapActions(['setInitialState', 'replaceSelectedLabels']), + handleDropdownClose() { + $(this.$el).trigger('hidden.gl.dropdown'); + }, + handleUpdateSelectedLabels(labels) { + const currentLabelIds = this.selectedLabels.map(label => label.id); + const userAddedLabelIds = labels.filter(label => label.set).map(label => label.id); + const userRemovedLabelIds = labels.filter(label => !label.set).map(label => label.id); + + const issuableLabels = difference( + union(currentLabelIds, userAddedLabelIds), + userRemovedLabelIds, + ); + + this.labelsSelectInProgress = true; + + axios({ + data: { + [this.issuableType]: { + label_ids: issuableLabels, + }, + }, + method: 'put', + url: this.labelsUpdatePath, + }) + .then(({ data }) => this.replaceSelectedLabels(data.labels)) + .catch(() => flash(__('An error occurred while updating labels.'))) + .finally(() => { + this.labelsSelectInProgress = false; + }); + }, + }, +}; +</script> + +<template> + <labels-select + class="block labels js-labels-block" + :allow-label-create="allowLabelCreate" + :allow-label-edit="allowLabelEdit" + :allow-multiselect="true" + :allow-scoped-labels="allowScopedLabels" + :footer-create-label-title="__('Create project label')" + :footer-manage-label-title="__('Manage project labels')" + :labels-create-title="__('Create project label')" + :labels-fetch-path="labelsFetchPath" + :labels-filter-base-path="projectIssuesPath" + :labels-manage-path="labelsManagePath" + :labels-select-in-progress="labelsSelectInProgress" + :selected-labels="selectedLabels" + :variant="$options.sidebar" + @onDropdownClose="handleDropdownClose" + @updateSelectedLabels="handleUpdateSelectedLabels" + > + {{ __('None') }} + </labels-select> +</template> diff --git a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue index 1b4968fabf6..53ee7f46ad9 100644 --- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue @@ -1,8 +1,8 @@ <script> import { mapGetters } from 'vuex'; +import { GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '~/sidebar/event_hub'; import editForm from './edit_form.vue'; @@ -22,7 +22,7 @@ export default { }, components: { editForm, - Icon, + GlIcon, }, directives: { @@ -88,7 +88,7 @@ export default { data-boundary="viewport" @click="toggleForm" > - <icon :name="lockStatus.icon" class="sidebar-item-icon is-active" /> + <gl-icon :name="lockStatus.icon" class="sidebar-item-icon is-active" /> </div> <div class="title hide-collapsed"> @@ -116,7 +116,7 @@ export default { /> <div data-testid="lock-status" class="sidebar-item-value" :class="lockStatus.class"> - <icon + <gl-icon :size="16" :name="lockStatus.icon" class="sidebar-item-icon" diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue index d2904f4157c..e7dbc47aea1 100644 --- a/app/assets/javascripts/sidebar/components/participants/participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/participants.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlIcon, GlLoadingIcon } from '@gitlab/ui'; import { __, n__, sprintf } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; @@ -10,6 +10,7 @@ export default { }, components: { userAvatarImage, + GlIcon, GlLoadingIcon, }, props: { @@ -94,7 +95,7 @@ export default { data-boundary="viewport" @click="onClickCollapsedIcon" > - <i class="fa fa-users" aria-hidden="true"> </i> + <gl-icon name="users" /> <gl-loading-icon v-if="loading" /> <span v-else data-testid="collapsed-count"> {{ participantCount }} </span> </div> diff --git a/app/assets/javascripts/sidebar/components/severity/constants.js b/app/assets/javascripts/sidebar/components/severity/constants.js new file mode 100644 index 00000000000..4f58ff38121 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/constants.js @@ -0,0 +1,41 @@ +import { __, s__ } from '~/locale'; + +export const INCIDENT_SEVERITY = { + CRITICAL: { + value: 'CRITICAL', + icon: 'critical', + label: s__('IncidentManagement|Critical - S1'), + }, + HIGH: { + value: 'HIGH', + icon: 'high', + label: s__('IncidentManagement|High - S2'), + }, + MEDIUM: { + value: 'MEDIUM', + icon: 'medium', + label: s__('IncidentManagement|Medium - S3'), + }, + LOW: { + value: 'LOW', + icon: 'low', + label: s__('IncidentManagement|Low - S4'), + }, + UNKNOWN: { + value: 'UNKNOWN', + icon: 'unknown', + label: s__('IncidentManagement|Unknown'), + }, +}; + +export const ISSUABLE_TYPES = { + INCIDENT: 'incident', +}; + +export const I18N = { + UPDATE_SEVERITY_ERROR: s__('SeverityWidget|There was an error while updating severity.'), + TRY_AGAIN: __('Please try again'), + EDIT: __('Edit'), + SEVERITY: s__('SeverityWidget|Severity'), + SEVERITY_VALUE: s__('SeverityWidget|Severity: %{severity}'), +}; diff --git a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql new file mode 100644 index 00000000000..750e757971f --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql @@ -0,0 +1,9 @@ +mutation updateIssuableSeverity($projectPath: ID!, $severity: IssuableSeverity!, $iid: String!) { + issueSetSeverity(input: { iid: $iid, severity: $severity, projectPath: $projectPath }) { + errors + issue { + iid + severity + } + } +} diff --git a/app/assets/javascripts/sidebar/components/severity/severity.vue b/app/assets/javascripts/sidebar/components/severity/severity.vue new file mode 100644 index 00000000000..7e7d62256c9 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/severity.vue @@ -0,0 +1,42 @@ +<script> +import { GlIcon } from '@gitlab/ui'; + +export default { + components: { + GlIcon, + }, + props: { + severity: { + type: Object, + required: true, + validator(severity) { + const { value, label, icon } = severity; + return value && label && icon; + }, + }, + iconSize: { + type: Number, + required: false, + default: 12, + }, + iconOnly: { + type: Boolean, + required: false, + default: false, + }, + }, +}; +</script> + +<template> + <div + class="incident-severity gl-display-inline-flex gl-align-items-center gl-justify-content-between" + > + <gl-icon + :size="iconSize" + :name="`severity-${severity.icon}`" + :class="[`icon-${severity.icon}`, { 'gl-mr-3': !iconOnly }]" + /> + <span v-if="!iconOnly">{{ severity.label }}</span> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue new file mode 100644 index 00000000000..8f3610b912a --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue @@ -0,0 +1,187 @@ +<script> +import { + GlDropdown, + GlDropdownItem, + GlLoadingIcon, + GlTooltip, + GlSprintf, + GlLink, +} from '@gitlab/ui'; +import { INCIDENT_SEVERITY, ISSUABLE_TYPES, I18N } from './constants'; +import updateIssuableSeverity from './graphql/mutations/update_issuable_severity.mutation.graphql'; +import SeverityToken from './severity.vue'; +import createFlash from '~/flash'; + +export default { + i18n: I18N, + components: { + GlLoadingIcon, + GlTooltip, + GlSprintf, + GlDropdown, + GlDropdownItem, + GlLink, + SeverityToken, + }, + props: { + projectPath: { + type: String, + required: true, + }, + iid: { + type: String, + required: true, + }, + initialSeverity: { + type: String, + required: false, + default: INCIDENT_SEVERITY.UNKNOWN.value, + }, + issuableType: { + type: String, + required: false, + default: ISSUABLE_TYPES.INCIDENT, + validator: value => { + // currently severity is supported only for incidents, but this list might be extended + return [ISSUABLE_TYPES.INCIDENT].includes(value); + }, + }, + }, + data() { + return { + isDropdownShowing: false, + isUpdating: false, + severity: this.initialSeverity, + }; + }, + computed: { + severitiesList() { + switch (this.issuableType) { + case ISSUABLE_TYPES.INCIDENT: + return Object.values(INCIDENT_SEVERITY); + default: + return []; + } + }, + dropdownClass() { + return this.isDropdownShowing ? 'show' : 'gl-display-none'; + }, + selectedItem() { + return this.severitiesList.find(severity => severity.value === this.severity); + }, + }, + mounted() { + document.addEventListener('click', this.handleOffClick); + }, + beforeDestroy() { + document.removeEventListener('click', this.handleOffClick); + }, + methods: { + handleOffClick(event) { + if (!this.isDropdownShowing) { + return; + } + + if (!this.$refs.sidebarSeverity.contains(event.target)) { + this.hideDropdown(); + } + }, + hideDropdown() { + this.isDropdownShowing = false; + const event = new Event('hidden.gl.dropdown'); + this.$el.dispatchEvent(event); + }, + toggleFormDropdown() { + this.isDropdownShowing = !this.isDropdownShowing; + }, + updateSeverity(value) { + this.hideDropdown(); + this.isUpdating = true; + this.$apollo + .mutate({ + mutation: updateIssuableSeverity, + variables: { + iid: this.iid, + severity: value, + projectPath: this.projectPath, + }, + }) + .then(resp => { + const { + data: { + issueSetSeverity: { + errors = [], + issue: { severity }, + }, + }, + } = resp; + + if (errors[0]) { + throw errors[0]; + } + this.severity = severity; + }) + .catch(() => + createFlash({ + message: `${this.$options.i18n.UPDATE_SEVERITY_ERROR} ${this.$options.i18n.TRY_AGAIN}`, + }), + ) + .finally(() => { + this.isUpdating = false; + }); + }, + }, +}; +</script> + +<template> + <div ref="sidebarSeverity" class="block"> + <div ref="severity" class="sidebar-collapsed-icon" @click="toggleFormDropdown"> + <severity-token :severity="selectedItem" :icon-size="14" :icon-only="true" /> + <gl-tooltip :target="() => $refs.severity" boundary="viewport" placement="left"> + <gl-sprintf :message="$options.i18n.SEVERITY_VALUE"> + <template #severity> + {{ selectedItem.label }} + </template> + </gl-sprintf> + </gl-tooltip> + </div> + + <div class="hide-collapsed"> + <p class="title gl-display-flex gl-justify-content-space-between"> + {{ $options.i18n.SEVERITY }} + <gl-link + data-testid="editButton" + href="#" + @click="toggleFormDropdown" + @keydown.esc="hideDropdown" + > + {{ $options.i18n.EDIT }} + </gl-link> + </p> + + <gl-dropdown + :class="dropdownClass" + block + :text="selectedItem.label" + toggle-class="dropdown-menu-toggle gl-mb-2" + @keydown.esc.native="hideDropdown" + > + <gl-dropdown-item + v-for="option in severitiesList" + :key="option.value" + data-testid="severityDropdownItem" + :is-check-item="true" + :is-checked="option.value === severity" + @click="updateSeverity(option.value)" + > + <severity-token :severity="option" /> + </gl-dropdown-item> + </gl-dropdown> + + <gl-loading-icon v-if="isUpdating" :inline="true" /> + + <severity-token v-else-if="!isDropdownShowing" :severity="selectedItem" /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue index 3b92ead8859..0457aad8795 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue @@ -1,7 +1,7 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; import Tracking from '~/tracking'; -import icon from '~/vue_shared/components/icon.vue'; import toggleButton from '~/vue_shared/components/toggle_button.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import eventHub from '../../event_hub'; @@ -16,7 +16,7 @@ export default { tooltip, }, components: { - icon, + GlIcon, toggleButton, }, mixins: [Tracking.mixin({ label: 'right_sidebar' })], @@ -118,7 +118,7 @@ export default { data-boundary="viewport" @click="onClickCollapsedIcon" > - <icon + <gl-icon :name="notificationIcon" :size="16" aria-hidden="true" diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue index 65ecd5be05d..bc2319c0f36 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue @@ -1,12 +1,12 @@ <script> +import { GlIcon } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; -import icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; export default { name: 'TimeTrackingCollapsedState', components: { - icon, + GlIcon, }, directives: { tooltip, @@ -105,7 +105,7 @@ export default { data-placement="left" data-boundary="viewport" > - <icon name="timer" /> + <gl-icon name="timer" /> <div class="time-tracking-collapsed-summary"> <div :class="divClass"> <span :class="spanClass"> {{ text }} </span> diff --git a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue index 67abde0c22a..b45746e789d 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { sprintf, s__ } from '../../../locale'; import { joinPaths } from '~/lib/utils/url_utility'; diff --git a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue index c2f30310e2e..b2b3b289c5c 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { sprintf, s__ } from '~/locale'; export default { diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue index 67a8f11b760..a2fb0ebcbc6 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue @@ -106,7 +106,7 @@ export default { <div class="title hide-collapsed"> {{ __('Time tracking') }} <div v-if="!showHelpState" class="help-button float-right" @click="toggleHelpState(true)"> - <i class="fa fa-question-circle" aria-hidden="true"> </i> + <gl-icon name="question-o" /> </div> <div v-if="showHelpState" diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue index 5281c03ab3f..51719df313f 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue @@ -1,10 +1,8 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; - const MARK_TEXT = __('Mark as done'); const TODO_TEXT = __('Add a To-Do'); @@ -13,7 +11,7 @@ export default { tooltip, }, components: { - Icon, + GlIcon, GlLoadingIcon, }, props: { @@ -85,7 +83,7 @@ export default { data-boundary="viewport" @click="handleButtonClick" > - <icon + <gl-icon v-show="collapsedButtonIconVisible" :class="collapsedButtonIconClasses" :name="collapsedButtonIcon" diff --git a/app/assets/javascripts/sidebar/event_hub.js b/app/assets/javascripts/sidebar/event_hub.js index f35506fd5de..dd4bd9a5ab7 100644 --- a/app/assets/javascripts/sidebar/event_hub.js +++ b/app/assets/javascripts/sidebar/event_hub.js @@ -1,6 +1,6 @@ -import Vue from 'vue'; +import createEventHub from '~/helpers/event_hub_factory'; -const eventHub = new Vue(); +const eventHub = createEventHub(); // TODO: remove eventHub hack after code splitting refactor window.emitSidebarEvent = (...args) => eventHub.$emit(...args); diff --git a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js index 0fb9cf22653..edeb1bba020 100644 --- a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js +++ b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js @@ -1,7 +1,7 @@ import $ from 'jquery'; -import '~/gl_dropdown'; import { escape } from 'lodash'; import { __ } from '~/locale'; +import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown'; function isValidProjectId(id) { return id > 0; @@ -27,7 +27,7 @@ class SidebarMoveIssue { } initDropdown() { - this.$dropdownToggle.glDropdown({ + initDeprecatedJQueryDropdown(this.$dropdownToggle, { search: { fields: ['name_with_namespace'], }, diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 015219200db..be559b16420 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -1,21 +1,26 @@ import $ from 'jquery'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; +import Vuex from 'vuex'; import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue'; import SidebarAssignees from './components/assignees/sidebar_assignees.vue'; +import SidebarLabels from './components/labels/sidebar_labels.vue'; import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue'; import SidebarMoveIssue from './lib/sidebar_move_issue'; import IssuableLockForm from './components/lock/issuable_lock_form.vue'; import sidebarParticipants from './components/participants/sidebar_participants.vue'; import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue'; +import SidebarSeverity from './components/severity/sidebar_severity.vue'; import Translate from '../vue_shared/translate'; import createDefaultClient from '~/lib/graphql'; import { store } from '~/notes/stores'; -import { isInIssuePage } from '~/lib/utils/common_utils'; +import { isInIssuePage, parseBoolean } from '~/lib/utils/common_utils'; import mergeRequestStore from '~/mr_notes/stores'; +import labelsSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store'; Vue.use(Translate); Vue.use(VueApollo); +Vue.use(Vuex); function getSidebarOptions() { return JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); @@ -51,6 +56,29 @@ function mountAssigneesComponent(mediator) { }); } +export function mountSidebarLabels() { + const el = document.querySelector('.js-sidebar-labels'); + + if (!el) { + return false; + } + + const labelsStore = new Vuex.Store(labelsSelectModule()); + + return new Vue({ + el, + provide: { + ...el.dataset, + allowLabelCreate: parseBoolean(el.dataset.allowLabelCreate), + allowLabelEdit: parseBoolean(el.dataset.canEdit), + allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels), + initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels), + }, + store: labelsStore, + render: createElement => createElement(SidebarLabels), + }); +} + function mountConfidentialComponent(mediator) { const el = document.getElementById('js-confidential-entry-point'); @@ -159,6 +187,35 @@ function mountTimeTrackingComponent() { }); } +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(), + }, + }), + }); +} + export function mountSidebar(mediator) { mountAssigneesComponent(mediator); mountConfidentialComponent(mediator); @@ -173,6 +230,8 @@ export function mountSidebar(mediator) { ).init(); mountTimeTrackingComponent(); + + mountSeverityComponent(); } export { getSidebarOptions }; diff --git a/app/assets/javascripts/sidebar/queries/sidebarDetailsForHealthStatusFeatureFlag.query.graphql b/app/assets/javascripts/sidebar/queries/sidebarDetailsForHealthStatusFeatureFlag.query.graphql deleted file mode 100644 index 2aff7da4605..00000000000 --- a/app/assets/javascripts/sidebar/queries/sidebarDetailsForHealthStatusFeatureFlag.query.graphql +++ /dev/null @@ -1,7 +0,0 @@ -query($fullPath: ID!, $iid: String!) { - project(fullPath: $fullPath) { - issue(iid: $iid) { - iid - } - } -} diff --git a/app/assets/javascripts/sidebar/services/sidebar_service.js b/app/assets/javascripts/sidebar/services/sidebar_service.js index 8714bea1729..a61af631661 100644 --- a/app/assets/javascripts/sidebar/services/sidebar_service.js +++ b/app/assets/javascripts/sidebar/services/sidebar_service.js @@ -1,5 +1,4 @@ import sidebarDetailsQuery from 'ee_else_ce/sidebar/queries/sidebarDetails.query.graphql'; -import sidebarDetailsForHealthStatusFeatureFlagQuery from 'ee_else_ce/sidebar/queries/sidebarDetailsForHealthStatusFeatureFlag.query.graphql'; import axios from '~/lib/utils/axios_utils'; import createGqClient, { fetchPolicies } from '~/lib/graphql'; @@ -27,14 +26,10 @@ export default class SidebarService { } get() { - const hasHealthStatusFeatureFlag = gon.features && gon.features.saveIssuableHealthStatus; - return Promise.all([ axios.get(this.endpoint), gqClient.query({ - query: hasHealthStatusFeatureFlag - ? sidebarDetailsForHealthStatusFeatureFlagQuery - : sidebarDetailsQuery, + query: sidebarDetailsQuery, variables: { fullPath: this.fullPath, iid: this.iid.toString(), |