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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-09-15 03:14:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-09-15 03:14:10 +0300
commit119c999cf1f1bb51d4324e3c4847435347eb32cf (patch)
tree83f92f606877455177bb57c7d2ad31704d10027b /app/assets/javascripts/packages_and_registries
parent5594a6badf033359b84c2e9822f145c66b0dce8f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/packages_and_registries')
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list_row.vue6
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/details/details_header.vue11
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue7
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_header.vue54
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list.vue82
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/components/tags/tags_list_row.vue74
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js12
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/pages/harbor_tags.vue103
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/router.js10
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,
+ },
+ },
],
});