diff options
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
7 files changed, 300 insertions, 29 deletions
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/details_title.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/details_title.vue new file mode 100644 index 00000000000..3e551706ed0 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/details_title.vue @@ -0,0 +1,82 @@ +<script> +import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui'; +import { mapState, mapGetters } from 'vuex'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; +import { __ } from '~/locale'; +import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; +import TitleArea from '~/vue_shared/components/registry/title_area.vue'; +import timeagoMixin from '~/vue_shared/mixins/timeago'; + +export default { + name: 'DetailsTitle', + components: { + TitleArea, + GlIcon, + GlSprintf, + MetadataItem, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + mixins: [timeagoMixin], + i18n: { + packageInfo: __('v%{version} published %{timeAgo}'), + }, + computed: { + ...mapState(['packageEntity', 'packageFiles']), + ...mapGetters(['packagePipeline']), + totalSize() { + return numberToHumanSize(this.packageFiles.reduce((acc, p) => acc + p.size, 0)); + }, + }, + methods: { + dynamicSlotName(index) { + return `metadata-tag${index}`; + }, + }, +}; +</script> + +<template> + <title-area :title="packageEntity.name" data-qa-selector="package_title"> + <template #sub-header> + <gl-icon name="eye" class="gl-mr-3" /> + <gl-sprintf :message="$options.i18n.packageInfo"> + <template #version> + {{ packageEntity.version }} + </template> + + <template #timeAgo> + <span v-gl-tooltip :title="tooltipTitle(packageEntity.created_at)"> + {{ timeFormatted(packageEntity.created_at) }} + </span> + </template> + </gl-sprintf> + </template> + + <template #metadata-type> + <metadata-item data-testid="package-type" icon="infrastructure-registry" text="Terraform" /> + </template> + + <template #metadata-size> + <metadata-item data-testid="package-size" icon="disk" :text="totalSize" /> + </template> + + <template v-if="packagePipeline" #metadata-pipeline> + <metadata-item + data-testid="pipeline-project" + icon="review-list" + :text="packagePipeline.project.name" + :link="packagePipeline.project.web_url" + /> + </template> + + <template v-if="packagePipeline" #metadata-ref> + <metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" /> + </template> + + <template #right-actions> + <slot name="delete-button"></slot> + </template> + </title-area> +</template> diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/terraform_installation.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/terraform_installation.vue new file mode 100644 index 00000000000..399a3e086f1 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/components/terraform_installation.vue @@ -0,0 +1,66 @@ +<script> +import { GlLink, GlSprintf } from '@gitlab/ui'; +import { mapState } from 'vuex'; +import { s__ } from '~/locale'; +import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; + +export default { + name: 'ConanInstallation', + components: { + CodeInstruction, + GlLink, + GlSprintf, + }, + computed: { + ...mapState(['packageEntity', 'terraformHelpPath', 'projectPath']), + provisionInstructions() { + // eslint-disable-next-line @gitlab/require-i18n-strings + return `module "${this.packageEntity.name}" { + source = "${this.projectPath}/${this.packageEntity.name}" + version = "${this.packageEntity.version}" +}`; + }, + registrySetup() { + return `credentials "gitlab.com" { + token = "<TOKEN>" +}`; + }, + }, + i18n: { + helpText: s__( + 'InfrastructureRegistry|For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}.', + ), + }, +}; +</script> + +<template> + <div> + <h3 class="gl-font-lg">{{ __('Provision instructions') }}</h3> + + <code-instruction + :label=" + s__( + 'InfrastructureRegistry|Copy and paste into your Terraform configuration, insert the variables, and run Terraform init:', + ) + " + :instruction="provisionInstructions" + :copy-text="s__('InfrastructureRegistry|Copy Terraform Command')" + multiline + /> + + <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> + + <code-instruction + :label="s__('InfrastructureRegistry|To authorize access to the Terraform registry:')" + :instruction="registrySetup" + :copy-text="s__('InfrastructureRegistry|Copy Terraform Setup Command')" + multiline + /> + <gl-sprintf :message="$options.i18n.helpText"> + <template #link="{ content }"> + <gl-link :href="terraformHelpPath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details_app_bundle.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details_app_bundle.js new file mode 100644 index 00000000000..98942b1e578 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details_app_bundle.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import PackagesApp from '~/packages/details/components/app.vue'; +import createStore from '~/packages/details/store'; +import Translate from '~/vue_shared/translate'; + +Vue.use(Translate); + +export default () => { + const el = document.querySelector('#js-vue-packages-detail'); + const { package: packageJson, canDelete: canDeleteStr, ...rest } = el.dataset; + const packageEntity = JSON.parse(packageJson); + const canDelete = parseBoolean(canDeleteStr); + + const store = createStore({ + packageEntity, + packageFiles: packageEntity.package_files, + canDelete, + ...rest, + }); + + return new Vue({ + el, + store, + provide: { + titleComponent: 'TerraformTitle', + }, + render(createElement) { + return createElement(PackagesApp); + }, + }); +}; 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 edbe9441e57..6da2e3a47e8 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 @@ -9,17 +9,28 @@ import { 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 CleanupPolicyEnabledAlert from '~/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue'; +import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; import SettingsForm from './settings_form.vue'; export default { components: { + SettingsBlock, SettingsForm, + CleanupPolicyEnabledAlert, GlAlert, GlSprintf, GlLink, }, - inject: ['projectPath', 'isAdmin', 'adminSettingsPath', 'enableHistoricEntries'], + inject: [ + 'projectPath', + 'isAdmin', + 'adminSettingsPath', + 'enableHistoricEntries', + 'helpPagePath', + 'showCleanupPolicyOnAlert', + ], i18n: { UNAVAILABLE_FEATURE_TITLE, UNAVAILABLE_FEATURE_INTRO_TEXT, @@ -75,32 +86,53 @@ export default { </script> <template> - <div> - <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 }} + <section data-testid="registry-settings-app"> + <cleanup-policy-enabled-alert v-if="showCleanupPolicyOnAlert" :project-path="projectPath" /> + <settings-block default-expanded> + <template #title> {{ __('Clean up image tags') }}</template> + <template #description> + <span data-testid="description"> + <gl-sprintf + :message=" + __( + 'Save space and find images in the container Registry. remove unneeded tags and keep only 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> - </div> + <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> + </section> </template> 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 65af6f846aa..2a3e2c28fa6 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 @@ -19,6 +19,8 @@ export default () => { projectPath, adminSettingsPath, tagsRegexHelpPagePath, + helpPagePath, + showCleanupPolicyOnAlert, } = el.dataset; return new Vue({ el, @@ -32,6 +34,8 @@ export default () => { projectPath, adminSettingsPath, tagsRegexHelpPagePath, + helpPagePath, + showCleanupPolicyOnAlert: parseBoolean(showCleanupPolicyOnAlert), }, render(createElement) { return createElement('registry-settings-app', {}); diff --git a/app/assets/javascripts/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue b/app/assets/javascripts/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue new file mode 100644 index 00000000000..d51c62e0623 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/shared/components/cleanup_policy_enabled_alert.vue @@ -0,0 +1,54 @@ +<script> +import { GlSprintf, GlAlert, GlLink } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; + +export default { + components: { + GlAlert, + GlLink, + GlSprintf, + LocalStorageSync, + }, + props: { + projectPath: { + type: String, + required: true, + }, + cleanupPoliciesSettingsPath: { + type: String, + required: false, + default: '', + }, + }, + data() { + return { + dismissed: false, + }; + }, + computed: { + storageKey() { + return `cleanup_policy_enabled_for_project_${this.projectPath}`; + }, + }, + i18n: { + message: s__( + 'ContainerRegistry|Cleanup policies are now available for this project. %{linkStart}Click here to get started.%{linkEnd}', + ), + }, +}; +</script> + +<template> + <local-storage-sync v-model="dismissed" :storage-key="storageKey"> + <gl-alert v-if="!dismissed" class="gl-mt-2" dismissible @dismiss="dismissed = true"> + <gl-sprintf :message="$options.i18n.message"> + <template #link="{ content }"> + <gl-link v-if="cleanupPoliciesSettingsPath" :href="cleanupPoliciesSettingsPath">{{ + content + }}</gl-link> + </template> + </gl-sprintf> + </gl-alert> + </local-storage-sync> +</template> diff --git a/app/assets/javascripts/packages_and_registries/shared/utils.js b/app/assets/javascripts/packages_and_registries/shared/utils.js index cc5c7ce82bf..93eb90535d1 100644 --- a/app/assets/javascripts/packages_and_registries/shared/utils.js +++ b/app/assets/javascripts/packages_and_registries/shared/utils.js @@ -1,7 +1,8 @@ import { queryToObject } from '~/lib/utils/url_utility'; import { FILTERED_SEARCH_TERM } from './constants'; -export const getQueryParams = (query) => queryToObject(query, { gatherArrays: true }); +export const getQueryParams = (query) => + queryToObject(query, { gatherArrays: true, legacySpacesDecode: true }); export const keyValueToFilterToken = (type, data) => ({ type, value: { data } }); |