Commit c3ee0b83 authored by David O'Regan's avatar David O'Regan

Merge branch '216795-show-last-update-and-visibility' into 'master'

Add visibility and last updated image repository details

See merge request gitlab-org/gitlab!49703
parents d8723861 b15e1197
<script> <script>
import { GlSprintf } from '@gitlab/ui'; import { GlSprintf } from '@gitlab/ui';
import { sprintf } from '~/locale';
import TitleArea from '~/vue_shared/components/registry/title_area.vue'; import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import { DETAILS_PAGE_TITLE } from '../../constants/index'; import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { DETAILS_PAGE_TITLE, UPDATED_AT } from '../../constants/index';
export default { export default {
components: { GlSprintf, TitleArea }, components: { GlSprintf, TitleArea, MetadataItem },
mixins: [timeagoMixin],
props: { props: {
imageName: { image: {
type: String, type: Object,
required: false, required: true,
default: '', },
},
computed: {
visibilityIcon() {
return this.image?.project?.visibility === 'public' ? 'eye' : 'eye-slash';
},
timeAgo() {
return this.timeFormatted(this.image.updatedAt);
},
updatedText() {
return sprintf(UPDATED_AT, { time: this.timeAgo });
}, },
}, },
i18n: { i18n: {
...@@ -23,9 +37,17 @@ export default { ...@@ -23,9 +37,17 @@ export default {
<template #title> <template #title>
<gl-sprintf :message="$options.i18n.DETAILS_PAGE_TITLE"> <gl-sprintf :message="$options.i18n.DETAILS_PAGE_TITLE">
<template #imageName> <template #imageName>
{{ imageName }} {{ image.name }}
</template> </template>
</gl-sprintf> </gl-sprintf>
</template> </template>
<template #metadata-updated>
<metadata-item
:icon="visibilityIcon"
:text="updatedText"
size="xl"
data-testid="updated-and-visibility"
/>
</template>
</title-area> </title-area>
</template> </template>
...@@ -56,6 +56,8 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__( ...@@ -56,6 +56,8 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__(
'ContainerRegistry|Invalid tag: missing manifest digest', 'ContainerRegistry|Invalid tag: missing manifest digest',
); );
export const UPDATED_AT = s__('ContainerRegistry|Last updated %{time}');
export const NOT_AVAILABLE_TEXT = __('N/A'); export const NOT_AVAILABLE_TEXT = __('N/A');
export const NOT_AVAILABLE_SIZE = __('0 bytes'); export const NOT_AVAILABLE_SIZE = __('0 bytes');
// Parameters // Parameters
......
...@@ -15,6 +15,7 @@ query getContainerRepositoryDetails( ...@@ -15,6 +15,7 @@ query getContainerRepositoryDetails(
location location
canDelete canDelete
createdAt createdAt
updatedAt
tagsCount tagsCount
expirationPolicyStartedAt expirationPolicyStartedAt
tags(after: $after, before: $before, first: $first, last: $last) { tags(after: $after, before: $before, first: $first, last: $last) {
...@@ -33,5 +34,8 @@ query getContainerRepositoryDetails( ...@@ -33,5 +34,8 @@ query getContainerRepositoryDetails(
...PageInfo ...PageInfo
} }
} }
project {
visibility
}
} }
} }
...@@ -183,7 +183,7 @@ export default { ...@@ -183,7 +183,7 @@ export default {
@dismiss="dismissPartialCleanupWarning = true" @dismiss="dismissPartialCleanupWarning = true"
/> />
<details-header :image-name="image.name" /> <details-header :image="image" />
<tags-loader v-if="isLoading" /> <tags-loader v-if="isLoading" />
<template v-else> <template v-else>
......
---
title: Add visibility and last updated image repository details
merge_request: 49703
author:
type: changed
...@@ -7450,6 +7450,9 @@ msgstr "" ...@@ -7450,6 +7450,9 @@ msgstr ""
msgid "ContainerRegistry|Keep these tags" msgid "ContainerRegistry|Keep these tags"
msgstr "" msgstr ""
msgid "ContainerRegistry|Last updated %{time}"
msgstr ""
msgid "ContainerRegistry|Login" msgid "ContainerRegistry|Login"
msgstr "" msgstr ""
......
...@@ -7,9 +7,27 @@ import { DETAILS_PAGE_TITLE } from '~/registry/explorer/constants'; ...@@ -7,9 +7,27 @@ import { DETAILS_PAGE_TITLE } from '~/registry/explorer/constants';
describe('Details Header', () => { describe('Details Header', () => {
let wrapper; let wrapper;
const mountComponent = propsData => { const defaultImage = {
name: 'foo',
updatedAt: '2020-11-03T13:29:21Z',
project: {
visibility: 'public',
},
};
const findLastUpdatedAndVisibility = () => wrapper.find('[data-testid="updated-and-visibility"]');
const waitForMetadataItems = async () => {
// Metadata items are printed by a loop in the title-area and it takes two ticks for them to be available
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick();
};
const mountComponent = (image = defaultImage) => {
wrapper = shallowMount(component, { wrapper = shallowMount(component, {
propsData, propsData: {
image,
},
stubs: { stubs: {
GlSprintf, GlSprintf,
TitleArea, TitleArea,
...@@ -23,12 +41,34 @@ describe('Details Header', () => { ...@@ -23,12 +41,34 @@ describe('Details Header', () => {
}); });
it('has the correct title ', () => { it('has the correct title ', () => {
mountComponent(); mountComponent({ ...defaultImage, name: '' });
expect(wrapper.text()).toMatchInterpolatedText(DETAILS_PAGE_TITLE); expect(wrapper.text()).toMatchInterpolatedText(DETAILS_PAGE_TITLE);
}); });
it('shows imageName in the title', () => { it('shows imageName in the title', () => {
mountComponent({ imageName: 'foo' }); mountComponent();
expect(wrapper.text()).toContain('foo'); expect(wrapper.text()).toContain('foo');
}); });
it('has a metadata item with last updated text', async () => {
mountComponent();
await waitForMetadataItems();
expect(findLastUpdatedAndVisibility().props('text')).toBe('Last updated 1 month ago');
});
describe('visibility icon', () => {
it('shows an eye when the project is public', async () => {
mountComponent();
await waitForMetadataItems();
expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye');
});
it('shows an eye slashed when the project is not public', async () => {
mountComponent({ ...defaultImage, project: { visibility: 'private' } });
await waitForMetadataItems();
expect(findLastUpdatedAndVisibility().props('icon')).toBe('eye-slash');
});
});
}); });
...@@ -114,8 +114,13 @@ export const containerRepositoryMock = { ...@@ -114,8 +114,13 @@ export const containerRepositoryMock = {
location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009', location: 'host.docker.internal:5000/gitlab-org/gitlab-test/rails-12009',
canDelete: true, canDelete: true,
createdAt: '2020-11-03T13:29:21Z', createdAt: '2020-11-03T13:29:21Z',
updatedAt: '2020-11-03T13:29:21Z',
tagsCount: 13, tagsCount: 13,
expirationPolicyStartedAt: null, expirationPolicyStartedAt: null,
project: {
visibility: 'public',
__typename: 'Project',
},
}; };
export const tagsPageInfo = { export const tagsPageInfo = {
......
...@@ -353,7 +353,12 @@ describe('Details Page', () => { ...@@ -353,7 +353,12 @@ describe('Details Page', () => {
mountComponent(); mountComponent();
await waitForApolloRequestRender(); await waitForApolloRequestRender();
expect(findDetailsHeader().props()).toEqual({ imageName: containerRepositoryMock.name }); expect(findDetailsHeader().props('image')).toMatchObject({
name: containerRepositoryMock.name,
project: {
visibility: containerRepositoryMock.project.visibility,
},
});
}); });
}); });
......
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