diff options
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
37 files changed, 477 insertions, 218 deletions
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue index 15d92ab0ef7..acf810257e6 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue @@ -25,6 +25,7 @@ import { NOT_AVAILABLE_TEXT, NOT_AVAILABLE_SIZE, MORE_ACTIONS_TEXT, + COPY_IMAGE_PATH_TITLE, } from '../../constants/index'; export default { @@ -72,6 +73,7 @@ export default { CONFIGURATION_DETAILS_ROW_TEST, MISSING_MANIFEST_WARNING_TOOLTIP, MORE_ACTIONS_TEXT, + COPY_IMAGE_PATH_TITLE, }, computed: { formattedSize() { @@ -130,6 +132,7 @@ export default { <div v-gl-tooltip="{ title: tag.name }" data-testid="name" + data-qa-selector="tag_name_content" class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap" :class="mobileClasses" > @@ -138,7 +141,7 @@ export default { <clipboard-button v-if="tag.location" - :title="tag.location" + :title="$options.i18n.COPY_IMAGE_PATH_TITLE" :text="tag.location" category="tertiary" :disabled="disabled" diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue index 3ae69731537..56da8e88b7a 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue @@ -56,6 +56,9 @@ export default { calculatedTimeTilNextRun() { return timeTilRun(this.expirationPolicy?.next_run); }, + expireIconName() { + return this.failedDelete ? 'expire' : 'clock'; + }, }, statusPopoverOptions: { triggers: 'hover', @@ -75,7 +78,7 @@ export default { class="gl-display-inline-flex gl-align-items-center" > <div class="gl-display-inline-flex gl-align-items-center"> - <gl-icon name="expire" data-testid="main-icon" /> + <gl-icon :name="expireIconName" data-testid="main-icon" /> </div> <span class="gl-mx-2"> {{ statusText }} diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue index d76a8245b63..e67d77210bb 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue @@ -14,6 +14,7 @@ import { IMAGE_FAILED_DELETED_STATUS, IMAGE_MIGRATING_STATE, ROOT_IMAGE_TEXT, + COPY_IMAGE_PATH_TITLE, } from '../../constants/index'; import DeleteButton from '../delete_button.vue'; import CleanupStatus from './cleanup_status.vue'; @@ -52,6 +53,7 @@ export default { i18n: { REMOVE_REPOSITORY_LABEL, ROW_SCHEDULED_FOR_DELETION, + COPY_IMAGE_PATH_TITLE, }, computed: { disabledDelete() { @@ -115,7 +117,7 @@ export default { v-if="item.location" :disabled="deleting" :text="item.location" - :title="item.location" + :title="$options.i18n.COPY_IMAGE_PATH_TITLE" category="tertiary" /> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue index 4ffd8390e4d..19d35a135fd 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue @@ -107,7 +107,7 @@ export default { <metadata-item v-if="!hideExpirationPolicyData" data-testid="expiration-policy" - icon="expire" + icon="clock" :text="expirationPolicyText" size="xl" /> 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 2a58933cd64..98c24350f09 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 @@ -67,7 +67,7 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__( export const UPDATED_AT = s__('ContainerRegistry|Last updated %{time}'); -export const NOT_AVAILABLE_TEXT = __('N/A'); +export const NOT_AVAILABLE_TEXT = __('Not applicable.'); export const NOT_AVAILABLE_SIZE = __('0 bytes'); export const CLEANUP_UNSCHEDULED_TEXT = s__('ContainerRegistry|Cleanup will run %{time}'); 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 ceaf8a65a10..c6a7591e0d9 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 @@ -41,6 +41,8 @@ export const EMPTY_RESULT_MESSAGE = s__( 'ContainerRegistry|To widen your search, change or remove the filters above.', ); +export const COPY_IMAGE_PATH_TITLE = s__('ContainerRegistry|Copy image path'); + // Parameters export const IMAGE_DELETE_SCHEDULED_STATUS = 'DELETE_SCHEDULED'; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js index 2519f6b74a2..b62c51bd208 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js @@ -35,5 +35,5 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__( 'HarborRegistry|Invalid tag: missing manifest digest', ); -export const NOT_AVAILABLE_TEXT = __('N/A'); +export const NOT_AVAILABLE_TEXT = __('Not applicable.'); export const NOT_AVAILABLE_SIZE = __('0 bytes'); diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue index 7aaef2ed57a..9c69059c968 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue @@ -1,5 +1,6 @@ <script> import { GlEmptyState, GlSprintf, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import { escape } from 'lodash'; import HarborListHeader from '~/packages_and_registries/harbor_registry/components/list/harbor_list_header.vue'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; import HarborList from '~/packages_and_registries/harbor_registry/components/list/harbor_list.vue'; @@ -80,7 +81,7 @@ export default { this.sorting = sort; const search = filters.find((i) => i.type === FILTERED_SEARCH_TERM); - this.name = search?.value?.data; + this.name = escape(search?.value?.data); this.fetchHarborImages(); }, diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/package_files.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/package_files.vue index ab4cfccd023..28bfb82093c 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/package_files.vue +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/package_files.vue @@ -100,7 +100,7 @@ export default { <template #cell(name)="{ item, toggleDetails, detailsShowing }"> <gl-button v-if="hasDetails(item)" - :icon="detailsShowing ? 'angle-up' : 'angle-down'" + :icon="detailsShowing ? 'chevron-lg-up' : 'chevron-lg-down'" :aria-label="detailsShowing ? __('Collapse') : __('Expand')" category="tertiary" size="small" diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue index d3c38da1531..2046b717362 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue @@ -31,7 +31,7 @@ export default { <url-sync> <template #default="{ updateQuery }"> <registry-search - :filter="filter" + :filters="filter" :sorting="sorting" :tokens="[] /* eslint-disable-line @gitlab/vue-no-new-non-primitive-in-template */" :sortable-fields="sortableFields" diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue index a5f367bc1f6..a465fea0b74 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue @@ -1,7 +1,7 @@ <script> import { GlPagination, GlModal, GlSprintf } from '@gitlab/ui'; import { mapState, mapGetters } from 'vuex'; -import { s__ } from '~/locale'; +import { __, s__ } from '~/locale'; import Tracking from '~/tracking'; import PackagesListRow from '~/packages_and_registries/infrastructure_registry/shared/package_list_row.vue'; import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue'; @@ -42,12 +42,22 @@ export default { isListEmpty() { return !this.list || this.list.length === 0; }, - modalAction() { - return s__('PackageRegistry|Delete package'); - }, deletePackageName() { return this.itemToBeDeleted?.name ?? ''; }, + deleteModalActionPrimaryProps() { + return { + text: this.$options.i18n.modalAction, + attributes: { + variant: 'danger', + }, + }; + }, + deleteModalActionCancelProps() { + return { + text: __('Cancel'), + }; + }, tracking() { return { category: TRACK_CATEGORY, @@ -74,6 +84,7 @@ export default { deleteModalContent: s__( 'PackageRegistry|You are about to delete %{name}, this operation is irreversible, are you sure?', ), + modalAction: s__('PackageRegistry|Delete package'), }, }; </script> @@ -110,12 +121,12 @@ export default { ref="packageListDeleteModal" size="sm" modal-id="confirm-delete-pacakge" - ok-variant="danger" + :action-primary="deleteModalActionPrimaryProps" + :action-cancel="deleteModalActionCancelProps" @ok="deleteItemConfirmation" @cancel="deleteItemCanceled" > - <template #modal-title>{{ modalAction }}</template> - <template #modal-ok>{{ modalAction }}</template> + <template #modal-title>{{ $options.i18n.modalAction }}</template> <gl-sprintf :message="$options.i18n.deleteModalContent"> <template #name> <strong>{{ deletePackageName }}</strong> 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 74c0cb44c51..a3bbd569f41 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,30 +1,68 @@ <script> +import { GlAlert } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; +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 { + FETCH_PACKAGE_METADATA_ERROR_MESSAGE, PACKAGE_TYPE_COMPOSER, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN, PACKAGE_TYPE_NUGET, PACKAGE_TYPE_PYPI, } from '~/packages_and_registries/package_registry/constants'; +import getPackageMetadataQuery from '../../graphql/queries/get_package_metadata.query.graphql'; +import AdditionalMetadataLoader from './additional_metadata_loader.vue'; export default { components: { Composer, Conan, + GlAlert, Maven, Nuget, Pypi, + AdditionalMetadataLoader, }, props: { - packageEntity: { - type: Object, + packageId: { + type: String, required: true, }, + packageType: { + type: String, + required: true, + }, + }, + apollo: { + packageMetadata: { + query: getPackageMetadataQuery, + context: { + isSingleRequest: true, + }, + variables() { + return { + id: this.packageId, + }; + }, + update(data) { + return data.package?.metadata || null; + }, + error(error) { + this.fetchPackageMetadataError = true; + Sentry.captureException(error); + }, + }, + }, + data() { + return { + packageMetadata: null, + fetchPackageMetadataError: false, + }; }, computed: { metadataComponent() { @@ -34,22 +72,43 @@ export default { [PACKAGE_TYPE_MAVEN]: Maven, [PACKAGE_TYPE_NUGET]: Nuget, [PACKAGE_TYPE_PYPI]: Pypi, - }[this.packageEntity.packageType]; + }[this.packageType]; }, showMetadata() { - return this.metadataComponent && this.packageEntity.metadata; + return this.metadataComponent && this.packageMetadata; + }, + isLoading() { + return this.$apollo.queries.packageMetadata.loading; }, }, + i18n: { + componentTitle: s__('PackageRegistry|Additional metadata'), + fetchPackageMetadataErrorMessage: FETCH_PACKAGE_METADATA_ERROR_MESSAGE, + }, }; </script> <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"> + <div> + <h3 v-if="isLoading || showMetadata" class="gl-font-lg" data-testid="title"> + {{ $options.i18n.componentTitle }} + </h3> + <gl-alert + v-if="fetchPackageMetadataError" + variant="danger" + @dismiss="fetchPackageMetadataError = false" + > + {{ $options.i18n.fetchPackageMetadataErrorMessage }} + </gl-alert> + <additional-metadata-loader v-if="isLoading" /> + <div + v-if="showMetadata" + class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" + data-testid="main" + > <component :is="metadataComponent" - :package-entity="packageEntity" + :package-metadata="packageMetadata" data-testid="component-is" /> </div> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata_loader.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata_loader.vue new file mode 100644 index 00000000000..628cf441831 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata_loader.vue @@ -0,0 +1,30 @@ +<script> +import { GlSkeletonLoader } from '@gitlab/ui'; + +export default { + components: { + GlSkeletonLoader, + }, + loader: { + width: 302, + height: 16, + repeat: 2, + }, +}; +</script> + +<template> + <div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base"> + <div + v-for="index in $options.loader.repeat" + :key="index" + class="gl-display-flex gl-align-items-center gl-p-4 gl-border-gray-100 gl-border-b-1" + > + <div class="gl-md-max-w-30p"> + <gl-skeleton-loader :width="$options.loader.width" :height="$options.loader.height"> + <rect :width="$options.loader.width" :height="$options.loader.height" rx="4" /> + </gl-skeleton-loader> + </div> + </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 index b6a36a0b00f..e3edaa3e45e 100644 --- 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 @@ -18,7 +18,7 @@ export default { ClipboardButton, }, props: { - packageEntity: { + packageMetadata: { type: Object, required: true, }, @@ -31,10 +31,10 @@ export default { <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> + <strong>{{ packageMetadata.targetSha }}</strong> <clipboard-button :title="$options.i18n.targetShaCopyButton" - :text="packageEntity.metadata.targetSha" + :text="packageMetadata.targetSha" category="tertiary" css-class="gl-p-0!" /> @@ -44,10 +44,10 @@ export default { <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> + <strong>{{ packageMetadata.composerJson.license }}</strong> </template> <template #version> - <strong>{{ packageEntity.metadata.composerJson.version }}</strong> + <strong>{{ packageMetadata.composerJson.version }}</strong> </template> </gl-sprintf> </details-row> 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 index 10797d74acf..de7c1bc4cd3 100644 --- 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 @@ -13,7 +13,7 @@ export default { GlSprintf, }, props: { - packageEntity: { + packageMetadata: { type: Object, required: true, }, @@ -25,7 +25,7 @@ export default { <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> + <template #recipe>{{ packageMetadata.recipe }}</template> </gl-sprintf> </details-row> </div> 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 index fd9fb49a9f2..7c3eb476a99 100644 --- 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 @@ -14,7 +14,7 @@ export default { GlSprintf, }, props: { - packageEntity: { + packageMetadata: { type: Object, required: true, }, @@ -27,14 +27,14 @@ export default { <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> + <strong>{{ packageMetadata.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> + <strong>{{ packageMetadata.appGroup }}</strong> </template> </gl-sprintf> </details-row> 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 index 1360b03856f..1ddd419a639 100644 --- 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 @@ -14,7 +14,7 @@ export default { GlSprintf, }, props: { - packageEntity: { + packageMetadata: { type: Object, required: true, }, @@ -25,7 +25,7 @@ export default { <template> <div> <details-row - v-if="packageEntity.metadata.projectUrl" + v-if="packageMetadata.projectUrl" icon="project" padding="gl-p-4" dashed @@ -33,22 +33,22 @@ export default { > <gl-sprintf :message="$options.i18n.sourceText"> <template #link> - <gl-link :href="packageEntity.metadata.projectUrl" target="_blank">{{ - packageEntity.metadata.projectUrl + <gl-link :href="packageMetadata.projectUrl" target="_blank">{{ + packageMetadata.projectUrl }}</gl-link> </template> </gl-sprintf> </details-row> <details-row - v-if="packageEntity.metadata.licenseUrl" + v-if="packageMetadata.licenseUrl" 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 :href="packageMetadata.licenseUrl" target="_blank">{{ + packageMetadata.licenseUrl }}</gl-link> </template> </gl-sprintf> 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 index 6534eef532c..ef35349c228 100644 --- 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 @@ -13,7 +13,7 @@ export default { GlSprintf, }, props: { - packageEntity: { + packageMetadata: { type: Object, required: true, }, @@ -26,7 +26,7 @@ export default { <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> + <strong>{{ packageMetadata.requiredPython }}</strong> </template> </gl-sprintf> </details-row> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue index 3724e371e01..9e700a5236f 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue @@ -1,5 +1,5 @@ <script> -import { GlLink, GlTable, GlDropdownItem, GlDropdown, GlIcon, GlButton } from '@gitlab/ui'; +import { GlLink, GlTableLite, GlDropdownItem, GlDropdown, GlIcon, GlButton } from '@gitlab/ui'; import { last } from 'lodash'; import { numberToHumanSize } from '~/lib/utils/number_utils'; import { __ } from '~/locale'; @@ -12,7 +12,7 @@ export default { name: 'PackageFiles', components: { GlLink, - GlTable, + GlTableLite, GlIcon, GlDropdown, GlDropdownItem, @@ -94,7 +94,7 @@ export default { <template> <div> <h3 class="gl-font-lg gl-mt-5">{{ __('Files') }}</h3> - <gl-table + <gl-table-lite :fields="filesTableHeaderFields" :items="filesTableRows" :tbody-tr-attr="{ 'data-testid': 'file-row' }" @@ -102,7 +102,7 @@ export default { <template #cell(name)="{ item, toggleDetails, detailsShowing }"> <gl-button v-if="hasDetails(item)" - :icon="detailsShowing ? 'angle-up' : 'angle-down'" + :icon="detailsShowing ? 'chevron-up' : 'chevron-down'" :aria-label="detailsShowing ? __('Collapse') : __('Expand')" category="tertiary" size="small" @@ -162,6 +162,6 @@ export default { <file-sha v-if="item.fileSha1" data-testid="sha-1" title="SHA-1" :sha="item.fileSha1" /> </div> </template> - </gl-table> + </gl-table-lite> </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 af6bd7079ba..96b82a20364 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,5 +1,6 @@ <script> -import { GlLink, GlSprintf } from '@gitlab/ui'; +import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; import { first } from 'lodash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { truncateSha } from '~/lib/utils/text_utility'; @@ -7,6 +8,12 @@ import { s__, n__ } from '~/locale'; import { HISTORY_PIPELINES_LIMIT } from '~/packages_and_registries/shared/constants'; import HistoryItem from '~/vue_shared/components/registry/history_item.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import { + GRAPHQL_PACKAGE_PIPELINES_PAGE_SIZE, + FETCH_PACKAGE_PIPELINES_ERROR_MESSAGE, +} from '../../constants'; +import getPackagePipelinesQuery from '../../graphql/queries/get_package_pipelines.query.graphql'; +import PackageHistoryLoader from './package_history_loader.vue'; export default { name: 'PackageHistory', @@ -20,11 +27,14 @@ export default { combinedUpdateText: s__( 'PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}', ), + fetchPackagePipelinesErrorMessage: FETCH_PACKAGE_PIPELINES_ERROR_MESSAGE, }, components: { + GlAlert, GlLink, GlSprintf, HistoryItem, + PackageHistoryLoader, TimeAgoTooltip, }, props: { @@ -37,15 +47,28 @@ export default { required: true, }, }, + apollo: { + pipelines: { + query: getPackagePipelinesQuery, + variables() { + return this.queryVariables; + }, + update(data) { + return data.package?.pipelines?.nodes || []; + }, + error(error) { + this.fetchPackagePipelinesError = true; + Sentry.captureException(error); + }, + }, + }, data() { return { - showDescription: false, + pipelines: [], + fetchPackagePipelinesError: false, }; }, computed: { - pipelines() { - return this.packageEntity?.pipelines?.nodes || []; - }, firstPipeline() { return first(this.pipelines); }, @@ -65,6 +88,15 @@ export default { this.archivedLines, ); }, + isLoading() { + return this.$apollo.queries.pipelines.loading; + }, + queryVariables() { + return { + id: this.packageEntity.id, + first: GRAPHQL_PACKAGE_PIPELINES_PAGE_SIZE, + }; + }, }, methods: { truncate(value) { @@ -80,7 +112,15 @@ export default { <template> <div class="issuable-discussion"> <h3 class="gl-font-lg" data-testid="title">{{ __('History') }}</h3> - <ul class="timeline main-notes-list notes gl-mb-4" data-testid="timeline"> + <gl-alert + v-if="fetchPackagePipelinesError" + variant="danger" + @dismiss="fetchPackagePipelinesError = false" + > + {{ $options.i18n.fetchPackagePipelinesErrorMessage }} + </gl-alert> + <package-history-loader v-if="isLoading" /> + <ul v-else class="timeline main-notes-list notes gl-mb-4" data-testid="timeline"> <history-item icon="clock" data-testid="created-on"> <gl-sprintf :message="$options.i18n.createdOn"> <template #name> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history_loader.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history_loader.vue new file mode 100644 index 00000000000..950971c2f11 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history_loader.vue @@ -0,0 +1,24 @@ +<script> +import { GlSkeletonLoader } from '@gitlab/ui'; + +export default { + components: { + GlSkeletonLoader, + }, + loader: { + width: 580, + height: 80, + }, +}; +</script> + +<template> + <div class="gl-ml-5 gl-md-max-w-70p"> + <gl-skeleton-loader :width="$options.loader.width" :height="$options.loader.height"> + <rect x="49" y="9" width="531" height="16" rx="4" /> + <circle cx="16" cy="16" r="16" /> + <rect x="49" y="57" width="302" height="16" rx="4" /> + <circle cx="16" cy="64" r="16" /> + </gl-skeleton-loader> + </div> +</template> 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 index 7a88e04d1f9..d28847c7900 100644 --- 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 @@ -105,7 +105,7 @@ export default { <template #default="{ updateQuery }"> <registry-search v-if="mountRegistrySearch" - :filter="filters" + :filters="filters" :sorting="sorting" :tokens="$options.tokens" :sortable-fields="sortableFields" 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 index 1aff23bc112..a6ac2eb1b2b 100644 --- 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 @@ -1,6 +1,6 @@ <script> import { GlAlert, GlModal, GlSprintf, GlKeysetPagination } from '@gitlab/ui'; -import { s__, sprintf } from '~/locale'; +import { __, s__, sprintf } from '~/locale'; import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue'; import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue'; import { @@ -73,6 +73,19 @@ export default { } }, }, + deleteModalActionPrimaryProps() { + return { + text: this.$options.i18n.modalAction, + attributes: { + variant: 'danger', + }, + }; + }, + deleteModalActionCancelProps() { + return { + text: __('Cancel'), + }; + }, errorTitleAlert() { return sprintf( s__('PackageRegistry|There was an error publishing a %{packageName} package'), @@ -161,12 +174,12 @@ export default { v-model="showDeleteModal" modal-id="confirm-delete-pacakge" size="sm" - ok-variant="danger" + :action-primary="deleteModalActionPrimaryProps" + :action-cancel="deleteModalActionCancelProps" @ok="deleteItemConfirmation" @cancel="deleteItemCanceled" > <template #modal-title>{{ $options.i18n.modalAction }}</template> - <template #modal-ok>{{ $options.i18n.modalAction }}</template> <gl-sprintf :message="$options.i18n.deleteModalContent"> <template #name> <strong>{{ deletePackageName }}</strong> 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 c4d331fa384..3c090951b7d 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js @@ -72,6 +72,12 @@ export const DELETE_PACKAGE_FILE_SUCCESS_MESSAGE = s__( export const FETCH_PACKAGE_DETAILS_ERROR_MESSAGE = s__( 'PackageRegistry|Failed to load the package data', ); +export const FETCH_PACKAGE_PIPELINES_ERROR_MESSAGE = s__( + 'PackageRegistry|Something went wrong while fetching the package history.', +); +export const FETCH_PACKAGE_METADATA_ERROR_MESSAGE = s__( + 'PackageRegistry|Something went wrong while fetching the package metadata.', +); export const DELETE_PACKAGE_SUCCESS_MESSAGE = s__('PackageRegistry|Package deleted successfully'); export const PACKAGE_REGISTRY_TITLE = __('Package Registry'); @@ -149,3 +155,5 @@ export const CONAN_HELP_PATH = helpPagePath('user/packages/conan_repository/inde export const NUGET_HELP_PATH = helpPagePath('user/packages/nuget_repository/index'); export const PYPI_HELP_PATH = helpPagePath('user/packages/pypi_repository/index'); export const COMPOSER_HELP_PATH = helpPagePath('user/packages/composer_repository/index'); + +export const GRAPHQL_PACKAGE_PIPELINES_PAGE_SIZE = 10; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql index 41b0c285fff..5574020c9e4 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql @@ -27,18 +27,10 @@ query getPackageDetails($id: PackagesPackageID!) { name } } - pipelines(first: 10) { + pipelines(first: 1) { nodes { ref id - sha - createdAt - commitPath - path - user { - id - name - } project { id name @@ -91,37 +83,15 @@ query getPackageDetails($id: PackagesPackageID!) { } } metadata { - ... on ComposerMetadata { - targetSha - composerJson { - license - version - } - } - ... on PypiMetadata { - id - requiredPython - } - ... on ConanMetadata { - id - packageChannel - packageUsername - recipe - recipePath - } ... on MavenMetadata { id appName appGroup appVersion - path } - ... on NugetMetadata { id iconUrl - licenseUrl - projectUrl } } } diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_metadata.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_metadata.query.graphql new file mode 100644 index 00000000000..fc8b39b37ab --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_metadata.query.graphql @@ -0,0 +1,39 @@ +query getPackageMetadata($id: PackagesPackageID!) { + package(id: $id) { + id + packageType + metadata { + ... on ComposerMetadata { + targetSha + composerJson { + license + version + } + } + ... on PypiMetadata { + id + requiredPython + } + ... on ConanMetadata { + id + packageChannel + packageUsername + recipe + recipePath + } + ... on MavenMetadata { + id + appName + appGroup + appVersion + path + } + ... on NugetMetadata { + id + iconUrl + licenseUrl + projectUrl + } + } + } +} diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_pipelines.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_pipelines.query.graphql new file mode 100644 index 00000000000..86e67320d63 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_pipelines.query.graphql @@ -0,0 +1,24 @@ +query getPackagePipelines($id: PackagesPackageID!, $first: Int) { + package(id: $id) { + id + pipelines(first: $first) { + nodes { + ref + id + sha + createdAt + commitPath + path + user { + id + name + } + project { + id + name + webUrl + } + } + } + } +} diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue index 162b420a784..768c8d6478b 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue @@ -27,6 +27,9 @@ import DeletePackage from '~/packages_and_registries/package_registry/components import { PACKAGE_TYPE_NUGET, PACKAGE_TYPE_COMPOSER, + PACKAGE_TYPE_CONAN, + PACKAGE_TYPE_MAVEN, + PACKAGE_TYPE_PYPI, DELETE_PACKAGE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_TRACKING_ACTION, @@ -122,6 +125,9 @@ export default { packageFiles() { return this.packageEntity.packageFiles?.nodes; }, + packageType() { + return this.packageEntity.packageType; + }, isLoading() { return this.$apollo.queries.packageEntity.loading; }, @@ -130,7 +136,7 @@ export default { }, tracking() { return { - category: packageTypeToTrackCategory(this.packageEntity.packageType), + category: packageTypeToTrackCategory(this.packageType), }; }, hasVersions() { @@ -140,10 +146,19 @@ export default { return this.packageEntity.dependencyLinks?.nodes || []; }, showDependencies() { - return this.packageEntity.packageType === PACKAGE_TYPE_NUGET; + return this.packageType === PACKAGE_TYPE_NUGET; }, showFiles() { - return this.packageEntity.packageType !== PACKAGE_TYPE_COMPOSER; + return this.packageType !== PACKAGE_TYPE_COMPOSER; + }, + showMetadata() { + return [ + PACKAGE_TYPE_COMPOSER, + PACKAGE_TYPE_CONAN, + PACKAGE_TYPE_MAVEN, + PACKAGE_TYPE_NUGET, + PACKAGE_TYPE_PYPI, + ].includes(this.packageType); }, }, methods: { @@ -262,7 +277,11 @@ export default { <installation-commands :package-entity="packageEntity" /> - <additional-metadata :package-entity="packageEntity" /> + <additional-metadata + v-if="showMetadata" + :package-id="packageEntity.id" + :package-type="packageType" + /> </div> <package-files diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue index a5189201112..130d6977936 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue +++ b/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue @@ -77,9 +77,6 @@ export default { this.updateDependencyProxyImageTtlGroupPolicy(payload); }, }, - helpText() { - return this.enabled ? this.$options.i18n.enabledProxyHelpText : ''; - }, }, methods: { mutationVariables(payload) { @@ -144,11 +141,10 @@ export default { v-model="enabled" :disabled="isLoading" :label="$options.i18n.enabledProxyLabel" - :help="helpText" data-qa-selector="dependency_proxy_setting_toggle" data-testid="dependency-proxy-setting-toggle" > - <template #help> + <template v-if="enabled" #help> <span class="gl-overflow-break-word gl-max-w-100vw gl-display-inline-block"> <gl-sprintf :message="$options.i18n.enabledProxyHelpText"> <template #link="{ content }"> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue new file mode 100644 index 00000000000..fdc7bd39780 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue @@ -0,0 +1,124 @@ +<script> +import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; +import { isEqual, get, isEmpty } from 'lodash'; +import { + CONTAINER_CLEANUP_POLICY_TITLE, + CONTAINER_CLEANUP_POLICY_DESCRIPTION, + FETCH_SETTINGS_ERROR_MESSAGE, + UNAVAILABLE_FEATURE_TITLE, + UNAVAILABLE_FEATURE_INTRO_TEXT, + UNAVAILABLE_USER_FEATURE_TEXT, + UNAVAILABLE_ADMIN_FEATURE_TEXT, +} from '~/packages_and_registries/settings/project/constants'; +import expirationPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql'; +import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; + +import ContainerExpirationPolicyForm from './container_expiration_policy_form.vue'; + +export default { + components: { + SettingsBlock, + GlAlert, + GlSprintf, + GlLink, + ContainerExpirationPolicyForm, + }, + inject: ['projectPath', 'isAdmin', 'adminSettingsPath', 'enableHistoricEntries', 'helpPagePath'], + i18n: { + CONTAINER_CLEANUP_POLICY_TITLE, + CONTAINER_CLEANUP_POLICY_DESCRIPTION, + UNAVAILABLE_FEATURE_TITLE, + UNAVAILABLE_FEATURE_INTRO_TEXT, + FETCH_SETTINGS_ERROR_MESSAGE, + }, + apollo: { + containerExpirationPolicy: { + query: expirationPolicyQuery, + variables() { + return { + projectPath: this.projectPath, + }; + }, + update: (data) => data.project?.containerExpirationPolicy, + result({ data }) { + this.workingCopy = { ...get(data, 'project.containerExpirationPolicy', {}) }; + }, + error(e) { + this.fetchSettingsError = e; + }, + }, + }, + data() { + return { + fetchSettingsError: false, + containerExpirationPolicy: null, + workingCopy: {}, + }; + }, + computed: { + isDisabled() { + return !(this.containerExpirationPolicy || this.enableHistoricEntries); + }, + showDisabledFormMessage() { + return this.isDisabled && !this.fetchSettingsError; + }, + unavailableFeatureMessage() { + return this.isAdmin ? UNAVAILABLE_ADMIN_FEATURE_TEXT : UNAVAILABLE_USER_FEATURE_TEXT; + }, + isEdited() { + if (isEmpty(this.containerExpirationPolicy) && isEmpty(this.workingCopy)) { + return false; + } + return !isEqual(this.containerExpirationPolicy, this.workingCopy); + }, + }, + methods: { + restoreOriginal() { + this.workingCopy = { ...this.containerExpirationPolicy }; + }, + }, +}; +</script> + +<template> + <settings-block :collapsible="false"> + <template #title> {{ $options.i18n.CONTAINER_CLEANUP_POLICY_TITLE }}</template> + <template #description> + <span> + <gl-sprintf :message="$options.i18n.CONTAINER_CLEANUP_POLICY_DESCRIPTION"> + <template #link="{ content }"> + <gl-link :href="helpPagePath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </span> + </template> + <template #default> + <container-expiration-policy-form + v-if="!isDisabled" + v-model="workingCopy" + :is-loading="$apollo.queries.containerExpirationPolicy.loading" + :is-edited="isEdited" + @reset="restoreOriginal" + /> + <template v-else> + <gl-alert + v-if="showDisabledFormMessage" + :dismissible="false" + :title="$options.i18n.UNAVAILABLE_FEATURE_TITLE" + variant="tip" + > + {{ $options.i18n.UNAVAILABLE_FEATURE_INTRO_TEXT }} + + <gl-sprintf :message="unavailableFeatureMessage"> + <template #link="{ content }"> + <gl-link :href="adminSettingsPath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </gl-alert> + <gl-alert v-else-if="fetchSettingsError" variant="warning" :dismissible="false"> + <gl-sprintf :message="$options.i18n.FETCH_SETTINGS_ERROR_MESSAGE" /> + </gl-alert> + </template> + </template> + </settings-block> +</template> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/settings_form.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue index ae2d5f4fbc5..ae2d5f4fbc5 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/settings_form.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue index d6d85189792..3fbbfd75ffb 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_input.vue @@ -104,7 +104,7 @@ export default { <span data-testid="description" class="gl-text-gray-400"> <gl-sprintf :message="description"> <template #link="{ content }"> - <gl-link :href="tagsRegexHelpPagePath" target="_blank">{{ content }}</gl-link> + <gl-link :href="tagsRegexHelpPagePath">{{ content }}</gl-link> </template> </gl-sprintf> </span> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue index 854c88b2ad3..95af19e6d85 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/registry_settings_app.vue @@ -1,128 +1,15 @@ <script> -import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; -import { isEqual, get, isEmpty } from 'lodash'; -import { - FETCH_SETTINGS_ERROR_MESSAGE, - UNAVAILABLE_FEATURE_TITLE, - UNAVAILABLE_FEATURE_INTRO_TEXT, - UNAVAILABLE_USER_FEATURE_TEXT, - UNAVAILABLE_ADMIN_FEATURE_TEXT, -} from '~/packages_and_registries/settings/project/constants'; -import expirationPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql'; -import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; - -import SettingsForm from './settings_form.vue'; +import ContainerExpirationPolicy from './container_expiration_policy.vue'; export default { components: { - SettingsBlock, - SettingsForm, - GlAlert, - GlSprintf, - GlLink, - }, - inject: ['projectPath', 'isAdmin', 'adminSettingsPath', 'enableHistoricEntries', 'helpPagePath'], - i18n: { - UNAVAILABLE_FEATURE_TITLE, - UNAVAILABLE_FEATURE_INTRO_TEXT, - FETCH_SETTINGS_ERROR_MESSAGE, - }, - apollo: { - containerExpirationPolicy: { - query: expirationPolicyQuery, - variables() { - return { - projectPath: this.projectPath, - }; - }, - update: (data) => data.project?.containerExpirationPolicy, - result({ data }) { - this.workingCopy = { ...get(data, 'project.containerExpirationPolicy', {}) }; - }, - error(e) { - this.fetchSettingsError = e; - }, - }, - }, - data() { - return { - fetchSettingsError: false, - containerExpirationPolicy: null, - workingCopy: {}, - }; - }, - computed: { - isDisabled() { - return !(this.containerExpirationPolicy || this.enableHistoricEntries); - }, - showDisabledFormMessage() { - return this.isDisabled && !this.fetchSettingsError; - }, - unavailableFeatureMessage() { - return this.isAdmin ? UNAVAILABLE_ADMIN_FEATURE_TEXT : UNAVAILABLE_USER_FEATURE_TEXT; - }, - isEdited() { - if (isEmpty(this.containerExpirationPolicy) && isEmpty(this.workingCopy)) { - return false; - } - return !isEqual(this.containerExpirationPolicy, this.workingCopy); - }, - }, - methods: { - restoreOriginal() { - this.workingCopy = { ...this.containerExpirationPolicy }; - }, + ContainerExpirationPolicy, }, }; </script> <template> <section data-testid="registry-settings-app"> - <settings-block :collapsible="false"> - <template #title> {{ __('Clean up image tags') }}</template> - <template #description> - <span data-testid="description"> - <gl-sprintf - :message=" - __( - 'Save storage space by automatically deleting tags from the container registry and keeping the ones you want. %{linkStart}How does cleanup work?%{linkEnd}', - ) - " - > - <template #link="{ content }"> - <gl-link :href="helpPagePath" target="_blank">{{ content }}</gl-link> - </template> - </gl-sprintf> - </span> - </template> - <template #default> - <settings-form - v-if="!isDisabled" - v-model="workingCopy" - :is-loading="$apollo.queries.containerExpirationPolicy.loading" - :is-edited="isEdited" - @reset="restoreOriginal" - /> - <template v-else> - <gl-alert - v-if="showDisabledFormMessage" - :dismissible="false" - :title="$options.i18n.UNAVAILABLE_FEATURE_TITLE" - variant="tip" - > - {{ $options.i18n.UNAVAILABLE_FEATURE_INTRO_TEXT }} - - <gl-sprintf :message="unavailableFeatureMessage"> - <template #link="{ content }"> - <gl-link :href="adminSettingsPath" target="_blank">{{ content }}</gl-link> - </template> - </gl-sprintf> - </gl-alert> - <gl-alert v-else-if="fetchSettingsError" variant="warning" :dismissible="false"> - <gl-sprintf :message="$options.i18n.FETCH_SETTINGS_ERROR_MESSAGE" /> - </gl-alert> - </template> - </template> - </settings-block> + <container-expiration-policy /> </section> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/constants.js b/app/assets/javascripts/packages_and_registries/settings/project/constants.js index 841585c5646..40f980d15fb 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/constants.js +++ b/app/assets/javascripts/packages_and_registries/settings/project/constants.js @@ -1,5 +1,9 @@ import { s__, __ } from '~/locale'; +export const CONTAINER_CLEANUP_POLICY_TITLE = s__(`ContainerRegistry|Clean up image tags`); +export const CONTAINER_CLEANUP_POLICY_DESCRIPTION = s__( + `ContainerRegistry|Save storage space by automatically deleting tags from the container registry and keeping the ones you want. %{linkStart}How does cleanup work?%{linkEnd}`, +); export const SET_CLEANUP_POLICY_BUTTON = __('Save'); export const UNAVAILABLE_FEATURE_TITLE = s__( `ContainerRegistry|Cleanup policy for tags is disabled`, diff --git a/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue b/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue index de7ab3e6d7b..dc61f3c788c 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue @@ -49,7 +49,7 @@ export default { <template> <gl-dropdown :text="$options.i18n.QUICK_START" - variant="info" + variant="confirm" right @shown="track('click_dropdown')" > 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 index 9b2de1a1b84..b2b1d2c8212 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue @@ -66,7 +66,7 @@ export default { <template #default="{ updateQuery }"> <registry-search v-if="mountRegistrySearch" - :filter="filters" + :filters="filters" :sorting="sorting" :tokens="$options.tokens" :sortable-fields="sortableFields" diff --git a/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue b/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue index a1e3c06812c..e7b4229052e 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue @@ -49,7 +49,7 @@ export default { <gl-breadcrumb :key="isLoaded" :items="allCrumbs"> <template #separator> <span class="gl-mx-n5"> - <gl-icon name="angle-right" :size="8" /> + <gl-icon name="chevron-lg-right" :size="8" /> </span> </template> </gl-breadcrumb> |