diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-25 18:10:56 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-25 18:10:56 +0000 |
commit | d612723c35d7fdaeb8b09e91232053e04850c2ae (patch) | |
tree | 0a55d7d5dcb3745f60b25aabe508c27a734a9e37 /app/assets/javascripts/sidebar | |
parent | 35e5a7c8455f916bc969ec814c74cefd98d24f19 (diff) | |
download | gitlab-ce-d612723c35d7fdaeb8b09e91232053e04850c2ae.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/sidebar')
33 files changed, 698 insertions, 56 deletions
diff --git a/app/assets/javascripts/sidebar/components/copy_email/copy_email_to_clipboard.vue b/app/assets/javascripts/sidebar/components/copy/copy_email_to_clipboard.vue index fd652583f76..96ecdc84ef5 100644 --- a/app/assets/javascripts/sidebar/components/copy_email/copy_email_to_clipboard.vue +++ b/app/assets/javascripts/sidebar/components/copy/copy_email_to_clipboard.vue @@ -1,5 +1,5 @@ <script> -import CopyableField from '~/vue_shared/components/sidebar/copyable_field.vue'; +import CopyableField from './copyable_field.vue'; export default { components: { diff --git a/app/assets/javascripts/sidebar/components/copy/copyable_field.vue b/app/assets/javascripts/sidebar/components/copy/copyable_field.vue new file mode 100644 index 00000000000..6538de085b0 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/copy/copyable_field.vue @@ -0,0 +1,86 @@ +<script> +import { GlLoadingIcon, GlSprintf } from '@gitlab/ui'; +import { s__, __, sprintf } from '~/locale'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; + +/** + * Renders an inline field, whose value can be copied to the clipboard, + * for use in the GitLab sidebar (issues, MRs, etc.). + */ +export default { + name: 'CopyableField', + components: { + ClipboardButton, + GlLoadingIcon, + GlSprintf, + }, + props: { + value: { + type: String, + required: true, + }, + name: { + type: String, + required: true, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + clipboardTooltipText: { + type: String, + required: false, + default: undefined, + }, + }, + computed: { + clipboardProps() { + return { + category: 'tertiary', + tooltipBoundary: 'viewport', + tooltipPlacement: 'left', + text: this.value, + title: + this.clipboardTooltipText || + sprintf(this.$options.i18n.clipboardTooltip, { name: this.name }), + }; + }, + loadingIconLabel() { + return sprintf(this.$options.i18n.loadingIconLabel, { name: this.name }); + }, + }, + i18n: { + loadingIconLabel: __('Loading %{name}'), + clipboardTooltip: __('Copy %{name}'), + templateText: s__('Sidebar|%{name}: %{value}'), + }, +}; +</script> + +<template> + <div> + <clipboard-button + v-if="!isLoading" + css-class="sidebar-collapsed-icon js-dont-change-state gl-rounded-0! gl-hover-bg-transparent" + v-bind="clipboardProps" + /> + + <div + class="gl-display-flex gl-align-items-center gl-justify-content-space-between hide-collapsed" + > + <span + class="gl-overflow-hidden gl-text-overflow-ellipsis gl-white-space-nowrap" + :title="value" + > + <gl-sprintf :message="$options.i18n.templateText"> + <template #name>{{ name }}</template> + <template #value>{{ value }}</template> + </gl-sprintf> + </span> + + <gl-loading-icon v-if="isLoading" size="sm" inline :label="loadingIconLabel" /> + <clipboard-button v-else size="small" v-bind="clipboardProps" /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/reference/sidebar_reference_widget.vue b/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue index d07c6e0cbd2..b7922c63c36 100644 --- a/app/assets/javascripts/sidebar/components/reference/sidebar_reference_widget.vue +++ b/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue @@ -1,7 +1,7 @@ <script> import { __ } from '~/locale'; import { referenceQueries } from '~/sidebar/constants'; -import CopyableField from '~/vue_shared/components/sidebar/copyable_field.vue'; +import CopyableField from './copyable_field.vue'; export default { components: { 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 81090bfa062..0660e4f58e4 100644 --- a/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue +++ b/app/assets/javascripts/sidebar/components/crm_contacts/crm_contacts.vue @@ -4,8 +4,8 @@ import { __, n__, sprintf } from '~/locale'; import { createAlert } from '~/flash'; import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; import { TYPE_ISSUE } from '~/graphql_shared/constants'; -import getIssueCrmContactsQuery from './queries/get_issue_crm_contacts.query.graphql'; -import issueCrmContactsSubscription from './queries/issue_crm_contacts.subscription.graphql'; +import getIssueCrmContactsQuery from '../../queries/get_issue_crm_contacts.query.graphql'; +import issueCrmContactsSubscription from '../../queries/issue_crm_contacts.subscription.graphql'; export default { components: { diff --git a/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue new file mode 100644 index 00000000000..02323e5a0c6 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue @@ -0,0 +1,217 @@ +<script> +import { + GlIcon, + GlLoadingIcon, + GlDropdown, + GlDropdownForm, + GlDropdownItem, + GlSearchBoxByType, + GlButton, + GlTooltipDirective as GlTooltip, +} from '@gitlab/ui'; + +import axios from '~/lib/utils/axios_utils'; + +export default { + components: { + GlIcon, + GlLoadingIcon, + GlDropdown, + GlDropdownForm, + GlDropdownItem, + GlSearchBoxByType, + GlButton, + }, + directives: { + GlTooltip, + }, + props: { + projectsFetchPath: { + type: String, + required: true, + }, + dropdownButtonTitle: { + type: String, + required: true, + }, + dropdownHeaderTitle: { + type: String, + required: true, + }, + moveInProgress: { + type: Boolean, + required: false, + default: false, + }, + disabled: { + type: Boolean, + required: false, + default: false, + }, + }, + data() { + return { + projectsListLoading: false, + projectsListLoadFailed: false, + searchKey: '', + projects: [], + selectedProject: null, + projectItemClick: false, + }; + }, + computed: { + hasNoSearchResults() { + return Boolean( + !this.projectsListLoading && + !this.projectsListLoadFailed && + this.searchKey && + !this.projects.length, + ); + }, + failedToLoadResults() { + return !this.projectsListLoading && this.projectsListLoadFailed; + }, + }, + watch: { + searchKey(value = '') { + this.fetchProjects(value); + }, + }, + methods: { + fetchProjects(search = '') { + this.projectsListLoading = true; + this.projectsListLoadFailed = false; + return axios + .get(this.projectsFetchPath, { + params: { + search, + }, + }) + .then(({ data }) => { + this.projects = data; + this.$refs.searchInput.focusInput(); + }) + .catch(() => { + this.projectsListLoadFailed = true; + }) + .finally(() => { + this.projectsListLoading = false; + }); + }, + isSelectedProject(project) { + if (this.selectedProject) { + return this.selectedProject.id === project.id; + } + return false; + }, + /** + * This handler is to prevent dropdown + * from closing when an item is selected + * and emit an event only when dropdown closes. + */ + handleDropdownHide(e) { + if (this.projectItemClick) { + e.preventDefault(); + this.projectItemClick = false; + } else { + this.$emit('dropdown-close'); + } + }, + handleDropdownCloseClick() { + this.$refs.dropdown.hide(); + }, + handleProjectSelect(project) { + this.selectedProject = project.id === this.selectedProject?.id ? null : project; + this.projectItemClick = true; + }, + handleMoveClick() { + this.$refs.dropdown.hide(); + this.$emit('move-issuable', this.selectedProject); + }, + }, +}; +</script> + +<template> + <div class="js-issuable-move-block issuable-move-dropdown sidebar-move-issue-dropdown"> + <div + v-gl-tooltip.left.viewport + data-testid="move-collapsed" + :title="dropdownButtonTitle" + class="sidebar-collapsed-icon" + @click="$emit('toggle-collapse')" + > + <gl-icon name="arrow-right" /> + </div> + <gl-dropdown + ref="dropdown" + :block="true" + :disabled="moveInProgress || disabled" + class="hide-collapsed" + toggle-class="js-sidebar-dropdown-toggle" + @shown="fetchProjects" + @hide="handleDropdownHide" + > + <template #button-content + ><gl-loading-icon v-if="moveInProgress" size="sm" class="gl-mr-3" />{{ + dropdownButtonTitle + }}</template + > + <gl-dropdown-form class="gl-pt-0"> + <div + data-testid="header" + class="gl-display-flex gl-pb-3 gl-border-1 gl-border-b-solid gl-border-gray-100" + > + <span class="gl-flex-grow-1 gl-text-center gl-font-weight-bold gl-py-1">{{ + dropdownHeaderTitle + }}</span> + <gl-button + variant="link" + icon="close" + class="gl-mr-2 gl-w-auto! gl-p-2!" + :aria-label="__('Close')" + @click.prevent="handleDropdownCloseClick" + /> + </div> + <gl-search-box-by-type + ref="searchInput" + v-model.trim="searchKey" + :placeholder="__('Search project')" + :debounce="300" + /> + <div data-testid="content" class="dropdown-content"> + <gl-loading-icon v-if="projectsListLoading" size="lg" class="gl-p-5" /> + <ul v-else> + <gl-dropdown-item + v-for="project in projects" + :key="project.id" + is-check-item + :is-checked="isSelectedProject(project)" + @click.stop.prevent="handleProjectSelect(project)" + >{{ project.name_with_namespace }}</gl-dropdown-item + > + </ul> + <div v-if="hasNoSearchResults" class="gl-text-center gl-p-3"> + {{ __('No matching results') }} + </div> + <div v-if="failedToLoadResults" class="gl-text-center gl-p-3"> + {{ __('Failed to load projects') }} + </div> + </div> + <div + data-testid="footer" + class="gl-pt-3 gl-px-3 gl-border-1 gl-border-t-solid gl-border-gray-100" + > + <gl-button + category="primary" + variant="confirm" + :disabled="!Boolean(selectedProject)" + class="gl-text-center! issuable-move-button" + @click="handleMoveClick" + >{{ __('Move') }}</gl-button + > + </div> + </gl-dropdown-form> + </gl-dropdown> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/move/move_issues_button.vue b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue index a3a5072fc2d..afe47adc1d3 100644 --- a/app/assets/javascripts/sidebar/components/move/move_issues_button.vue +++ b/app/assets/javascripts/sidebar/components/move/move_issues_button.vue @@ -1,6 +1,5 @@ <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'; @@ -14,6 +13,7 @@ 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'; +import IssuableMoveDropdown from './issuable_move_dropdown.vue'; export default { name: 'MoveIssuesButton', diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue index 5f1350690eb..72bf04b4c69 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue @@ -8,9 +8,9 @@ import { __ } from '~/locale'; import eventHub from '~/sidebar/event_hub'; import Store from '~/sidebar/stores/sidebar_store'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import getMergeRequestReviewersQuery from '~/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql'; -import mergeRequestReviewersUpdatedSubscription from '~/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import getMergeRequestReviewersQuery from '../../queries/get_merge_request_reviewers.query.graphql'; +import mergeRequestReviewersUpdatedSubscription from '../../queries/merge_request_reviewers.subscription.graphql'; import ReviewerTitle from './reviewer_title.vue'; import Reviewers from './reviewers.vue'; diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue index f02e0c783e1..370ca9f74a3 100644 --- a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue +++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue @@ -8,8 +8,8 @@ import { GlButton, } from '@gitlab/ui'; import { createAlert } from '~/flash'; +import updateIssuableSeverity from '../../queries/update_issuable_severity.mutation.graphql'; import { INCIDENT_SEVERITY, ISSUABLE_TYPES, I18N } from './constants'; -import updateIssuableSeverity from './graphql/mutations/update_issuable_severity.mutation.graphql'; import SeverityToken from './severity.vue'; export default { diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue index 124464088cf..16e6a914fd5 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue @@ -6,7 +6,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils'; import { formatDate, parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; import { __, s__ } from '~/locale'; import { timelogQueries } from '~/sidebar/constants'; -import deleteTimelogMutation from './graphql/mutations/delete_timelog.mutation.graphql'; +import deleteTimelogMutation from '../../queries/delete_timelog.mutation.graphql'; const TIME_DATE_FORMAT = 'mmmm d, yyyy, HH:MM ("UTC:" o)'; diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue index 5da2d65723a..b86ff279fd8 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue @@ -3,11 +3,11 @@ import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { produce } from 'immer'; import { createAlert } from '~/flash'; import { __, sprintf } from '~/locale'; -import { todoQueries, TodoMutationTypes, todoMutations } from '~/sidebar/constants'; -import { todoLabel } from '~/vue_shared/components/sidebar/todo_toggle//utils'; -import TodoButton from '~/vue_shared/components/sidebar/todo_toggle/todo_button.vue'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import Tracking from '~/tracking'; +import { todoQueries, TodoMutationTypes, todoMutations } from '../../constants'; +import { todoLabel } from '../../utils'; +import TodoButton from './todo_button.vue'; const trackingMixin = Tracking.mixin(); diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo_button.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo_button.vue new file mode 100644 index 00000000000..b49b8fc389b --- /dev/null +++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo_button.vue @@ -0,0 +1,44 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import { todoLabel, updateGlobalTodoCount } from '../../utils'; + +export default { + components: { + GlButton, + }, + props: { + isTodo: { + type: Boolean, + required: false, + default: true, + }, + }, + computed: { + buttonLabel() { + return todoLabel(this.isTodo); + }, + }, + methods: { + incrementGlobalTodoCount() { + updateGlobalTodoCount(1); + }, + decrementGlobalTodoCount() { + updateGlobalTodoCount(-1); + }, + onToggle(event) { + if (this.isTodo) { + this.decrementGlobalTodoCount(); + } else { + this.incrementGlobalTodoCount(); + } + this.$emit('click', event); + }, + }, +}; +</script> + +<template> + <gl-button v-bind="$attrs" :aria-label="buttonLabel" @click="onToggle($event)"> + {{ buttonLabel }} + </gl-button> +</template> diff --git a/app/assets/javascripts/sidebar/components/toggle/toggle_sidebar.vue b/app/assets/javascripts/sidebar/components/toggle/toggle_sidebar.vue new file mode 100644 index 00000000000..6dacf4e10d3 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/toggle/toggle_sidebar.vue @@ -0,0 +1,55 @@ +<script> +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; +import { __ } from '~/locale'; + +export default { + name: 'ToggleSidebar', + components: { + GlButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + collapsed: { + type: Boolean, + required: true, + }, + cssClasses: { + type: String, + required: false, + default: '', + }, + }, + computed: { + tooltipLabel() { + return this.collapsed ? __('Expand sidebar') : __('Collapse sidebar'); + }, + buttonIcon() { + return this.collapsed ? 'chevron-double-lg-left' : 'chevron-double-lg-right'; + }, + allCssClasses() { + return [this.cssClasses, { 'js-sidebar-collapsed': this.collapsed }]; + }, + }, + methods: { + toggle() { + this.$emit('toggle'); + }, + }, +}; +</script> + +<template> + <gl-button + v-gl-tooltip:body.viewport.left + :title="tooltipLabel" + :class="allCssClasses" + class="gutter-toggle btn-sidebar-action js-sidebar-vue-toggle" + :icon="buttonIcon" + category="tertiary" + size="small" + :aria-label="__('toggle collapse')" + @click="toggle" + /> +</template> diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js index 499b03cd931..0316a6a4688 100644 --- a/app/assets/javascripts/sidebar/constants.js +++ b/app/assets/javascripts/sidebar/constants.js @@ -4,37 +4,6 @@ import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutatio import userSearchQuery from '~/graphql_shared/queries/users_search.query.graphql'; import userSearchWithMRPermissionsQuery from '~/graphql_shared/queries/users_search_with_mr_permissions.graphql'; import { IssuableType, WorkspaceType } from '~/issues/constants'; -import epicConfidentialQuery from '~/sidebar/queries/epic_confidential.query.graphql'; -import epicDueDateQuery from '~/sidebar/queries/epic_due_date.query.graphql'; -import epicParticipantsQuery from '~/sidebar/queries/epic_participants.query.graphql'; -import epicReferenceQuery from '~/sidebar/queries/epic_reference.query.graphql'; -import epicStartDateQuery from '~/sidebar/queries/epic_start_date.query.graphql'; -import epicSubscribedQuery from '~/sidebar/queries/epic_subscribed.query.graphql'; -import epicTodoQuery from '~/sidebar/queries/epic_todo.query.graphql'; -import issuableAssigneesSubscription from '~/sidebar/queries/issuable_assignees.subscription.graphql'; -import issueConfidentialQuery from '~/sidebar/queries/issue_confidential.query.graphql'; -import issueDueDateQuery from '~/sidebar/queries/issue_due_date.query.graphql'; -import issueReferenceQuery from '~/sidebar/queries/issue_reference.query.graphql'; -import issueSubscribedQuery from '~/sidebar/queries/issue_subscribed.query.graphql'; -import issueTimeTrackingQuery from '~/sidebar/queries/issue_time_tracking.query.graphql'; -import issueTodoQuery from '~/sidebar/queries/issue_todo.query.graphql'; -import mergeRequestMilestone from '~/sidebar/queries/merge_request_milestone.query.graphql'; -import mergeRequestReferenceQuery from '~/sidebar/queries/merge_request_reference.query.graphql'; -import mergeRequestSubscribed from '~/sidebar/queries/merge_request_subscribed.query.graphql'; -import mergeRequestTimeTrackingQuery from '~/sidebar/queries/merge_request_time_tracking.query.graphql'; -import mergeRequestTodoQuery from '~/sidebar/queries/merge_request_todo.query.graphql'; -import todoCreateMutation from '~/sidebar/queries/todo_create.mutation.graphql'; -import todoMarkDoneMutation from '~/sidebar/queries/todo_mark_done.mutation.graphql'; -import updateEpicConfidentialMutation from '~/sidebar/queries/update_epic_confidential.mutation.graphql'; -import updateEpicDueDateMutation from '~/sidebar/queries/update_epic_due_date.mutation.graphql'; -import updateEpicStartDateMutation from '~/sidebar/queries/update_epic_start_date.mutation.graphql'; -import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscription.mutation.graphql'; -import updateIssueConfidentialMutation from '~/sidebar/queries/update_issue_confidential.mutation.graphql'; -import updateIssueDueDateMutation from '~/sidebar/queries/update_issue_due_date.mutation.graphql'; -import updateIssueSubscriptionMutation from '~/sidebar/queries/update_issue_subscription.mutation.graphql'; -import mergeRequestMilestoneMutation from '~/sidebar/queries/update_merge_request_milestone.mutation.graphql'; -import updateMergeRequestLabelsMutation from '~/sidebar/queries/update_merge_request_labels.mutation.graphql'; -import updateMergeRequestSubscriptionMutation from '~/sidebar/queries/update_merge_request_subscription.mutation.graphql'; import updateAlertAssigneesMutation from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql'; import epicLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql'; import updateEpicLabelsMutation from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_update_labels.mutation.graphql'; @@ -42,17 +11,48 @@ import groupLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widg import issueLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql'; import mergeRequestLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql'; import projectLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql'; -import getAlertAssignees from '~/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql'; -import getIssueAssignees from '~/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql'; -import issueParticipantsQuery from '~/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql'; -import getIssueTimelogsQuery from '~/vue_shared/components/sidebar/queries/get_issue_timelogs.query.graphql'; -import getMergeRequestAssignees from '~/vue_shared/components/sidebar/queries/get_mr_assignees.query.graphql'; -import getMergeRequestParticipants from '~/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql'; -import getMrTimelogsQuery from '~/vue_shared/components/sidebar/queries/get_mr_timelogs.query.graphql'; -import updateIssueAssigneesMutation from '~/vue_shared/components/sidebar/queries/update_issue_assignees.mutation.graphql'; -import updateMergeRequestAssigneesMutation from '~/vue_shared/components/sidebar/queries/update_mr_assignees.mutation.graphql'; -import getEscalationStatusQuery from '~/sidebar/queries/escalation_status.query.graphql'; -import updateEscalationStatusMutation from '~/sidebar/queries/update_escalation_status.mutation.graphql'; +import epicConfidentialQuery from './queries/epic_confidential.query.graphql'; +import epicDueDateQuery from './queries/epic_due_date.query.graphql'; +import epicParticipantsQuery from './queries/epic_participants.query.graphql'; +import epicReferenceQuery from './queries/epic_reference.query.graphql'; +import epicStartDateQuery from './queries/epic_start_date.query.graphql'; +import epicSubscribedQuery from './queries/epic_subscribed.query.graphql'; +import epicTodoQuery from './queries/epic_todo.query.graphql'; +import issuableAssigneesSubscription from './queries/issuable_assignees.subscription.graphql'; +import issueConfidentialQuery from './queries/issue_confidential.query.graphql'; +import issueDueDateQuery from './queries/issue_due_date.query.graphql'; +import issueReferenceQuery from './queries/issue_reference.query.graphql'; +import issueSubscribedQuery from './queries/issue_subscribed.query.graphql'; +import issueTimeTrackingQuery from './queries/issue_time_tracking.query.graphql'; +import issueTodoQuery from './queries/issue_todo.query.graphql'; +import mergeRequestMilestone from './queries/merge_request_milestone.query.graphql'; +import mergeRequestReferenceQuery from './queries/merge_request_reference.query.graphql'; +import mergeRequestSubscribed from './queries/merge_request_subscribed.query.graphql'; +import mergeRequestTimeTrackingQuery from './queries/merge_request_time_tracking.query.graphql'; +import mergeRequestTodoQuery from './queries/merge_request_todo.query.graphql'; +import todoCreateMutation from './queries/todo_create.mutation.graphql'; +import todoMarkDoneMutation from './queries/todo_mark_done.mutation.graphql'; +import updateEpicConfidentialMutation from './queries/update_epic_confidential.mutation.graphql'; +import updateEpicDueDateMutation from './queries/update_epic_due_date.mutation.graphql'; +import updateEpicStartDateMutation from './queries/update_epic_start_date.mutation.graphql'; +import updateEpicSubscriptionMutation from './queries/update_epic_subscription.mutation.graphql'; +import updateIssueConfidentialMutation from './queries/update_issue_confidential.mutation.graphql'; +import updateIssueDueDateMutation from './queries/update_issue_due_date.mutation.graphql'; +import updateIssueSubscriptionMutation from './queries/update_issue_subscription.mutation.graphql'; +import mergeRequestMilestoneMutation from './queries/update_merge_request_milestone.mutation.graphql'; +import updateMergeRequestLabelsMutation from './queries/update_merge_request_labels.mutation.graphql'; +import updateMergeRequestSubscriptionMutation from './queries/update_merge_request_subscription.mutation.graphql'; +import getAlertAssignees from './queries/get_alert_assignees.query.graphql'; +import getIssueAssignees from './queries/get_issue_assignees.query.graphql'; +import issueParticipantsQuery from './queries/get_issue_participants.query.graphql'; +import getIssueTimelogsQuery from './queries/get_issue_timelogs.query.graphql'; +import getMergeRequestAssignees from './queries/get_mr_assignees.query.graphql'; +import getMergeRequestParticipants from './queries/get_mr_participants.query.graphql'; +import getMrTimelogsQuery from './queries/get_mr_timelogs.query.graphql'; +import updateIssueAssigneesMutation from './queries/update_issue_assignees.mutation.graphql'; +import updateMergeRequestAssigneesMutation from './queries/update_mr_assignees.mutation.graphql'; +import getEscalationStatusQuery from './queries/escalation_status.query.graphql'; +import updateEscalationStatusMutation from './queries/update_escalation_status.mutation.graphql'; import groupMilestonesQuery from './queries/group_milestones.query.graphql'; import projectIssueMilestoneMutation from './queries/project_issue_milestone.mutation.graphql'; import projectIssueMilestoneQuery from './queries/project_issue_milestone.query.graphql'; diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 3fc98f86316..646152bfea4 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -24,14 +24,14 @@ import CollapsedAssigneeList from './components/assignees/collapsed_assignee_lis import SidebarAssignees from './components/assignees/sidebar_assignees.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 CopyEmailToClipboard from './components/copy/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 SidebarReferenceWidget from './components/copy/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'; diff --git a/app/assets/javascripts/sidebar/components/time_tracking/graphql/mutations/delete_timelog.mutation.graphql b/app/assets/javascripts/sidebar/queries/delete_timelog.mutation.graphql index 6e916893b5a..6e916893b5a 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/graphql/mutations/delete_timelog.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/delete_timelog.mutation.graphql diff --git a/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql b/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql new file mode 100644 index 00000000000..bb6c7181e5c --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_alert_assignees.query.graphql @@ -0,0 +1,21 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query alertAssignees( + $domain: AlertManagementDomainFilter = threat_monitoring + $fullPath: ID! + $iid: String! +) { + workspace: project(fullPath: $fullPath) { + id + issuable: alertManagementAlert(domain: $domain, iid: $iid) { + iid + assignees { + nodes { + ...User + ...UserAvailability + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql b/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql new file mode 100644 index 00000000000..4af07366a6d --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_issue_assignees.query.graphql @@ -0,0 +1,21 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query issueAssignees($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + id + issuable: issue(iid: $iid) { + id + author { + ...User + ...UserAvailability + } + assignees { + nodes { + ...User + ...UserAvailability + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/components/crm_contacts/queries/get_issue_crm_contacts.query.graphql b/app/assets/javascripts/sidebar/queries/get_issue_crm_contacts.query.graphql index 30a0af10d56..30a0af10d56 100644 --- a/app/assets/javascripts/sidebar/components/crm_contacts/queries/get_issue_crm_contacts.query.graphql +++ b/app/assets/javascripts/sidebar/queries/get_issue_crm_contacts.query.graphql diff --git a/app/assets/javascripts/sidebar/queries/get_issue_participants.query.graphql b/app/assets/javascripts/sidebar/queries/get_issue_participants.query.graphql new file mode 100644 index 00000000000..eae5e96ac46 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_issue_participants.query.graphql @@ -0,0 +1,17 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query issueParticipants($fullPath: ID!, $iid: String!, $getStatus: Boolean = false) { + workspace: project(fullPath: $fullPath) { + id + issuable: issue(iid: $iid) { + id + participants { + nodes { + ...User + ...UserAvailability @include(if: $getStatus) + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_issue_timelogs.query.graphql b/app/assets/javascripts/sidebar/queries/get_issue_timelogs.query.graphql new file mode 100644 index 00000000000..b127b8ec5a9 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_issue_timelogs.query.graphql @@ -0,0 +1,13 @@ +#import "~/graphql_shared/fragments/issuable_timelogs.fragment.graphql" + +query issueTimeTrackingReport($id: IssueID!) { + issuable: issue(id: $id) { + id + title + timelogs { + nodes { + ...TimelogFragment + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_merge_request_reviewers.query.graphql b/app/assets/javascripts/sidebar/queries/get_merge_request_reviewers.query.graphql new file mode 100644 index 00000000000..f087ca6c982 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_merge_request_reviewers.query.graphql @@ -0,0 +1,26 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query mergeRequestReviewers($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + id + issuable: mergeRequest(iid: $iid) { + id + reviewers { + nodes { + ...User + ...UserAvailability + mergeRequestInteraction { + canMerge + canUpdate + approved + reviewed + } + } + } + userPermissions { + adminMergeRequest + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_mr_assignees.query.graphql b/app/assets/javascripts/sidebar/queries/get_mr_assignees.query.graphql new file mode 100644 index 00000000000..f70cd723f2e --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_mr_assignees.query.graphql @@ -0,0 +1,30 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query getMrAssignees($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + id + issuable: mergeRequest(iid: $iid) { + id + author { + ...User + ...UserAvailability + mergeRequestInteraction { + canMerge + } + } + assignees { + nodes { + ...User + ...UserAvailability + mergeRequestInteraction { + canMerge + } + } + } + userPermissions { + canMerge + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_mr_participants.query.graphql b/app/assets/javascripts/sidebar/queries/get_mr_participants.query.graphql new file mode 100644 index 00000000000..2781ac71f31 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_mr_participants.query.graphql @@ -0,0 +1,17 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +query getMrParticipants($fullPath: ID!, $iid: String!, $getStatus: Boolean = false) { + workspace: project(fullPath: $fullPath) { + id + issuable: mergeRequest(iid: $iid) { + id + participants { + nodes { + ...User + ...UserAvailability @include(if: $getStatus) + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/get_mr_timelogs.query.graphql b/app/assets/javascripts/sidebar/queries/get_mr_timelogs.query.graphql new file mode 100644 index 00000000000..17f548b44b5 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/get_mr_timelogs.query.graphql @@ -0,0 +1,13 @@ +#import "~/graphql_shared/fragments/issuable_timelogs.fragment.graphql" + +query mrTimeTrackingReport($id: MergeRequestID!) { + issuable: mergeRequest(id: $id) { + id + title + timelogs { + nodes { + ...TimelogFragment + } + } + } +} diff --git a/app/assets/javascripts/sidebar/components/crm_contacts/queries/issue_crm_contacts.fragment.graphql b/app/assets/javascripts/sidebar/queries/issue_crm_contacts.fragment.graphql index 750e1f1d1af..750e1f1d1af 100644 --- a/app/assets/javascripts/sidebar/components/crm_contacts/queries/issue_crm_contacts.fragment.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_crm_contacts.fragment.graphql diff --git a/app/assets/javascripts/sidebar/components/crm_contacts/queries/issue_crm_contacts.subscription.graphql b/app/assets/javascripts/sidebar/queries/issue_crm_contacts.subscription.graphql index f3b6e4ec06f..f3b6e4ec06f 100644 --- a/app/assets/javascripts/sidebar/components/crm_contacts/queries/issue_crm_contacts.subscription.graphql +++ b/app/assets/javascripts/sidebar/queries/issue_crm_contacts.subscription.graphql diff --git a/app/assets/javascripts/sidebar/queries/merge_request_reviewers.subscription.graphql b/app/assets/javascripts/sidebar/queries/merge_request_reviewers.subscription.graphql new file mode 100644 index 00000000000..a1b16b378b3 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/merge_request_reviewers.subscription.graphql @@ -0,0 +1,22 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +subscription mergeRequestReviewersUpdated($issuableId: IssuableID!) { + mergeRequestReviewersUpdated(issuableId: $issuableId) { + ... on MergeRequest { + id + reviewers { + nodes { + ...User + ...UserAvailability + mergeRequestInteraction { + canMerge + canUpdate + approved + reviewed + } + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_issuable_severity.mutation.graphql index c9d36dfdb67..c9d36dfdb67 100644 --- a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/update_issuable_severity.mutation.graphql diff --git a/app/assets/javascripts/sidebar/queries/update_issue_assignees.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_issue_assignees.mutation.graphql new file mode 100644 index 00000000000..24de5ea4fe3 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/update_issue_assignees.mutation.graphql @@ -0,0 +1,18 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +mutation issueSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullPath: ID!) { + issuableSetAssignees: issueSetAssignees( + input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $fullPath } + ) { + issuable: issue { + id + assignees { + nodes { + ...User + ...UserAvailability + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_issue_lock.mutation.graphql index cb9ee6abc9b..cb9ee6abc9b 100644 --- a/app/assets/javascripts/sidebar/components/lock/mutations/update_issue_lock.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/update_issue_lock.mutation.graphql diff --git a/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_merge_request_lock.mutation.graphql index 11eb3611006..11eb3611006 100644 --- a/app/assets/javascripts/sidebar/components/lock/mutations/update_merge_request_lock.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/update_merge_request_lock.mutation.graphql diff --git a/app/assets/javascripts/sidebar/queries/update_mr_assignees.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_mr_assignees.mutation.graphql new file mode 100644 index 00000000000..5fec2ccbdfb --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/update_mr_assignees.mutation.graphql @@ -0,0 +1,21 @@ +#import "~/graphql_shared/fragments/user.fragment.graphql" +#import "~/graphql_shared/fragments/user_availability.fragment.graphql" + +mutation mergeRequestSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullPath: ID!) { + issuableSetAssignees: mergeRequestSetAssignees( + input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $fullPath } + ) { + issuable: mergeRequest { + id + assignees { + nodes { + ...User + ...UserAvailability + mergeRequestInteraction { + canMerge + } + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/utils.js b/app/assets/javascripts/sidebar/utils.js new file mode 100644 index 00000000000..098ab72dfb5 --- /dev/null +++ b/app/assets/javascripts/sidebar/utils.js @@ -0,0 +1,21 @@ +import { __ } from '~/locale'; + +export const todoLabel = (hasTodo) => { + return hasTodo ? __('Mark as done') : __('Add a to do'); +}; + +export const updateGlobalTodoCount = (additionalTodoCount) => { + const countContainer = document.querySelector('.js-todos-count'); + + if (countContainer === null) return; + + const currentCount = parseInt(countContainer.innerText, 10); + + const todoToggleEvent = new CustomEvent('todo:toggle', { + detail: { + count: Math.max(currentCount + additionalTodoCount, 0), + }, + }); + + document.dispatchEvent(todoToggleEvent); +}; |