summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue')
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue135
1 files changed, 104 insertions, 31 deletions
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 8edc9a08c9e..a4a2feba716 100644
--- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -1,12 +1,14 @@
<script>
-import { GlButton, GlEmptyState, GlTooltipDirective } from '@gitlab/ui';
+import { GlButton, GlEmptyState, GlFilteredSearchToken, GlTooltipDirective } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import getIssuesQuery from 'ee_else_ce/issues/dashboard/queries/get_issues.query.graphql';
import IssueCardStatistics from 'ee_else_ce/issues/list/components/issue_card_statistics.vue';
import IssueCardTimeInfo from 'ee_else_ce/issues/list/components/issue_card_time_info.vue';
-import { IssuableStatus } from '~/issues/constants';
+import { STATUS_CLOSED } from '~/issues/constants';
import {
CREATED_DESC,
+ defaultTypeTokenOptions,
+ i18n,
PAGE_SIZE,
PARAM_STATE,
UPDATED_DESC,
@@ -26,21 +28,29 @@ import {
import axios from '~/lib/utils/axios_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { getParameterByName } from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
import {
+ OPERATORS_IS,
+ OPERATORS_IS_NOT_OR,
TOKEN_TITLE_ASSIGNEE,
TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_CONFIDENTIAL,
TOKEN_TITLE_LABEL,
TOKEN_TITLE_MILESTONE,
TOKEN_TITLE_MY_REACTION,
+ TOKEN_TITLE_SEARCH_WITHIN,
+ TOKEN_TITLE_TYPE,
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
TOKEN_TYPE_LABEL,
TOKEN_TYPE_MILESTONE,
TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_SEARCH_WITHIN,
+ TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+import getIssuesCountsQuery from '../queries/get_issues_counts.query.graphql';
import { AutocompleteCache } from '../utils';
const UserToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/user_token.vue');
@@ -52,17 +62,7 @@ const MilestoneToken = () =>
import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue');
export default {
- i18n: {
- calendarButtonText: __('Subscribe to calendar'),
- closed: __('CLOSED'),
- closedMoved: __('CLOSED (MOVED)'),
- emptyStateWithFilterTitle: __('Sorry, your filter produced no results'),
- emptyStateWithFilterDescription: __('To widen your search, change or remove filters above'),
- emptyStateWithoutFilterTitle: __('Please select at least one filter to see results'),
- errorFetchingIssues: __('An error occurred while loading issues'),
- rssButtonText: __('Subscribe to RSS feed'),
- searchInputPlaceholder: __('Search or filter results...'),
- },
+ i18n,
IssuableListTabs,
components: {
GlButton,
@@ -105,6 +105,7 @@ export default {
return {
filterTokens: getFilterTokens(window.location.search),
issues: [],
+ issuesCounts: {},
issuesError: null,
pageInfo: {},
pageParams: getInitialPageParams(),
@@ -116,15 +117,7 @@ export default {
issues: {
query: getIssuesQuery,
variables() {
- return {
- hideUsers: this.isPublicVisibilityRestricted && !this.isSignedIn,
- isSignedIn: this.isSignedIn,
- search: this.searchQuery,
- sort: this.sortKey,
- state: this.state,
- ...this.pageParams,
- ...this.apiFilterParams,
- };
+ return this.queryVariables;
},
update(data) {
return data.issues.nodes ?? [];
@@ -141,13 +134,33 @@ export default {
},
debounce: 200,
},
+ issuesCounts: {
+ query: getIssuesCountsQuery,
+ variables() {
+ return this.queryVariables;
+ },
+ update(data) {
+ return data ?? {};
+ },
+ error(error) {
+ this.issuesError = this.$options.i18n.errorFetchingCounts;
+ Sentry.captureException(error);
+ },
+ skip() {
+ return !this.hasSearch;
+ },
+ debounce: 200,
+ context: {
+ isSingleRequest: true,
+ },
+ },
},
computed: {
apiFilterParams() {
return convertToApiParams(this.filterTokens);
},
emptyStateDescription() {
- return this.hasSearch ? this.$options.i18n.emptyStateWithFilterDescription : undefined;
+ return this.hasSearch ? this.$options.i18n.noSearchResultsDescription : undefined;
},
emptyStateSvgPath() {
return this.hasSearch
@@ -156,12 +169,23 @@ export default {
},
emptyStateTitle() {
return this.hasSearch
- ? this.$options.i18n.emptyStateWithFilterTitle
- : this.$options.i18n.emptyStateWithoutFilterTitle;
+ ? this.$options.i18n.noSearchResultsTitle
+ : this.$options.i18n.noSearchNoFilterTitle;
},
hasSearch() {
return Boolean(this.searchQuery || Object.keys(this.urlFilterParams).length);
},
+ queryVariables() {
+ return {
+ hideUsers: this.isPublicVisibilityRestricted && !this.isSignedIn,
+ isSignedIn: this.isSignedIn,
+ search: this.searchQuery,
+ sort: this.sortKey,
+ state: this.state,
+ ...this.pageParams,
+ ...this.apiFilterParams,
+ };
+ },
renderedIssues() {
return this.hasSearch ? this.issues : [];
},
@@ -186,6 +210,7 @@ export default {
title: TOKEN_TITLE_ASSIGNEE,
icon: 'user',
token: UserToken,
+ operators: OPERATORS_IS_NOT_OR,
fetchUsers: this.fetchUsers,
preloadedUsers,
recentSuggestionsStorageKey: 'dashboard-issues-recent-tokens-assignee',
@@ -195,6 +220,7 @@ export default {
title: TOKEN_TITLE_AUTHOR,
icon: 'pencil',
token: UserToken,
+ operators: OPERATORS_IS_NOT_OR,
fetchUsers: this.fetchUsers,
defaultUsers: [],
preloadedUsers,
@@ -205,6 +231,7 @@ export default {
title: TOKEN_TITLE_LABEL,
icon: 'labels',
token: LabelToken,
+ operators: OPERATORS_IS_NOT_OR,
fetchLabels: this.fetchLabels,
recentSuggestionsStorageKey: 'dashboard-issues-recent-tokens-label',
},
@@ -217,10 +244,46 @@ export default {
recentSuggestionsStorageKey: 'dashboard-issues-recent-tokens-milestone',
shouldSkipSort: true,
},
+ {
+ type: TOKEN_TYPE_SEARCH_WITHIN,
+ title: TOKEN_TITLE_SEARCH_WITHIN,
+ icon: 'search',
+ token: GlFilteredSearchToken,
+ unique: true,
+ operators: OPERATORS_IS,
+ options: [
+ { icon: 'title', value: 'TITLE', title: this.$options.i18n.titles },
+ {
+ icon: 'text-description',
+ value: 'DESCRIPTION',
+ title: this.$options.i18n.descriptions,
+ },
+ ],
+ },
+ {
+ type: TOKEN_TYPE_TYPE,
+ title: TOKEN_TITLE_TYPE,
+ icon: 'issues',
+ token: GlFilteredSearchToken,
+ options: defaultTypeTokenOptions,
+ },
];
if (this.isSignedIn) {
tokens.push({
+ type: TOKEN_TYPE_CONFIDENTIAL,
+ title: TOKEN_TITLE_CONFIDENTIAL,
+ icon: 'eye-slash',
+ token: GlFilteredSearchToken,
+ unique: true,
+ operators: OPERATORS_IS,
+ options: [
+ { icon: 'eye-slash', value: 'yes', title: this.$options.i18n.confidentialYes },
+ { icon: 'eye', value: 'no', title: this.$options.i18n.confidentialNo },
+ ],
+ });
+
+ tokens.push({
type: TOKEN_TYPE_MY_REACTION,
title: TOKEN_TITLE_MY_REACTION,
icon: 'thumb-up',
@@ -248,6 +311,14 @@ export default {
hasIssueWeightsFeature: this.hasIssueWeightsFeature,
});
},
+ tabCounts() {
+ const { openedIssues, closedIssues, allIssues } = this.issuesCounts;
+ return {
+ [IssuableStates.Opened]: openedIssues?.count,
+ [IssuableStates.Closed]: closedIssues?.count,
+ [IssuableStates.All]: allIssues?.count,
+ };
+ },
urlFilterParams() {
return convertToUrlParams(this.filterTokens);
},
@@ -292,10 +363,10 @@ export default {
return axios.get('/-/autocomplete/users.json', { params: { active: true, search } });
},
getStatus(issue) {
- if (issue.state === IssuableStatus.Closed && issue.moved) {
+ if (issue.state === STATUS_CLOSED && issue.moved) {
return this.$options.i18n.closedMoved;
}
- if (issue.state === IssuableStatus.Closed) {
+ if (issue.state === STATUS_CLOSED) {
return this.$options.i18n.closed;
}
return undefined;
@@ -372,12 +443,14 @@ export default {
:issuables-loading="$apollo.queries.issues.loading"
namespace="dashboard"
recent-searches-storage-key="issues"
- :search-input-placeholder="$options.i18n.searchInputPlaceholder"
+ :search-input-placeholder="$options.i18n.searchPlaceholder"
:search-tokens="searchTokens"
:show-pagination-controls="showPaginationControls"
show-work-item-type-icon
:sort-options="sortOptions"
+ :tab-counts="tabCounts"
:tabs="$options.IssuableListTabs"
+ truncate-counts
:url-params="urlParams"
use-keyset-pagination
@click-tab="handleClickTab"
@@ -389,10 +462,10 @@ export default {
>
<template #nav-actions>
<gl-button :href="rssPath" icon="rss">
- {{ $options.i18n.rssButtonText }}
+ {{ $options.i18n.rssLabel }}
</gl-button>
<gl-button :href="calendarPath" icon="calendar">
- {{ $options.i18n.calendarButtonText }}
+ {{ $options.i18n.calendarLabel }}
</gl-button>
</template>