diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /app/assets/javascripts/packages_and_registries | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
28 files changed, 464 insertions, 107 deletions
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue index ab0418388cd..5d77ff9dc0d 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue @@ -20,7 +20,6 @@ import { UNSCHEDULED_STATUS, SCHEDULED_STATUS, ONGOING_STATUS, - ROOT_IMAGE_TEXT, ROOT_IMAGE_TOOLTIP, } from '../../constants/index'; @@ -100,7 +99,7 @@ export default { return !this.imageDetails.name ? ROOT_IMAGE_TOOLTIP : ''; }, imageName() { - return this.imageDetails.name || ROOT_IMAGE_TEXT; + return this.imageDetails.name || this.imageDetails.project?.path; }, formattedSize() { const { size } = this.imageDetails; 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 56da8e88b7a..bfa99c01c3f 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 @@ -1,4 +1,5 @@ <script> +import { uniqueId } from 'lodash'; import { GlIcon, GlPopover, GlLink, GlSprintf } from '@gitlab/ui'; import { helpPagePath } from '~/helpers/help_page_helper'; import { timeTilRun } from '../../utils'; @@ -43,6 +44,11 @@ export default { CLEANUP_STATUS_UNFINISHED, PARTIAL_CLEANUP_CONTINUE_MESSAGE, }, + data() { + return { + iconId: uniqueId('status-info-'), + }; + }, computed: { showStatus() { return this.status !== UNSCHEDULED_STATUS; @@ -85,14 +91,14 @@ export default { </span> <gl-icon v-if="failedDelete" - id="status-info" + :id="iconId" :size="14" class="gl-text-gray-500" data-testid="extra-info" name="information-o" /> <gl-popover - target="status-info" + :target="iconId" container="status-popover-container" v-bind="$options.statusPopoverOptions" > 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 e67d77210bb..aecc0bf92ea 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 @@ -1,10 +1,12 @@ <script> -import { GlTooltipDirective, GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui'; +import { GlTooltipDirective, GlIcon, GlSprintf, GlSkeletonLoader, GlButton } from '@gitlab/ui'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { n__ } from '~/locale'; - +import Tracking from '~/tracking'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue'; +import { joinPaths } from '~/lib/utils/url_utility'; import { LIST_DELETE_BUTTON_DISABLED, LIST_DELETE_BUTTON_DISABLED_FOR_MIGRATION, @@ -13,8 +15,10 @@ import { IMAGE_DELETE_SCHEDULED_STATUS, IMAGE_FAILED_DELETED_STATUS, IMAGE_MIGRATING_STATE, - ROOT_IMAGE_TEXT, COPY_IMAGE_PATH_TITLE, + IMAGE_FULL_PATH_LABEL, + TRACKING_ACTION_CLICK_SHOW_FULL_PATH, + TRACKING_LABEL_REGISTRY_IMAGE_LIST, } from '../../constants/index'; import DeleteButton from '../delete_button.vue'; import CleanupStatus from './cleanup_status.vue'; @@ -25,6 +29,7 @@ export default { ClipboardButton, DeleteButton, GlSprintf, + GlButton, GlIcon, ListItem, GlSkeletonLoader, @@ -33,6 +38,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, + mixins: [Tracking.mixin(), glFeatureFlagsMixin()], inject: ['config'], props: { item: { @@ -54,6 +60,12 @@ export default { REMOVE_REPOSITORY_LABEL, ROW_SCHEDULED_FOR_DELETION, COPY_IMAGE_PATH_TITLE, + IMAGE_FULL_PATH_LABEL, + }, + data() { + return { + showFullPath: false, + }; }, computed: { disabledDelete() { @@ -79,7 +91,17 @@ export default { ); }, imageName() { - return this.item.name ? this.item.path : `${this.item.path}/ ${ROOT_IMAGE_TEXT}`; + if (this.glFeatures.containerRegistryShowShortenedPath) { + if (this.showFullPath) { + return this.item.path; + } + const projectPath = this.item?.project?.path ?? ''; + if (this.item.name) { + return joinPaths(projectPath, this.item.name); + } + return projectPath; + } + return this.item.path; }, routerLinkEvent() { return this.deleting ? '' : 'click'; @@ -90,6 +112,15 @@ export default { : LIST_DELETE_BUTTON_DISABLED; }, }, + methods: { + hideButton() { + this.showFullPath = true; + this.$refs.imageName.$el.focus(); + this.track(TRACKING_ACTION_CLICK_SHOW_FULL_PATH, { + label: TRACKING_LABEL_REGISTRY_IMAGE_LIST, + }); + }, + }, }; </script> @@ -104,7 +135,20 @@ export default { :disabled="deleting" > <template #left-primary> + <gl-button + v-if="glFeatures.containerRegistryShowShortenedPath && !showFullPath" + v-gl-tooltip="{ + placement: 'top', + title: $options.i18n.IMAGE_FULL_PATH_LABEL, + }" + icon="ellipsis_h" + size="small" + class="gl-mr-2" + :aria-label="$options.i18n.IMAGE_FULL_PATH_LABEL" + @click="hideButton" + /> <router-link + ref="imageName" class="gl-text-body gl-font-weight-bold" data-testid="details-link" data-qa-selector="registry_image_content" 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 17adaec7a7d..67ad281b835 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 @@ -1,6 +1,5 @@ -import { s__, __ } from '~/locale'; +import { __ } 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/list.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js index c6a7591e0d9..020d78ad364 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 @@ -43,6 +43,13 @@ export const EMPTY_RESULT_MESSAGE = s__( export const COPY_IMAGE_PATH_TITLE = s__('ContainerRegistry|Copy image path'); +export const IMAGE_FULL_PATH_LABEL = s__('ContainerRegistry|Show full path'); + +// Tracking + +export const TRACKING_LABEL_REGISTRY_IMAGE_LIST = 'registry_image_list'; +export const TRACKING_ACTION_CLICK_SHOW_FULL_PATH = 'click_show_full_path'; + // Parameters export const IMAGE_DELETE_SCHEDULED_STATUS = 'DELETE_SCHEDULED'; 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 71a85d8885e..9ebbdfa920d 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 @@ -24,7 +24,6 @@ import { FETCH_IMAGES_LIST_ERROR_MESSAGE, UNFINISHED_STATUS, MISSING_OR_DELETED_IMAGE_BREADCRUMB, - ROOT_IMAGE_TEXT, GRAPHQL_PAGE_SIZE, MISSING_OR_DELETED_IMAGE_TITLE, MISSING_OR_DELETED_IMAGE_MESSAGE, @@ -111,7 +110,7 @@ export default { methods: { updateBreadcrumb() { const name = this.containerRepository?.id - ? this.containerRepository?.name || ROOT_IMAGE_TEXT + ? this.containerRepository?.name || this.containerRepository?.project?.path : MISSING_OR_DELETED_IMAGE_BREADCRUMB; this.breadCrumbState.updateName(name); }, diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue index a25839be7e1..b91af19d623 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue @@ -2,6 +2,12 @@ import { s__ } from '~/locale'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; +import Tracking from '~/tracking'; +import { packageTypeToTrackCategory } from '~/packages_and_registries/package_registry/utils'; +import { + TRACKING_ACTION_COPY_PACKAGE_ASSET_SHA, + TRACKING_LABEL_PACKAGE_ASSET, +} from '~/packages_and_registries/package_registry/constants'; export default { name: 'FileSha', @@ -9,6 +15,7 @@ export default { DetailsRow, ClipboardButton, }, + mixins: [Tracking.mixin()], props: { sha: { type: String, @@ -22,6 +29,18 @@ export default { i18n: { copyButtonTitle: s__('PackageRegistry|Copy SHA'), }, + computed: { + tracking() { + return { + category: packageTypeToTrackCategory(this.packageType), + }; + }, + }, + methods: { + copySha() { + this.track(TRACKING_ACTION_COPY_PACKAGE_ASSET_SHA, { label: TRACKING_LABEL_PACKAGE_ASSET }); + }, + }, }; </script> @@ -35,6 +54,7 @@ export default { :title="$options.i18n.copyButtonTitle" category="tertiary" size="small" + @click="copySha" /> </div> </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 9e700a5236f..a049b0eff8d 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 @@ -5,8 +5,13 @@ import { numberToHumanSize } from '~/lib/utils/number_utils'; import { __ } from '~/locale'; import FileSha from '~/packages_and_registries/package_registry/components/details/file_sha.vue'; import Tracking from '~/tracking'; +import { packageTypeToTrackCategory } from '~/packages_and_registries/package_registry/utils'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import { + TRACKING_LABEL_PACKAGE_ASSET, + TRACKING_ACTION_EXPAND_PACKAGE_ASSET, +} from '~/packages_and_registries/package_registry/constants'; export default { name: 'PackageFiles', @@ -76,6 +81,11 @@ export default { }, ].filter((c) => !c.hide); }, + tracking() { + return { + category: packageTypeToTrackCategory(this.packageType), + }; + }, }, methods: { formatSize(size) { @@ -84,6 +94,11 @@ export default { hasDetails(item) { return item.fileSha256 || item.fileMd5 || item.fileSha1; }, + trackToggleDetails(detailsShowing) { + if (!detailsShowing) { + this.track(TRACKING_ACTION_EXPAND_PACKAGE_ASSET, { label: TRACKING_LABEL_PACKAGE_ASSET }); + } + }, }, i18n: { deleteFile: __('Delete file'), @@ -106,7 +121,10 @@ export default { :aria-label="detailsShowing ? __('Collapse') : __('Expand')" category="tertiary" size="small" - @click="toggleDetails" + @click=" + toggleDetails(); + trackToggleDetails(detailsShowing); + " /> <gl-link :href="item.downloadPath" @@ -129,8 +147,8 @@ export default { :href="item.pipeline.commitPath" class="gl-text-gray-500" data-testid="commit-link" - >{{ item.pipeline.sha }}</gl-link - > + >{{ item.pipeline.sha }} + </gl-link> </template> <template #cell(created)="{ item }"> 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 3c090951b7d..cea053992f8 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js @@ -9,6 +9,7 @@ export { DELETE_PACKAGE_FILE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION, + DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION, } from '~/packages_and_registries/shared/constants'; export const PACKAGE_TYPE_CONAN = 'CONAN'; @@ -62,6 +63,12 @@ export const TRACKING_ACTION_COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND = export const TRACKING_ACTION_COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND = 'copy_composer_package_include_command'; +export const TRACKING_LABEL_PACKAGE_ASSET = 'package_assets'; + +export const TRACKING_ACTION_DOWNLOAD_PACKAGE_ASSET = 'download_package_asset'; +export const TRACKING_ACTION_EXPAND_PACKAGE_ASSET = 'expand_package_asset'; +export const TRACKING_ACTION_COPY_PACKAGE_ASSET_SHA = 'copy_package_asset_sha'; + export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert'; export const DELETE_PACKAGE_FILE_ERROR_MESSAGE = s__( 'PackageRegistry|Something went wrong while deleting the package file.', 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 768c8d6478b..29438fba86b 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 @@ -33,7 +33,6 @@ import { DELETE_PACKAGE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_TRACKING_ACTION, - PULL_PACKAGE_TRACKING_ACTION, DELETE_PACKAGE_FILE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION, @@ -41,6 +40,7 @@ import { FETCH_PACKAGE_DETAILS_ERROR_MESSAGE, DELETE_PACKAGE_FILE_ERROR_MESSAGE, DELETE_PACKAGE_FILE_SUCCESS_MESSAGE, + DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION, } from '~/packages_and_registries/package_registry/constants'; import destroyPackageFileMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql'; @@ -76,10 +76,10 @@ export default { DELETE_PACKAGE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_TRACKING_ACTION, - PULL_PACKAGE_TRACKING_ACTION, DELETE_PACKAGE_FILE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION, + DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION, }, data() { return { @@ -288,7 +288,7 @@ export default { v-if="showFiles" :can-delete="packageEntity.canDestroy" :package-files="packageFiles" - @download-file="track($options.trackingActions.PULL_PACKAGE)" + @download-file="track($options.trackingActions.DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION)" @delete-file="handleFileDelete" /> </gl-tab> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/bundle.js b/app/assets/javascripts/packages_and_registries/settings/group/bundle.js index 482a3ef2ead..3689199751d 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/bundle.js +++ b/app/assets/javascripts/packages_and_registries/settings/group/bundle.js @@ -1,7 +1,6 @@ import { GlToast } from '@gitlab/ui'; import Vue from 'vue'; -import { parseBoolean } from '~/lib/utils/common_utils'; import Translate from '~/vue_shared/translate'; import SettingsApp from './components/group_settings_app.vue'; import { apolloProvider } from './graphql'; @@ -20,7 +19,6 @@ export default () => { provide: { groupPath: el.dataset.groupPath, groupDependencyProxyPath: el.dataset.groupDependencyProxyPath, - defaultExpanded: parseBoolean(el.dataset.defaultExpanded), }, render(createElement) { return createElement(SettingsApp); 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 130d6977936..59d4f5e24d0 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 @@ -1,8 +1,7 @@ <script> import { GlToggle, GlSprintf, GlLink } from '@gitlab/ui'; import { s__ } from '~/locale'; -import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; -import SettingsTitles from '~/packages_and_registries/settings/group/components/settings_titles.vue'; +import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue'; import updateDependencyProxySettings from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_settings.mutation.graphql'; import updateDependencyProxyImageTtlGroupPolicy from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_image_ttl_group_policy.mutation.graphql'; import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update'; @@ -13,6 +12,7 @@ import { import { DEPENDENCY_PROXY_HEADER, + DEPENDENCY_PROXY_DESCRIPTION, DEPENDENCY_PROXY_DOCS_PATH, } from '~/packages_and_registries/settings/group/constants'; @@ -23,15 +23,14 @@ export default { GlSprintf, GlLink, SettingsBlock, - SettingsTitles, }, i18n: { DEPENDENCY_PROXY_HEADER, + DEPENDENCY_PROXY_DESCRIPTION, enabledProxyLabel: s__('DependencyProxy|Enable Dependency Proxy'), enabledProxyHelpText: s__( 'DependencyProxy|To see the image prefix and what is in the cache, visit the %{linkStart}Dependency Proxy%{linkEnd}', ), - storageSettingsTitle: s__('DependencyProxy|Storage settings'), ttlPolicyEnabledLabel: s__('DependencyProxy|Clear the Dependency Proxy cache automatically'), ttlPolicyEnabledHelpText: s__( 'DependencyProxy|When enabled, images older than 90 days will be removed from the cache.', @@ -40,7 +39,7 @@ export default { links: { DEPENDENCY_PROXY_DOCS_PATH, }, - inject: ['defaultExpanded', 'groupPath', 'groupDependencyProxyPath'], + inject: ['groupPath', 'groupDependencyProxyPath'], props: { dependencyProxySettings: { type: Object, @@ -130,11 +129,9 @@ export default { </script> <template> - <settings-block - :default-expanded="defaultExpanded" - data-qa-selector="dependency_proxy_settings_content" - > + <settings-block data-qa-selector="dependency_proxy_settings_content"> <template #title> {{ $options.i18n.DEPENDENCY_PROXY_HEADER }} </template> + <template #description> {{ $options.i18n.DEPENDENCY_PROXY_DESCRIPTION }} </template> <template #default> <div> <gl-toggle @@ -156,13 +153,12 @@ export default { </span> </template> </gl-toggle> - - <settings-titles :title="$options.i18n.storageSettingsTitle" class="gl-my-6" /> <gl-toggle v-model="ttlEnabled" :disabled="isLoading" :label="$options.i18n.ttlPolicyEnabledLabel" :help="$options.i18n.ttlPolicyEnabledHelpText" + class="gl-mt-6" data-testid="dependency-proxy-ttl-policies-toggle" /> </div> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/duplicates_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/duplicates_settings.vue index b0088838acc..51a97aead49 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/components/duplicates_settings.vue +++ b/app/assets/javascripts/packages_and_registries/settings/group/components/duplicates_settings.vue @@ -1,11 +1,9 @@ <script> -import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui'; +import { GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui'; import { isEqual } from 'lodash'; import { DUPLICATES_TOGGLE_LABEL, - DUPLICATES_ALLOWED_DISABLED, - DUPLICATES_ALLOWED_ENABLED, DUPLICATES_SETTING_EXCEPTION_TITLE, DUPLICATES_SETTINGS_EXCEPTION_LEGEND, } from '~/packages_and_registries/settings/group/constants'; @@ -18,7 +16,6 @@ export default { DUPLICATES_SETTINGS_EXCEPTION_LEGEND, }, components: { - GlSprintf, GlToggle, GlFormGroup, GlFormInput, @@ -63,9 +60,6 @@ export default { }, }, computed: { - enabledButtonLabel() { - return this.duplicatesAllowed ? DUPLICATES_ALLOWED_ENABLED : DUPLICATES_ALLOWED_DISABLED; - }, isExceptionRegexValid() { return !this.duplicateExceptionRegexError; }, @@ -80,41 +74,30 @@ export default { <template> <form> - <div class="gl-display-flex"> - <gl-toggle - :data-qa-selector="toggleQaSelector" - :label="$options.i18n.DUPLICATES_TOGGLE_LABEL" - label-position="hidden" - :value="duplicatesAllowed" + <gl-toggle + :data-qa-selector="toggleQaSelector" + :label="$options.i18n.DUPLICATES_TOGGLE_LABEL" + :value="!duplicatesAllowed" + :disabled="loading" + @change="update(modelNames.allowed, !$event)" + /> + <gl-form-group + v-if="!duplicatesAllowed" + class="gl-mt-4" + :label="$options.i18n.DUPLICATES_SETTING_EXCEPTION_TITLE" + label-size="sm" + :state="isExceptionRegexValid" + :invalid-feedback="duplicateExceptionRegexError" + :description="$options.i18n.DUPLICATES_SETTINGS_EXCEPTION_LEGEND" + label-for="maven-duplicated-settings-regex-input" + > + <gl-form-input + id="maven-duplicated-settings-regex-input" :disabled="loading" - @change="update(modelNames.allowed, $event)" + size="lg" + :value="duplicateExceptionRegex" + @change="update(modelNames.exception, $event)" /> - <div class="gl-ml-5"> - <div data-testid="toggle-label" :data-qa-selector="labelQaSelector"> - <gl-sprintf :message="enabledButtonLabel"> - <template #bold="{ content }"> - <strong>{{ content }}</strong> - </template> - </gl-sprintf> - </div> - <gl-form-group - v-if="!duplicatesAllowed" - class="gl-mt-4" - :label="$options.i18n.DUPLICATES_SETTING_EXCEPTION_TITLE" - label-size="sm" - :state="isExceptionRegexValid" - :invalid-feedback="duplicateExceptionRegexError" - :description="$options.i18n.DUPLICATES_SETTINGS_EXCEPTION_LEGEND" - label-for="maven-duplicated-settings-regex-input" - > - <gl-form-input - id="maven-duplicated-settings-regex-input" - :disabled="loading" - :value="duplicateExceptionRegex" - @change="update(modelNames.exception, $event)" - /> - </gl-form-group> - </div> - </div> + </gl-form-group> </form> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue index b7e88945dbd..abb9f02d290 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue +++ b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue @@ -1,17 +1,15 @@ <script> -import { GlSprintf, GlLink } from '@gitlab/ui'; import DuplicatesSettings from '~/packages_and_registries/settings/group/components/duplicates_settings.vue'; import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue'; import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue'; import { PACKAGE_SETTINGS_HEADER, PACKAGE_SETTINGS_DESCRIPTION, - PACKAGES_DOCS_PATH, } from '~/packages_and_registries/settings/group/constants'; import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql'; import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update'; import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses'; -import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; +import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue'; export default { name: 'PackageSettings', @@ -19,18 +17,13 @@ export default { PACKAGE_SETTINGS_HEADER, PACKAGE_SETTINGS_DESCRIPTION, }, - links: { - PACKAGES_DOCS_PATH, - }, components: { - GlSprintf, - GlLink, SettingsBlock, MavenSettings, GenericSettings, DuplicatesSettings, }, - inject: ['defaultExpanded', 'groupPath'], + inject: ['groupPath'], props: { packageSettings: { type: Object, @@ -91,20 +84,11 @@ export default { </script> <template> - <settings-block - :default-expanded="defaultExpanded" - data-qa-selector="package_registry_settings_content" - > + <settings-block data-qa-selector="package_registry_settings_content"> <template #title> {{ $options.i18n.PACKAGE_SETTINGS_HEADER }}</template> <template #description> <span data-testid="description"> - <gl-sprintf :message="$options.i18n.PACKAGE_SETTINGS_DESCRIPTION"> - <template #link="{ content }"> - <gl-link :href="$options.links.PACKAGES_DOCS_PATH" target="_blank">{{ - content - }}</gl-link> - </template> - </gl-sprintf> + {{ $options.i18n.PACKAGE_SETTINGS_DESCRIPTION }} </span> </template> <template #default> @@ -116,8 +100,8 @@ export default { :duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex" :model-names="modelNames" :loading="isLoading" - toggle-qa-selector="allow_duplicates_toggle" - label-qa-selector="allow_duplicates_label" + toggle-qa-selector="reject_duplicates_toggle" + label-qa-selector="reject_duplicates_label" @update="updateSettings" /> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/constants.js b/app/assets/javascripts/packages_and_registries/settings/group/constants.js index 0249b475e46..34764663892 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/constants.js +++ b/app/assets/javascripts/packages_and_registries/settings/group/constants.js @@ -1,17 +1,13 @@ import { helpPagePath } from '~/helpers/help_page_helper'; import { s__, __ } from '~/locale'; -export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Package Registry'); +export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Duplicate packages'); export const PACKAGE_SETTINGS_DESCRIPTION = s__( - 'PackageRegistry|Use GitLab as a private registry for common package formats. %{linkStart}Learn more.%{linkEnd}', + 'PackageRegistry|Allow packages with the same name and version to be uploaded to the registry. The newest version of a package is always used when installing.', ); -export const DUPLICATES_TOGGLE_LABEL = s__('PackageRegistry|Allow duplicates'); -export const DUPLICATES_ALLOWED_DISABLED = s__( - 'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Reject packages with the same name and version.', -); -export const DUPLICATES_ALLOWED_ENABLED = s__( - 'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Accept packages with the same name and version.', +export const DUPLICATES_TOGGLE_LABEL = s__( + 'PackageRegistry|Reject packages with the same name and version', ); export const DUPLICATES_SETTING_EXCEPTION_TITLE = __('Exceptions'); export const DUPLICATES_SETTINGS_EXCEPTION_LEGEND = s__( @@ -19,6 +15,9 @@ export const DUPLICATES_SETTINGS_EXCEPTION_LEGEND = s__( ); export const DEPENDENCY_PROXY_HEADER = s__('DependencyProxy|Dependency Proxy'); +export const DEPENDENCY_PROXY_DESCRIPTION = s__( + 'DependencyProxy|Enable the Dependency Proxy and settings for clearing the cache.', +); // Parameters 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 index fdc7bd39780..90a18d5cf5a 100644 --- 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 @@ -81,7 +81,7 @@ export default { </script> <template> - <settings-block :collapsible="false"> + <settings-block data-testid="container-expiration-policy-project-settings"> <template #title> {{ $options.i18n.CONTAINER_CLEANUP_POLICY_TITLE }}</template> <template #description> <span> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue index d75fb31fd98..7682754fdcb 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue @@ -30,6 +30,11 @@ export default { type: String, required: true, }, + description: { + type: String, + required: false, + default: '', + }, }, }; </script> @@ -46,5 +51,10 @@ export default { {{ option.label }} </option> </gl-form-select> + <template v-if="description" #description> + <span data-testid="description" class="gl-text-gray-400"> + {{ description }} + </span> + </template> </gl-form-group> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue new file mode 100644 index 00000000000..1170407a349 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue @@ -0,0 +1,68 @@ +<script> +import { GlAlert, GlSprintf } from '@gitlab/ui'; +import { + FETCH_SETTINGS_ERROR_MESSAGE, + PACKAGES_CLEANUP_POLICY_TITLE, + PACKAGES_CLEANUP_POLICY_DESCRIPTION, +} from '~/packages_and_registries/settings/project/constants'; +import packagesCleanupPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql'; +import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; + +import PackagesCleanupPolicyForm from './packages_cleanup_policy_form.vue'; + +export default { + components: { + SettingsBlock, + GlAlert, + GlSprintf, + PackagesCleanupPolicyForm, + }, + inject: ['projectPath'], + i18n: { + FETCH_SETTINGS_ERROR_MESSAGE, + PACKAGES_CLEANUP_POLICY_TITLE, + PACKAGES_CLEANUP_POLICY_DESCRIPTION, + }, + apollo: { + packagesCleanupPolicy: { + query: packagesCleanupPolicyQuery, + variables() { + return { + projectPath: this.projectPath, + }; + }, + update: (data) => data.project?.packagesCleanupPolicy || {}, + error(e) { + this.fetchSettingsError = e; + }, + }, + }, + data() { + return { + fetchSettingsError: false, + packagesCleanupPolicy: {}, + }; + }, +}; +</script> + +<template> + <settings-block> + <template #title> {{ $options.i18n.PACKAGES_CLEANUP_POLICY_TITLE }}</template> + <template #description> + <span data-testid="description"> + <gl-sprintf :message="$options.i18n.PACKAGES_CLEANUP_POLICY_DESCRIPTION" /> + </span> + </template> + <template #default> + <gl-alert v-if="fetchSettingsError" variant="warning" :dismissible="false"> + <gl-sprintf :message="$options.i18n.FETCH_SETTINGS_ERROR_MESSAGE" /> + </gl-alert> + <packages-cleanup-policy-form + v-else + v-model="packagesCleanupPolicy" + :is-loading="$apollo.queries.packagesCleanupPolicy.loading" + /> + </template> + </settings-block> +</template> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue new file mode 100644 index 00000000000..b1751d5174a --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue @@ -0,0 +1,137 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import { + UPDATE_SETTINGS_ERROR_MESSAGE, + UPDATE_SETTINGS_SUCCESS_MESSAGE, + SET_CLEANUP_POLICY_BUTTON, + KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION, + KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME, + KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL, +} from '~/packages_and_registries/settings/project/constants'; +import updatePackagesCleanupPolicyMutation from '~/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql'; +import { formOptionsGenerator } from '~/packages_and_registries/settings/project/utils'; +import Tracking from '~/tracking'; +import ExpirationDropdown from './expiration_dropdown.vue'; + +export default { + components: { + GlButton, + ExpirationDropdown, + }, + mixins: [Tracking.mixin()], + inject: ['projectPath'], + props: { + value: { + type: Object, + required: true, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + }, + formOptions: formOptionsGenerator(), + i18n: { + KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL, + KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION, + SET_CLEANUP_POLICY_BUTTON, + }, + data() { + return { + tracking: { + label: 'packages_cleanup_policies', + }, + mutationLoading: false, + }; + }, + computed: { + prefilledForm() { + return { + ...this.value, + keepNDuplicatedPackageFiles: this.findDefaultOption( + KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME, + ), + }; + }, + showLoadingIcon() { + return this.isLoading || this.mutationLoading; + }, + isSubmitButtonDisabled() { + return this.showLoadingIcon; + }, + isFieldDisabled() { + return this.showLoadingIcon; + }, + mutationVariables() { + return { + projectPath: this.projectPath, + keepNDuplicatedPackageFiles: this.prefilledForm.keepNDuplicatedPackageFiles, + }; + }, + }, + methods: { + findDefaultOption(option) { + return this.value[option] || this.$options.formOptions[option].find((f) => f.default)?.key; + }, + submit() { + this.track('submit_packages_cleanup_form'); + this.mutationLoading = true; + return this.$apollo + .mutate({ + mutation: updatePackagesCleanupPolicyMutation, + variables: { + input: this.mutationVariables, + }, + }) + .then(({ data }) => { + const [errorMessage] = data?.updatePackagesCleanupPolicy?.errors ?? []; + if (errorMessage) { + throw errorMessage; + } else { + this.$toast.show(UPDATE_SETTINGS_SUCCESS_MESSAGE); + } + }) + .catch(() => { + this.$toast.show(UPDATE_SETTINGS_ERROR_MESSAGE); + }) + .finally(() => { + this.mutationLoading = false; + }); + }, + onModelChange(newValue, model) { + this.$emit('input', { ...this.value, [model]: newValue }); + }, + }, +}; +</script> + +<template> + <form ref="form-element" @submit.prevent="submit"> + <div class="gl-md-max-w-50p"> + <expiration-dropdown + v-model="prefilledForm.keepNDuplicatedPackageFiles" + :disabled="isFieldDisabled" + :form-options="$options.formOptions.keepNDuplicatedPackageFiles" + :label="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL" + :description="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION" + name="keep-n-duplicated-package-files" + data-testid="keep-n-duplicated-package-files-dropdown" + @input="onModelChange($event, 'keepNDuplicatedPackageFiles')" + /> + </div> + <div class="gl-mt-7 gl-display-flex gl-align-items-center"> + <gl-button + data-testid="save-button" + type="submit" + :disabled="isSubmitButtonDisabled" + :loading="showLoadingIcon" + category="primary" + variant="confirm" + class="js-no-auto-disable gl-mr-4" + > + {{ $options.i18n.SET_CLEANUP_POLICY_BUTTON }} + </gl-button> + </div> + </form> +</template> 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 95af19e6d85..710cfe7b1eb 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,15 +1,19 @@ <script> import ContainerExpirationPolicy from './container_expiration_policy.vue'; +import PackagesCleanupPolicy from './packages_cleanup_policy.vue'; export default { components: { ContainerExpirationPolicy, + PackagesCleanupPolicy, }, + inject: ['showContainerRegistrySettings', 'showPackageRegistrySettings'], }; </script> <template> - <section data-testid="registry-settings-app"> - <container-expiration-policy /> - </section> + <div> + <packages-cleanup-policy v-if="showPackageRegistrySettings" /> + <container-expiration-policy v-if="showContainerRegistrySettings" /> + </div> </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 40f980d15fb..948520151ce 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/constants.js +++ b/app/assets/javascripts/packages_and_registries/settings/project/constants.js @@ -55,6 +55,31 @@ export const EXPIRATION_POLICY_FOOTER_NOTE = s__( 'ContainerRegistry|Note: Any policy update will result in a change to the scheduled run date and time', ); +export const PACKAGES_CLEANUP_POLICY_TITLE = s__( + 'PackageRegistry|Manage storage used by package assets', +); +export const PACKAGES_CLEANUP_POLICY_DESCRIPTION = s__( + 'PackageRegistry|When a package with same name and version is uploaded to the registry, more assets are added to the package. To save storage space, keep only the most recent assets.', +); +export const KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL = s__( + 'PackageRegistry|Number of duplicate assets to keep', +); +export const KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION = s__( + 'PackageRegistry|Examples of assets include .pom & .jar files', +); + +export const KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME = 'keepNDuplicatedPackageFiles'; + +export const KEEP_N_DUPLICATED_PACKAGE_FILES_OPTIONS = [ + { key: 'ONE_PACKAGE_FILE', label: 1, default: false }, + { key: 'TEN_PACKAGE_FILES', label: 10, default: false }, + { key: 'TWENTY_PACKAGE_FILES', label: 20, default: false }, + { key: 'THIRTY_PACKAGE_FILES', label: 30, default: false }, + { key: 'FORTY_PACKAGE_FILES', label: 40, default: false }, + { key: 'FIFTY_PACKAGE_FILES', label: 50, default: false }, + { key: 'ALL_PACKAGE_FILES', label: __('All'), default: true }, +]; + export const KEEP_N_OPTIONS = [ { key: 'ONE_TAG', variable: 1, default: false }, { key: 'FIVE_TAGS', variable: 5, default: false }, diff --git a/app/assets/javascripts/packages_and_registries/settings/project/graphql/fragments/packages_cleanup_policy.fragment.graphql b/app/assets/javascripts/packages_and_registries/settings/project/graphql/fragments/packages_cleanup_policy.fragment.graphql new file mode 100644 index 00000000000..a77ede37884 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/graphql/fragments/packages_cleanup_policy.fragment.graphql @@ -0,0 +1,4 @@ +fragment PackagesCleanupPolicyFields on PackagesCleanupPolicy { + keepNDuplicatedPackageFiles + nextRunAt +} diff --git a/app/assets/javascripts/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql b/app/assets/javascripts/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql new file mode 100644 index 00000000000..31cdd67e881 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql @@ -0,0 +1,10 @@ +#import "../fragments/packages_cleanup_policy.fragment.graphql" + +mutation updatePackagesCleanupPolicy($input: UpdatePackagesCleanupPolicyInput!) { + updatePackagesCleanupPolicy(input: $input) { + packagesCleanupPolicy { + ...PackagesCleanupPolicyFields + } + errors + } +} diff --git a/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql b/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql new file mode 100644 index 00000000000..0e9af253f2c --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql @@ -0,0 +1,10 @@ +#import "../fragments/packages_cleanup_policy.fragment.graphql" + +query getProjectPackagesCleanupPolicy($projectPath: ID!) { + project(fullPath: $projectPath) { + id + packagesCleanupPolicy { + ...PackagesCleanupPolicyFields + } + } +} diff --git a/app/assets/javascripts/packages_and_registries/settings/project/registry_settings_bundle.js b/app/assets/javascripts/packages_and_registries/settings/project/registry_settings_bundle.js index 17c33073668..daf1da6eac8 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/registry_settings_bundle.js +++ b/app/assets/javascripts/packages_and_registries/settings/project/registry_settings_bundle.js @@ -20,6 +20,8 @@ export default () => { adminSettingsPath, tagsRegexHelpPagePath, helpPagePath, + showContainerRegistrySettings, + showPackageRegistrySettings, } = el.dataset; return new Vue({ el, @@ -34,6 +36,8 @@ export default () => { adminSettingsPath, tagsRegexHelpPagePath, helpPagePath, + showContainerRegistrySettings: parseBoolean(showContainerRegistrySettings), + showPackageRegistrySettings: parseBoolean(showPackageRegistrySettings), }, render(createElement) { return createElement('registry-settings-app', {}); diff --git a/app/assets/javascripts/packages_and_registries/settings/project/utils.js b/app/assets/javascripts/packages_and_registries/settings/project/utils.js index b577a051862..847965454e9 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/utils.js +++ b/app/assets/javascripts/packages_and_registries/settings/project/utils.js @@ -1,5 +1,11 @@ import { n__ } from '~/locale'; -import { KEEP_N_OPTIONS, CADENCE_OPTIONS, OLDER_THAN_OPTIONS } from './constants'; +import { + KEEP_N_OPTIONS, + CADENCE_OPTIONS, + OLDER_THAN_OPTIONS, + KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME, + KEEP_N_DUPLICATED_PACKAGE_FILES_OPTIONS, +} from './constants'; export const findDefaultOption = (options) => { const item = options.find((o) => o.default); @@ -25,5 +31,6 @@ export const formOptionsGenerator = () => { olderThan: optionLabelGenerator(OLDER_THAN_OPTIONS, olderThanTranslationGenerator), cadence: CADENCE_OPTIONS, keepN: optionLabelGenerator(KEEP_N_OPTIONS, keepNTranslationGenerator), + [KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME]: KEEP_N_DUPLICATED_PACKAGE_FILES_OPTIONS, }; }; diff --git a/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue b/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue new file mode 100644 index 00000000000..5caf95cd050 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue @@ -0,0 +1,17 @@ +<template> + <section class="settings gl-py-7"> + <div class="gl-lg-display-flex"> + <div class="gl-lg-w-half gl-pr-10"> + <h4> + <slot name="title"></slot> + </h4> + <p> + <slot name="description"></slot> + </p> + </div> + <div class="gl-lg-w-half gl-pt-3"> + <slot></slot> + </div> + </div> + </section> +</template> diff --git a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js index afc72a2c627..5505205cf33 100644 --- a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js +++ b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js @@ -11,6 +11,7 @@ export const PULL_PACKAGE_TRACKING_ACTION = 'pull_package'; export const DELETE_PACKAGE_FILE_TRACKING_ACTION = 'delete_package_file'; export const REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION = 'request_delete_package_file'; export const CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION = 'cancel_delete_package_file'; +export const DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION = 'download_package_asset'; export const TRACKING_ACTIONS = { DELETE_PACKAGE: DELETE_PACKAGE_TRACKING_ACTION, @@ -20,6 +21,7 @@ export const TRACKING_ACTIONS = { DELETE_PACKAGE_FILE: DELETE_PACKAGE_FILE_TRACKING_ACTION, REQUEST_DELETE_PACKAGE_FILE: REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION, CANCEL_DELETE_PACKAGE_FILE: CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION, + DOWNLOAD_PACKAGE_ASSET: DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION, }; export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert'; |