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>2021-10-20 11:43:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
commitd9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch)
tree2341ef426af70ad1e289c38036737e04b0aa5007 /app/assets/javascripts/issues_list
parentd6e514dd13db8947884cd58fe2a9c2a063400a9b (diff)
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/assets/javascripts/issues_list')
-rw-r--r--app/assets/javascripts/issues_list/components/issue_card_time_info.vue17
-rw-r--r--app/assets/javascripts/issues_list/components/issues_list_app.vue49
-rw-r--r--app/assets/javascripts/issues_list/components/new_issue_dropdown.vue124
-rw-r--r--app/assets/javascripts/issues_list/index.js6
-rw-r--r--app/assets/javascripts/issues_list/queries/search_projects.query.graphql12
5 files changed, 174 insertions, 34 deletions
diff --git a/app/assets/javascripts/issues_list/components/issue_card_time_info.vue b/app/assets/javascripts/issues_list/components/issue_card_time_info.vue
index a687a58a6ad..4a2f7861492 100644
--- a/app/assets/javascripts/issues_list/components/issue_card_time_info.vue
+++ b/app/assets/javascripts/issues_list/components/issue_card_time_info.vue
@@ -85,7 +85,7 @@ export default {
<span>
<span
v-if="issue.milestone"
- class="issuable-milestone gl-display-none gl-sm-display-inline-block! gl-mr-3"
+ class="issuable-milestone gl-mr-3"
data-testid="issuable-milestone"
>
<gl-link v-gl-tooltip :href="milestoneLink" :title="milestoneDate">
@@ -96,7 +96,7 @@ export default {
<span
v-if="issue.dueDate"
v-gl-tooltip
- class="issuable-due-date gl-display-none gl-sm-display-inline-block! gl-mr-3"
+ class="issuable-due-date gl-mr-3"
:class="{ 'gl-text-red-500': showDueDateInRed }"
:title="__('Due date')"
data-testid="issuable-due-date"
@@ -107,21 +107,14 @@ export default {
<span
v-if="timeEstimate"
v-gl-tooltip
- class="gl-display-none gl-sm-display-inline-block! gl-mr-3"
+ class="gl-mr-3"
:title="__('Estimate')"
data-testid="time-estimate"
>
<gl-icon name="timer" />
{{ timeEstimate }}
</span>
- <weight-count
- class="issuable-weight gl-display-none gl-sm-display-inline-block gl-mr-3"
- :weight="issue.weight"
- />
- <issue-health-status
- v-if="showHealthStatus"
- class="gl-display-none gl-sm-display-inline-block"
- :health-status="healthStatus"
- />
+ <weight-count class="issuable-weight gl-mr-3" :weight="issue.weight" />
+ <issue-health-status v-if="showHealthStatus" :health-status="healthStatus" />
</span>
</template>
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 8e37339fca6..7b51f6ee46a 100644
--- a/app/assets/javascripts/issues_list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue
@@ -68,13 +68,6 @@ import {
TOKEN_TITLE_TYPE,
TOKEN_TITLE_WEIGHT,
} from '~/vue_shared/components/filtered_search_bar/constants';
-import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
-import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
-import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
-import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
-import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
-import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
-import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
import eventHub from '../eventhub';
import reorderIssuesMutation from '../queries/reorder_issues.mutation.graphql';
import searchIterationsQuery from '../queries/search_iterations.query.graphql';
@@ -82,6 +75,21 @@ import searchLabelsQuery from '../queries/search_labels.query.graphql';
import searchMilestonesQuery from '../queries/search_milestones.query.graphql';
import searchUsersQuery from '../queries/search_users.query.graphql';
import IssueCardTimeInfo from './issue_card_time_info.vue';
+import NewIssueDropdown from './new_issue_dropdown.vue';
+
+const AuthorToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/author_token.vue');
+const EmojiToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue');
+const EpicToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue');
+const IterationToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue');
+const LabelToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/label_token.vue');
+const MilestoneToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue');
+const WeightToken = () =>
+ import('~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue');
export default {
i18n,
@@ -96,6 +104,7 @@ export default {
IssuableByEmail,
IssuableList,
IssueCardTimeInfo,
+ NewIssueDropdown,
BlockingIssuesCount: () => import('ee_component/issues/components/blocking_issues_count.vue'),
},
directives: {
@@ -120,12 +129,15 @@ export default {
fullPath: {
default: '',
},
- groupEpicsPath: {
+ groupPath: {
default: '',
},
hasAnyIssues: {
default: false,
},
+ hasAnyProjects: {
+ default: false,
+ },
hasBlockedIssuesFeature: {
default: false,
},
@@ -253,6 +265,9 @@ export default {
showCsvButtons() {
return this.isProject && this.isSignedIn;
},
+ showNewIssueDropdown() {
+ return !this.isProject && this.hasAnyProjects;
+ },
apiFilterParams() {
return convertToApiParams(this.filterTokens);
},
@@ -363,16 +378,18 @@ export default {
});
}
- if (this.groupEpicsPath) {
+ if (this.groupPath) {
tokens.push({
type: TOKEN_TYPE_EPIC,
title: TOKEN_TITLE_EPIC,
icon: 'epic',
token: EpicToken,
unique: true,
+ symbol: '&',
idProperty: 'id',
useIdValue: true,
- fetchEpics: this.fetchEpics,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-epic_id`,
+ fullPath: this.groupPath,
});
}
@@ -442,16 +459,6 @@ export default {
fetchEmojis(search) {
return this.fetchWithCache(this.autocompleteAwardEmojisPath, 'emojis', 'name', search);
},
- async fetchEpics({ search }) {
- const epics = await this.fetchWithCache(this.groupEpicsPath, 'epics');
- if (!search) {
- return epics.slice(0, MAX_LIST_SIZE);
- }
- const number = Number(search);
- return Number.isNaN(number)
- ? fuzzaldrinPlus.filter(epics, search, { key: 'title' })
- : epics.filter((epic) => epic.id === number);
- },
fetchLabels(search) {
return this.$apollo
.query({
@@ -662,6 +669,7 @@ export default {
<gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm">
{{ $options.i18n.newIssueLabel }}
</gl-button>
+ <new-issue-dropdown v-if="showNewIssueDropdown" />
</template>
<template #timeframe="{ issuable = {} }">
@@ -765,6 +773,7 @@ export default {
:export-csv-path="exportCsvPathWithQuery"
:issuable-count="currentTabCount"
/>
+ <new-issue-dropdown v-if="showNewIssueDropdown" />
</template>
</gl-empty-state>
<hr />
diff --git a/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue b/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue
new file mode 100644
index 00000000000..037fd9be542
--- /dev/null
+++ b/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue
@@ -0,0 +1,124 @@
+<script>
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import createFlash from '~/flash';
+import searchProjectsQuery from '~/issues_list/queries/search_projects.query.graphql';
+import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
+import { __, sprintf } from '~/locale';
+import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
+
+export default {
+ i18n: {
+ defaultDropdownText: __('Select project to create issue'),
+ noMatchesFound: __('No matches found'),
+ toggleButtonLabel: __('Toggle project select'),
+ },
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+ },
+ inject: ['fullPath'],
+ data() {
+ return {
+ projects: [],
+ search: '',
+ selectedProject: {},
+ shouldSkipQuery: true,
+ };
+ },
+ apollo: {
+ projects: {
+ query: searchProjectsQuery,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ search: this.search,
+ };
+ },
+ update: ({ group }) => group.projects.nodes ?? [],
+ error(error) {
+ createFlash({
+ message: __('An error occurred while loading projects.'),
+ captureError: true,
+ error,
+ });
+ },
+ skip() {
+ return this.shouldSkipQuery;
+ },
+ debounce: DEBOUNCE_DELAY,
+ },
+ },
+ computed: {
+ dropdownHref() {
+ return this.hasSelectedProject
+ ? joinPaths(this.selectedProject.webUrl, DASH_SCOPE, 'issues/new')
+ : undefined;
+ },
+ dropdownText() {
+ return this.hasSelectedProject
+ ? sprintf(__('New issue in %{project}'), { project: this.selectedProject.name })
+ : this.$options.i18n.defaultDropdownText;
+ },
+ hasSelectedProject() {
+ return this.selectedProject.id;
+ },
+ showNoSearchResultsText() {
+ return !this.projects.length && this.search;
+ },
+ },
+ methods: {
+ handleDropdownClick() {
+ if (!this.dropdownHref) {
+ this.$refs.dropdown.show();
+ }
+ },
+ handleDropdownShown() {
+ if (this.shouldSkipQuery) {
+ this.shouldSkipQuery = false;
+ }
+ this.$refs.search.focusInput();
+ },
+ selectProject(project) {
+ this.selectedProject = project;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="dropdown"
+ right
+ split
+ :split-href="dropdownHref"
+ :text="dropdownText"
+ :toggle-text="$options.i18n.toggleButtonLabel"
+ variant="confirm"
+ @click="handleDropdownClick"
+ @shown="handleDropdownShown"
+ >
+ <gl-search-box-by-type ref="search" v-model.trim="search" />
+ <gl-loading-icon v-if="$apollo.queries.projects.loading" />
+ <template v-else>
+ <gl-dropdown-item
+ v-for="project of projects"
+ :key="project.id"
+ @click="selectProject(project)"
+ >
+ {{ project.nameWithNamespace }}
+ </gl-dropdown-item>
+ <gl-dropdown-text v-if="showNoSearchResultsText">
+ {{ $options.i18n.noMatchesFound }}
+ </gl-dropdown-text>
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/issues_list/index.js b/app/assets/javascripts/issues_list/index.js
index e89e3e8e681..47af20f5271 100644
--- a/app/assets/javascripts/issues_list/index.js
+++ b/app/assets/javascripts/issues_list/index.js
@@ -119,8 +119,9 @@ export function mountIssuesListApp() {
emptyStateSvgPath,
exportCsvPath,
fullPath,
- groupEpicsPath,
+ groupPath,
hasAnyIssues,
+ hasAnyProjects,
hasBlockedIssuesFeature,
hasIssuableHealthStatusFeature,
hasIssueWeightsFeature,
@@ -151,8 +152,9 @@ export function mountIssuesListApp() {
canBulkUpdate: parseBoolean(canBulkUpdate),
emptyStateSvgPath,
fullPath,
- groupEpicsPath,
+ groupPath,
hasAnyIssues: parseBoolean(hasAnyIssues),
+ hasAnyProjects: parseBoolean(hasAnyProjects),
hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature),
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
diff --git a/app/assets/javascripts/issues_list/queries/search_projects.query.graphql b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql
new file mode 100644
index 00000000000..df1f330139a
--- /dev/null
+++ b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql
@@ -0,0 +1,12 @@
+query searchProjects($fullPath: ID!, $search: String) {
+ group(fullPath: $fullPath) {
+ projects(search: $search, includeSubgroups: true) {
+ nodes {
+ id
+ name
+ nameWithNamespace
+ webUrl
+ }
+ }
+ }
+}