Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
9b06a994
Commit
9b06a994
authored
Jul 10, 2020
by
Nicolò Maria Mezzopera
Committed by
Martin Wortschack
Jul 10, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add broken tag state to tag list item
- update component - adjust tests
parent
ff479a15
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
133 additions
and
41 deletions
+133
-41
app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue
...gistry/explorer/components/details_page/tags_list_row.vue
+24
-7
app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue
...registry/explorer/components/list_page/image_list_row.vue
+1
-1
app/assets/javascripts/registry/explorer/constants/details.js
...assets/javascripts/registry/explorer/constants/details.js
+7
-1
changelogs/unreleased/227558-missing-digest-revision-and-short-revision-in-tags.yml
...58-missing-digest-revision-and-short-revision-in-tags.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+9
-0
spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
...ry/explorer/components/details_page/tags_list_row_spec.js
+87
-32
No files found.
app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue
View file @
9b06a994
<
script
>
import
{
GlFormCheckbox
,
GlTooltipDirective
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
GlFormCheckbox
,
GlTooltipDirective
,
GlSprintf
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
n__
}
from
'
~/locale
'
;
import
ClipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
...
...
@@ -16,12 +16,16 @@ import {
PUBLISHED_DETAILS_ROW_TEXT
,
MANIFEST_DETAILS_ROW_TEST
,
CONFIGURATION_DETAILS_ROW_TEST
,
MISSING_MANIFEST_WARNING_TOOLTIP
,
NOT_AVAILABLE_TEXT
,
NOT_AVAILABLE_SIZE
,
}
from
'
../../constants/index
'
;
export
default
{
components
:
{
GlSprintf
,
GlFormCheckbox
,
GlIcon
,
DeleteButton
,
ListItem
,
ClipboardButton
,
...
...
@@ -55,10 +59,11 @@ export default {
PUBLISHED_DETAILS_ROW_TEXT
,
MANIFEST_DETAILS_ROW_TEST
,
CONFIGURATION_DETAILS_ROW_TEST
,
MISSING_MANIFEST_WARNING_TOOLTIP
,
},
computed
:
{
formattedSize
()
{
return
this
.
tag
.
total_size
?
numberToHumanSize
(
this
.
tag
.
total_size
)
:
''
;
return
this
.
tag
.
total_size
?
numberToHumanSize
(
this
.
tag
.
total_size
)
:
NOT_AVAILABLE_SIZE
;
},
layers
()
{
return
this
.
tag
.
layers
?
n__
(
'
%d layer
'
,
'
%d layers
'
,
this
.
tag
.
layers
)
:
''
;
...
...
@@ -68,7 +73,7 @@ export default {
},
shortDigest
()
{
// remove sha256: from the string, and show only the first 7 char
return
this
.
tag
.
digest
?.
substring
(
7
,
14
);
return
this
.
tag
.
digest
?.
substring
(
7
,
14
)
??
NOT_AVAILABLE_TEXT
;
},
publishedDate
()
{
return
formatDate
(
this
.
tag
.
created_at
,
'
isoDate
'
);
...
...
@@ -85,6 +90,9 @@ export default {
tagLocation
()
{
return
this
.
tag
.
path
?.
replace
(
`:
${
this
.
tag
.
name
}
`
,
''
);
},
invalidTag
()
{
return
!
this
.
tag
.
digest
;
},
},
};
</
script
>
...
...
@@ -94,6 +102,7 @@ export default {
<template
#left-action
>
<gl-form-checkbox
v-if=
"Boolean(tag.destroy_path)"
:disabled=
"invalidTag"
class=
"gl-m-0"
:checked=
"selected"
@
change=
"$emit('select')"
...
...
@@ -116,6 +125,13 @@ export default {
:text=
"tag.location"
css-class=
"btn-default btn-transparent btn-clipboard"
/>
<gl-icon
v-if=
"invalidTag"
v-gl-tooltip=
"
{ title: $options.i18n.MISSING_MANIFEST_WARNING_TOOLTIP }"
name="warning"
class="gl-text-orange-500 gl-mb-2 gl-ml-2"
/>
</div>
</
template
>
...
...
@@ -146,7 +162,7 @@ export default {
</template>
<
template
#right-action
>
<delete-button
:disabled=
"!tag.destroy_path"
:disabled=
"!tag.destroy_path
|| invalidTag
"
:title=
"$options.i18n.REMOVE_TAG_BUTTON_TITLE"
:tooltip-title=
"$options.i18n.REMOVE_TAG_BUTTON_DISABLE_TOOLTIP"
:tooltip-disabled=
"Boolean(tag.destroy_path)"
...
...
@@ -154,7 +170,8 @@ export default {
@
delete=
"$emit('delete')"
/>
</
template
>
<
template
#details_published
>
<
template
v-if=
"!invalidTag"
#details_published
>
<details-row
icon=
"clock"
data-testid=
"published-date-detail"
>
<gl-sprintf
:message=
"$options.i18n.PUBLISHED_DETAILS_ROW_TEXT"
>
<template
#repositoryPath
>
...
...
@@ -169,7 +186,7 @@ export default {
</gl-sprintf>
</details-row>
</template>
<
template
#details_manifest_digest
>
<
template
v-if=
"!invalidTag"
#details_manifest_digest
>
<details-row
icon=
"log"
data-testid=
"manifest-detail"
>
<gl-sprintf
:message=
"$options.i18n.MANIFEST_DETAILS_ROW_TEST"
>
<template
#digest
>
...
...
@@ -184,7 +201,7 @@ export default {
/>
</details-row>
</template>
<
template
#details_configuration_digest
>
<
template
v-if=
"!invalidTag"
#details_configuration_digest
>
<details-row
icon=
"cloud-gear"
data-testid=
"configuration-detail"
>
<gl-sprintf
:message=
"$options.i18n.CONFIGURATION_DETAILS_ROW_TEST"
>
<template
#digest
>
...
...
app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue
View file @
9b06a994
...
...
@@ -88,7 +88,7 @@ export default {
v-if=
"item.failedDelete"
v-gl-tooltip=
"
{ title: $options.i18n.ASYNC_DELETE_IMAGE_ERROR_MESSAGE }"
name="warning"
class="
text-warning
"
class="
gl-text-orange-500
"
/>
</
template
>
<
template
#left-secondary
>
...
...
app/assets/javascripts/registry/explorer/constants/details.js
View file @
9b06a994
import
{
s__
}
from
'
~/locale
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
// Translations strings
export
const
DETAILS_PAGE_TITLE
=
s__
(
'
ContainerRegistry|%{imageName} tags
'
);
...
...
@@ -48,6 +48,12 @@ export const REMOVE_TAG_BUTTON_DISABLE_TOOLTIP = s__(
'
ContainerRegistry|Deletion disabled due to missing or insufficient permissions.
'
,
);
export
const
MISSING_MANIFEST_WARNING_TOOLTIP
=
s__
(
'
ContainerRegistry|Invalid tag: missing manifest digest
'
,
);
export
const
NOT_AVAILABLE_TEXT
=
__
(
'
N/A
'
);
export
const
NOT_AVAILABLE_SIZE
=
__
(
'
0 bytes
'
);
// Parameters
export
const
DEFAULT_PAGE
=
1
;
...
...
changelogs/unreleased/227558-missing-digest-revision-and-short-revision-in-tags.yml
0 → 100644
View file @
9b06a994
---
title
:
Add broken tag state to tags list items
merge_request
:
36442
author
:
type
:
changed
locale/gitlab.pot
View file @
9b06a994
...
...
@@ -824,6 +824,9 @@ msgstr ""
msgid "- show less"
msgstr ""
msgid "0 bytes"
msgstr ""
msgid "0 for unlimited"
msgstr ""
...
...
@@ -6294,6 +6297,9 @@ msgstr ""
msgid "ContainerRegistry|Image tags"
msgstr ""
msgid "ContainerRegistry|Invalid tag: missing manifest digest"
msgstr ""
msgid "ContainerRegistry|Login"
msgstr ""
...
...
@@ -15062,6 +15068,9 @@ msgstr ""
msgid "My-Reaction"
msgstr ""
msgid "N/A"
msgstr ""
msgid "Name"
msgstr ""
...
...
spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
View file @
9b06a994
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
GlFormCheckbox
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
GlFormCheckbox
,
GlSprintf
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
ClipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
import
TimeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
...
...
@@ -9,6 +9,9 @@ import DetailsRow from '~/registry/explorer/components/details_page/details_row.
import
{
REMOVE_TAG_BUTTON_TITLE
,
REMOVE_TAG_BUTTON_DISABLE_TOOLTIP
,
MISSING_MANIFEST_WARNING_TOOLTIP
,
NOT_AVAILABLE_TEXT
,
NOT_AVAILABLE_SIZE
,
}
from
'
~/registry/explorer/constants/index
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
...
...
@@ -33,6 +36,7 @@ describe('tags list row', () => {
const
findPublishedDateDetail
=
()
=>
wrapper
.
find
(
'
[data-testid="published-date-detail"]
'
);
const
findManifestDetail
=
()
=>
wrapper
.
find
(
'
[data-testid="manifest-detail"]
'
);
const
findConfigurationDetail
=
()
=>
wrapper
.
find
(
'
[data-testid="configuration-detail"]
'
);
const
findWarningIcon
=
()
=>
wrapper
.
find
(
GlIcon
);
const
mountComponent
=
(
propsData
=
defaultProps
)
=>
{
wrapper
=
shallowMount
(
component
,
{
...
...
@@ -68,6 +72,11 @@ describe('tags list row', () => {
expect
(
findCheckbox
().
exists
()).
toBe
(
false
);
});
it
(
'
is disabled when the digest is missing
'
,
()
=>
{
mountComponent
({
tag
:
{
...
tag
,
digest
:
null
}
});
expect
(
findCheckbox
().
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
});
it
(
'
is wired to the selected prop
'
,
()
=>
{
mountComponent
({
...
defaultProps
,
selected
:
true
});
...
...
@@ -134,6 +143,27 @@ describe('tags list row', () => {
});
});
describe
(
'
warning icon
'
,
()
=>
{
it
(
'
is normally hidden
'
,
()
=>
{
mountComponent
();
expect
(
findWarningIcon
().
exists
()).
toBe
(
false
);
});
it
(
'
is shown when the tag is broken
'
,
()
=>
{
mountComponent
({
tag
:
{
...
tag
,
digest
:
null
}
});
expect
(
findWarningIcon
().
exists
()).
toBe
(
true
);
});
it
(
'
has an appropriate tooltip
'
,
()
=>
{
mountComponent
({
tag
:
{
...
tag
,
digest
:
null
}
});
const
tooltip
=
getBinding
(
findWarningIcon
().
element
,
'
gl-tooltip
'
);
expect
(
tooltip
.
value
.
title
).
toBe
(
MISSING_MANIFEST_WARNING_TOOLTIP
);
});
});
describe
(
'
size
'
,
()
=>
{
it
(
'
exists
'
,
()
=>
{
mountComponent
();
...
...
@@ -150,7 +180,7 @@ describe('tags list row', () => {
it
(
'
when total_size is missing
'
,
()
=>
{
mountComponent
();
expect
(
findSize
().
text
()).
toMatchInterpolatedText
(
'
10 layers
'
);
expect
(
findSize
().
text
()).
toMatchInterpolatedText
(
`
${
NOT_AVAILABLE_SIZE
}
· 10 layers`
);
});
it
(
'
when layers are missing
'
,
()
=>
{
...
...
@@ -162,7 +192,7 @@ describe('tags list row', () => {
it
(
'
when there is 1 layer
'
,
()
=>
{
mountComponent
({
...
defaultProps
,
tag
:
{
...
tag
,
layers
:
1
}
});
expect
(
findSize
().
text
()).
toMatchInterpolatedText
(
'
1 layer
'
);
expect
(
findSize
().
text
()).
toMatchInterpolatedText
(
`
${
NOT_AVAILABLE_SIZE
}
· 1 layer`
);
});
});
...
...
@@ -204,6 +234,12 @@ describe('tags list row', () => {
expect
(
findShortRevision
().
text
()).
toMatchInterpolatedText
(
'
Digest: 1ab51d5
'
);
});
it
(
`displays
${
NOT_AVAILABLE_TEXT
}
when digest is missing`
,
()
=>
{
mountComponent
({
tag
:
{
...
tag
,
digest
:
null
}
});
expect
(
findShortRevision
().
text
()).
toMatchInterpolatedText
(
`Digest:
${
NOT_AVAILABLE_TEXT
}
`
);
});
});
describe
(
'
delete button
'
,
()
=>
{
...
...
@@ -223,11 +259,19 @@ describe('tags list row', () => {
});
});
it
(
'
is disabled when tag has no destroy path
'
,
()
=>
{
mountComponent
({
...
defaultProps
,
tag
:
{
...
tag
,
destroy_path
:
null
}
});
it
.
each
`
destroy_path | digest
${
'
foo
'
}
|
${
null
}
${
null
}
|
${
'
foo
'
}
${
null
}
|
${
null
}
`
(
'
is disabled when destroy_path is $destroy_path and digest is $digest
'
,
({
destroy_path
,
digest
})
=>
{
mountComponent
({
...
defaultProps
,
tag
:
{
...
tag
,
destroy_path
,
digest
}
});
expect
(
findDeleteButton
().
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
});
},
);
it
(
'
delete event emits delete
'
,
()
=>
{
mountComponent
();
...
...
@@ -239,6 +283,7 @@ describe('tags list row', () => {
});
describe
(
'
details rows
'
,
()
=>
{
describe
(
'
when the tag has a digest
'
,
()
=>
{
beforeEach
(()
=>
{
mountComponent
();
...
...
@@ -272,4 +317,14 @@ describe('tags list row', () => {
});
});
});
describe
(
'
when the tag does not have a digest
'
,
()
=>
{
it
(
'
hides the details rows
'
,
async
()
=>
{
mountComponent
({
tag
:
{
...
tag
,
digest
:
null
}
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findDetailsRows
().
length
).
toBe
(
0
);
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment