diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-20 13:18:24 +0000 |
commit | 0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch) | |
tree | 4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /app/assets/javascripts/packages_and_registries/package_registry | |
parent | 744144d28e3e7fddc117924fef88de5d9674fe4c (diff) | |
download | gitlab-ce-0653e08efd039a5905f3fa4f6e9cef9f5d2f799c.tar.gz |
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'app/assets/javascripts/packages_and_registries/package_registry')
15 files changed, 660 insertions, 80 deletions
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue index 4d6a1d5462b..74c0cb44c51 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue @@ -1,25 +1,24 @@ <script> -import { GlLink, GlSprintf } from '@gitlab/ui'; -import { s__ } from '~/locale'; +import Composer from '~/packages_and_registries/package_registry/components/details/metadata/composer.vue'; +import Conan from '~/packages_and_registries/package_registry/components/details/metadata/conan.vue'; +import Maven from '~/packages_and_registries/package_registry/components/details/metadata/maven.vue'; +import Nuget from '~/packages_and_registries/package_registry/components/details/metadata/nuget.vue'; +import Pypi from '~/packages_and_registries/package_registry/components/details/metadata/pypi.vue'; import { - PACKAGE_TYPE_NUGET, + PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN, + PACKAGE_TYPE_NUGET, + PACKAGE_TYPE_PYPI, } from '~/packages_and_registries/package_registry/constants'; -import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; export default { - i18n: { - sourceText: s__('PackageRegistry|Source project located at %{link}'), - licenseText: s__('PackageRegistry|License information located at %{link}'), - recipeText: s__('PackageRegistry|Recipe: %{recipe}'), - appGroup: s__('PackageRegistry|App group: %{group}'), - appName: s__('PackageRegistry|App name: %{name}'), - }, components: { - DetailsRow, - GlLink, - GlSprintf, + Composer, + Conan, + Maven, + Nuget, + Pypi, }, props: { packageEntity: { @@ -28,21 +27,17 @@ export default { }, }, computed: { - showMetadata() { - return ( - [PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes( - this.packageEntity.packageType, - ) && this.packageEntity.metadata - ); - }, - showNugetMetadata() { - return this.packageEntity.packageType === PACKAGE_TYPE_NUGET; + metadataComponent() { + return { + [PACKAGE_TYPE_COMPOSER]: Composer, + [PACKAGE_TYPE_CONAN]: Conan, + [PACKAGE_TYPE_MAVEN]: Maven, + [PACKAGE_TYPE_NUGET]: Nuget, + [PACKAGE_TYPE_PYPI]: Pypi, + }[this.packageEntity.packageType]; }, - showConanMetadata() { - return this.packageEntity.packageType === PACKAGE_TYPE_CONAN; - }, - showMavenMetadata() { - return this.packageEntity.packageType === PACKAGE_TYPE_MAVEN; + showMetadata() { + return this.metadataComponent && this.packageEntity.metadata; }, }, }; @@ -51,56 +46,12 @@ export default { <template> <div v-if="showMetadata"> <h3 class="gl-font-lg" data-testid="title">{{ __('Additional Metadata') }}</h3> - <div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" data-testid="main"> - <template v-if="showNugetMetadata"> - <details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source"> - <gl-sprintf :message="$options.i18n.sourceText"> - <template #link> - <gl-link :href="packageEntity.metadata.projectUrl" target="_blank">{{ - packageEntity.metadata.projectUrl - }}</gl-link> - </template> - </gl-sprintf> - </details-row> - <details-row icon="license" padding="gl-p-4" data-testid="nuget-license"> - <gl-sprintf :message="$options.i18n.licenseText"> - <template #link> - <gl-link :href="packageEntity.metadata.licenseUrl" target="_blank">{{ - packageEntity.metadata.licenseUrl - }}</gl-link> - </template> - </gl-sprintf> - </details-row> - </template> - - <details-row - v-else-if="showConanMetadata" - icon="information-o" - padding="gl-p-4" - data-testid="conan-recipe" - > - <gl-sprintf :message="$options.i18n.recipeText"> - <template #recipe>{{ packageEntity.metadata.recipe }}</template> - </gl-sprintf> - </details-row> - - <template v-else-if="showMavenMetadata"> - <details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app"> - <gl-sprintf :message="$options.i18n.appName"> - <template #name> - <strong>{{ packageEntity.metadata.appName }}</strong> - </template> - </gl-sprintf> - </details-row> - <details-row icon="information-o" padding="gl-p-4" data-testid="maven-group"> - <gl-sprintf :message="$options.i18n.appGroup"> - <template #group> - <strong>{{ packageEntity.metadata.appGroup }}</strong> - </template> - </gl-sprintf> - </details-row> - </template> + <component + :is="metadataComponent" + :package-entity="packageEntity" + data-testid="component-is" + /> </div> </div> </template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/composer.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/composer.vue new file mode 100644 index 00000000000..b6a36a0b00f --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/composer.vue @@ -0,0 +1,55 @@ +<script> +import { GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + targetShaCopyButton: s__('PackageRegistry|Copy target SHA'), + targetSha: s__('PackageRegistry|Target SHA: %{sha}'), + composerJson: s__( + 'PackageRegistry|Composer.json with license: %{license} and version: %{version}', + ), + }, + components: { + DetailsRow, + GlSprintf, + ClipboardButton, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, +}; +</script> + +<template> + <div> + <details-row icon="information-o" padding="gl-p-4" dashed data-testid="composer-target-sha"> + <gl-sprintf :message="$options.i18n.targetSha"> + <template #sha> + <strong>{{ packageEntity.metadata.targetSha }}</strong> + <clipboard-button + :title="$options.i18n.targetShaCopyButton" + :text="packageEntity.metadata.targetSha" + category="tertiary" + css-class="gl-p-0!" + /> + </template> + </gl-sprintf> + </details-row> + <details-row icon="information-o" padding="gl-p-4" data-testid="composer-json"> + <gl-sprintf :message="$options.i18n.composerJson"> + <template #license> + <strong>{{ packageEntity.metadata.composerJson.license }}</strong> + </template> + <template #version> + <strong>{{ packageEntity.metadata.composerJson.version }}</strong> + </template> + </gl-sprintf> + </details-row> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/conan.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/conan.vue new file mode 100644 index 00000000000..10797d74acf --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/conan.vue @@ -0,0 +1,32 @@ +<script> +import { GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + recipeText: s__('PackageRegistry|Recipe: %{recipe}'), + }, + components: { + DetailsRow, + GlSprintf, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, +}; +</script> + +<template> + <div> + <details-row icon="information-o" padding="gl-p-4" data-testid="conan-recipe"> + <gl-sprintf :message="$options.i18n.recipeText"> + <template #recipe>{{ packageEntity.metadata.recipe }}</template> + </gl-sprintf> + </details-row> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/maven.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/maven.vue new file mode 100644 index 00000000000..fd9fb49a9f2 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/maven.vue @@ -0,0 +1,42 @@ +<script> +import { GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + appGroup: s__('PackageRegistry|App group: %{group}'), + appName: s__('PackageRegistry|App name: %{name}'), + }, + components: { + DetailsRow, + GlSprintf, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, +}; +</script> + +<template> + <div> + <details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app"> + <gl-sprintf :message="$options.i18n.appName"> + <template #name> + <strong>{{ packageEntity.metadata.appName }}</strong> + </template> + </gl-sprintf> + </details-row> + <details-row icon="information-o" padding="gl-p-4" data-testid="maven-group"> + <gl-sprintf :message="$options.i18n.appGroup"> + <template #group> + <strong>{{ packageEntity.metadata.appGroup }}</strong> + </template> + </gl-sprintf> + </details-row> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/nuget.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/nuget.vue new file mode 100644 index 00000000000..f0da7db6c91 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/nuget.vue @@ -0,0 +1,46 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + sourceText: s__('PackageRegistry|Source project located at %{link}'), + licenseText: s__('PackageRegistry|License information located at %{link}'), + }, + components: { + DetailsRow, + GlLink, + GlSprintf, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, +}; +</script> + +<template> + <div> + <details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source"> + <gl-sprintf :message="$options.i18n.sourceText"> + <template #link> + <gl-link :href="packageEntity.metadata.projectUrl" target="_blank">{{ + packageEntity.metadata.projectUrl + }}</gl-link> + </template> + </gl-sprintf> + </details-row> + <details-row icon="license" padding="gl-p-4" data-testid="nuget-license"> + <gl-sprintf :message="$options.i18n.licenseText"> + <template #link> + <gl-link :href="packageEntity.metadata.licenseUrl" target="_blank">{{ + packageEntity.metadata.licenseUrl + }}</gl-link> + </template> + </gl-sprintf> + </details-row> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/pypi.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/pypi.vue new file mode 100644 index 00000000000..6534eef532c --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/metadata/pypi.vue @@ -0,0 +1,34 @@ +<script> +import { GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; + +export default { + i18n: { + requiredPython: s__('PackageRegistry|Required Python: %{pythonVersion}'), + }, + components: { + DetailsRow, + GlSprintf, + }, + props: { + packageEntity: { + type: Object, + required: true, + }, + }, +}; +</script> + +<template> + <div> + <details-row icon="information-o" padding="gl-p-4" data-testid="pypi-required-python"> + <gl-sprintf :message="$options.i18n.requiredPython"> + <template #pythonVersion> + <strong>{{ packageEntity.metadata.requiredPython }}</strong> + </template> + </gl-sprintf> + </details-row> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue index af4a984add4..408bd2e3dfe 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable @gitlab/require-string-literal-i18n-helpers */ import { GlLink, GlSprintf } from '@gitlab/ui'; import { first } from 'lodash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue index 65547af3913..44d7807639d 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue @@ -1,5 +1,5 @@ <script> -import { GlIcon, GlSprintf, GlBadge } from '@gitlab/ui'; +import { GlIcon, GlSprintf, GlBadge, GlResizeObserverDirective } from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; import { __ } from '~/locale'; @@ -21,6 +21,9 @@ export default { GlBadge, TimeAgoTooltip, }, + directives: { + GlResizeObserver: GlResizeObserverDirective, + }, i18n: { packageInfo: __('v%{version} published %{timeAgo}'), }, @@ -60,18 +63,26 @@ export default { }, }, mounted() { - this.isDesktop = GlBreakpointInstance.isDesktop(); + this.checkBreakpoints(); }, methods: { dynamicSlotName(index) { return `metadata-tag${index}`; }, + checkBreakpoints() { + this.isDesktop = GlBreakpointInstance.isDesktop(); + }, }, }; </script> <template> - <title-area :title="packageEntity.name" :avatar="packageIcon" data-qa-selector="package_title"> + <title-area + v-gl-resize-observer="checkBreakpoints" + :title="packageEntity.name" + :avatar="packageIcon" + data-qa-selector="package_title" + > <template #sub-header> <gl-icon name="eye" class="gl-mr-3" /> <span data-testid="sub-header"> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue new file mode 100644 index 00000000000..280d292ce0b --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue @@ -0,0 +1,57 @@ +<script> +import { mapState, mapActions } from 'vuex'; +import { s__ } from '~/locale'; +import { sortableFields } from '~/packages/list/utils'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; +import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; +import UrlSync from '~/vue_shared/components/url_sync.vue'; +import PackageTypeToken from './tokens/package_type_token.vue'; + +export default { + tokens: [ + { + type: 'type', + icon: 'package', + title: s__('PackageRegistry|Type'), + unique: true, + token: PackageTypeToken, + operators: OPERATOR_IS_ONLY, + }, + ], + components: { RegistrySearch, UrlSync }, + computed: { + ...mapState({ + isGroupPage: (state) => state.config.isGroupPage, + sorting: (state) => state.sorting, + filter: (state) => state.filter, + }), + sortableFields() { + return sortableFields(this.isGroupPage); + }, + }, + methods: { + ...mapActions(['setSorting', 'setFilter']), + updateSorting(newValue) { + this.setSorting(newValue); + this.$emit('update'); + }, + }, +}; +</script> + +<template> + <url-sync> + <template #default="{ updateQuery }"> + <registry-search + :filter="filter" + :sorting="sorting" + :tokens="$options.tokens" + :sortable-fields="sortableFields" + @sorting:changed="updateSorting" + @filter:changed="setFilter" + @filter:submit="$emit('update')" + @query:changed="updateQuery" + /> + </template> + </url-sync> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_title.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_title.vue new file mode 100644 index 00000000000..6e00a48586e --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_title.vue @@ -0,0 +1,47 @@ +<script> +import { n__ } from '~/locale'; +import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '~/packages/list/constants'; +import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; +import TitleArea from '~/vue_shared/components/registry/title_area.vue'; + +export default { + name: 'PackageTitle', + components: { + TitleArea, + MetadataItem, + }, + props: { + count: { + type: Number, + required: false, + default: null, + }, + helpUrl: { + type: String, + required: true, + }, + }, + computed: { + showPackageCount() { + return Number.isInteger(this.count); + }, + packageAmountText() { + return n__(`%d Package`, `%d Packages`, this.count); + }, + infoMessages() { + return [{ text: LIST_INTRO_TEXT, link: this.helpUrl }]; + }, + }, + i18n: { + LIST_TITLE_TEXT, + }, +}; +</script> + +<template> + <title-area :title="$options.i18n.LIST_TITLE_TEXT" :info-messages="infoMessages"> + <template #metadata-amount> + <metadata-item v-if="showPackageCount" icon="package" :text="packageAmountText" /> + </template> + </title-area> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue new file mode 100644 index 00000000000..25bac687dbf --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue @@ -0,0 +1,129 @@ +<script> +import { GlPagination, GlModal, GlSprintf } from '@gitlab/ui'; +import { mapState, mapGetters } from 'vuex'; +import { s__ } from '~/locale'; +import PackagesListRow from '~/packages/shared/components/package_list_row.vue'; +import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue'; +import { TrackingActions } from '~/packages/shared/constants'; +import { packageTypeToTrackCategory } from '~/packages/shared/utils'; +import Tracking from '~/tracking'; + +export default { + components: { + GlPagination, + GlModal, + GlSprintf, + PackagesListLoader, + PackagesListRow, + }, + mixins: [Tracking.mixin()], + data() { + return { + itemToBeDeleted: null, + }; + }, + computed: { + ...mapState({ + perPage: (state) => state.pagination.perPage, + totalItems: (state) => state.pagination.total, + page: (state) => state.pagination.page, + isGroupPage: (state) => state.config.isGroupPage, + isLoading: 'isLoading', + }), + ...mapGetters({ list: 'getList' }), + currentPage: { + get() { + return this.page; + }, + set(value) { + this.$emit('page:changed', value); + }, + }, + isListEmpty() { + return !this.list || this.list.length === 0; + }, + modalAction() { + return s__('PackageRegistry|Delete package'); + }, + deletePackageName() { + return this.itemToBeDeleted?.name ?? ''; + }, + tracking() { + const category = this.itemToBeDeleted + ? packageTypeToTrackCategory(this.itemToBeDeleted.package_type) + : undefined; + return { + category, + }; + }, + }, + methods: { + setItemToBeDeleted(item) { + this.itemToBeDeleted = { ...item }; + this.track(TrackingActions.REQUEST_DELETE_PACKAGE); + this.$refs.packageListDeleteModal.show(); + }, + deleteItemConfirmation() { + this.$emit('package:delete', this.itemToBeDeleted); + this.track(TrackingActions.DELETE_PACKAGE); + this.itemToBeDeleted = null; + }, + deleteItemCanceled() { + this.track(TrackingActions.CANCEL_DELETE_PACKAGE); + this.itemToBeDeleted = null; + }, + }, + i18n: { + deleteModalContent: s__( + 'PackageRegistry|You are about to delete %{name}, this operation is irreversible, are you sure?', + ), + }, +}; +</script> + +<template> + <div class="gl-display-flex gl-flex-direction-column"> + <slot v-if="isListEmpty && !isLoading" name="empty-state"></slot> + + <div v-else-if="isLoading"> + <packages-list-loader /> + </div> + + <template v-else> + <div data-qa-selector="packages-table"> + <packages-list-row + v-for="packageEntity in list" + :key="packageEntity.id" + :package-entity="packageEntity" + :package-link="packageEntity._links.web_path" + :is-group="isGroupPage" + @packageToDelete="setItemToBeDeleted" + /> + </div> + + <gl-pagination + v-model="currentPage" + :per-page="perPage" + :total-items="totalItems" + align="center" + class="gl-w-full gl-mt-3" + /> + + <gl-modal + ref="packageListDeleteModal" + modal-id="confirm-delete-pacakge" + ok-variant="danger" + @ok="deleteItemConfirmation" + @cancel="deleteItemCanceled" + > + <template #modal-title>{{ modalAction }}</template> + <template #modal-ok>{{ modalAction }}</template> + <gl-sprintf :message="$options.i18n.deleteModalContent"> + <template #name> + <strong>{{ deletePackageName }}</strong> + </template> + </gl-sprintf> + </gl-modal> + </template> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list_app.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list_app.vue new file mode 100644 index 00000000000..75fbdb80192 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list_app.vue @@ -0,0 +1,132 @@ +<script> +import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui'; +import { mapActions, mapState } from 'vuex'; +import createFlash from '~/flash'; +import { historyReplaceState } from '~/lib/utils/common_utils'; +import { s__ } from '~/locale'; +import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages/list/constants'; +import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants'; +import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; +import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils'; +import PackageList from './packages_list.vue'; + +export default { + components: { + GlEmptyState, + GlLink, + GlSprintf, + PackageList, + PackageTitle: () => + import(/* webpackChunkName: 'package_registry_components' */ './package_title.vue'), + PackageSearch: () => + import(/* webpackChunkName: 'package_registry_components' */ './package_search.vue'), + InfrastructureTitle: () => + import( + /* webpackChunkName: 'infrastructure_registry_components' */ '~/packages_and_registries/infrastructure_registry/components/infrastructure_title.vue' + ), + InfrastructureSearch: () => + import( + /* webpackChunkName: 'infrastructure_registry_components' */ '~/packages_and_registries/infrastructure_registry/components/infrastructure_search.vue' + ), + }, + inject: { + titleComponent: { + from: 'titleComponent', + default: 'PackageTitle', + }, + searchComponent: { + from: 'searchComponent', + default: 'PackageSearch', + }, + emptyPageTitle: { + from: 'emptyPageTitle', + default: s__('PackageRegistry|There are no packages yet'), + }, + noResultsText: { + from: 'noResultsText', + default: s__( + 'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.', + ), + }, + }, + computed: { + ...mapState({ + emptyListIllustration: (state) => state.config.emptyListIllustration, + emptyListHelpUrl: (state) => state.config.emptyListHelpUrl, + filter: (state) => state.filter, + selectedType: (state) => state.selectedType, + packageHelpUrl: (state) => state.config.packageHelpUrl, + packagesCount: (state) => state.pagination?.total, + }), + emptySearch() { + return ( + this.filter.filter((f) => f.type !== FILTERED_SEARCH_TERM || f.value?.data).length === 0 + ); + }, + + emptyStateTitle() { + return this.emptySearch + ? this.emptyPageTitle + : s__('PackageRegistry|Sorry, your filter produced no results'); + }, + }, + mounted() { + const queryParams = getQueryParams(window.document.location.search); + const { sorting, filters } = extractFilterAndSorting(queryParams); + this.setSorting(sorting); + this.setFilter(filters); + this.requestPackagesList(); + this.checkDeleteAlert(); + }, + methods: { + ...mapActions([ + 'requestPackagesList', + 'requestDeletePackage', + 'setSelectedType', + 'setSorting', + 'setFilter', + ]), + onPageChanged(page) { + return this.requestPackagesList({ page }); + }, + onPackageDeleteRequest(item) { + return this.requestDeletePackage(item); + }, + checkDeleteAlert() { + const urlParams = new URLSearchParams(window.location.search); + const showAlert = urlParams.get(SHOW_DELETE_SUCCESS_ALERT); + if (showAlert) { + // to be refactored to use gl-alert + createFlash({ message: DELETE_PACKAGE_SUCCESS_MESSAGE, type: 'notice' }); + const cleanUrl = window.location.href.split('?')[0]; + historyReplaceState(cleanUrl); + } + }, + }, + i18n: { + widenFilters: s__('PackageRegistry|To widen your search, change or remove the filters above.'), + }, +}; +</script> + +<template> + <div> + <component :is="titleComponent" :help-url="packageHelpUrl" :count="packagesCount" /> + <component :is="searchComponent" @update="requestPackagesList" /> + + <package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest"> + <template #empty-state> + <gl-empty-state :title="emptyStateTitle" :svg-path="emptyListIllustration"> + <template #description> + <gl-sprintf v-if="!emptySearch" :message="$options.i18n.widenFilters" /> + <gl-sprintf v-else :message="noResultsText"> + <template #noPackagesLink="{ content }"> + <gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </template> + </gl-empty-state> + </template> + </package-list> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/tokens/package_type_token.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/tokens/package_type_token.vue new file mode 100644 index 00000000000..529a7893dfc --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/tokens/package_type_token.vue @@ -0,0 +1,26 @@ +<script> +import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui'; +import { PACKAGE_TYPES } from '~/packages/list/constants'; + +export default { + components: { + GlFilteredSearchToken, + GlFilteredSearchSuggestion, + }, + PACKAGE_TYPES, +}; +</script> + +<template> + <gl-filtered-search-token v-bind="{ ...$attrs }" v-on="$listeners"> + <template #suggestions> + <gl-filtered-search-suggestion + v-for="(type, index) in $options.PACKAGE_TYPES" + :key="index" + :value="type.type" + > + {{ type.title }} + </gl-filtered-search-suggestion> + </template> + </gl-filtered-search-token> +</template> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/constants.js b/app/assets/javascripts/packages_and_registries/package_registry/constants.js index aad888b4433..f023b4481a0 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js @@ -1,3 +1,4 @@ +/* eslint-disable @gitlab/require-string-literal-i18n-helpers */ import { __, s__ } from '~/locale'; export const PACKAGE_TYPE_CONAN = 'CONAN'; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/list.js b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.js new file mode 100644 index 00000000000..1e01b75aabc --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.js @@ -0,0 +1,16 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import PackagesListApp from '../components/list/packages_list_app.vue'; + +Vue.use(Translate); + +export default () => { + const el = document.getElementById('js-vue-packages-list'); + + return new Vue({ + el, + render(createElement) { + return createElement(PackagesListApp); + }, + }); +}; |