diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-15 03:14:10 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-15 03:14:10 +0300 |
commit | 119c999cf1f1bb51d4324e3c4847435347eb32cf (patch) | |
tree | 83f92f606877455177bb57c7d2ad31704d10027b /app/assets/javascripts/packages_and_registries | |
parent | 5594a6badf033359b84c2e9822f145c66b0dce8f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
9 files changed, 347 insertions, 12 deletions
diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list_row.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list_row.vue index 4b459860346..b489f126f75 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list_row.vue @@ -72,7 +72,7 @@ export default { linkTo() { const { project, image } = this.$route.params; - return { name: 'details', params: { project, image, digest: this.artifact.digest } }; + return { name: 'tags', params: { project, image, digest: this.artifact.digest } }; }, }, }; @@ -99,10 +99,10 @@ export default { </template> <template #left-secondary> - <span class="gl-mr-2" data-testid="size"> + <span class="gl-mr-3" data-testid="size"> {{ formattedSize }} </span> - <span id="tagsCount" data-testid="tags-count"> + <span id="tagsCount" class="gl-display-flex gl-align-items-center" data-testid="tags-count"> <gl-icon name="tag" class="gl-mr-2" /> {{ tagsCountText }} </span> diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/details_header.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/details_header.vue index cc5398ccf8f..bfb097601d5 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/details_header.vue +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/details/details_header.vue @@ -1,10 +1,13 @@ <script> import { isEmpty } from 'lodash'; -import { n__, s__ } 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'; -import { ROOT_IMAGE_TEXT } from '~/packages_and_registries/harbor_registry/constants/index'; +import { + ROOT_IMAGE_TEXT, + EMPTY_ARTIFACTS_LABEL, + artifactsLabel, +} from '~/packages_and_registries/harbor_registry/constants/index'; export default { name: 'DetailsHeader', @@ -19,9 +22,9 @@ export default { computed: { artifactCountText() { if (isEmpty(this.imagesDetail)) { - return s__('HarborRegistry|-- artifacts'); + return EMPTY_ARTIFACTS_LABEL; } - return n__('%d artifact', '%d artifacts', this.imagesDetail.artifactCount); + return artifactsLabel(this.imagesDetail.artifactCount); }, repositoryFullName() { return this.imagesDetail.name || ROOT_IMAGE_TEXT; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue index 72aaa762547..ac1df5cf93f 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue @@ -1,8 +1,7 @@ <script> -// We are using gl-breadcrumb only at the last child of the handwritten breadcrumb -// until this gitlab-ui issue is resolved: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1079 -// -// See the CSS workaround in app/assets/stylesheets/pages/registry.scss when this file is changed. +// Since app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue +// can only handle two levels of breadcrumbs, but we have three levels here. +// So we extended the registry_breadcrumb.vue component with harbor_registry_breadcrumb.vue to support multiple levels of breadcrumbs import { GlBreadcrumb, GlIcon } from '@gitlab/ui'; import { isArray, last } from 'lodash'; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_header.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_header.vue new file mode 100644 index 00000000000..e7f6989c49f --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_header.vue @@ -0,0 +1,54 @@ +<script> +import { isEmpty } from 'lodash'; +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'; +import { + EMPTY_TAG_LABEL, + tagsCountText, +} from '~/packages_and_registries/harbor_registry/constants'; + +export default { + name: 'TagsHeader', + components: { + TitleArea, + MetadataItem, + }, + mixins: [timeagoMixin], + props: { + artifactDetail: { + type: Object, + required: true, + }, + pageInfo: { + type: Object, + required: true, + }, + tagsLoading: { + type: Boolean, + required: true, + }, + }, + computed: { + tagCountText() { + if (isEmpty(this.pageInfo)) { + return EMPTY_TAG_LABEL; + } + return tagsCountText(this.pageInfo.total); + }, + }, +}; +</script> + +<template> + <title-area :metadata-loading="tagsLoading"> + <template #title> + <span class="gl-word-break-all" data-testid="title"> + {{ artifactDetail.digest }} + </span> + </template> + <template #metadata-tags-count> + <metadata-item icon="tag" :text="tagCountText" data-testid="tags-count" /> + </template> + </title-area> +</template> diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list.vue new file mode 100644 index 00000000000..b34d3a950c0 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list.vue @@ -0,0 +1,82 @@ +<script> +import { GlEmptyState } from '@gitlab/ui'; +import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue'; +import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue'; +import TagsListRow from '~/packages_and_registries/harbor_registry/components/tags/tags_list_row.vue'; +import { + NO_ARTIFACTS_TITLE, + NO_TAGS_MATCHING_FILTERS_TITLE, + NO_TAGS_MATCHING_FILTERS_DESCRIPTION, +} from '~/packages_and_registries/harbor_registry/constants'; + +export default { + name: 'TagsList', + components: { + GlEmptyState, + TagsLoader, + TagsListRow, + RegistryList, + }, + inject: ['noContainersImage'], + props: { + tags: { + type: Array, + required: true, + }, + pageInfo: { + type: Object, + required: true, + }, + isLoading: { + type: Boolean, + default: false, + required: false, + }, + }, + computed: { + hasNoTags() { + return this.tags.length === 0; + }, + emptyStateTitle() { + return this.filter ? NO_TAGS_MATCHING_FILTERS_TITLE : NO_ARTIFACTS_TITLE; + }, + emptyStateDescription() { + return this.filter ? NO_TAGS_MATCHING_FILTERS_DESCRIPTION : ''; + }, + }, + methods: { + fetchNextPage() { + this.$emit('next-page'); + }, + fetchPreviousPage() { + this.$emit('prev-page'); + }, + }, +}; +</script> + +<template> + <div> + <tags-loader v-if="isLoading" /> + <gl-empty-state + v-else-if="hasNoTags" + :title="emptyStateTitle" + :svg-path="noContainersImage" + :description="emptyStateDescription" + class="gl-mx-auto gl-my-0" + /> + <registry-list + v-else + :pagination="pageInfo" + :items="tags" + hidden-delete + id-property="name" + @prev-page="fetchPreviousPage" + @next-page="fetchNextPage" + > + <template #default="{ item }"> + <tags-list-row :tag="item" /> + </template> + </registry-list> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list_row.vue new file mode 100644 index 00000000000..63e046c1abc --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list_row.vue @@ -0,0 +1,74 @@ +<script> +import { GlSprintf } from '@gitlab/ui'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import ListItem from '~/vue_shared/components/registry/list_item.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import { CREATED_AT_LABEL } from '~/packages_and_registries/harbor_registry/constants'; +import { tagPullCommand } from '~/packages_and_registries/harbor_registry/utils'; + +export default { + name: 'TagsListRow', + components: { + GlSprintf, + ListItem, + ClipboardButton, + TimeAgoTooltip, + }, + inject: ['harborIntegrationProjectName', 'repositoryUrl'], + props: { + tag: { + type: Object, + required: true, + }, + }, + i18n: { + createdAtLabel: CREATED_AT_LABEL, + }, + methods: { + getPullCommand(tagName) { + if (tagName) { + const { image } = this.$route.params; + + return tagPullCommand({ + imageName: image, + tag: tagName, + repositoryUrl: this.repositoryUrl, + harborProjectName: this.harborIntegrationProjectName, + }); + } + + return ''; + }, + }, +}; +</script> + +<template> + <list-item v-bind="$attrs"> + <template #left-primary> + <div class="gl-display-flex gl-align-items-center"> + <div + data-testid="name" + class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap" + > + {{ tag.name }} + </div> + <clipboard-button + :title="getPullCommand(tag.name)" + :text="getPullCommand(tag.name)" + category="tertiary" + /> + </div> + </template> + + <template #right-primary> + <span data-testid="time"> + <gl-sprintf :message="$options.i18n.createdAtLabel"> + <template #timeInfo> + <time-ago-tooltip :time="tag.pushTime" /> + </template> + </gl-sprintf> + </span> + </template> + </list-item> +</template> diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js index e10a24315d8..5b4b85ec31e 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js @@ -1,4 +1,4 @@ -import { s__, __ } from '~/locale'; +import { s__, __, n__ } from '~/locale'; export const FETCH_ARTIFACT_LIST_ERROR_MESSAGE = s__( 'HarborRegistry|Something went wrong while fetching the artifact list.', @@ -25,3 +25,13 @@ export const FETCH_TAGS_ERROR_MESSAGE = s__( ); export const TAG_LABEL = s__('HarborRegistry|Tag'); +export const EMPTY_TAG_LABEL = s__('HarborRegistry|-- tags'); + +export const EMPTY_ARTIFACTS_LABEL = s__('HarborRegistry|-- artifacts'); +export const artifactsLabel = (count) => { + return n__('%d artifact', '%d artifacts', count); +}; + +export const tagsCountText = (count) => { + return n__('%d tag', '%d tags', count); +}; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue new file mode 100644 index 00000000000..1323d347d10 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue @@ -0,0 +1,103 @@ +<script> +import TagsHeader from '~/packages_and_registries/harbor_registry/components/tags/tags_header.vue'; +import TagsList from '~/packages_and_registries/harbor_registry/components/tags/tags_list.vue'; +import { getHarborTags } from '~/rest_api'; +import { FETCH_TAGS_ERROR_MESSAGE } from '~/packages_and_registries/harbor_registry/constants'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { createAlert } from '~/flash'; +import { formatPagination } from '~/packages_and_registries/harbor_registry/utils'; + +export default { + name: 'HarborTagsPage', + components: { + TagsHeader, + TagsList, + }, + inject: ['endpoint', 'breadCrumbState'], + data() { + return { + tagsLoading: false, + pageInfo: {}, + tags: [], + }; + }, + computed: { + currentPage() { + return this.pageInfo?.page || 1; + }, + artifactDetail() { + const { project, image, digest } = this.$route.params; + + return { + project, + image, + digest, + }; + }, + }, + mounted() { + this.updateBreadcrumb(); + this.fetchTagsData(); + }, + methods: { + updateBreadcrumb() { + const artifactPath = `${this.artifactDetail.project}/${this.artifactDetail.image}`; + const nameList = [artifactPath, this.artifactDetail.digest]; + const hrefList = [`/${artifactPath}`, this.$route.path]; + + this.breadCrumbState.updateName(nameList); + this.breadCrumbState.updateHref(hrefList); + }, + fetchPrevPage() { + const prevPageNum = this.currentPage - 1; + this.fetchTagsData(prevPageNum); + }, + fetchNextPage() { + const nextPageNum = this.currentPage + 1; + this.fetchTagsData(nextPageNum); + }, + fetchTagsData(requestPage) { + this.tagsLoading = true; + + const params = { + page: requestPage, + requestPath: this.endpoint, + repoName: this.artifactDetail.image, + digest: this.artifactDetail.digest, + }; + + getHarborTags(params) + .then((res) => { + this.pageInfo = formatPagination(res.headers); + + this.tags = (res?.data || []).map((tagInfo) => { + return convertObjectPropsToCamelCase(tagInfo); + }); + }) + .catch(() => { + createAlert({ message: FETCH_TAGS_ERROR_MESSAGE }); + }) + .finally(() => { + this.tagsLoading = false; + }); + }, + }, +}; +</script> + +<template> + <div> + <tags-header + :artifact-detail="artifactDetail" + :page-info="pageInfo" + :tags-loading="tagsLoading" + /> + <tags-list + :tags="tags" + :is-loading="tagsLoading" + :page-info="pageInfo" + @prev-page="fetchPrevPage" + @next-page="fetchNextPage" + /> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/router.js b/app/assets/javascripts/packages_and_registries/harbor_registry/router.js index 8744204b5c7..5a792e30c62 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/router.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/router.js @@ -3,6 +3,7 @@ import VueRouter from 'vue-router'; import { HARBOR_REGISTRY_TITLE } from './constants/index'; import List from './pages/list.vue'; import Details from './pages/details.vue'; +import HarborTags from './pages/harbor_tags.vue'; Vue.use(VueRouter); @@ -29,6 +30,15 @@ export default function createRouter(base, breadCrumbState) { hrefGenerator: () => breadCrumbState.href, }, }, + { + name: 'tags', + path: '/:project/:image/:digest', + component: HarborTags, + meta: { + nameGenerator: () => breadCrumbState.name, + hrefGenerator: () => breadCrumbState.href, + }, + }, ], }); |