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
f5c1aa66
Commit
f5c1aa66
authored
Nov 06, 2020
by
Nicolò Maria Mezzopera
Committed by
Mark Florian
Nov 06, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for dynamic slots
- source - tests
parent
9fc33b59
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
110 additions
and
6 deletions
+110
-6
app/assets/javascripts/packages/details/components/package_title.vue
...javascripts/packages/details/components/package_title.vue
+31
-4
app/assets/javascripts/vue_shared/components/registry/title_area.vue
...javascripts/vue_shared/components/registry/title_area.vue
+7
-2
changelogs/unreleased/238594-package-detail-on-mobile-view-is-impossible-to-see-multiple-tags.yml
...ail-on-mobile-view-is-impossible-to-see-multiple-tags.yml
+5
-0
spec/frontend/packages/details/components/package_title_spec.js
...rontend/packages/details/components/package_title_spec.js
+10
-0
spec/frontend/vue_shared/components/registry/title_area_spec.js
...rontend/vue_shared/components/registry/title_area_spec.js
+57
-0
No files found.
app/assets/javascripts/packages/details/components/package_title.vue
View file @
f5c1aa66
<
script
>
<
script
>
/* eslint-disable vue/v-slot-style */
import
{
mapState
,
mapGetters
}
from
'
vuex
'
;
import
{
mapState
,
mapGetters
}
from
'
vuex
'
;
import
{
GlIcon
,
GlSprintf
,
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
{
GlIcon
,
GlSprintf
,
GlTooltipDirective
,
GlBadge
}
from
'
@gitlab/ui
'
;
import
{
GlBreakpointInstance
}
from
'
@gitlab/ui/dist/utils
'
;
import
PackageTags
from
'
../../shared/components/package_tags.vue
'
;
import
PackageTags
from
'
../../shared/components/package_tags.vue
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
{
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
...
@@ -16,11 +18,20 @@ export default {
...
@@ -16,11 +18,20 @@ export default {
GlSprintf
,
GlSprintf
,
PackageTags
,
PackageTags
,
MetadataItem
,
MetadataItem
,
GlBadge
,
},
},
directives
:
{
directives
:
{
GlTooltip
:
GlTooltipDirective
,
GlTooltip
:
GlTooltipDirective
,
},
},
mixins
:
[
timeagoMixin
],
mixins
:
[
timeagoMixin
],
i18n
:
{
packageInfo
:
__
(
'
v%{version} published %{timeAgo}
'
),
},
data
()
{
return
{
isDesktop
:
true
,
};
},
computed
:
{
computed
:
{
...
mapState
([
'
packageEntity
'
,
'
packageFiles
'
]),
...
mapState
([
'
packageEntity
'
,
'
packageFiles
'
]),
...
mapGetters
([
'
packageTypeDisplay
'
,
'
packagePipeline
'
,
'
packageIcon
'
]),
...
mapGetters
([
'
packageTypeDisplay
'
,
'
packagePipeline
'
,
'
packageIcon
'
]),
...
@@ -31,8 +42,13 @@ export default {
...
@@ -31,8 +42,13 @@ export default {
return
numberToHumanSize
(
this
.
packageFiles
.
reduce
((
acc
,
p
)
=>
acc
+
p
.
size
,
0
));
return
numberToHumanSize
(
this
.
packageFiles
.
reduce
((
acc
,
p
)
=>
acc
+
p
.
size
,
0
));
},
},
},
},
i18n
:
{
mounted
()
{
packageInfo
:
__
(
'
v%{version} published %{timeAgo}
'
),
this
.
isDesktop
=
GlBreakpointInstance
.
isDesktop
();
},
methods
:
{
dynamicSlotName
(
index
)
{
return
`metadata-tag
${
index
}
`
;
},
},
},
};
};
</
script
>
</
script
>
...
@@ -75,10 +91,21 @@ export default {
...
@@ -75,10 +91,21 @@ export default {
<metadata-item
data-testid=
"package-ref"
icon=
"branch"
:text=
"packagePipeline.ref"
/>
<metadata-item
data-testid=
"package-ref"
icon=
"branch"
:text=
"packagePipeline.ref"
/>
</
template
>
</
template
>
<
template
v-if=
"hasTagsToDisplay"
#metadata-tags
>
<
template
v-if=
"
isDesktop &&
hasTagsToDisplay"
#metadata-tags
>
<package-tags
:tag-display-limit=
"2"
:tags=
"packageEntity.tags"
hide-label
/>
<package-tags
:tag-display-limit=
"2"
:tags=
"packageEntity.tags"
hide-label
/>
</
template
>
</
template
>
<!-- we need to duplicate the package tags on mobile to ensure proper styling inside the flex wrap -->
<
template
v-for=
"(tag, index) in packageEntity.tags"
v-else-if=
"hasTagsToDisplay"
v-slot:
[
dynamicSlotName
(
index
)]
>
<gl-badge
:key=
"index"
class=
"gl-my-1"
data-testid=
"tag-badge"
variant=
"info"
size=
"sm"
>
{{
tag
.
name
}}
</gl-badge>
</
template
>
<
template
#right-actions
>
<
template
#right-actions
>
<slot
name=
"delete-button"
></slot>
<slot
name=
"delete-button"
></slot>
</
template
>
</
template
>
...
...
app/assets/javascripts/vue_shared/components/registry/title_area.vue
View file @
f5c1aa66
...
@@ -30,8 +30,13 @@ export default {
...
@@ -30,8 +30,13 @@ export default {
metadataSlots
:
[],
metadataSlots
:
[],
};
};
},
},
mounted
()
{
async
mounted
()
{
this
.
metadataSlots
=
Object
.
keys
(
this
.
$slots
).
filter
(
k
=>
k
.
startsWith
(
'
metadata-
'
));
const
METADATA_PREFIX
=
'
metadata-
'
;
this
.
metadataSlots
=
Object
.
keys
(
this
.
$slots
).
filter
(
k
=>
k
.
startsWith
(
METADATA_PREFIX
));
// we need to wait for next tick to ensure that dynamic names slots are picked up
await
this
.
$nextTick
();
this
.
metadataSlots
=
Object
.
keys
(
this
.
$slots
).
filter
(
k
=>
k
.
startsWith
(
METADATA_PREFIX
));
},
},
};
};
</
script
>
</
script
>
...
...
changelogs/unreleased/238594-package-detail-on-mobile-view-is-impossible-to-see-multiple-tags.yml
0 → 100644
View file @
f5c1aa66
---
title
:
'
Package
details:
on
mobile
show
all
the
tags'
merge_request
:
46679
author
:
type
:
changed
spec/frontend/packages/details/components/package_title_spec.js
View file @
f5c1aa66
import
Vuex
from
'
vuex
'
;
import
Vuex
from
'
vuex
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
GlBreakpointInstance
}
from
'
@gitlab/ui/dist/utils
'
;
import
PackageTitle
from
'
~/packages/details/components/package_title.vue
'
;
import
PackageTitle
from
'
~/packages/details/components/package_title.vue
'
;
import
PackageTags
from
'
~/packages/shared/components/package_tags.vue
'
;
import
PackageTags
from
'
~/packages/shared/components/package_tags.vue
'
;
import
TitleArea
from
'
~/vue_shared/components/registry/title_area.vue
'
;
import
TitleArea
from
'
~/vue_shared/components/registry/title_area.vue
'
;
...
@@ -53,6 +54,7 @@ describe('PackageTitle', () => {
...
@@ -53,6 +54,7 @@ describe('PackageTitle', () => {
const
pipelineProject
=
()
=>
wrapper
.
find
(
'
[data-testid="pipeline-project"]
'
);
const
pipelineProject
=
()
=>
wrapper
.
find
(
'
[data-testid="pipeline-project"]
'
);
const
packageRef
=
()
=>
wrapper
.
find
(
'
[data-testid="package-ref"]
'
);
const
packageRef
=
()
=>
wrapper
.
find
(
'
[data-testid="package-ref"]
'
);
const
packageTags
=
()
=>
wrapper
.
find
(
PackageTags
);
const
packageTags
=
()
=>
wrapper
.
find
(
PackageTags
);
const
packageBadges
=
()
=>
wrapper
.
findAll
(
'
[data-testid="tag-badge"]
'
);
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
...
@@ -70,6 +72,14 @@ describe('PackageTitle', () => {
...
@@ -70,6 +72,14 @@ describe('PackageTitle', () => {
expect
(
wrapper
.
element
).
toMatchSnapshot
();
expect
(
wrapper
.
element
).
toMatchSnapshot
();
});
});
it
(
'
with tags on mobile
'
,
async
()
=>
{
jest
.
spyOn
(
GlBreakpointInstance
,
'
isDesktop
'
).
mockReturnValue
(
false
);
await
createComponent
({
packageEntity
:
{
...
mavenPackage
,
tags
:
mockTags
}
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
packageBadges
()).
toHaveLength
(
mockTags
.
length
);
});
});
});
describe
(
'
package title
'
,
()
=>
{
describe
(
'
package title
'
,
()
=>
{
...
...
spec/frontend/vue_shared/components/registry/title_area_spec.js
View file @
f5c1aa66
...
@@ -5,12 +5,16 @@ import component from '~/vue_shared/components/registry/title_area.vue';
...
@@ -5,12 +5,16 @@ import component from '~/vue_shared/components/registry/title_area.vue';
describe
(
'
title area
'
,
()
=>
{
describe
(
'
title area
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
const
DYNAMIC_SLOT
=
'
metadata-dynamic-slot
'
;
const
findSubHeaderSlot
=
()
=>
wrapper
.
find
(
'
[data-testid="sub-header"]
'
);
const
findSubHeaderSlot
=
()
=>
wrapper
.
find
(
'
[data-testid="sub-header"]
'
);
const
findRightActionsSlot
=
()
=>
wrapper
.
find
(
'
[data-testid="right-actions"]
'
);
const
findRightActionsSlot
=
()
=>
wrapper
.
find
(
'
[data-testid="right-actions"]
'
);
const
findMetadataSlot
=
name
=>
wrapper
.
find
(
`[data-testid="
${
name
}
"]`
);
const
findMetadataSlot
=
name
=>
wrapper
.
find
(
`[data-testid="
${
name
}
"]`
);
const
findTitle
=
()
=>
wrapper
.
find
(
'
[data-testid="title"]
'
);
const
findTitle
=
()
=>
wrapper
.
find
(
'
[data-testid="title"]
'
);
const
findAvatar
=
()
=>
wrapper
.
find
(
GlAvatar
);
const
findAvatar
=
()
=>
wrapper
.
find
(
GlAvatar
);
const
findInfoMessages
=
()
=>
wrapper
.
findAll
(
'
[data-testid="info-message"]
'
);
const
findInfoMessages
=
()
=>
wrapper
.
findAll
(
'
[data-testid="info-message"]
'
);
const
findDynamicSlot
=
()
=>
wrapper
.
find
(
`[data-testid="
${
DYNAMIC_SLOT
}
`
);
const
findSlotOrderElements
=
()
=>
wrapper
.
findAll
(
'
[slot-test]
'
);
const
mountComponent
=
({
propsData
=
{
title
:
'
foo
'
},
slots
}
=
{})
=>
{
const
mountComponent
=
({
propsData
=
{
title
:
'
foo
'
},
slots
}
=
{})
=>
{
wrapper
=
shallowMount
(
component
,
{
wrapper
=
shallowMount
(
component
,
{
...
@@ -98,6 +102,59 @@ describe('title area', () => {
...
@@ -98,6 +102,59 @@ describe('title area', () => {
});
});
});
});
describe
(
'
dynamic slots
'
,
()
=>
{
const
createDynamicSlot
=
()
=>
{
return
wrapper
.
vm
.
$createElement
(
'
div
'
,
{
attrs
:
{
'
data-testid
'
:
DYNAMIC_SLOT
,
'
slot-test
'
:
true
,
},
});
};
it
(
'
shows dynamic slots
'
,
async
()
=>
{
mountComponent
();
// we manually add a new slot to simulate dynamic slots being evaluated after the initial mount
wrapper
.
vm
.
$slots
[
DYNAMIC_SLOT
]
=
createDynamicSlot
();
await
wrapper
.
vm
.
$nextTick
();
expect
(
findDynamicSlot
().
exists
()).
toBe
(
false
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findDynamicSlot
().
exists
()).
toBe
(
true
);
});
it
(
'
preserve the order of the slots
'
,
async
()
=>
{
mountComponent
({
slots
:
{
'
metadata-foo
'
:
'
<div slot-test data-testid="metadata-foo"></div>
'
,
},
});
// rewrite slot putting dynamic slot as first
wrapper
.
vm
.
$slots
=
{
'
metadata-dynamic-slot
'
:
createDynamicSlot
(),
'
metadata-foo
'
:
wrapper
.
vm
.
$slots
[
'
metadata-foo
'
],
};
await
wrapper
.
vm
.
$nextTick
();
expect
(
findDynamicSlot
().
exists
()).
toBe
(
false
);
expect
(
findMetadataSlot
(
'
metadata-foo
'
).
exists
()).
toBe
(
true
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findSlotOrderElements
()
.
at
(
0
)
.
attributes
(
'
data-testid
'
),
).
toBe
(
DYNAMIC_SLOT
);
expect
(
findSlotOrderElements
()
.
at
(
1
)
.
attributes
(
'
data-testid
'
),
).
toBe
(
'
metadata-foo
'
);
});
});
describe
(
'
info-messages
'
,
()
=>
{
describe
(
'
info-messages
'
,
()
=>
{
it
(
'
shows a message when the props contains one
'
,
()
=>
{
it
(
'
shows a message when the props contains one
'
,
()
=>
{
mountComponent
({
propsData
:
{
infoMessages
:
[{
text
:
'
foo foo bar bar
'
}]
}
});
mountComponent
({
propsData
:
{
infoMessages
:
[{
text
:
'
foo foo bar bar
'
}]
}
});
...
...
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