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-01-05 18:13:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-01-05 18:13:51 +0300
commit67d7efba05353044f927a30634c63b921b2efb73 (patch)
tree9bc6fefcae4141dd80434b4a72e8eae57ab14466 /app/assets/javascripts/packages_and_registries
parent6d29831123c8c806dc75d64e29b7691576cbea7f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue44
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue67
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/common.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js7
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js3
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql4
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue19
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue80
8 files changed, 172 insertions, 54 deletions
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue
deleted file mode 100644
index a16d95a6b30..00000000000
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import {
- NO_TAGS_TITLE,
- NO_TAGS_MESSAGE,
- MISSING_OR_DELETED_IMAGE_TITLE,
- MISSING_OR_DELETED_IMAGE_MESSAGE,
-} from '../../constants/index';
-
-export default {
- components: {
- GlEmptyState,
- },
- props: {
- noContainersImage: {
- type: String,
- required: false,
- default: '',
- },
- isEmptyImage: {
- type: Boolean,
- default: false,
- required: false,
- },
- },
- computed: {
- title() {
- return this.isEmptyImage ? MISSING_OR_DELETED_IMAGE_TITLE : NO_TAGS_TITLE;
- },
- description() {
- return this.isEmptyImage ? MISSING_OR_DELETED_IMAGE_MESSAGE : NO_TAGS_MESSAGE;
- },
- },
-};
-</script>
-
-<template>
- <gl-empty-state
- :title="title"
- :svg-path="noContainersImage"
- :description="description"
- class="gl-mx-auto gl-my-0"
- />
-</template>
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
index 2d32295b537..4fda4058711 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue
@@ -1,28 +1,38 @@
<script>
+import { GlEmptyState } from '@gitlab/ui';
import createFlash from '~/flash';
import { n__ } from '~/locale';
import { joinPaths } from '~/lib/utils/url_utility';
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
+
+import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
+import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
import {
REMOVE_TAGS_BUTTON_TITLE,
TAGS_LIST_TITLE,
GRAPHQL_PAGE_SIZE,
FETCH_IMAGES_LIST_ERROR_MESSAGE,
+ NAME_SORT_FIELD,
+ NO_TAGS_TITLE,
+ NO_TAGS_MESSAGE,
+ NO_TAGS_MATCHING_FILTERS_TITLE,
+ NO_TAGS_MATCHING_FILTERS_DESCRIPTION,
} from '../../constants/index';
import getContainerRepositoryTagsQuery from '../../graphql/queries/get_container_repository_tags.query.graphql';
-import EmptyState from './empty_state.vue';
import TagsListRow from './tags_list_row.vue';
import TagsLoader from './tags_loader.vue';
export default {
name: 'TagsList',
components: {
+ GlEmptyState,
TagsListRow,
- EmptyState,
TagsLoader,
RegistryList,
+ PersistedSearch,
},
inject: ['config'],
+
props: {
id: {
type: [Number, String],
@@ -44,6 +54,7 @@ export default {
required: false,
},
},
+ searchConfig: { NAME_SORT_FIELD },
i18n: {
REMOVE_TAGS_BUTTON_TITLE,
TAGS_LIST_TITLE,
@@ -51,6 +62,9 @@ export default {
apollo: {
containerRepository: {
query: getContainerRepositoryTagsQuery,
+ skip() {
+ return !this.sort;
+ },
variables() {
return this.queryVariables;
},
@@ -62,6 +76,8 @@ export default {
data() {
return {
containerRepository: {},
+ filters: {},
+ sort: null,
};
},
computed: {
@@ -78,6 +94,8 @@ export default {
return {
id: joinPaths(this.config.gidPrefix, `${this.id}`),
first: GRAPHQL_PAGE_SIZE,
+ name: this.filters?.name,
+ sort: this.sort,
};
},
showMultiDeleteButton() {
@@ -87,7 +105,16 @@ export default {
return this.tags.length === 0;
},
isLoading() {
- return this.isImageLoading || this.$apollo.queries.containerRepository.loading;
+ return this.isImageLoading || this.$apollo.queries.containerRepository.loading || !this.sort;
+ },
+ hasFilters() {
+ return this.filters?.name;
+ },
+ emptyStateTitle() {
+ return this.hasFilters ? NO_TAGS_MATCHING_FILTERS_TITLE : NO_TAGS_TITLE;
+ },
+ emptyStateDescription() {
+ return this.hasFilters ? NO_TAGS_MATCHING_FILTERS_DESCRIPTION : NO_TAGS_MESSAGE;
},
},
methods: {
@@ -114,15 +141,47 @@ export default {
},
});
},
+ handleSearchUpdate({ sort, filters }) {
+ this.sort = sort;
+
+ const parsed = {
+ name: '',
+ };
+
+ // This takes in account the fact that we will be adding more filters types
+ // this is why is an object and not an array or a simple string
+ this.filters = filters.reduce((acc, filter) => {
+ if (filter.type === FILTERED_SEARCH_TERM) {
+ return {
+ ...acc,
+ name: `${acc.name} ${filter.value.data}`.trim(),
+ };
+ }
+ return acc;
+ }, parsed);
+ },
},
};
</script>
<template>
<div>
+ <persisted-search
+ class="gl-mb-5"
+ :sortable-fields="[$options.searchConfig.NAME_SORT_FIELD]"
+ :default-order="$options.searchConfig.NAME_SORT_FIELD.orderBy"
+ default-sort="asc"
+ @update="handleSearchUpdate"
+ />
<tags-loader v-if="isLoading" />
<template v-else>
- <empty-state v-if="hasNoTags" :no-containers-image="config.noContainersImage" />
+ <gl-empty-state
+ v-if="hasNoTags"
+ :title="emptyStateTitle"
+ :svg-path="config.noContainersImage"
+ :description="emptyStateDescription"
+ class="gl-mx-auto gl-my-0"
+ />
<template v-else>
<registry-list
:title="listTitle"
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/common.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/common.js
index f7beec2c935..17adaec7a7d 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/common.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/common.js
@@ -2,3 +2,5 @@ import { s__, __ } from '~/locale';
export const ROOT_IMAGE_TEXT = s__('ContainerRegistry|Root image');
export const MORE_ACTIONS_TEXT = __('More actions');
+
+export const NAME_SORT_FIELD = { orderBy: 'NAME', label: __('Name') };
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
index 19e1a75fb2f..8b8769a884d 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
@@ -116,6 +116,13 @@ export const ROOT_IMAGE_TOOLTIP = s__(
'ContainerRegistry|Image repository with no name located at the project URL.',
);
+export const NO_TAGS_MATCHING_FILTERS_TITLE = s__(
+ 'ContainerRegistry|The filter returned no results',
+);
+export const NO_TAGS_MATCHING_FILTERS_DESCRIPTION = s__(
+ 'ContainerRegistry|Please try different search criteria',
+);
+
// Parameters
export const DEFAULT_PAGE = 1;
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
index d21a154d1b8..7fa950ccfd0 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
@@ -1,4 +1,5 @@
import { s__, __ } from '~/locale';
+import { NAME_SORT_FIELD } from './common';
// Translations strings
@@ -49,5 +50,5 @@ export const GRAPHQL_PAGE_SIZE = 10;
export const SORT_FIELDS = [
{ orderBy: 'UPDATED', label: __('Updated') },
{ orderBy: 'CREATED', label: __('Created') },
- { orderBy: 'NAME', label: __('Name') },
+ NAME_SORT_FIELD,
];
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
index 502382010f9..d753d33a02c 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql
@@ -6,11 +6,13 @@ query getContainerRepositoryTags(
$last: Int
$after: String
$before: String
+ $name: String
+ $sort: ContainerRepositoryTagSort
) {
containerRepository(id: $id) {
id
tagsCount
- tags(after: $after, before: $before, first: $first, last: $last) {
+ tags(after: $after, before: $before, first: $first, last: $last, name: $name, sort: $sort) {
nodes {
digest
location
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
index bc6e3091f0e..bb687ffdb89 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue
@@ -1,5 +1,5 @@
<script>
-import { GlResizeObserverDirective } from '@gitlab/ui';
+import { GlResizeObserverDirective, GlEmptyState } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
@@ -9,7 +9,6 @@ import DeleteImage from '../components/delete_image.vue';
import DeleteAlert from '../components/details_page/delete_alert.vue';
import DeleteModal from '../components/details_page/delete_modal.vue';
import DetailsHeader from '../components/details_page/details_header.vue';
-import EmptyState from '../components/details_page/empty_state.vue';
import PartialCleanupAlert from '../components/details_page/partial_cleanup_alert.vue';
import StatusAlert from '../components/details_page/status_alert.vue';
import TagsList from '../components/details_page/tags_list.vue';
@@ -26,6 +25,8 @@ import {
MISSING_OR_DELETED_IMAGE_BREADCRUMB,
ROOT_IMAGE_TEXT,
GRAPHQL_PAGE_SIZE,
+ MISSING_OR_DELETED_IMAGE_TITLE,
+ MISSING_OR_DELETED_IMAGE_MESSAGE,
} from '../constants/index';
import deleteContainerRepositoryTagsMutation from '../graphql/mutations/delete_container_repository_tags.mutation.graphql';
import getContainerRepositoryDetailsQuery from '../graphql/queries/get_container_repository_details.query.graphql';
@@ -34,13 +35,13 @@ import getContainerRepositoryTagsQuery from '../graphql/queries/get_container_re
export default {
name: 'RegistryDetailsPage',
components: {
+ GlEmptyState,
DeleteAlert,
PartialCleanupAlert,
DetailsHeader,
DeleteModal,
TagsList,
TagsLoader,
- EmptyState,
StatusAlert,
DeleteImage,
},
@@ -49,6 +50,10 @@ export default {
},
mixins: [Tracking.mixin()],
inject: ['breadCrumbState', 'config'],
+ i18n: {
+ MISSING_OR_DELETED_IMAGE_TITLE,
+ MISSING_OR_DELETED_IMAGE_MESSAGE,
+ },
apollo: {
containerRepository: {
query: getContainerRepositoryDetailsQuery,
@@ -230,6 +235,12 @@ export default {
@cancel="track('cancel_delete')"
/>
</template>
- <empty-state v-else is-empty-image :no-containers-image="config.noContainersImage" />
+ <gl-empty-state
+ v-else
+ :title="$options.i18n.MISSING_OR_DELETED_IMAGE_TITLE"
+ :description="$options.i18n.MISSING_OR_DELETED_IMAGE_MESSAGE"
+ :svg-path="config.noContainersImage"
+ class="gl-mx-auto gl-my-0"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue b/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue
new file mode 100644
index 00000000000..9b2de1a1b84
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue
@@ -0,0 +1,80 @@
+<script>
+import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
+import UrlSync from '~/vue_shared/components/url_sync.vue';
+import { extractFilterAndSorting, getQueryParams } from '~/packages_and_registries/shared/utils';
+
+export default {
+ components: { RegistrySearch, UrlSync },
+ props: {
+ sortableFields: {
+ type: Array,
+ required: true,
+ },
+ defaultOrder: {
+ type: String,
+ required: true,
+ },
+ defaultSort: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ filters: [],
+ sorting: {
+ orderBy: this.defaultOrder,
+ sort: this.defaultSort,
+ },
+ mountRegistrySearch: false,
+ };
+ },
+ computed: {
+ parsedSorting() {
+ const cleanOrderBy = this.sorting?.orderBy.replace('_at', '');
+ return `${cleanOrderBy}_${this.sorting?.sort}`.toUpperCase();
+ },
+ },
+ mounted() {
+ const queryParams = getQueryParams(window.document.location.search);
+ const { sorting, filters } = extractFilterAndSorting(queryParams);
+ this.updateSorting(sorting);
+ this.updateFilters(filters);
+ this.mountRegistrySearch = true;
+ this.emitUpdate();
+ },
+ methods: {
+ updateFilters(newValue) {
+ this.filters = newValue;
+ },
+ updateSorting(newValue) {
+ this.sorting = { ...this.sorting, ...newValue };
+ },
+ updateSortingAndEmitUpdate(newValue) {
+ this.updateSorting(newValue);
+ this.emitUpdate();
+ },
+ emitUpdate() {
+ this.$emit('update', { sort: this.parsedSorting, filters: this.filters });
+ },
+ },
+};
+</script>
+
+<template>
+ <url-sync>
+ <template #default="{ updateQuery }">
+ <registry-search
+ v-if="mountRegistrySearch"
+ :filter="filters"
+ :sorting="sorting"
+ :tokens="$options.tokens"
+ :sortable-fields="sortableFields"
+ @sorting:changed="updateSortingAndEmitUpdate"
+ @filter:changed="updateFilters"
+ @filter:submit="emitUpdate"
+ @query:changed="updateQuery"
+ />
+ </template>
+ </url-sync>
+</template>