diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 13:43:29 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 13:43:29 +0300 |
commit | 3b1af5cc7ed2666ff18b718ce5d30fa5a2756674 (patch) | |
tree | 3bc4a40e0ee51ec27eabf917c537033c0c5b14d4 /app/assets/javascripts/issues | |
parent | 9bba14be3f2c211bf79e15769cd9b77bc73a13bc (diff) |
Add latest changes from gitlab-org/gitlab@16-1-stable-eev16.1.0-rc42
Diffstat (limited to 'app/assets/javascripts/issues')
18 files changed, 202 insertions, 150 deletions
diff --git a/app/assets/javascripts/issues/constants.js b/app/assets/javascripts/issues/constants.js index c79612ad5d0..444ee704521 100644 --- a/app/assets/javascripts/issues/constants.js +++ b/app/assets/javascripts/issues/constants.js @@ -14,6 +14,7 @@ export const TYPE_EPIC = 'epic'; export const TYPE_INCIDENT = 'incident'; export const TYPE_ISSUE = 'issue'; export const TYPE_MERGE_REQUEST = 'merge_request'; +export const TYPE_MILESTONE = 'milestone'; export const TYPE_TEST_CASE = 'test_case'; export const WORKSPACE_GROUP = 'group'; diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue index b9e4d0df3f2..14fe88b8f61 100644 --- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue +++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue @@ -29,6 +29,7 @@ import { getSortOptions, isSortKey, } from '~/issues/list/utils'; +import { fetchPolicies } from '~/lib/graphql'; import axios from '~/lib/utils/axios_utils'; import { scrollUp } from '~/lib/utils/scroll_utils'; import { getParameterByName } from '~/lib/utils/url_utility'; @@ -126,6 +127,10 @@ export default { update(data) { return data.issues.nodes ?? []; }, + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, + // We need this for handling loading state when using frontend cache + // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106004#note_1217325202 for details + notifyOnNetworkStatusChange: true, result({ data }) { this.pageInfo = data?.issues.pageInfo ?? {}; }, @@ -183,6 +188,17 @@ export default { hasSearch() { return Boolean(this.searchQuery || Object.keys(this.urlFilterParams).length); }, + // due to the issues with cache-and-network, we need this hack to check if there is any data for the query in the cache. + // if we have cached data, we disregard the loading state + isLoading() { + return ( + this.$apollo.queries.issues.loading && + !this.$apollo.provider.clients.defaultClient.readQuery({ + query: getIssuesQuery, + variables: this.queryVariables, + }) + ); + }, queryVariables() { return { hideUsers: this.isPublicVisibilityRestricted && !this.isSignedIn, @@ -446,7 +462,7 @@ export default { :initial-filter-value="filterTokens" :initial-sort-by="sortKey" :issuables="renderedIssues" - :issuables-loading="$apollo.queries.issues.loading" + :issuables-loading="isLoading" namespace="dashboard" recent-searches-storage-key="issues" :search-input-placeholder="$options.i18n.searchPlaceholder" @@ -494,6 +510,7 @@ export default { <gl-empty-state :description="emptyStateDescription" :svg-path="emptyStateSvgPath" + :svg-height="150" :title="emptyStateTitle" /> </template> diff --git a/app/assets/javascripts/issues/dashboard/index.js b/app/assets/javascripts/issues/dashboard/index.js index 005ab5ce3b0..999f07781b2 100644 --- a/app/assets/javascripts/issues/dashboard/index.js +++ b/app/assets/javascripts/issues/dashboard/index.js @@ -1,10 +1,10 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; -import createDefaultClient from '~/lib/graphql'; +import { gqlClient } from '~/issues/list/graphql'; import { parseBoolean } from '~/lib/utils/common_utils'; import IssuesDashboardApp from './components/issues_dashboard_app.vue'; -export function mountIssuesDashboardApp() { +export async function mountIssuesDashboardApp() { const el = document.querySelector('.js-issues-dashboard'); if (!el) { @@ -34,7 +34,7 @@ export function mountIssuesDashboardApp() { el, name: 'IssuesDashboardRoot', apolloProvider: new VueApollo({ - defaultClient: createDefaultClient(), + defaultClient: await gqlClient(), }), provide: { autocompleteAwardEmojisPath, diff --git a/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql b/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql index 5625e6afad3..5c331fe95e2 100644 --- a/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql +++ b/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql @@ -1,5 +1,5 @@ #import "~/graphql_shared/fragments/page_info.fragment.graphql" -#import "./issue.fragment.graphql" +#import "~/issues/list/queries/issue.fragment.graphql" query getDashboardIssues( $hideUsers: Boolean = false @@ -44,8 +44,9 @@ query getDashboardIssues( before: $beforeCursor first: $firstPageSize last: $lastPageSize - ) { + ) @persist { nodes { + __persist ...IssueFragment reference(full: true) } diff --git a/app/assets/javascripts/issues/dashboard/queries/issue.fragment.graphql b/app/assets/javascripts/issues/dashboard/queries/issue.fragment.graphql deleted file mode 100644 index 040763f2ba4..00000000000 --- a/app/assets/javascripts/issues/dashboard/queries/issue.fragment.graphql +++ /dev/null @@ -1,56 +0,0 @@ -fragment IssueFragment on Issue { - id - iid - confidential - createdAt - downvotes - dueDate - hidden - humanTimeEstimate - mergeRequestsCount - moved - state - title - updatedAt - closedAt - upvotes - userDiscussionsCount @include(if: $isSignedIn) - webPath - webUrl - type - assignees @skip(if: $hideUsers) { - nodes { - id - avatarUrl - name - username - webUrl - } - } - author @skip(if: $hideUsers) { - id - avatarUrl - name - username - webUrl - } - labels { - nodes { - id - color - title - description - } - } - milestone { - id - dueDate - startDate - webPath - title - } - taskCompletionStatus { - completedCount - count - } -} diff --git a/app/assets/javascripts/issues/list/components/empty_state_with_any_issues.vue b/app/assets/javascripts/issues/list/components/empty_state_with_any_issues.vue index 8aece24de0c..3c58843bcbc 100644 --- a/app/assets/javascripts/issues/list/components/empty_state_with_any_issues.vue +++ b/app/assets/javascripts/issues/list/components/empty_state_with_any_issues.vue @@ -28,6 +28,7 @@ export default { :description="$options.i18n.noSearchResultsDescription" :title="$options.i18n.noSearchResultsTitle" :svg-path="emptyStateSvgPath" + :svg-height="150" > <template #actions> <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm"> @@ -49,5 +50,10 @@ export default { </template> </gl-empty-state> - <gl-empty-state v-else :title="$options.i18n.noClosedIssuesTitle" :svg-path="emptyStateSvgPath" /> + <gl-empty-state + v-else + :title="$options.i18n.noClosedIssuesTitle" + :svg-path="emptyStateSvgPath" + :svg-height="150" + /> </template> diff --git a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue index 98429f3ffd1..3f29fc66abb 100644 --- a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue +++ b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue @@ -1,5 +1,5 @@ <script> -import { GlButton, GlDropdown, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui'; +import { GlButton, GlDisclosureDropdown, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui'; import { helpPagePath } from '~/helpers/help_page_helper'; import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue'; import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue'; @@ -12,7 +12,7 @@ export default { components: { CsvImportExportButtons, GlButton, - GlDropdown, + GlDisclosureDropdown, GlEmptyState, GlLink, GlSprintf, @@ -56,7 +56,11 @@ export default { <template> <div v-if="isSignedIn"> - <gl-empty-state :title="$options.i18n.noIssuesTitle" :svg-path="emptyStateSvgPath"> + <gl-empty-state + :title="$options.i18n.noIssuesTitle" + :svg-path="emptyStateSvgPath" + :svg-height="150" + > <template #description> <gl-link :href="$options.issuesHelpPagePath"> {{ $options.i18n.noIssuesDescription }} @@ -73,17 +77,17 @@ export default { {{ $options.i18n.newIssueLabel }} </gl-button> - <gl-dropdown + <gl-disclosure-dropdown v-if="showCsvButtons" class="gl-w-full gl-sm-w-auto gl-sm-mr-3" - :text="$options.i18n.importIssues" + :toggle-text="$options.i18n.importIssues" data-qa-selector="import_issues_dropdown" > <csv-import-export-buttons :export-csv-path="exportCsvPathWithQuery" :issuable-count="currentTabCount" /> - </gl-dropdown> + </gl-disclosure-dropdown> <new-resource-dropdown v-if="showNewIssueDropdown" diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue index 5fb83dfd1ab..83b0bcebe67 100644 --- a/app/assets/javascripts/issues/list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue @@ -1,11 +1,11 @@ <script> import { GlButton, + GlButtonGroup, + GlDisclosureDropdown, + GlDisclosureDropdownGroup, GlFilteredSearchToken, GlTooltipDirective, - GlDropdown, - GlDropdownItem, - GlDropdownDivider, } from '@gitlab/ui'; import * as Sentry from '@sentry/browser'; import fuzzaldrinPlus from 'fuzzaldrin-plus'; @@ -14,6 +14,7 @@ import IssueCardStatistics from 'ee_else_ce/issues/list/components/issue_card_st import IssueCardTimeInfo from 'ee_else_ce/issues/list/components/issue_card_time_info.vue'; import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql'; import getIssuesCountsQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import { createAlert, VARIANT_INFO } from '~/alert'; import { TYPENAME_USER } from '~/graphql_shared/constants'; import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue'; @@ -68,6 +69,9 @@ import { defaultWorkItemTypes, i18n, ISSUE_REFERENCE, + ISSUES_GRID_VIEW_KEY, + ISSUES_LIST_VIEW_KEY, + ISSUES_VIEW_TYPE_KEY, MAX_LIST_SIZE, PARAM_FIRST_PAGE_SIZE, PARAM_LAST_PAGE_SIZE, @@ -116,19 +120,23 @@ const CrmOrganizationToken = () => export default { i18n, issuableListTabs, + ISSUES_VIEW_TYPE_KEY, + ISSUES_GRID_VIEW_KEY, + ISSUES_LIST_VIEW_KEY, components: { CsvImportExportButtons, + GlDisclosureDropdown, + GlDisclosureDropdownGroup, EmptyStateWithAnyIssues, EmptyStateWithoutAnyIssues, GlButton, - GlDropdown, - GlDropdownDivider, - GlDropdownItem, + GlButtonGroup, IssuableByEmail, IssuableList, IssueCardStatistics, IssueCardTimeInfo, NewResourceDropdown, + LocalStorageSync, }, directives: { GlTooltip: GlTooltipDirective, @@ -194,6 +202,21 @@ export default { sortKey: CREATED_DESC, state: STATUS_OPEN, pageSize: DEFAULT_PAGE_SIZE, + viewType: ISSUES_LIST_VIEW_KEY, + subscribeDropdownOptions: { + items: [ + { + text: i18n.rssLabel, + href: this.rssPath, + extraAttrs: { 'data-testid': 'subscribe-rss' }, + }, + { + text: i18n.calendarLabel, + href: this.calendarPath, + extraAttrs: { 'data-testid': 'subscribe-calendar' }, + }, + ], + }, }; }, apollo: { @@ -504,6 +527,12 @@ export default { }) ); }, + gridViewFeatureEnabled() { + return Boolean(this.glFeatures?.issuesGridView); + }, + isGridView() { + return this.viewType === ISSUES_GRID_VIEW_KEY; + }, }, watch: { $route(newValue, oldValue) { @@ -764,6 +793,15 @@ export default { this.sortKey = sortKey; this.state = state || STATUS_OPEN; }, + switchViewType(type) { + // Filter the wrong data from localStorage + if (type === ISSUES_GRID_VIEW_KEY) { + this.viewType = ISSUES_GRID_VIEW_KEY; + return; + } + // The default view is list view + this.viewType = ISSUES_LIST_VIEW_KEY; + }, }, }; </script> @@ -798,6 +836,7 @@ export default { :has-next-page="pageInfo.hasNextPage" :has-previous-page="pageInfo.hasPreviousPage" :show-filtered-search-friendly-text="hasOrFeature" + :is-grid-view="isGridView" show-work-item-type-icon @click-tab="handleClickTab" @dismiss-alert="handleDismissAlert" @@ -810,6 +849,30 @@ export default { @page-size-change="handlePageSizeChange" > <template #nav-actions> + <local-storage-sync + v-if="gridViewFeatureEnabled" + :value="viewType" + :storage-key="$options.ISSUES_VIEW_TYPE_KEY" + @input="switchViewType" + > + <gl-button-group> + <gl-button + :variant="isGridView ? 'default' : 'confirm'" + data-testid="list-view-type" + @click="switchViewType($options.ISSUES_LIST_VIEW_KEY)" + > + {{ $options.i18n.listLabel }} + </gl-button> + <gl-button + :variant="isGridView ? 'confirm' : 'default'" + data-testid="grid-view-type" + @click="switchViewType($options.ISSUES_GRID_VIEW_KEY)" + > + {{ $options.i18n.gridLabel }} + </gl-button> + </gl-button-group> + </local-storage-sync> + <gl-button v-if="canBulkUpdate" :disabled="isBulkEditButtonDisabled" @@ -831,12 +894,12 @@ export default { :query-variables="newIssueDropdownQueryVariables" :extract-projects="extractProjects" /> - <gl-dropdown + <gl-disclosure-dropdown v-gl-tooltip.hover="$options.i18n.actionsLabel" category="tertiary" icon="ellipsis_v" no-caret - :text="$options.i18n.actionsLabel" + :toggle-text="$options.i18n.actionsLabel" text-sr-only data-qa-selector="issues_list_more_actions_dropdown" > @@ -845,16 +908,8 @@ export default { :export-csv-path="exportCsvPathWithQuery" :issuable-count="currentTabCount" /> - - <gl-dropdown-divider v-if="showCsvButtons" /> - - <gl-dropdown-item :href="rssPath"> - {{ $options.i18n.rssLabel }} - </gl-dropdown-item> - <gl-dropdown-item :href="calendarPath"> - {{ $options.i18n.calendarLabel }} - </gl-dropdown-item> - </gl-dropdown> + <gl-disclosure-dropdown-group :bordered="true" :group="subscribeDropdownOptions" /> + </gl-disclosure-dropdown> </template> <template #timeframe="{ issuable = {} }"> diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js index 56d3a57457b..1a3d97277c7 100644 --- a/app/assets/javascripts/issues/list/constants.js +++ b/app/assets/javascripts/issues/list/constants.js @@ -75,6 +75,10 @@ export const NORMAL_FILTER = 'normalFilter'; export const SPECIAL_FILTER = 'specialFilter'; export const ALTERNATIVE_FILTER = 'alternativeFilter'; +export const ISSUES_VIEW_TYPE_KEY = 'issuesViewType'; +export const ISSUES_LIST_VIEW_KEY = 'List'; +export const ISSUES_GRID_VIEW_KEY = 'Grid'; + export const i18n = { actionsLabel: __('Actions'), calendarLabel: __('Subscribe to calendar'), @@ -116,6 +120,8 @@ export const i18n = { upvotes: __('Upvotes'), titles: __('Titles'), descriptions: __('Descriptions'), + listLabel: __('List'), + gridLabel: __('Grid'), }; export const urlSortParams = { diff --git a/app/assets/javascripts/issues/list/queries/search_users.query.graphql b/app/assets/javascripts/issues/list/queries/search_users.query.graphql index 46b48e4e41c..6a1967a8875 100644 --- a/app/assets/javascripts/issues/list/queries/search_users.query.graphql +++ b/app/assets/javascripts/issues/list/queries/search_users.query.graphql @@ -14,7 +14,10 @@ query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false) } project(fullPath: $fullPath) @include(if: $isProject) { id - projectMembers(search: $search, relations: [DIRECT, INHERITED, INVITED_GROUPS]) { + projectMembers( + search: $search + relations: [DIRECT, INHERITED, INVITED_GROUPS, SHARED_INTO_ANCESTORS] + ) { nodes { id user { diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue index 86311b99f7c..fcdf1f7741b 100644 --- a/app/assets/javascripts/issues/show/components/app.vue +++ b/app/assets/javascripts/issues/show/components/app.vue @@ -188,6 +188,11 @@ export default { required: false, default: null, }, + issueIid: { + type: Number, + required: false, + default: null, + }, }, data() { const store = new Store({ @@ -446,7 +451,10 @@ export default { }, showStickyHeader() { - this.isStickyHeaderShowing = true; + // only if scrolled under the issue's title + if (this.$refs.title.$el.offsetTop < window.pageYOffset) { + this.isStickyHeaderShowing = true; + } }, handleSaveDescription(description) { @@ -496,6 +504,7 @@ export default { </div> <div v-else> <title-component + ref="title" :issuable-ref="issuableRef" :can-update="canUpdate" :title-html="state.titleHtml" @@ -522,7 +531,13 @@ export default { statusText }}</span></gl-badge > - <span v-if="isLocked" data-testid="locked" class="issuable-warning-icon"> + <span + v-if="isLocked" + v-gl-tooltip.bottom + data-testid="locked" + class="issuable-warning-icon" + :title="__('This issue is locked. Only project members can comment.')" + > <gl-icon name="lock" :aria-label="__('Locked')" /> </span> <confidentiality-badge @@ -533,19 +548,20 @@ export default { /> <span v-if="isHidden" - v-gl-tooltip + v-gl-tooltip.bottom :title="__('This issue is hidden because its author has been banned')" data-testid="hidden" class="issuable-warning-icon" > <gl-icon name="spam" /> </span> - <p - class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0" + <a + href="#top" + class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-text-black-normal" :title="state.titleText" > {{ state.titleText }} - </p> + </a> </div> </div> </transition> @@ -560,6 +576,7 @@ export default { <component :is="descriptionComponent" :issue-id="issueId" + :issue-iid="issueIid" :can-update="canUpdate" :description-html="state.descriptionHtml" :description-text="state.descriptionText" diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue index 3721f224d5e..3bf4dfc7a99 100644 --- a/app/assets/javascripts/issues/show/components/description.vue +++ b/app/assets/javascripts/issues/show/components/description.vue @@ -11,8 +11,7 @@ import { TYPE_ISSUE } from '~/issues/constants'; import { __, s__, sprintf } from '~/locale'; import { getSortableDefaultOptions, isDragging } from '~/sortable/utils'; import TaskList from '~/task_list'; -import addHierarchyChildMutation from '~/work_items/graphql/add_hierarchy_child.mutation.graphql'; -import removeHierarchyChildMutation from '~/work_items/graphql/remove_hierarchy_child.mutation.graphql'; +import { addHierarchyChild, removeHierarchyChild } from '~/work_items/graphql/cache_utils'; import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql'; import deleteWorkItemMutation from '~/work_items/graphql/delete_work_item.mutation.graphql'; import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql'; @@ -78,6 +77,11 @@ export default { required: false, default: null, }, + issueIid: { + type: Number, + required: false, + default: null, + }, isUpdating: { type: Boolean, required: false, @@ -330,29 +334,33 @@ export default { async createTask({ taskTitle, taskDescription, oldDescription }) { try { const { title, description } = extractTaskTitleAndDescription(taskTitle, taskDescription); + const iterationInput = { iterationWidget: { iterationId: this.issueDetails.iteration?.id ?? null, }, }; - const input = { - confidential: this.issueDetails.confidential, - description, - hierarchyWidget: { - parentId: this.issueGid, - }, - ...(this.hasIterationsFeature && iterationInput), - milestoneWidget: { - milestoneId: this.issueDetails.milestone?.id ?? null, - }, - projectPath: this.fullPath, - title, - workItemTypeId: this.taskWorkItemTypeId, - }; const { data } = await this.$apollo.mutate({ mutation: createWorkItemMutation, - variables: { input }, + variables: { + input: { + confidential: this.issueDetails.confidential, + description, + hierarchyWidget: { + parentId: this.issueGid, + }, + ...(this.hasIterationsFeature && iterationInput), + milestoneWidget: { + milestoneId: this.issueDetails.milestone?.id ?? null, + }, + projectPath: this.fullPath, + title, + workItemTypeId: this.taskWorkItemTypeId, + }, + }, + update: (cache, { data: { workItemCreate } }) => + addHierarchyChild(cache, this.fullPath, String(this.issueIid), workItemCreate.workItem), }); const { workItem, errors } = data.workItemCreate; @@ -361,11 +369,6 @@ export default { throw new Error(errors); } - await this.$apollo.mutate({ - mutation: addHierarchyChildMutation, - variables: { id: this.issueGid, workItem }, - }); - this.$toast.show(s__('WorkItem|Converted to task'), { action: { text: s__('WorkItem|Undo'), @@ -386,19 +389,14 @@ export default { const { data } = await this.$apollo.mutate({ mutation: deleteWorkItemMutation, variables: { input: { id } }, + update: (cache) => + removeHierarchyChild(cache, this.fullPath, String(this.issueIid), { id }), }); - const { errors } = data.workItemDelete; - - if (errors?.length) { - throw new Error(errors); + if (data.workItemDelete.errors?.length) { + throw new Error(data.workItemDelete.errors); } - await this.$apollo.mutate({ - mutation: removeHierarchyChildMutation, - variables: { id: this.issueGid, workItem: { id } }, - }); - this.$toast.show(s__('WorkItem|Task reverted')); } catch (error) { this.showAlert(I18N_WORK_ITEM_ERROR_DELETING, error); diff --git a/app/assets/javascripts/issues/show/components/fields/type.vue b/app/assets/javascripts/issues/show/components/fields/type.vue index 775f25bdbc0..576d157e0fc 100644 --- a/app/assets/javascripts/issues/show/components/fields/type.vue +++ b/app/assets/javascripts/issues/show/components/fields/type.vue @@ -71,7 +71,7 @@ export default { :label="$options.i18n.label" label-class="sr-only" label-for="issuable-type" - class="mb-2 mb-md-0" + class="gl-mb-0" > <gl-collapsible-listbox v-model="selectedIssueType" diff --git a/app/assets/javascripts/issues/show/components/form.vue b/app/assets/javascripts/issues/show/components/form.vue index 2e99c03d250..c9e21b296e4 100644 --- a/app/assets/javascripts/issues/show/components/form.vue +++ b/app/assets/javascripts/issues/show/components/form.vue @@ -222,7 +222,7 @@ export default { <convert-description-modal v-if="issueId && glFeatures.generateDescriptionAi" - class="gl-pl-5 gl-sm-pl-0" + class="gl-pl-5 gl-md-pl-0" :resource-id="resourceId" :user-id="userId" @contentGenerated="setDescription" diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue index 4d9b69ddf99..a36b0c46927 100644 --- a/app/assets/javascripts/issues/show/components/header_actions.vue +++ b/app/assets/javascripts/issues/show/components/header_actions.vue @@ -20,7 +20,7 @@ import { NEW_ACTIONS_POPOVER_KEY, } from '~/issues/show/constants'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; -import { getCookie, parseBoolean, setCookie } from '~/lib/utils/common_utils'; +import { getCookie, parseBoolean, setCookie, isLoggedIn } from '~/lib/utils/common_utils'; import { visitUrl } from '~/lib/utils/url_utility'; import { s__, __, sprintf } from '~/locale'; import eventHub from '~/notes/event_hub'; @@ -137,6 +137,7 @@ export default { data() { return { isReportAbuseDrawerOpen: false, + isUserSignedIn: isLoggedIn(), }; }, apollo: { @@ -204,7 +205,11 @@ export default { }, hasDesktopDropdown() { return ( - this.canCreateIssue || this.canPromoteToEpic || !this.isIssueAuthor || this.canReportSpam + this.canCreateIssue || + this.canPromoteToEpic || + !this.isIssueAuthor || + this.canReportSpam || + this.issuableReference ); }, hasMobileDropdown() { @@ -219,7 +224,10 @@ export default { return this.glFeatures.movedMrSidebar; }, showLockIssueOption() { - return this.isMrSidebarMoved && this.issueType === TYPE_ISSUE; + return this.isMrSidebarMoved && this.issueType === TYPE_ISSUE && this.isUserSignedIn; + }, + showMovedSidebarOptions() { + return this.isMrSidebarMoved && this.isUserSignedIn; }, }, created() { @@ -326,17 +334,16 @@ export default { </script> <template> - <div class="detail-page-header-actions gl-display-flex gl-align-self-start gl-gap-3"> + <div class="detail-page-header-actions gl-display-flex gl-align-self-start gl-sm-gap-3"> <gl-dropdown v-if="hasMobileDropdown" class="gl-sm-display-none! w-100" block :text="dropdownText" - data-qa-selector="issue_actions_dropdown" data-testid="mobile-dropdown" :loading="isToggleStateButtonLoading" > - <template v-if="isMrSidebarMoved"> + <template v-if="showMovedSidebarOptions"> <sidebar-subscriptions-widget :iid="String(iid)" :full-path="fullPath" @@ -356,7 +363,7 @@ export default { </gl-dropdown-item> <gl-dropdown-item v-if="showToggleIssueStateButton" - :data-qa-selector="`mobile_${qaSelector}`" + :data-testid="`mobile_${qaSelector}`" @click="toggleIssueState" > {{ buttonText }} @@ -375,7 +382,7 @@ export default { >{{ $options.i18n.copyReferenceText }}</gl-dropdown-item > <gl-dropdown-item - v-if="issuableEmailAddress" + v-if="issuableEmailAddress && showMovedSidebarOptions" :data-clipboard-text="issuableEmailAddress" data-testid="copy-email" @click="copyEmailAddress" @@ -401,7 +408,7 @@ export default { </gl-dropdown-item> </template> <gl-dropdown-item - v-if="!isIssueAuthor" + v-if="!isIssueAuthor && isUserSignedIn" data-testid="report-abuse-item" @click="toggleReportAbuseDrawer(true)" > @@ -426,7 +433,7 @@ export default { class="gl-display-none gl-sm-display-inline-flex!" :data-qa-selector="qaSelector" :loading="isToggleStateButtonLoading" - data-testid="toggle-button" + data-testid="toggle-issue-state-button" @click="toggleIssueState" > {{ buttonText }} @@ -439,7 +446,6 @@ export default { class="gl-display-none gl-sm-display-inline-flex!" icon="ellipsis_v" category="tertiary" - data-qa-selector="issue_actions_ellipsis_dropdown" :text="dropdownText" :text-sr-only="true" :title="dropdownText" @@ -449,7 +455,7 @@ export default { right @shown="dismissPopover" > - <template v-if="isMrSidebarMoved"> + <template v-if="showMovedSidebarOptions"> <sidebar-subscriptions-widget :iid="String(iid)" :full-path="fullPath" @@ -460,7 +466,7 @@ export default { <gl-dropdown-divider /> </template> - <gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath"> + <gl-dropdown-item v-if="canCreateIssue && isUserSignedIn" :href="newIssuePath"> {{ newIssueTypeText }} </gl-dropdown-item> <gl-dropdown-item @@ -482,7 +488,7 @@ export default { >{{ $options.i18n.copyReferenceText }}</gl-dropdown-item > <gl-dropdown-item - v-if="issuableEmailAddress" + v-if="issuableEmailAddress && showMovedSidebarOptions" :data-clipboard-text="issuableEmailAddress" data-testid="copy-email" @click="copyEmailAddress" @@ -502,14 +508,14 @@ export default { <gl-dropdown-item v-gl-modal="$options.deleteModalId" variant="danger" - data-qa-selector="delete_issue_button" + data-testid="delete_issue_button" @click="track('click_dropdown')" > {{ deleteButtonText }} </gl-dropdown-item> </template> <gl-dropdown-item - v-if="!isIssueAuthor" + v-if="!isIssueAuthor && isUserSignedIn" data-testid="report-abuse-item" @click="toggleReportAbuseDrawer(true)" > diff --git a/app/assets/javascripts/issues/show/components/task_list_item_actions.vue b/app/assets/javascripts/issues/show/components/task_list_item_actions.vue index 5160903c762..64b916caddb 100644 --- a/app/assets/javascripts/issues/show/components/task_list_item_actions.vue +++ b/app/assets/javascripts/issues/show/components/task_list_item_actions.vue @@ -17,14 +17,9 @@ export default { methods: { convertToTask() { eventHub.$emit('convert-task-list-item', this.$el.closest('li').dataset.sourcepos); - this.closeDropdown(); }, deleteTaskListItem() { eventHub.$emit('delete-task-list-item', this.$el.closest('li').dataset.sourcepos); - this.closeDropdown(); - }, - closeDropdown() { - this.$refs.dropdown.close(); }, }, }; @@ -33,7 +28,6 @@ export default { <template> <gl-disclosure-dropdown v-if="canUpdate" - ref="dropdown" class="task-list-item-actions-wrapper" category="tertiary" icon="ellipsis_v" diff --git a/app/assets/javascripts/issues/show/components/title.vue b/app/assets/javascripts/issues/show/components/title.vue index 2d2ef327018..c464f48d574 100644 --- a/app/assets/javascripts/issues/show/components/title.vue +++ b/app/assets/javascripts/issues/show/components/title.vue @@ -60,7 +60,6 @@ export default { 'issue-realtime-trigger-pulse': pulseAnimation, }" class="title gl-font-size-h-display" - data-qa-selector="title_content" data-testid="issue-title" dir="auto" ></h1> diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js index 5a51ac18446..bc4284457f6 100644 --- a/app/assets/javascripts/issues/show/index.js +++ b/app/assets/javascripts/issues/show/index.js @@ -133,6 +133,7 @@ export function initIssueApp(issueData, store) { isLocked: this.getNoteableData?.discussion_locked, issuableStatus: this.getNoteableData?.state, issueId: this.getNoteableData?.id, + issueIid: this.getNoteableData?.iid, }, }); }, |