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-22 15:07:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-22 15:07:45 +0300
commit25bf8a36335fa281dc8fe56f355f3829ace703a5 (patch)
tree33731aef63f86469a57185a8dfb46071007ed61c /app/assets/javascripts/sidebar
parent02a0289d4077552778c0eeb0cc0172dfd7b6b331 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/sidebar')
-rw-r--r--app/assets/javascripts/sidebar/components/copy_email/copy_email_to_clipboard.vue (renamed from app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue)0
-rw-r--r--app/assets/javascripts/sidebar/components/move/move_issues_button.vue171
-rw-r--r--app/assets/javascripts/sidebar/components/status/status_dropdown.vue57
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/subscriptions_dropdown.vue51
-rw-r--r--app/assets/javascripts/sidebar/constants.js22
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js83
-rw-r--r--app/assets/javascripts/sidebar/queries/move_issue.mutation.graphql5
7 files changed, 376 insertions, 13 deletions
diff --git a/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue b/app/assets/javascripts/sidebar/components/copy_email/copy_email_to_clipboard.vue
index fd652583f76..fd652583f76 100644
--- a/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
+++ b/app/assets/javascripts/sidebar/components/copy_email/copy_email_to_clipboard.vue
diff --git a/app/assets/javascripts/sidebar/components/move/move_issues_button.vue b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue
new file mode 100644
index 00000000000..a3a5072fc2d
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue
@@ -0,0 +1,171 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import IssuableMoveDropdown from '~/vue_shared/components/sidebar/issuable_move_dropdown.vue';
+import createFlash from '~/flash';
+import { logError } from '~/lib/logger';
+import { s__ } from '~/locale';
+import {
+ WORK_ITEM_TYPE_ENUM_ISSUE,
+ WORK_ITEM_TYPE_ENUM_INCIDENT,
+ WORK_ITEM_TYPE_ENUM_TASK,
+ WORK_ITEM_TYPE_ENUM_TEST_CASE,
+} from '~/work_items/constants';
+import issuableEventHub from '~/issues/list/eventhub';
+import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql';
+import getIssuesCountQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql';
+import moveIssueMutation from '../../queries/move_issue.mutation.graphql';
+
+export default {
+ name: 'MoveIssuesButton',
+ components: {
+ IssuableMoveDropdown,
+ GlAlert,
+ },
+ props: {
+ projectFullPath: {
+ type: String,
+ required: true,
+ },
+ projectsFetchPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ selectedIssuables: [],
+ moveInProgress: false,
+ };
+ },
+ computed: {
+ cannotMoveTasksWarningTitle() {
+ if (this.tasksSelected && this.testCasesSelected) {
+ return s__('Issues|Tasks and test cases can not be moved.');
+ }
+
+ if (this.testCasesSelected) {
+ return s__('Issues|Test cases can not be moved.');
+ }
+
+ return s__('Issues|Tasks can not be moved.');
+ },
+ issuesSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_ISSUE);
+ },
+ incidentsSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_INCIDENT);
+ },
+ tasksSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_TASK);
+ },
+ testCasesSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_TEST_CASE);
+ },
+ },
+ mounted() {
+ issuableEventHub.$on('issuables:issuableChecked', this.handleIssuableChecked);
+ },
+ beforeDestroy() {
+ issuableEventHub.$off('issuables:issuableChecked', this.handleIssuableChecked);
+ },
+ methods: {
+ handleIssuableChecked(issuable, value) {
+ if (value) {
+ this.selectedIssuables.push(issuable);
+ } else {
+ const index = this.selectedIssuables.indexOf(issuable);
+ if (index > -1) {
+ this.selectedIssuables.splice(index, 1);
+ }
+ }
+ },
+ moveIssues(targetProject) {
+ const iids = this.selectedIssuables.reduce((result, issueData) => {
+ if (
+ issueData.type === WORK_ITEM_TYPE_ENUM_ISSUE ||
+ issueData.type === WORK_ITEM_TYPE_ENUM_INCIDENT
+ ) {
+ result.push(issueData.iid);
+ }
+ return result;
+ }, []);
+
+ if (iids.length === 0) {
+ return;
+ }
+
+ this.moveInProgress = true;
+ issuableEventHub.$emit('issuables:bulkMoveStarted');
+
+ const promises = iids.map((id) => {
+ return this.moveIssue(id, targetProject);
+ });
+
+ Promise.all(promises)
+ .then((promisesResult) => {
+ let foundError = false;
+
+ for (const promiseResult of promisesResult) {
+ if (promiseResult.data.issueMove?.errors?.length) {
+ foundError = true;
+ logError(
+ `Error moving issue. Error message: ${promiseResult.data.issueMove.errors[0].message}`,
+ );
+ }
+ }
+
+ if (!foundError) {
+ const client = this.$apollo.provider.defaultClient;
+ client.refetchQueries({
+ include: [getIssuesQuery, getIssuesCountQuery],
+ });
+ this.moveInProgress = false;
+ this.selectedIssuables = [];
+ issuableEventHub.$emit('issuables:bulkMoveEnded');
+ } else {
+ throw new Error();
+ }
+ })
+ .catch(() => {
+ this.moveInProgress = false;
+ issuableEventHub.$emit('issuables:bulkMoveEnded');
+
+ createFlash({
+ message: s__(`Issues|There was an error while moving the issues.`),
+ });
+ });
+ },
+ moveIssue(issueIid, targetProject) {
+ return this.$apollo.mutate({
+ mutation: moveIssueMutation,
+ variables: {
+ moveIssueInput: {
+ projectPath: this.projectFullPath,
+ iid: issueIid,
+ targetProjectPath: targetProject.full_path,
+ },
+ },
+ });
+ },
+ },
+ i18n: {
+ dropdownButtonTitle: s__('Issues|Move selected'),
+ },
+};
+</script>
+<template>
+ <div>
+ <issuable-move-dropdown
+ :project-full-path="projectFullPath"
+ :projects-fetch-path="projectsFetchPath"
+ :move-in-progress="moveInProgress"
+ :disabled="!issuesSelected && !incidentsSelected"
+ :dropdown-header-title="$options.i18n.dropdownButtonTitle"
+ :dropdown-button-title="$options.i18n.dropdownButtonTitle"
+ @move-issuable="moveIssues"
+ />
+ <gl-alert v-if="tasksSelected || testCasesSelected" :dismissible="false" variant="warning">
+ {{ cannotMoveTasksWarningTitle }}
+ </gl-alert>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/status/status_dropdown.vue b/app/assets/javascripts/sidebar/components/status/status_dropdown.vue
new file mode 100644
index 00000000000..7763ec00091
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/status/status_dropdown.vue
@@ -0,0 +1,57 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { statusDropdownOptions } from '../../constants';
+
+export default {
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ data() {
+ return {
+ status: null,
+ };
+ },
+ computed: {
+ dropdownText() {
+ return this.status?.text ?? this.$options.i18n.defaultDropdownText;
+ },
+ selectedValue() {
+ return this.status?.value;
+ },
+ },
+ methods: {
+ onDropdownItemClick(statusOption) {
+ // clear status if the currently checked status is clicked again
+ if (this.status?.value === statusOption.value) {
+ this.status = null;
+ } else {
+ this.status = statusOption;
+ }
+ },
+ },
+ i18n: {
+ dropdownTitle: __('Change status'),
+ defaultDropdownText: __('Select status'),
+ },
+ statusDropdownOptions,
+};
+</script>
+<template>
+ <div>
+ <input type="hidden" name="update[state_event]" :value="selectedValue" />
+ <gl-dropdown :text="dropdownText" :title="$options.i18n.dropdownTitle" class="gl-w-full">
+ <gl-dropdown-item
+ v-for="statusOption in $options.statusDropdownOptions"
+ :key="statusOption.value"
+ :is-checked="selectedValue === statusOption.value"
+ is-check-item
+ :title="statusOption.text"
+ @click="onDropdownItemClick(statusOption)"
+ >
+ {{ statusOption.text }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions_dropdown.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions_dropdown.vue
new file mode 100644
index 00000000000..4c3ba76d12d
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions_dropdown.vue
@@ -0,0 +1,51 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { subscriptionsDropdownOptions } from '../../constants';
+
+export default {
+ subscriptionsDropdownOptions,
+ i18n: {
+ defaultDropdownText: __('Select subscription'),
+ headerText: __('Change subscription'),
+ },
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ data() {
+ return {
+ subscription: undefined,
+ };
+ },
+ computed: {
+ dropdownText() {
+ return this.subscription?.text ?? this.$options.i18n.defaultDropdownText;
+ },
+ selectedValue() {
+ return this.subscription?.value;
+ },
+ },
+ methods: {
+ handleClick(option) {
+ this.subscription = option.value === this.subscription?.value ? undefined : option;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <input type="hidden" name="update[subscription_event]" :value="selectedValue" />
+ <gl-dropdown class="gl-w-full" :header-text="$options.i18n.headerText" :text="dropdownText">
+ <gl-dropdown-item
+ v-for="subscriptionsOption in $options.subscriptionsDropdownOptions"
+ :key="subscriptionsOption.value"
+ is-check-item
+ :is-checked="selectedValue === subscriptionsOption.value"
+ @click="handleClick(subscriptionsOption)"
+ >
+ {{ subscriptionsOption.text }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 67b9b540e91..499b03cd931 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -350,3 +350,25 @@ export const escalationStatusQuery = getEscalationStatusQuery;
export const escalationStatusMutation = updateEscalationStatusMutation;
export const HOW_TO_TRACK_TIME = __('How to track time');
+
+export const statusDropdownOptions = [
+ {
+ text: __('Open'),
+ value: 'reopen',
+ },
+ {
+ text: __('Closed'),
+ value: 'close',
+ },
+];
+
+export const subscriptionsDropdownOptions = [
+ {
+ text: __('Subscribe'),
+ value: 'subscribe',
+ },
+ {
+ text: __('Unsubscribe'),
+ value: 'unsubscribe',
+ },
+];
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index b37486283ca..3fc98f86316 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -6,6 +6,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { IssuableType } from '~/issues/constants';
+import { gqlClient } from '~/issues/list/graphql';
import {
isInIssuePage,
isInDesignPage,
@@ -14,33 +15,36 @@ import {
parseBoolean,
} from '~/lib/utils/common_utils';
import { __ } from '~/locale';
-import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue';
-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';
-import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import { apolloProvider } from '~/graphql_shared/issuable_client';
-import trackShowInviteMemberLink from '~/sidebar/track_invite_members';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_vue/constants';
import LabelsSelectWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
-import Translate from '../vue_shared/translate';
+import Translate from '~/vue_shared/translate';
+import CollapsedAssigneeList from './components/assignees/collapsed_assignee_list.vue';
import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
-import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue';
+import SidebarAssigneesWidget from './components/assignees/sidebar_assignees_widget.vue';
+import SidebarConfidentialityWidget from './components/confidential/sidebar_confidentiality_widget.vue';
+import CopyEmailToClipboard from './components/copy_email/copy_email_to_clipboard.vue';
+import SidebarDueDateWidget from './components/date/sidebar_date_widget.vue';
import SidebarEscalationStatus from './components/incidents/sidebar_escalation_status.vue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
+import MilestoneDropdown from './components/milestone/milestone_dropdown.vue';
+import MoveIssuesButton from './components/move/move_issues_button.vue';
+import SidebarParticipantsWidget from './components/participants/sidebar_participants_widget.vue';
+import SidebarReferenceWidget from './components/reference/sidebar_reference_widget.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 SidebarDropdownWidget from './components/sidebar_dropdown_widget.vue';
+import StatusDropdown from './components/status/status_dropdown.vue';
import SidebarSubscriptionsWidget from './components/subscriptions/sidebar_subscriptions_widget.vue';
+import SubscriptionsDropdown from './components/subscriptions/subscriptions_dropdown.vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
+import SidebarTodoWidget from './components/todo_toggle/sidebar_todo_widget.vue';
import { IssuableAttributeType } from './constants';
-import SidebarMoveIssue from './lib/sidebar_move_issue';
import CrmContacts from './components/crm_contacts/crm_contacts.vue';
+import SidebarMoveIssue from './lib/sidebar_move_issue';
+import trackShowInviteMemberLink from './track_invite_members';
Vue.use(Translate);
Vue.use(VueApollo);
@@ -635,6 +639,59 @@ function mountCopyEmailToClipboard() {
});
}
+export function mountMoveIssuesButton() {
+ const el = document.querySelector('.js-move-issues');
+
+ if (!el) {
+ return null;
+ }
+
+ Vue.use(VueApollo);
+
+ return new Vue({
+ el,
+ name: 'MoveIssuesRoot',
+ apolloProvider: new VueApollo({
+ defaultClient: gqlClient,
+ }),
+ render: (createElement) =>
+ createElement(MoveIssuesButton, {
+ props: {
+ projectFullPath: el.dataset.projectFullPath,
+ projectsFetchPath: el.dataset.projectsFetchPath,
+ },
+ }),
+ });
+}
+
+export function mountStatusDropdown() {
+ const el = document.querySelector('.js-status-dropdown');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ name: 'StatusDropdownRoot',
+ render: (createElement) => createElement(StatusDropdown),
+ });
+}
+
+export function mountSubscriptionsDropdown() {
+ const el = document.querySelector('.js-subscriptions-dropdown');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ name: 'SubscriptionsDropdownRoot',
+ render: (createElement) => createElement(SubscriptionsDropdown),
+ });
+}
+
const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage() || isInMRPage()) && gon.features.issueAssigneesWidget;
diff --git a/app/assets/javascripts/sidebar/queries/move_issue.mutation.graphql b/app/assets/javascripts/sidebar/queries/move_issue.mutation.graphql
new file mode 100644
index 00000000000..d350072425b
--- /dev/null
+++ b/app/assets/javascripts/sidebar/queries/move_issue.mutation.graphql
@@ -0,0 +1,5 @@
+mutation moveIssue($moveIssueInput: IssueMoveInput!) {
+ issueMove(input: $moveIssueInput) {
+ errors
+ }
+}