Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue')
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue350
1 files changed, 350 insertions, 0 deletions
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
new file mode 100644
index 00000000000..162b420a784
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue
@@ -0,0 +1,350 @@
+<script>
+import {
+ GlBadge,
+ GlButton,
+ GlModal,
+ GlModalDirective,
+ GlTooltipDirective,
+ GlEmptyState,
+ GlTab,
+ GlTabs,
+ GlSprintf,
+} from '@gitlab/ui';
+import createFlash from '~/flash';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import { objectToQuery } from '~/lib/utils/url_utility';
+import { s__, __ } from '~/locale';
+import { packageTypeToTrackCategory } from '~/packages_and_registries/package_registry/utils';
+import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
+import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue';
+import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue';
+import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
+import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
+import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
+import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
+import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
+import {
+ PACKAGE_TYPE_NUGET,
+ PACKAGE_TYPE_COMPOSER,
+ 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,
+ SHOW_DELETE_SUCCESS_ALERT,
+ FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
+ DELETE_PACKAGE_FILE_ERROR_MESSAGE,
+ DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
+} from '~/packages_and_registries/package_registry/constants';
+
+import destroyPackageFileMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_file.mutation.graphql';
+import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql';
+import Tracking from '~/tracking';
+
+export default {
+ name: 'PackagesApp',
+ components: {
+ GlBadge,
+ GlButton,
+ GlEmptyState,
+ GlModal,
+ GlTab,
+ GlTabs,
+ GlSprintf,
+ PackageTitle,
+ VersionRow,
+ DependencyRow,
+ PackageHistory,
+ AdditionalMetadata,
+ InstallationCommands,
+ PackageFiles,
+ DeletePackage,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ GlModal: GlModalDirective,
+ },
+ mixins: [Tracking.mixin()],
+ inject: ['emptyListIllustration', 'projectListUrl', 'groupListUrl', 'breadCrumbState'],
+ trackingActions: {
+ 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,
+ },
+ data() {
+ return {
+ fileToDelete: null,
+ packageEntity: {},
+ };
+ },
+ apollo: {
+ packageEntity: {
+ query: getPackageDetails,
+ variables() {
+ return this.queryVariables;
+ },
+ update(data) {
+ return data.package || {};
+ },
+ error(error) {
+ createFlash({
+ message: FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
+ captureError: true,
+ error,
+ });
+ },
+ result() {
+ this.breadCrumbState.updateName(
+ `${this.packageEntity?.name} v ${this.packageEntity?.version}`,
+ );
+ },
+ },
+ },
+ computed: {
+ projectName() {
+ return this.packageEntity.project?.name;
+ },
+ packageId() {
+ return this.$route.params.id;
+ },
+ queryVariables() {
+ return {
+ id: convertToGraphQLId('Packages::Package', this.packageId),
+ };
+ },
+ packageFiles() {
+ return this.packageEntity.packageFiles?.nodes;
+ },
+ isLoading() {
+ return this.$apollo.queries.packageEntity.loading;
+ },
+ isValidPackage() {
+ return this.isLoading || Boolean(this.packageEntity.name);
+ },
+ tracking() {
+ return {
+ category: packageTypeToTrackCategory(this.packageEntity.packageType),
+ };
+ },
+ hasVersions() {
+ return this.packageEntity.versions?.nodes?.length > 0;
+ },
+ packageDependencies() {
+ return this.packageEntity.dependencyLinks?.nodes || [];
+ },
+ showDependencies() {
+ return this.packageEntity.packageType === PACKAGE_TYPE_NUGET;
+ },
+ showFiles() {
+ return this.packageEntity.packageType !== PACKAGE_TYPE_COMPOSER;
+ },
+ },
+ methods: {
+ formatSize(size) {
+ return numberToHumanSize(size);
+ },
+ navigateToListWithSuccessModal() {
+ const returnTo =
+ !this.groupListUrl || document.referrer.includes(this.projectName)
+ ? this.projectListUrl
+ : this.groupListUrl; // to avoid security issue url are supplied from backend
+
+ const modalQuery = objectToQuery({ [SHOW_DELETE_SUCCESS_ALERT]: true });
+
+ window.location.replace(`${returnTo}?${modalQuery}`);
+ },
+ async deletePackageFile(id) {
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: destroyPackageFileMutation,
+ variables: {
+ id,
+ },
+ awaitRefetchQueries: true,
+ refetchQueries: [
+ {
+ query: getPackageDetails,
+ variables: this.queryVariables,
+ },
+ ],
+ });
+ if (data?.destroyPackageFile?.errors[0]) {
+ throw data.destroyPackageFile.errors[0];
+ }
+ createFlash({
+ message: DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
+ type: 'success',
+ });
+ } catch (error) {
+ createFlash({
+ message: DELETE_PACKAGE_FILE_ERROR_MESSAGE,
+ type: 'warning',
+ captureError: true,
+ error,
+ });
+ }
+ },
+ handleFileDelete(file) {
+ this.track(REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION);
+ this.fileToDelete = { ...file };
+ this.$refs.deleteFileModal.show();
+ },
+ confirmFileDelete() {
+ this.track(DELETE_PACKAGE_FILE_TRACKING_ACTION);
+ this.deletePackageFile(this.fileToDelete.id);
+ this.fileToDelete = null;
+ },
+ },
+ i18n: {
+ deleteModalTitle: s__(`PackageRegistry|Delete Package Version`),
+ deleteModalContent: s__(
+ `PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?`,
+ ),
+ deleteFileModalTitle: s__(`PackageRegistry|Delete Package File`),
+ deleteFileModalContent: s__(
+ `PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?`,
+ ),
+ },
+ modal: {
+ packageDeletePrimaryAction: {
+ text: __('Delete'),
+ attributes: [
+ { variant: 'danger' },
+ { category: 'primary' },
+ { 'data-qa-selector': 'delete_modal_button' },
+ ],
+ },
+ fileDeletePrimaryAction: {
+ text: __('Delete'),
+ attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ },
+ cancelAction: {
+ text: __('Cancel'),
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state
+ v-if="!isValidPackage"
+ :title="s__('PackageRegistry|Unable to load package')"
+ :description="s__('PackageRegistry|There was a problem fetching the details for this package.')"
+ :svg-path="emptyListIllustration"
+ />
+ <div v-else-if="!isLoading" class="packages-app">
+ <package-title :package-entity="packageEntity">
+ <template #delete-button>
+ <gl-button
+ v-if="packageEntity.canDestroy"
+ v-gl-modal="'delete-modal'"
+ variant="danger"
+ category="primary"
+ data-qa-selector="delete_button"
+ data-testid="delete-package"
+ >
+ {{ __('Delete') }}
+ </gl-button>
+ </template>
+ </package-title>
+
+ <gl-tabs>
+ <gl-tab :title="__('Detail')">
+ <div v-if="!isLoading" data-qa-selector="package_information_content">
+ <package-history :package-entity="packageEntity" :project-name="projectName" />
+
+ <installation-commands :package-entity="packageEntity" />
+
+ <additional-metadata :package-entity="packageEntity" />
+ </div>
+
+ <package-files
+ v-if="showFiles"
+ :can-delete="packageEntity.canDestroy"
+ :package-files="packageFiles"
+ @download-file="track($options.trackingActions.PULL_PACKAGE)"
+ @delete-file="handleFileDelete"
+ />
+ </gl-tab>
+
+ <gl-tab v-if="showDependencies">
+ <template #title>
+ <span>{{ __('Dependencies') }}</span>
+ <gl-badge size="sm">{{ packageDependencies.length }}</gl-badge>
+ </template>
+
+ <template v-if="packageDependencies.length > 0">
+ <dependency-row v-for="dep in packageDependencies" :key="dep.id" :dependency-link="dep" />
+ </template>
+
+ <p v-else class="gl-mt-3" data-testid="no-dependencies-message">
+ {{ s__('PackageRegistry|This NuGet package has no dependencies.') }}
+ </p>
+ </gl-tab>
+
+ <gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
+ <template v-if="hasVersions">
+ <version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
+ </template>
+
+ <p v-else class="gl-mt-3" data-testid="no-versions-message">
+ {{ s__('PackageRegistry|There are no other versions of this package.') }}
+ </p>
+ </gl-tab>
+ </gl-tabs>
+
+ <delete-package
+ @start="track($options.trackingActions.DELETE_PACKAGE_TRACKING_ACTION)"
+ @end="navigateToListWithSuccessModal"
+ >
+ <template #default="{ deletePackage }">
+ <gl-modal
+ ref="deleteModal"
+ size="sm"
+ modal-id="delete-modal"
+ data-testid="delete-modal"
+ :action-primary="$options.modal.packageDeletePrimaryAction"
+ :action-cancel="$options.modal.cancelAction"
+ @primary="deletePackage(packageEntity)"
+ @canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE)"
+ >
+ <template #modal-title>{{ $options.i18n.deleteModalTitle }}</template>
+ <gl-sprintf :message="$options.i18n.deleteModalContent">
+ <template #version>
+ <strong>{{ packageEntity.version }}</strong>
+ </template>
+
+ <template #name>
+ <strong>{{ packageEntity.name }}</strong>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+ </template>
+ </delete-package>
+
+ <gl-modal
+ ref="deleteFileModal"
+ size="sm"
+ modal-id="delete-file-modal"
+ :action-primary="$options.modal.fileDeletePrimaryAction"
+ :action-cancel="$options.modal.cancelAction"
+ data-testid="delete-file-modal"
+ @primary="confirmFileDelete"
+ @canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE_FILE)"
+ >
+ <template #modal-title>{{ $options.i18n.deleteFileModalTitle }}</template>
+ <gl-sprintf v-if="fileToDelete" :message="$options.i18n.deleteFileModalContent">
+ <template #filename>
+ <strong>{{ fileToDelete.file_name }}</strong>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+ </div>
+</template>