Commit 8a71d767 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Peter Hegman

Add basic components to display dep proxy manifests

parent 880383fd
<script>
import { GlAlert, GlFormGroup, GlFormInputGroup, GlSkeletonLoader, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import { s__ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import {
DEPENDENCY_PROXY_SETTINGS_DESCRIPTION,
DEPENDENCY_PROXY_DOCS_PATH,
} from '~/packages_and_registries/settings/group/constants';
import { GRAPHQL_PAGE_SIZE } from '~/packages_and_registries/dependency_proxy/constants';
import getDependencyProxyDetailsQuery from '~/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql';
......@@ -22,11 +23,16 @@ export default {
},
inject: ['groupPath', 'dependencyProxyAvailable'],
i18n: {
proxyNotAvailableText: __('Dependency Proxy feature is limited to public groups for now.'),
proxyDisabledText: __('Dependency Proxy disabled. To enable it, contact the group owner.'),
proxyImagePrefix: __('Dependency Proxy image prefix'),
copyImagePrefixText: __('Copy prefix'),
blobCountAndSize: __('Contains %{count} blobs of images (%{size})'),
proxyNotAvailableText: s__(
'DependencyProxy|Dependency Proxy feature is limited to public groups for now.',
),
proxyDisabledText: s__(
'DependencyProxy|Dependency Proxy disabled. To enable it, contact the group owner.',
),
proxyImagePrefix: s__('DependencyProxy|Dependency Proxy image prefix'),
copyImagePrefixText: s__('DependencyProxy|Copy prefix'),
blobCountAndSize: s__('DependencyProxy|Contains %{count} blobs of images (%{size})'),
pageTitle: s__('DependencyProxy|Dependency Proxy'),
},
data() {
return {
......@@ -40,7 +46,7 @@ export default {
return !this.dependencyProxyAvailable;
},
variables() {
return { fullPath: this.groupPath };
return { fullPath: this.groupPath, first: GRAPHQL_PAGE_SIZE };
},
},
},
......@@ -62,7 +68,7 @@ export default {
<template>
<div>
<title-area :title="__('Dependency Proxy')" :info-messages="infoMessages" />
<title-area :title="$options.i18n.pageTitle" :info-messages="infoMessages" />
<gl-alert
v-if="!dependencyProxyAvailable"
:dismissible="false"
......
<script>
import { GlSprintf } from '@gitlab/ui';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { s__ } from '~/locale';
export default {
name: 'ManifestRow',
components: {
GlSprintf,
ListItem,
TimeagoTooltip,
},
props: {
manifest: {
type: Object,
required: true,
},
},
computed: {
name() {
return this.manifest?.imageName.split(':')[0];
},
version() {
return this.manifest?.imageName.split(':')[1];
},
},
i18n: {
cachedAgoMessage: s__('DependencyProxy|Cached %{time}'),
},
};
</script>
<template>
<list-item>
<template #left-primary> {{ name }} </template>
<template #left-secondary> {{ version }} </template>
<template #right-primary> &nbsp; </template>
<template #right-secondary>
<timeago-tooltip :time="manifest.createdAt" data-testid="cached-message">
<template #default="{ timeAgo }">
<gl-sprintf :message="$options.i18n.cachedAgoMessage">
<template #time>{{ timeAgo }}</template>
</gl-sprintf>
</template>
</timeago-tooltip>
</template>
</list-item>
</template>
<script>
import { GlKeysetPagination } from '@gitlab/ui';
import { s__ } from '~/locale';
import ManifestRow from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
export default {
name: 'ManifestsLists',
components: {
ManifestRow,
GlKeysetPagination,
},
props: {
manifests: {
type: Array,
required: false,
default: () => [],
},
pagination: {
type: Object,
required: true,
},
},
i18n: {
listTitle: s__('DependencyProxy|Manifest list'),
},
};
</script>
<template>
<div class="gl-mt-5">
<h3 class="gl-font-base">{{ $options.i18n.listTitle }}</h3>
<div
class="gl-border-t-1 gl-border-gray-100 gl-border-t-solid gl-display-flex gl-flex-direction-column"
>
<manifest-row v-for="(manifest, index) in manifests" :key="index" :manifest="manifest" />
</div>
<div class="gl-display-flex gl-justify-content-center">
<gl-keyset-pagination
v-bind="pagination"
class="gl-mt-3"
@prev="$emit('prev-page')"
@next="$emit('next-page')"
/>
</div>
</div>
</template>
query getDependencyProxyDetails($fullPath: ID!) {
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query getDependencyProxyDetails(
$fullPath: ID!
$first: Int
$last: Int
$after: String
$before: String
) {
group(fullPath: $fullPath) {
dependencyProxyBlobCount
dependencyProxyTotalSize
......@@ -6,5 +14,14 @@ query getDependencyProxyDetails($fullPath: ID!) {
dependencyProxySetting {
enabled
}
dependencyProxyManifests(after: $after, before: $before, first: $first, last: $last) {
nodes {
createdAt
imageName
}
pageInfo {
...PageInfo
}
}
}
}
- page_title _("Dependency Proxy")
- @content_class = "limit-container-width" unless fluid_layout
- dependency_proxy_available = Feature.enabled?(:dependency_proxy_for_private_groups, default_enabled: true) || @group.public?
#js-dependency-proxy{ data: { group_path: @group.full_path,
......
......@@ -9178,9 +9178,6 @@ msgstr ""
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
msgid "Contains %{count} blobs of images (%{size})"
msgstr ""
msgid "Content parsed with %{link}."
msgstr ""
......@@ -9370,9 +9367,6 @@ msgstr ""
msgid "Copy link to chart"
msgstr ""
msgid "Copy prefix"
msgstr ""
msgid "Copy reference"
msgstr ""
......@@ -11230,16 +11224,16 @@ msgstr ""
msgid "Dependency Proxy"
msgstr ""
msgid "Dependency Proxy disabled. To enable it, contact the group owner."
msgid "Dependency Scanning"
msgstr ""
msgid "Dependency Proxy feature is limited to public groups for now."
msgid "DependencyProxy|Cached %{time}"
msgstr ""
msgid "Dependency Proxy image prefix"
msgid "DependencyProxy|Contains %{count} blobs of images (%{size})"
msgstr ""
msgid "Dependency Scanning"
msgid "DependencyProxy|Copy prefix"
msgstr ""
msgid "DependencyProxy|Create a local proxy for storing frequently used upstream images. %{docLinkStart}Learn more%{docLinkEnd} about dependency proxies."
......@@ -11248,9 +11242,21 @@ msgstr ""
msgid "DependencyProxy|Dependency Proxy"
msgstr ""
msgid "DependencyProxy|Dependency Proxy disabled. To enable it, contact the group owner."
msgstr ""
msgid "DependencyProxy|Dependency Proxy feature is limited to public groups for now."
msgstr ""
msgid "DependencyProxy|Dependency Proxy image prefix"
msgstr ""
msgid "DependencyProxy|Enable Proxy"
msgstr ""
msgid "DependencyProxy|Manifest list"
msgstr ""
msgid "Depends on %d merge request being merged"
msgid_plural "Depends on %d merge requests being merged"
msgstr[0] ""
......
import { GlKeysetPagination } from '@gitlab/ui';
import { stripTypenames } from 'helpers/graphql_helpers';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ManifestRow from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
import Component from '~/packages_and_registries/dependency_proxy/components/manifests_list.vue';
import {
proxyManifests,
pagination,
} from 'jest/packages_and_registries/dependency_proxy/mock_data';
describe('Manifests List', () => {
let wrapper;
const defaultProps = {
manifests: proxyManifests(),
pagination: stripTypenames(pagination()),
};
const createComponent = (propsData = defaultProps) => {
wrapper = shallowMountExtended(Component, {
propsData,
});
};
const findRows = () => wrapper.findAllComponents(ManifestRow);
const findPagination = () => wrapper.findComponent(GlKeysetPagination);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('has the correct title', () => {
expect(wrapper.text()).toContain(Component.i18n.listTitle);
});
it('shows a row for every manifest', () => {
expect(findRows().length).toBe(defaultProps.manifests.length);
});
it('binds a manifest to each row', () => {
expect(findRows().at(0).props()).toMatchObject({
manifest: defaultProps.manifests[0],
});
});
describe('pagination', () => {
it('has the correct props', () => {
expect(findPagination().props()).toMatchObject({
...defaultProps.pagination,
});
});
it('emits the next-page event', () => {
findPagination().vm.$emit('next');
expect(wrapper.emitted('next-page')).toEqual([[]]);
});
it('emits the prev-page event', () => {
findPagination().vm.$emit('prev');
expect(wrapper.emitted('prev-page')).toEqual([[]]);
});
});
});
import { GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import Component from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
import { proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data';
describe('Manifest Row', () => {
let wrapper;
const defaultProps = {
manifest: proxyManifests()[0],
};
const createComponent = (propsData = defaultProps) => {
wrapper = shallowMountExtended(Component, {
propsData,
stubs: {
GlSprintf,
TimeagoTooltip,
ListItem,
},
});
};
const findListItem = () => wrapper.findComponent(ListItem);
const findCachedMessages = () => wrapper.findByTestId('cached-message');
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('has a list item', () => {
expect(findListItem().exists()).toBe(true);
});
it('displays the name', () => {
expect(wrapper.text()).toContain('alpine');
});
it('displays the version', () => {
expect(wrapper.text()).toContain('latest');
});
it('displays the cached time', () => {
expect(findCachedMessages().text()).toContain('Cached');
});
it('has a time ago tooltip component', () => {
expect(findTimeAgoTooltip().props()).toMatchObject({
time: defaultProps.manifest.createdAt,
});
});
});
......@@ -7,6 +7,20 @@ export const proxyData = () => ({
export const proxySettings = (extend = {}) => ({ enabled: true, ...extend });
export const proxyManifests = () => [
{ createdAt: '2021-09-22T09:45:28Z', imageName: 'alpine:latest' },
{ createdAt: '2021-09-21T09:45:28Z', imageName: 'alpine:stable' },
];
export const pagination = (extend) => ({
endCursor: 'eyJpZCI6IjIwNSIsIm5hbWUiOiJteS9jb21wYW55L2FwcC9teS1hcHAifQ',
hasNextPage: true,
hasPreviousPage: true,
startCursor: 'eyJpZCI6IjI0NyIsIm5hbWUiOiJ2ZXJzaW9uX3Rlc3QxIn0',
__typename: 'PageInfo',
...extend,
});
export const proxyDetailsQuery = ({ extendSettings = {} } = {}) => ({
data: {
group: {
......@@ -16,6 +30,10 @@ export const proxyDetailsQuery = ({ extendSettings = {} } = {}) => ({
...proxySettings(extendSettings),
__typename: 'DependencyProxySetting',
},
dependencyProxyManifests: {
nodes: proxyManifests(),
pageInfo: pagination(),
},
},
},
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment