diff options
Diffstat (limited to 'app/assets/javascripts/sidebar/components')
33 files changed, 336 insertions, 269 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue index 240e12ee597..323f6f23df6 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue @@ -1,6 +1,6 @@ <script> import { GlIcon } from '@gitlab/ui'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; export default { @@ -19,7 +19,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, computed: { 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 d17c8a123d5..73cd0044c16 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue @@ -1,6 +1,6 @@ <script> import { GlTooltipDirective, GlLink } from '@gitlab/ui'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; import { isUserBusy } from '~/set_status_modal/utils'; @@ -67,7 +67,7 @@ export default { }, issuableType: { type: String, - default: 'issue', + default: TYPE_ISSUE, required: false, }, }, diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue index cf07752a0b8..5cdebee04ad 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue @@ -1,4 +1,5 @@ <script> +import { TYPE_ISSUE } from '~/issues/constants'; import CollapsedAssigneeList from './collapsed_assignee_list.vue'; import UncollapsedAssigneeList from './uncollapsed_assignee_list.vue'; @@ -22,7 +23,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, computed: { diff --git a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue index 46bda26c327..fab856883cc 100644 --- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue +++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue @@ -1,4 +1,5 @@ <script> +import { TYPE_ISSUE } from '~/issues/constants'; import AssigneeAvatar from './assignee_avatar.vue'; import UserNameWithStatus from './user_name_with_status.vue'; @@ -15,7 +16,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, computed: { 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 f894ef0c42d..d2f0ceb19c9 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,6 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import { isUserBusy } from '~/set_status_modal/utils'; import CollapsedAssignee from './collapsed_assignee.vue'; @@ -41,7 +42,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, computed: { diff --git a/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue index fd51cd5bb16..ed29ccb3447 100644 --- a/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue @@ -1,5 +1,6 @@ <script> import { GlButton } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { n__ } from '~/locale'; import UncollapsedAssigneeList from './uncollapsed_assignee_list.vue'; @@ -16,7 +17,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, signedIn: { type: Boolean, diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue index 7979f450fdd..caf3bb2f798 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue @@ -1,6 +1,7 @@ <script> import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; import { createAlert } from '~/flash'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __ } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import eventHub from '../../event_hub'; @@ -34,7 +35,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, issuableIid: { type: String, @@ -63,7 +64,7 @@ export default { computed: { shouldEnableRealtime() { // Note: Realtime is only available on issues right now, future support for MR wil be built later. - return this.issuableType === 'issue'; + return this.issuableType === TYPE_ISSUE; }, queryVariables() { return { diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue index d6c679f2f07..8893e90b1e5 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue @@ -2,7 +2,7 @@ import { GlDropdownItem } from '@gitlab/ui'; import Vue from 'vue'; import { createAlert } from '~/flash'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { __, n__ } from '~/locale'; import UserSelect from '~/vue_shared/components/user_select/user_select.vue'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -58,9 +58,9 @@ export default { issuableType: { type: String, required: false, - default: IssuableType.Issue, + default: TYPE_ISSUE, validator(value) { - return [IssuableType.Issue, IssuableType.MergeRequest, IssuableType.Alert].includes(value); + return [TYPE_ISSUE, IssuableType.MergeRequest, IssuableType.Alert].includes(value); }, }, issuableId: { @@ -118,7 +118,7 @@ export default { computed: { shouldEnableRealtime() { // Note: Realtime is only available on issues right now, future support for MR wil be built later. - return this.issuableType === IssuableType.Issue; + return this.issuableType === TYPE_ISSUE; }, queryVariables() { return { diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue index 29298ef7627..ddbd8866680 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue @@ -1,6 +1,6 @@ <script> import { GlAvatarLabeled, GlIcon } from '@gitlab/ui'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { s__, sprintf } from '~/locale'; const AVAILABILITY_STATUS = { @@ -21,7 +21,7 @@ export default { issuableType: { type: String, required: false, - default: IssuableType.Issue, + default: TYPE_ISSUE, }, }, computed: { 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 d83ae782e26..71f349bb87e 100644 --- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue +++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue @@ -1,6 +1,6 @@ <script> import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import AssigneeAvatarLink from './assignee_avatar_link.vue'; import UserNameWithStatus from './user_name_with_status.vue'; @@ -21,7 +21,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, data() { diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue index 6afaee91d7a..1eeb725d5c9 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_content.vue @@ -1,7 +1,7 @@ <script> import { GlIcon, GlAlert, GlTooltipDirective } from '@gitlab/ui'; import { __ } from '~/locale'; -import { IssuableType, WorkspaceType } from '~/issues/constants'; +import { TYPE_EPIC, WorkspaceType } from '~/issues/constants'; import { confidentialityInfoText } from '~/vue_shared/constants'; export default { @@ -25,7 +25,7 @@ export default { computed: { confidentialBodyText() { return confidentialityInfoText( - this.issuableType === IssuableType.Epic ? WorkspaceType.group : WorkspaceType.project, + this.issuableType === TYPE_EPIC ? WorkspaceType.group : WorkspaceType.project, this.issuableType, ); }, diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue index dbedfe57325..f7526bcff3d 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue @@ -1,7 +1,7 @@ <script> import { GlSprintf, GlButton } from '@gitlab/ui'; import { createAlert } from '~/flash'; -import { IssuableType } from '~/issues/constants'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import { confidentialityQueries } from '../../constants'; @@ -53,11 +53,14 @@ export default { ? this.$options.i18n.confidentialityOffWarning : this.$options.i18n.confidentialityOnWarning; }, + isIssue() { + return this.issuableType === TYPE_ISSUE; + }, context() { - return this.issuableType === IssuableType.Issue ? __('project') : __('group'); + return this.isIssue ? __('project') : __('group'); }, workspacePath() { - return this.issuableType === IssuableType.Issue + return this.isIssue ? { projectPath: this.fullPath, } @@ -66,7 +69,7 @@ export default { }; }, permissions() { - return this.issuableType === IssuableType.Issue + return this.isIssue ? __('at least the Reporter role, the author, and assignees') : __('at least the Reporter role'); }, diff --git a/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue b/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue index 0660e4f58e4..c9ecaf4102f 100644 --- a/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue +++ b/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue @@ -3,7 +3,7 @@ import { GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui'; import { __, n__, sprintf } from '~/locale'; import { createAlert } from '~/flash'; import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { TYPE_ISSUE } from '~/graphql_shared/constants'; +import { TYPENAME_ISSUE } from '~/graphql_shared/constants'; import getIssueCrmContactsQuery from '../../queries/get_issue_crm_contacts.query.graphql'; import issueCrmContactsSubscription from '../../queries/issue_crm_contacts.subscription.graphql'; @@ -65,7 +65,7 @@ export default { return this.contacts?.length; }, queryVariables() { - return { id: convertToGraphQLId(TYPE_ISSUE, this.issueId) }; + return { id: convertToGraphQLId(TYPENAME_ISSUE, this.issueId) }; }, contactsLabel() { return sprintf(n__('%{count} contact', '%{count} contacts', this.contactCount), { 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 eb48732f558..77be8022ec0 100644 --- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue +++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue @@ -1,7 +1,7 @@ <script> import { GlIcon, GlDatepicker, GlTooltipDirective, GlLink, GlPopover } from '@gitlab/ui'; import { createAlert } from '~/flash'; -import { IssuableType } from '~/issues/constants'; +import { TYPE_ISSUE } from '~/issues/constants'; import { dateInWords, formatDate, parsePikadayDate } from '~/lib/utils/datetime_utility'; import { __, sprintf } from '~/locale'; import { dateFields, dateTypes, dueDateQueries, startDateQueries, Tracking } from '../../constants'; @@ -142,7 +142,7 @@ export default { return dateInWords(this.parsedDate, true); }, workspacePath() { - return this.issuableType === IssuableType.Issue + return this.issuableType === TYPE_ISSUE ? { projectPath: this.fullPath, } @@ -235,7 +235,7 @@ export default { help: __('Help'), learnMore: __('Learn more'), }, - dateHelpUrl: '/help/user/group/epics/index.md#start-date-and-due-date', + dateHelpUrl: '/help/user/group/epics/manage_epics.md#start-and-due-date-inheritance', }; </script> diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/issue_labels.query.graphql b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/issue_labels.query.graphql index 2904857270e..d7456a71aff 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/issue_labels.query.graphql +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/issue_labels.query.graphql @@ -1,9 +1,9 @@ #import "~/graphql_shared/fragments/label.fragment.graphql" -query issueLabels($fullPath: ID!, $iid: String) { +query issueLabels($fullPath: ID!, $iid: String, $types: [IssueType!]) { workspace: project(fullPath: $fullPath) { id - issuable: issue(iid: $iid) { + issuable: issue(iid: $iid, types: $types) { id labels { nodes { diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/update_test_case_labels.mutation.graphql b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/update_test_case_labels.mutation.graphql new file mode 100644 index 00000000000..9ff7ce64d3b --- /dev/null +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/graphql/update_test_case_labels.mutation.graphql @@ -0,0 +1,20 @@ +#import "~/graphql_shared/fragments/author.fragment.graphql" +#import "~/graphql_shared/fragments/label.fragment.graphql" + +mutation updateTestCaseLabels($input: UpdateIssueInput!) { + updateIssuableLabels: updateIssue(input: $input) { + issuable: issue { + id + updatedAt + updatedBy { + ...Author + } + labels { + nodes { + ...Label + } + } + } + errors + } +} diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue index b7b4bbac661..bf916e26a15 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue @@ -4,7 +4,7 @@ import issuableLabelsSubscription from 'ee_else_ce/sidebar/queries/issuable_labe import { MutationOperationMode, getIdFromGraphQLId } from '~/graphql_shared/utils'; import { createAlert } from '~/flash'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants'; import { __ } from '~/locale'; import { issuableLabelsQueries } from '../../../constants'; @@ -161,10 +161,16 @@ export default { return !isDropdownVariantSidebar(this.variant); }, variables() { - return { + const queryVariables = { iid: this.iid, fullPath: this.fullPath, }; + + if (this.issuableType === IssuableType.TestCase) { + queryVariables.types = ['TEST_CASE']; + } + + return queryVariables; }, update(data) { return data.workspace?.issuable; @@ -255,14 +261,15 @@ export default { }; switch (this.issuableType) { - case IssuableType.Issue: + case TYPE_ISSUE: + case IssuableType.TestCase: return updateVariables; case IssuableType.MergeRequest: return { ...updateVariables, operationMode: MutationOperationMode.Replace, }; - case IssuableType.Epic: + case TYPE_EPIC: return { iid: currentIid, groupPath: this.fullPath, @@ -311,7 +318,8 @@ export default { }; switch (this.issuableType) { - case IssuableType.Issue: + case TYPE_ISSUE: + case IssuableType.TestCase: return { ...removeVariables, removeLabelIds: [labelId], @@ -322,7 +330,7 @@ export default { labelIds: [labelId], operationMode: MutationOperationMode.Remove, }; - case IssuableType.Epic: + case TYPE_EPIC: return { iid: this.iid, removeLabelIds: [getIdFromGraphQLId(labelId)], 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 cdce6617591..9d8f1304911 100644 --- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue @@ -1,6 +1,7 @@ <script> import { GlIcon, GlTooltipDirective, GlOutsideDirective as Outside } from '@gitlab/ui'; import { mapGetters, mapActions } from 'vuex'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { createAlert } from '~/flash'; @@ -9,7 +10,6 @@ import eventHub from '../../event_hub'; import EditForm from './edit_form.vue'; export default { - issue: 'issue', locked: { icon: 'lock', class: 'value', @@ -49,7 +49,7 @@ export default { return this.getNoteableData.targetType === 'merge_request' && this.glFeatures.movedMrSidebar; }, issuableDisplayName() { - const isInIssuePage = this.getNoteableData.targetType === this.$options.issue; + const isInIssuePage = this.getNoteableData.targetType === TYPE_ISSUE; return isInIssuePage ? __('issue') : __('merge request'); }, isLocked() { diff --git a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue index 1fff089eab4..8072154cd28 100644 --- a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue +++ b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue @@ -1,8 +1,8 @@ <script> import { GlDropdownItem } from '@gitlab/ui'; -import { TYPE_MILESTONE } from '~/graphql_shared/constants'; +import { TYPENAME_MILESTONE } from '~/graphql_shared/constants'; import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { IssuableType, WorkspaceType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE, WorkspaceType } from '~/issues/constants'; import { __ } from '~/locale'; import { IssuableAttributeType } from '../../constants'; import SidebarDropdown from '../sidebar_dropdown.vue'; @@ -37,7 +37,7 @@ export default { type: String, required: true, validator(value) { - return [IssuableType.Issue, IssuableType.MergeRequest].includes(value); + return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value); }, }, inputName: { @@ -71,7 +71,10 @@ export default { data() { return { milestone: this.milestoneId - ? { id: convertToGraphQLId(TYPE_MILESTONE, this.milestoneId), title: this.milestoneTitle } + ? { + id: convertToGraphQLId(TYPENAME_MILESTONE, this.milestoneId), + title: this.milestoneTitle, + } : placeholderMilestone, }; }, diff --git a/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue index 02323e5a0c6..9f64ddc8721 100644 --- a/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue +++ b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue @@ -206,7 +206,7 @@ export default { category="primary" variant="confirm" :disabled="!Boolean(selectedProject)" - class="gl-text-center! issuable-move-button" + class="gl-w-full issuable-move-button" @click="handleMoveClick" >{{ __('Move') }}</gl-button > diff --git a/app/assets/javascripts/sidebar/components/move/move_issue_button.vue b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue new file mode 100644 index 00000000000..e1259fad6a7 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/move/move_issue_button.vue @@ -0,0 +1,71 @@ +<script> +import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue'; +import { __ } from '~/locale'; +import { createAlert } from '~/flash'; +import { visitUrl } from '~/lib/utils/url_utility'; +import moveIssueMutation from '../../queries/move_issue.mutation.graphql'; + +export default { + name: 'MoveIssueButton', + components: { ProjectSelect }, + inject: ['projectsAutocompleteEndpoint', 'projectFullPath', 'issueIid'], + + i18n: { + title: __('Move issue'), + titleInProgress: __('Moving issue'), + moveErrorMessage: __('An error occurred while moving the issue.'), + }, + data() { + return { + moveInProgress: false, + }; + }, + computed: { + dropdownButtonTitle() { + return this.moveInProgress ? this.$options.i18n.titleInProgress : this.$options.i18n.title; + }, + }, + methods: { + moveIssue(targetProject) { + this.moveInProgress = true; + return this.$apollo + .mutate({ + mutation: moveIssueMutation, + variables: { + moveIssueInput: { + projectPath: this.projectFullPath, + iid: this.issueIid, + targetProjectPath: targetProject.full_path, + }, + }, + }) + .then(({ data = {} }) => { + if (!data.issueMove) return; + + const { errors } = data.issueMove; + if (errors?.length > 0) { + throw new Error(`Error moving the issue. Error message: ${errors[0].message}`); + } + visitUrl(data.issueMove?.issue.webUrl); + }) + .catch((error) => { + this.moveInProgress = false; + createAlert({ + message: this.$options.i18n.moveErrorMessage, + captureError: true, + error, + }); + }); + }, + }, +}; +</script> +<template> + <project-select + :projects-fetch-path="projectsAutocompleteEndpoint" + :dropdown-button-title="dropdownButtonTitle" + :dropdown-header-title="$options.i18n.title" + :move-in-progress="moveInProgress" + @move-issuable="moveIssue" + /> +</template> diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue index f69c027e201..56ac4c39e84 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue @@ -2,6 +2,7 @@ // NOTE! For the first iteration, we are simply copying the implementation of Assignees // It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736 import { GlTooltipDirective, GlLink } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import ReviewerAvatar from './reviewer_avatar.vue'; @@ -34,7 +35,7 @@ export default { }, issuableType: { type: String, - default: 'issue', + default: TYPE_ISSUE, required: false, }, }, diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue index 7af8dcb4e3e..bd1d9fbff0c 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue @@ -1,6 +1,7 @@ <script> // NOTE! For the first iteration, we are simply copying the implementation of Assignees // It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736 +import { TYPE_ISSUE } from '~/issues/constants'; import CollapsedReviewerList from './collapsed_reviewer_list.vue'; import UncollapsedReviewerList from './uncollapsed_reviewer_list.vue'; @@ -28,7 +29,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, computed: { diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue index faa36f3d8d2..8dd58d33ecf 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue @@ -4,8 +4,8 @@ import Vue from 'vue'; import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; import { createAlert } from '~/flash'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __ } from '~/locale'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import eventHub from '../../event_hub'; import getMergeRequestReviewersQuery from '../../queries/get_merge_request_reviewers.query.graphql'; @@ -26,7 +26,6 @@ export default { ReviewerTitle, Reviewers, }, - mixins: [glFeatureFlagsMixin()], props: { mediator: { type: Object, @@ -39,7 +38,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, issuableIid: { type: String, @@ -78,7 +77,7 @@ export default { }; }, skip() { - return !this.issuable?.id || !this.isRealtimeEnabled; + return !this.issuable?.id; }, updateQuery( _, @@ -119,9 +118,6 @@ 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/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue index 217ca2e2548..a3710d9534e 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue @@ -1,5 +1,6 @@ <script> import { GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf, s__ } from '~/locale'; import ReviewerAvatarLink from './reviewer_avatar_link.vue'; @@ -30,7 +31,7 @@ export default { issuableType: { type: String, required: false, - default: 'issue', + default: TYPE_ISSUE, }, }, data() { diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue deleted file mode 100644 index 5b624c17b0c..00000000000 --- a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue +++ /dev/null @@ -1,195 +0,0 @@ -<script> -import { - GlDropdown, - GlDropdownItem, - GlLoadingIcon, - GlTooltip, - GlSprintf, - GlButton, -} from '@gitlab/ui'; -import { createAlert } from '~/flash'; -import updateIssuableSeverity from '../../queries/update_issuable_severity.mutation.graphql'; -import { INCIDENT_SEVERITY, ISSUABLE_TYPES, SEVERITY_I18N as I18N } from '../../constants'; -import SeverityToken from './severity.vue'; - -export default { - i18n: I18N, - components: { - GlLoadingIcon, - GlTooltip, - GlSprintf, - GlDropdown, - GlDropdownItem, - GlButton, - SeverityToken, - }, - inject: ['canUpdate'], - 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(() => - createAlert({ - 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"> - <div - class="gl-display-flex gl-align-items-center gl-line-height-20 gl-text-gray-900 gl-font-weight-bold" - > - {{ $options.i18n.SEVERITY }} - <gl-button - v-if="canUpdate" - category="tertiary" - size="small" - class="gl-ml-auto hide-collapsed gl-mr-n2" - data-testid="editButton" - @click="toggleFormDropdown" - @keydown.esc="hideDropdown" - > - {{ $options.i18n.EDIT }} - </gl-button> - </div> - - <gl-dropdown - class="gl-mt-3" - :class="dropdownClass" - block - :header-text="__('Assign severity')" - :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 - :is-checked="option.value === severity" - @click="updateSeverity(option.value)" - > - <severity-token :severity="option" /> - </gl-dropdown-item> - </gl-dropdown> - - <gl-loading-icon v-if="isUpdating" size="sm" :inline="true" /> - - <severity-token v-else-if="!isDropdownShowing" :severity="selectedItem" /> - </div> - </div> -</template> diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue new file mode 100644 index 00000000000..ecb9a2809a0 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity_widget.vue @@ -0,0 +1,154 @@ +<script> +import { GlDropdown, GlDropdownItem, GlTooltip, GlSprintf } from '@gitlab/ui'; +import { createAlert } from '~/flash'; +import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; +import updateIssuableSeverity from '../../queries/update_issuable_severity.mutation.graphql'; +import { INCIDENT_SEVERITY, ISSUABLE_TYPES, SEVERITY_I18N as I18N } from '../../constants'; +import SeverityToken from './severity.vue'; + +export default { + i18n: I18N, + components: { + GlTooltip, + GlSprintf, + GlDropdown, + GlDropdownItem, + SeverityToken, + SidebarEditableItem, + }, + inject: ['canUpdate'], + 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 { + isUpdating: false, + severity: this.initialSeverity, + }; + }, + computed: { + severitiesList() { + switch (this.issuableType) { + case ISSUABLE_TYPES.INCIDENT: + return Object.values(INCIDENT_SEVERITY); + default: + return []; + } + }, + selectedItem() { + return this.severitiesList.find((severity) => severity.value === this.severity); + }, + }, + methods: { + updateSeverity(value) { + this.$refs.toggle.collapse(); + 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(() => + createAlert({ + message: `${this.$options.i18n.UPDATE_SEVERITY_ERROR} ${this.$options.i18n.TRY_AGAIN}`, + }), + ) + .finally(() => { + this.isUpdating = false; + }); + }, + showDropdown() { + this.$refs.dropdown.show(); + }, + }, +}; +</script> + +<template> + <div ref="sidebarSeverity" class="block"> + <sidebar-editable-item + ref="toggle" + :loading="isUpdating" + :title="$options.i18n.SEVERITY" + :can-edit="canUpdate" + @open="showDropdown" + > + <template #collapsed> + <div ref="severity" class="sidebar-collapsed-icon"> + <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"> + <severity-token :severity="selectedItem" /> + </div> + </template> + + <template #default> + <gl-dropdown + ref="dropdown" + class="gl-mt-3" + block + :header-text="__('Assign severity')" + :text="selectedItem.label" + > + <gl-dropdown-item + v-for="option in severitiesList" + :key="option.value" + data-testid="severityDropdownItem" + is-check-item + :is-checked="option.value === severity" + @click="updateSeverity(option.value)" + > + <severity-token :severity="option" /> + </gl-dropdown-item> + </gl-dropdown> + </template> + </sidebar-editable-item> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue index 26e2bc96f54..d68e4974ea4 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue @@ -8,7 +8,7 @@ import { GlSearchBoxByType, } from '@gitlab/ui'; import { kebabCase, snakeCase } from 'lodash'; -import { IssuableType, WorkspaceType } from '~/issues/constants'; +import { IssuableType, TYPE_EPIC, TYPE_ISSUE, WorkspaceType } from '~/issues/constants'; import { __ } from '~/locale'; import { defaultEpicSort, @@ -70,7 +70,7 @@ export default { type: String, required: true, validator(value) { - return [IssuableType.Issue, IssuableType.MergeRequest].includes(value); + return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value); }, }, workspaceType: { @@ -155,7 +155,7 @@ export default { }, isEpic() { // MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311 - return this.issuableAttribute === IssuableType.Epic; + return this.issuableAttribute === TYPE_EPIC; }, issuableAttributeQuery() { return this.issuableAttributesQueries[this.issuableAttribute]; diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index 35667495ace..5df65c4aaaf 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -3,7 +3,7 @@ import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab import { kebabCase, snakeCase } from 'lodash'; import { createAlert } from '~/flash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants'; import { timeFor } from '~/lib/utils/datetime_utility'; import { __ } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -71,7 +71,7 @@ export default { type: String, required: true, validator(value) { - return [IssuableType.Issue, IssuableType.MergeRequest].includes(value); + return [TYPE_ISSUE, IssuableType.MergeRequest].includes(value); }, }, icon: { @@ -153,7 +153,7 @@ export default { }, isEpic() { // MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311 - return this.issuableAttribute === IssuableType.Epic; + return this.issuableAttribute === TYPE_EPIC; }, formatIssuableAttribute() { return { @@ -188,7 +188,7 @@ export default { fullPath: this.workspacePath, attributeId: this.issuableAttribute === IssuableAttributeType.Milestone && - this.issuableType === IssuableType.Issue + this.issuableType === TYPE_ISSUE ? getIdFromGraphQLId(id) : id, iid: this.iid, diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue index 0fba1cb5e4e..cbe839d1112 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue @@ -1,7 +1,7 @@ <script> import { GlDropdownForm, GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui'; import { createAlert } from '~/flash'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_EPIC } from '~/issues/constants'; import { isLoggedIn } from '~/lib/utils/common_utils'; import { __, sprintf } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -105,7 +105,7 @@ export default { return ICON_ON; }, parentIsGroup() { - return this.issuableType === IssuableType.Epic; + return this.issuableType === TYPE_EPIC; }, subscribeDisabledDescription() { return sprintf(__('Disabled by %{parent} owner'), { diff --git a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue index ec8e1ee9952..964da3b6138 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue @@ -10,8 +10,9 @@ import { GlSprintf, } from '@gitlab/ui'; import { convertToGraphQLId } from '~/graphql_shared/utils'; +import { TYPE_ISSUE } from '~/issues/constants'; import { formatDate } from '~/lib/utils/datetime_utility'; -import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants'; +import { TYPENAME_ISSUE, TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants'; import { joinPaths } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import createTimelogMutation from '../../queries/create_timelog.mutation.graphql'; @@ -127,10 +128,10 @@ export default { }); }, isIssue() { - return this.issuableType === 'issue'; + return this.issuableType === TYPE_ISSUE; }, getGraphQLEntityType() { - return this.isIssue() ? TYPE_ISSUE : TYPE_MERGE_REQUEST; + return this.isIssue() ? TYPENAME_ISSUE : TYPENAME_MERGE_REQUEST; }, updateSpentAtDate(val) { this.spentAt = val; diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue index 6f4ced06ddf..cffbb6466f2 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue @@ -1,8 +1,9 @@ <script> import { GlLoadingIcon, GlTableLite, GlButton, GlTooltipDirective } from '@gitlab/ui'; import { createAlert } from '~/flash'; -import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants'; +import { TYPENAME_ISSUE, TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; +import { TYPE_ISSUE } from '~/issues/constants'; import { formatDate, parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; import { __, s__ } from '~/locale'; import { timelogQueries } from '../../constants'; @@ -61,7 +62,7 @@ export default { return this.removingIds.includes(timelogId); }, isIssue() { - return this.issuableType === 'issue'; + return this.issuableType === TYPE_ISSUE; }, getQueryVariables() { return { @@ -69,7 +70,7 @@ export default { }; }, getGraphQLEntityType() { - return this.isIssue() ? TYPE_ISSUE : TYPE_MERGE_REQUEST; + return this.isIssue() ? TYPENAME_ISSUE : TYPENAME_MERGE_REQUEST; }, extractTimelogs(data) { const timelogs = data?.issuable?.timelogs?.nodes || []; 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 b32836dc87d..c645b1649d2 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue @@ -8,7 +8,7 @@ import { GlLoadingIcon, GlTooltipDirective, } from '@gitlab/ui'; -import { IssuableType } from '~/issues/constants'; +import { IssuableType, TYPE_ISSUE } from '~/issues/constants'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import { s__, __ } from '~/locale'; @@ -173,10 +173,7 @@ export default { return Boolean(this.showHelp); }, isTimeReportSupported() { - return ( - [IssuableType.Issue, IssuableType.MergeRequest].includes(this.issuableType) && - this.issuableId - ); + return [TYPE_ISSUE, IssuableType.MergeRequest].includes(this.issuableType) && this.issuableId; }, timeTrackingIconTitle() { return this.showHelpState ? '' : HOW_TO_TRACK_TIME; |