diff options
Diffstat (limited to 'app/assets/javascripts/packages')
19 files changed, 200 insertions, 375 deletions
diff --git a/app/assets/javascripts/packages/details/components/additional_metadata.vue b/app/assets/javascripts/packages/details/components/additional_metadata.vue index 76e0976ac05..4e99099b0a1 100644 --- a/app/assets/javascripts/packages/details/components/additional_metadata.vue +++ b/app/assets/javascripts/packages/details/components/additional_metadata.vue @@ -2,7 +2,6 @@ import { GlLink, GlSprintf } from '@gitlab/ui'; import { s__ } from '~/locale'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; -import { generateConanRecipe } from '../utils'; import { PackageType } from '../../shared/constants'; export default { @@ -25,9 +24,6 @@ export default { }, }, computed: { - conanRecipe() { - return generateConanRecipe(this.packageEntity); - }, showMetadata() { const visibilityConditions = { [PackageType.NUGET]: this.packageEntity.nuget_metadatum, @@ -73,7 +69,7 @@ export default { data-testid="conan-recipe" > <gl-sprintf :message="$options.i18n.recipeText"> - <template #recipe>{{ conanRecipe }}</template> + <template #recipe>{{ packageEntity.name }}</template> </gl-sprintf> </details-row> diff --git a/app/assets/javascripts/packages/details/components/composer_installation.vue b/app/assets/javascripts/packages/details/components/composer_installation.vue index 60ad468c293..9d87ae8f836 100644 --- a/app/assets/javascripts/packages/details/components/composer_installation.vue +++ b/app/assets/javascripts/packages/details/components/composer_installation.vue @@ -14,12 +14,12 @@ export default { }, computed: { ...mapState(['composerHelpPath']), - ...mapGetters(['composerRegistryInclude', 'composerPackageInclude']), + ...mapGetters(['composerRegistryInclude', 'composerPackageInclude', 'groupExists']), }, i18n: { - registryInclude: s__('PackageRegistry|composer.json registry include'), + registryInclude: s__('PackageRegistry|Add composer registry'), copyRegistryInclude: s__('PackageRegistry|Copy registry include'), - packageInclude: s__('PackageRegistry|composer.json require package include'), + packageInclude: s__('PackageRegistry|Install package version'), copyPackageInclude: s__('PackageRegistry|Copy require package include'), infoLine: s__( 'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}', @@ -31,7 +31,7 @@ export default { </script> <template> - <div> + <div v-if="groupExists" data-testid="root-node"> <h3 class="gl-font-lg">{{ __('Installation') }}</h3> <code-instruction diff --git a/app/assets/javascripts/packages/details/components/package_title.vue b/app/assets/javascripts/packages/details/components/package_title.vue index 69dd494f11a..2789be30818 100644 --- a/app/assets/javascripts/packages/details/components/package_title.vue +++ b/app/assets/javascripts/packages/details/components/package_title.vue @@ -54,15 +54,15 @@ export default { </gl-sprintf> </template> - <template v-if="packageTypeDisplay" #metadata_type> + <template v-if="packageTypeDisplay" #metadata-type> <metadata-item data-testid="package-type" icon="package" :text="packageTypeDisplay" /> </template> - <template #metadata_size> + <template #metadata-size> <metadata-item data-testid="package-size" icon="disk" :text="totalSize" /> </template> - <template v-if="packagePipeline" #metadata_pipeline> + <template v-if="packagePipeline" #metadata-pipeline> <metadata-item data-testid="pipeline-project" icon="review-list" @@ -71,11 +71,11 @@ export default { /> </template> - <template v-if="packagePipeline" #metadata_ref> + <template v-if="packagePipeline" #metadata-ref> <metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" /> </template> - <template v-if="hasTagsToDisplay" #metadata_tags> + <template v-if="hasTagsToDisplay" #metadata-tags> <package-tags :tag-display-limit="2" :tags="packageEntity.tags" hide-label /> </template> diff --git a/app/assets/javascripts/packages/details/store/getters.js b/app/assets/javascripts/packages/details/store/getters.js index ede6d39bde7..14e76ac84bd 100644 --- a/app/assets/javascripts/packages/details/store/getters.js +++ b/app/assets/javascripts/packages/details/store/getters.js @@ -1,4 +1,3 @@ -import { generateConanRecipe } from '../utils'; import { PackageType } from '../../shared/constants'; import { getPackageTypeLabel } from '../../shared/utils'; import { NpmManager } from '../constants'; @@ -20,10 +19,8 @@ export const packageIcon = ({ packageEntity }) => { }; export const conanInstallationCommand = ({ packageEntity }) => { - const recipe = generateConanRecipe(packageEntity); - // eslint-disable-next-line @gitlab/require-i18n-strings - return `conan install ${recipe} --remote=gitlab`; + return `conan install ${packageEntity.name} --remote=gitlab`; }; export const conanSetupCommand = ({ conanPath }) => @@ -98,18 +95,19 @@ export const nugetSetupCommand = ({ nugetPath }) => export const pypiPipCommand = ({ pypiPath, packageEntity }) => // eslint-disable-next-line @gitlab/require-i18n-strings - `pip install ${packageEntity.name} --index-url ${pypiPath}`; + `pip install ${packageEntity.name} --extra-index-url ${pypiPath}`; export const pypiSetupCommand = ({ pypiSetupPath }) => `[gitlab] repository = ${pypiSetupPath} username = __token__ password = <your personal access token>`; -export const composerRegistryInclude = ({ composerPath }) => { - const base = { type: 'composer', url: composerPath }; - return JSON.stringify(base); -}; -export const composerPackageInclude = ({ packageEntity }) => { - const base = { [packageEntity.name]: packageEntity.version }; - return JSON.stringify(base); -}; +export const composerRegistryInclude = ({ composerPath, composerConfigRepositoryName }) => + // eslint-disable-next-line @gitlab/require-i18n-strings + `composer config repositories.${composerConfigRepositoryName} '{"type": "composer", "url": "${composerPath}"}'`; + +export const composerPackageInclude = ({ packageEntity }) => + // eslint-disable-next-line @gitlab/require-i18n-strings + `composer req ${[packageEntity.name]}:${packageEntity.version}`; + +export const groupExists = ({ groupListUrl }) => groupListUrl.length > 0; diff --git a/app/assets/javascripts/packages/details/utils.js b/app/assets/javascripts/packages/details/utils.js index 454c83c9ccd..27cc95566d3 100644 --- a/app/assets/javascripts/packages/details/utils.js +++ b/app/assets/javascripts/packages/details/utils.js @@ -8,16 +8,3 @@ export const trackInstallationTabChange = { }, }, }; - -export function generateConanRecipe(packageEntity = {}) { - const { - name = '', - version = '', - conan_metadatum: { - package_username: packageUsername = '', - package_channel: packageChannel = '', - } = {}, - } = packageEntity; - - return `${name}/${version}@${packageUsername}/${packageChannel}`; -} diff --git a/app/assets/javascripts/packages/list/coming_soon/helpers.js b/app/assets/javascripts/packages/list/coming_soon/helpers.js deleted file mode 100644 index 5b6a4b3aa87..00000000000 --- a/app/assets/javascripts/packages/list/coming_soon/helpers.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Context: - * https://gitlab.com/gitlab-org/gitlab/-/issues/198524 - * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29491 - * - */ - -/** - * Constants - * - * LABEL_NAMES - an array of labels to filter issues in the GraphQL query - * WORKFLOW_PREFIX - the prefix for workflow labels - * ACCEPTING_CONTRIBUTIONS_TITLE - the accepting contributions label - */ -export const LABEL_NAMES = ['Package::Coming soon']; -const WORKFLOW_PREFIX = 'workflow::'; -const ACCEPTING_CONTRIBUTIONS_TITLE = 'accepting merge requests'; - -const setScoped = (label, scoped) => (label ? { ...label, scoped } : label); - -/** - * Finds workflow:: scoped labels and returns the first or null. - * @param {Object[]} labels Labels from the issue - */ -export const findWorkflowLabel = (labels = []) => - labels.find(l => l.title.toLowerCase().includes(WORKFLOW_PREFIX.toLowerCase())); - -/** - * Determines if an issue is accepting community contributions by checking if - * the "Accepting merge requests" label is present. - * @param {Object[]} labels - */ -export const findAcceptingContributionsLabel = (labels = []) => - labels.find(l => l.title.toLowerCase() === ACCEPTING_CONTRIBUTIONS_TITLE.toLowerCase()); - -/** - * Formats the GraphQL response into the format that the view template expects. - * @param {Object} data GraphQL response - */ -export const toViewModel = data => { - // This just flatterns the issues -> nodes and labels -> nodes hierarchy - // into an array of objects. - const issues = (data.project?.issues?.nodes || []).map(i => ({ - ...i, - labels: (i.labels?.nodes || []).map(node => node), - })); - - return issues.map(x => ({ - ...x, - labels: [ - setScoped(findWorkflowLabel(x.labels), true), - setScoped(findAcceptingContributionsLabel(x.labels), false), - ].filter(Boolean), - })); -}; diff --git a/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue b/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue deleted file mode 100644 index 766402d3619..00000000000 --- a/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue +++ /dev/null @@ -1,172 +0,0 @@ -<script> -import { - GlAlert, - GlEmptyState, - GlIcon, - GlLabel, - GlLink, - GlSkeletonLoader, - GlSprintf, -} from '@gitlab/ui'; -import { ApolloQuery } from 'vue-apollo'; -import Tracking from '~/tracking'; -import { TrackingActions } from '../../shared/constants'; -import { s__ } from '~/locale'; -import comingSoonIssuesQuery from './queries/issues.graphql'; -import { toViewModel, LABEL_NAMES } from './helpers'; - -export default { - name: 'ComingSoon', - components: { - GlAlert, - GlEmptyState, - GlIcon, - GlLabel, - GlLink, - GlSkeletonLoader, - GlSprintf, - ApolloQuery, - }, - mixins: [Tracking.mixin()], - props: { - illustration: { - type: String, - required: true, - }, - projectPath: { - type: String, - required: true, - }, - suggestedContributionsPath: { - type: String, - required: true, - }, - }, - computed: { - variables() { - return { - projectPath: this.projectPath, - labelNames: LABEL_NAMES, - }; - }, - }, - mounted() { - this.track(TrackingActions.COMING_SOON_REQUESTED); - }, - methods: { - onIssueLinkClick(issueIid, label) { - this.track(TrackingActions.COMING_SOON_LIST, { - label, - value: issueIid, - }); - }, - onDocsLinkClick() { - this.track(TrackingActions.COMING_SOON_HELP); - }, - }, - loadingRows: 5, - i18n: { - alertTitle: s__('PackageRegistry|Upcoming package managers'), - alertIntro: s__( - "PackageRegistry|Is your favorite package manager missing? We'd love your help in building first-class support for it into GitLab! %{contributionLinkStart}Visit the contribution documentation%{contributionLinkEnd} to learn more about how to build support for new package managers into GitLab. Below is a list of package managers that are on our radar.", - ), - emptyStateTitle: s__('PackageRegistry|No upcoming issues'), - emptyStateDescription: s__('PackageRegistry|There are no upcoming issues to display.'), - }, - comingSoonIssuesQuery, - toViewModel, -}; -</script> - -<template> - <apollo-query - :query="$options.comingSoonIssuesQuery" - :variables="variables" - :update="$options.toViewModel" - > - <template #default="{ result: { data }, isLoading }"> - <div> - <gl-alert :title="$options.i18n.alertTitle" :dismissible="false" variant="tip"> - <gl-sprintf :message="$options.i18n.alertIntro"> - <template #contributionLink="{ content }"> - <gl-link - :href="suggestedContributionsPath" - target="_blank" - @click="onDocsLinkClick" - >{{ content }}</gl-link - > - </template> - </gl-sprintf> - </gl-alert> - </div> - - <div v-if="isLoading" class="gl-display-flex gl-flex-direction-column"> - <gl-skeleton-loader - v-for="index in $options.loadingRows" - :key="index" - :width="1000" - :height="80" - preserve-aspect-ratio="xMinYMax meet" - > - <rect width="700" height="10" x="0" y="16" rx="4" /> - <rect width="60" height="10" x="0" y="45" rx="4" /> - <rect width="60" height="10" x="70" y="45" rx="4" /> - </gl-skeleton-loader> - </div> - - <template v-else-if="data && data.length"> - <div - v-for="issue in data" - :key="issue.iid" - data-testid="issue-row" - class="gl-responsive-table-row gl-flex-direction-column gl-align-items-baseline" - > - <div class="table-section section-100 gl-white-space-normal text-truncate"> - <gl-link - data-testid="issue-title-link" - :href="issue.webUrl" - class="gl-text-gray-900 gl-font-weight-bold" - @click="onIssueLinkClick(issue.iid, issue.title)" - > - {{ issue.title }} - </gl-link> - </div> - - <div class="table-section section-100 gl-white-space-normal mt-md-3"> - <div class="gl-display-flex gl-text-gray-400"> - <gl-icon name="issues" class="gl-mr-2" /> - <gl-link - data-testid="issue-id-link" - :href="issue.webUrl" - class="gl-text-gray-400 gl-mr-5" - @click="onIssueLinkClick(issue.iid, issue.title)" - >#{{ issue.iid }}</gl-link - > - - <div v-if="issue.milestone" class="gl-display-flex gl-align-items-center gl-mr-5"> - <gl-icon name="clock" class="gl-mr-2" /> - <span data-testid="milestone">{{ issue.milestone.title }}</span> - </div> - - <gl-label - v-for="label in issue.labels" - :key="label.title" - class="gl-mr-3" - size="sm" - :background-color="label.color" - :title="label.title" - :scoped="Boolean(label.scoped)" - /> - </div> - </div> - </div> - </template> - - <gl-empty-state v-else :title="$options.i18n.emptyStateTitle" :svg-path="illustration"> - <template #description> - <p>{{ $options.i18n.emptyStateDescription }}</p> - </template> - </gl-empty-state> - </template> - </apollo-query> -</template> diff --git a/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql b/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql deleted file mode 100644 index 36c27d9ad70..00000000000 --- a/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql +++ /dev/null @@ -1,20 +0,0 @@ -query getComingSoonIssues($projectPath: ID!, $labelNames: [String]) { - project(fullPath: $projectPath) { - issues(state: opened, labelName: $labelNames) { - nodes { - iid - title - webUrl - labels { - nodes { - title - color - } - } - milestone { - title - } - } - } - } -} diff --git a/app/assets/javascripts/packages/list/components/package_title.vue b/app/assets/javascripts/packages/list/components/package_title.vue new file mode 100644 index 00000000000..f94a98e4ca7 --- /dev/null +++ b/app/assets/javascripts/packages/list/components/package_title.vue @@ -0,0 +1,47 @@ +<script> +import { n__ } from '~/locale'; +import TitleArea from '~/vue_shared/components/registry/title_area.vue'; +import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; +import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '../constants'; + +export default { + name: 'PackageTitle', + components: { + TitleArea, + MetadataItem, + }, + props: { + packagesCount: { + type: Number, + required: false, + default: null, + }, + packageHelpUrl: { + type: String, + required: true, + }, + }, + computed: { + showPackageCount() { + return Number.isInteger(this.packagesCount); + }, + packageAmountText() { + return n__(`%d Package`, `%d Packages`, this.packagesCount); + }, + infoMessages() { + return [{ text: LIST_INTRO_TEXT, link: this.packageHelpUrl }]; + }, + }, + i18n: { + LIST_TITLE_TEXT, + }, +}; +</script> + +<template> + <title-area :title="$options.i18n.LIST_TITLE_TEXT" :info-messages="infoMessages"> + <template #metadata-amount> + <metadata-item v-if="showPackageCount" icon="package" :text="packageAmountText" /> + </template> + </title-area> +</template> diff --git a/app/assets/javascripts/packages/list/components/packages_list_app.vue b/app/assets/javascripts/packages/list/components/packages_list_app.vue index 6304f723f6a..cbb3bfd35ac 100644 --- a/app/assets/javascripts/packages/list/components/packages_list_app.vue +++ b/app/assets/javascripts/packages/list/components/packages_list_app.vue @@ -3,13 +3,13 @@ import { mapActions, mapState } from 'vuex'; import { GlEmptyState, GlTab, GlTabs, GlLink, GlSprintf } from '@gitlab/ui'; import { s__, sprintf } from '~/locale'; import createFlash from '~/flash'; +import { historyReplaceState } from '~/lib/utils/common_utils'; +import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants'; import PackageFilter from './packages_filter.vue'; import PackageList from './packages_list.vue'; import PackageSort from './packages_sort.vue'; import { PACKAGE_REGISTRY_TABS, DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants'; -import PackagesComingSoon from '../coming_soon/packages_coming_soon.vue'; -import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants'; -import { historyReplaceState } from '~/lib/utils/common_utils'; +import PackageTitle from './package_title.vue'; export default { components: { @@ -21,15 +21,16 @@ export default { PackageFilter, PackageList, PackageSort, - PackagesComingSoon, + PackageTitle, }, computed: { ...mapState({ emptyListIllustration: state => state.config.emptyListIllustration, emptyListHelpUrl: state => state.config.emptyListHelpUrl, - comingSoon: state => state.config.comingSoon, filterQuery: state => state.filterQuery, selectedType: state => state.selectedType, + packageHelpUrl: state => state.config.packageHelpUrl, + packagesCount: state => state.pagination?.total, }), tabsToRender() { return PACKAGE_REGISTRY_TABS; @@ -89,39 +90,35 @@ export default { </script> <template> - <gl-tabs @input="tabChanged"> - <template #tabs-end> - <div - class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" - > - <package-filter class="mr-1" @filter="requestPackagesList" /> - <package-sort @sort:changed="requestPackagesList" /> - </div> - </template> + <div> + <package-title :package-help-url="packageHelpUrl" :packages-count="packagesCount" /> - <gl-tab v-for="(tab, index) in tabsToRender" :key="index" :title="tab.title"> - <package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest"> - <template #empty-state> - <gl-empty-state :title="emptyStateTitle(tab)" :svg-path="emptyListIllustration"> - <template #description> - <gl-sprintf v-if="filterQuery" :message="$options.i18n.widenFilters" /> - <gl-sprintf v-else :message="$options.i18n.noResults"> - <template #noPackagesLink="{content}"> - <gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link> - </template> - </gl-sprintf> - </template> - </gl-empty-state> - </template> - </package-list> - </gl-tab> + <gl-tabs @input="tabChanged"> + <template #tabs-end> + <div + class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" + > + <package-filter class="gl-mr-2" @filter="requestPackagesList" /> + <package-sort @sort:changed="requestPackagesList" /> + </div> + </template> - <gl-tab v-if="comingSoon" :title="__('Coming soon')" lazy> - <packages-coming-soon - :illustration="emptyListIllustration" - :project-path="comingSoon.projectPath" - :suggested-contributions-path="comingSoon.suggestedContributions" - /> - </gl-tab> - </gl-tabs> + <gl-tab v-for="(tab, index) in tabsToRender" :key="index" :title="tab.title"> + <package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest"> + <template #empty-state> + <gl-empty-state :title="emptyStateTitle(tab)" :svg-path="emptyListIllustration"> + <template #description> + <gl-sprintf v-if="filterQuery" :message="$options.i18n.widenFilters" /> + <gl-sprintf v-else :message="$options.i18n.noResults"> + <template #noPackagesLink="{content}"> + <gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </template> + </gl-empty-state> + </template> + </package-list> + </gl-tab> + </gl-tabs> + </div> </template> diff --git a/app/assets/javascripts/packages/list/components/packages_sort.vue b/app/assets/javascripts/packages/list/components/packages_sort.vue index fa8f4f39d54..47e51bbdca5 100644 --- a/app/assets/javascripts/packages/list/components/packages_sort.vue +++ b/app/assets/javascripts/packages/list/components/packages_sort.vue @@ -51,7 +51,7 @@ export default { <gl-sorting-item v-for="item in sortableFields" ref="packageListSortItem" - :key="item.key" + :key="item.orderBy" @click="onSortItemClick(item.orderBy)" > {{ item.label }} diff --git a/app/assets/javascripts/packages/list/constants.js b/app/assets/javascripts/packages/list/constants.js index 0ff8c86362d..6a0e92bff2d 100644 --- a/app/assets/javascripts/packages/list/constants.js +++ b/app/assets/javascripts/packages/list/constants.js @@ -15,7 +15,7 @@ export const GROUP_PAGE_TYPE = 'groups'; export const LIST_KEY_NAME = 'name'; export const LIST_KEY_PROJECT = 'project_path'; export const LIST_KEY_VERSION = 'version'; -export const LIST_KEY_PACKAGE_TYPE = 'package_type'; +export const LIST_KEY_PACKAGE_TYPE = 'type'; export const LIST_KEY_CREATED_AT = 'created_at'; export const LIST_KEY_ACTIONS = 'actions'; @@ -23,47 +23,35 @@ export const LIST_LABEL_NAME = __('Name'); export const LIST_LABEL_PROJECT = __('Project'); export const LIST_LABEL_VERSION = __('Version'); export const LIST_LABEL_PACKAGE_TYPE = __('Type'); -export const LIST_LABEL_CREATED_AT = __('Created'); +export const LIST_LABEL_CREATED_AT = __('Published'); export const LIST_LABEL_ACTIONS = ''; -export const LIST_ORDER_BY_PACKAGE_TYPE = 'type'; - export const ASCENDING_ODER = 'asc'; export const DESCENDING_ORDER = 'desc'; // The following is not translated because it is used to build a JavaScript exception error message export const MISSING_DELETE_PATH_ERROR = 'Missing delete_api_path link'; -export const TABLE_HEADER_FIELDS = [ +export const SORT_FIELDS = [ { - key: LIST_KEY_NAME, - label: LIST_LABEL_NAME, orderBy: LIST_KEY_NAME, - class: ['text-left'], + label: LIST_LABEL_NAME, }, { - key: LIST_KEY_PROJECT, - label: LIST_LABEL_PROJECT, orderBy: LIST_KEY_PROJECT, - class: ['text-left'], + label: LIST_LABEL_PROJECT, }, { - key: LIST_KEY_VERSION, - label: LIST_LABEL_VERSION, orderBy: LIST_KEY_VERSION, - class: ['text-center'], + label: LIST_LABEL_VERSION, }, { - key: LIST_KEY_PACKAGE_TYPE, + orderBy: LIST_KEY_PACKAGE_TYPE, label: LIST_LABEL_PACKAGE_TYPE, - orderBy: LIST_ORDER_BY_PACKAGE_TYPE, - class: ['text-center'], }, { - key: LIST_KEY_CREATED_AT, - label: LIST_LABEL_CREATED_AT, orderBy: LIST_KEY_CREATED_AT, - class: ['text-center'], + label: LIST_LABEL_CREATED_AT, }, ]; @@ -94,7 +82,13 @@ export const PACKAGE_REGISTRY_TABS = [ type: PackageType.NUGET, }, { - title: s__('PackageRegistry|PyPi'), + title: s__('PackageRegistry|PyPI'), type: PackageType.PYPI, }, ]; + +export const LIST_TITLE_TEXT = s__('PackageRegistry|Package Registry'); + +export const LIST_INTRO_TEXT = s__( + 'PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}', +); diff --git a/app/assets/javascripts/packages/list/stores/mutations.js b/app/assets/javascripts/packages/list/stores/mutations.js index a47ba356c0a..2fe7981b3d9 100644 --- a/app/assets/javascripts/packages/list/stores/mutations.js +++ b/app/assets/javascripts/packages/list/stores/mutations.js @@ -1,19 +1,12 @@ import * as types from './mutation_types'; -import { - parseIntPagination, - normalizeHeaders, - convertObjectPropsToCamelCase, -} from '~/lib/utils/common_utils'; +import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { GROUP_PAGE_TYPE } from '../constants'; export default { [types.SET_INITIAL_STATE](state, config) { const { comingSoonJson, ...rest } = config; - const comingSoonObj = JSON.parse(comingSoonJson); - state.config = { ...rest, - comingSoon: comingSoonObj && convertObjectPropsToCamelCase(comingSoonObj), isGroupPage: config.pageType === GROUP_PAGE_TYPE, }; }, diff --git a/app/assets/javascripts/packages/list/utils.js b/app/assets/javascripts/packages/list/utils.js index 98d78db8706..6a300d7bfe6 100644 --- a/app/assets/javascripts/packages/list/utils.js +++ b/app/assets/javascripts/packages/list/utils.js @@ -1,7 +1,6 @@ -import { LIST_KEY_PROJECT, TABLE_HEADER_FIELDS } from './constants'; +import { LIST_KEY_PROJECT, SORT_FIELDS } from './constants'; -export default isGroupPage => - TABLE_HEADER_FIELDS.filter(f => f.key !== LIST_KEY_PROJECT || isGroupPage); +export default isGroupPage => SORT_FIELDS.filter(f => f.key !== LIST_KEY_PROJECT || isGroupPage); /** * A small util function that works out if the delete action has deleted the diff --git a/app/assets/javascripts/packages/shared/components/package_list_row.vue b/app/assets/javascripts/packages/shared/components/package_list_row.vue index f93bc51d185..d55ca80a7fc 100644 --- a/app/assets/javascripts/packages/shared/components/package_list_row.vue +++ b/app/assets/javascripts/packages/shared/components/package_list_row.vue @@ -1,6 +1,7 @@ <script> import { GlButton, GlIcon, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui'; import PackageTags from './package_tags.vue'; +import PackagePath from './package_path.vue'; import PublishMethod from './publish_method.vue'; import { getPackageTypeLabel } from '../utils'; import timeagoMixin from '~/vue_shared/mixins/timeago'; @@ -15,6 +16,7 @@ export default { GlSprintf, GlTruncate, PackageTags, + PackagePath, PublishMethod, ListItem, }, @@ -92,22 +94,12 @@ export default { </gl-sprintf> </div> - <div v-if="hasProjectLink" class="gl-display-flex gl-align-items-center"> - <gl-icon name="review-list" class="gl-ml-3 gl-mr-2 gl-min-w-0" /> - - <gl-link - class="gl-text-body gl-min-w-0" - data-testid="packages-row-project" - :href="`/${packageEntity.project_path}`" - > - <gl-truncate :text="packageEntity.projectPathName" /> - </gl-link> - </div> - <div v-if="showPackageType" class="d-flex align-items-center" data-testid="package-type"> <gl-icon name="package" class="gl-ml-3 gl-mr-2" /> <span>{{ packageType }}</span> </div> + + <package-path v-if="hasProjectLink" :path="packageEntity.project_path" /> </div> </template> diff --git a/app/assets/javascripts/packages/shared/components/package_path.vue b/app/assets/javascripts/packages/shared/components/package_path.vue new file mode 100644 index 00000000000..9afe06ab497 --- /dev/null +++ b/app/assets/javascripts/packages/shared/components/package_path.vue @@ -0,0 +1,71 @@ +<script> +import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui'; +import { joinPaths } from '~/lib/utils/url_utility'; + +export default { + name: 'PackagePath', + components: { + GlIcon, + GlLink, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + path: { + type: String, + required: true, + }, + }, + computed: { + pathPieces() { + return this.path.split('/'); + }, + root() { + // we skip the first part of the path since is the 'base' group + return this.pathPieces[1]; + }, + rootLink() { + return joinPaths(this.pathPieces[0], this.root); + }, + leaf() { + return this.pathPieces[this.pathPieces.length - 1]; + }, + deeplyNested() { + return this.pathPieces.length > 3; + }, + hasGroup() { + return this.root !== this.leaf; + }, + }, +}; +</script> + +<template> + <div data-qa-selector="package-path" class="gl-display-flex gl-align-items-center"> + <gl-icon data-testid="base-icon" name="project" class="gl-mx-3 gl-min-w-0" /> + + <gl-link data-testid="root-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${rootLink}`"> + {{ root }} + </gl-link> + + <template v-if="hasGroup"> + <gl-icon data-testid="root-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" /> + + <template v-if="deeplyNested"> + <span + v-gl-tooltip="{ title: path }" + data-testid="ellipsis-icon" + class="gl-inset-border-1-gray-200 gl-rounded-base gl-px-2 gl-min-w-0" + > + <gl-icon name="ellipsis_h" /> + </span> + <gl-icon data-testid="ellipsis-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" /> + </template> + + <gl-link data-testid="leaf-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${path}`"> + {{ leaf }} + </gl-link> + </template> + </div> +</template> diff --git a/app/assets/javascripts/packages/shared/components/publish_method.vue b/app/assets/javascripts/packages/shared/components/publish_method.vue index d17e23c4032..8a66a33f2ab 100644 --- a/app/assets/javascripts/packages/shared/components/publish_method.vue +++ b/app/assets/javascripts/packages/shared/components/publish_method.vue @@ -49,7 +49,8 @@ export default { <clipboard-button :text="packageEntity.pipeline.sha" :title="__('Copy commit SHA')" - css-class="gl-border-0 gl-py-0 gl-px-2" + category="tertiary" + size="small" /> </template> diff --git a/app/assets/javascripts/packages/shared/constants.js b/app/assets/javascripts/packages/shared/constants.js index e5131db59bf..c481abd8658 100644 --- a/app/assets/javascripts/packages/shared/constants.js +++ b/app/assets/javascripts/packages/shared/constants.js @@ -14,9 +14,6 @@ export const TrackingActions = { REQUEST_DELETE_PACKAGE: 'request_delete_package', CANCEL_DELETE_PACKAGE: 'cancel_delete_package', PULL_PACKAGE: 'pull_package', - COMING_SOON_REQUESTED: 'activate_coming_soon_requested', - COMING_SOON_LIST: 'click_coming_soon_issue_link', - COMING_SOON_HELP: 'click_coming_soon_documentation_link', }; export const TrackingCategories = { diff --git a/app/assets/javascripts/packages/shared/utils.js b/app/assets/javascripts/packages/shared/utils.js index a0c7389651d..b0807558266 100644 --- a/app/assets/javascripts/packages/shared/utils.js +++ b/app/assets/javascripts/packages/shared/utils.js @@ -18,7 +18,7 @@ export const getPackageTypeLabel = packageType => { case PackageType.NUGET: return s__('PackageType|NuGet'); case PackageType.PYPI: - return s__('PackageType|PyPi'); + return s__('PackageType|PyPI'); case PackageType.COMPOSER: return s__('PackageType|Composer'); |