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
9733f3cc
Commit
9733f3cc
authored
Nov 07, 2019
by
Nathan Friend
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add footer to release blocks
This commit adds a footer to each release block on the Releases page.
parent
485c10ab
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
310 additions
and
4 deletions
+310
-4
app/assets/javascripts/releases/list/components/release_block.vue
...ts/javascripts/releases/list/components/release_block.vue
+17
-1
app/assets/javascripts/releases/list/components/release_block_footer.vue
...scripts/releases/list/components/release_block_footer.vue
+112
-0
app/controllers/projects/releases_controller.rb
app/controllers/projects/releases_controller.rb
+1
-0
changelogs/unreleased/nfriend-move-release-data-into-footer.yml
...logs/unreleased/nfriend-move-release-data-into-footer.yml
+5
-0
spec/frontend/releases/list/components/release_block_footer_spec.js
...end/releases/list/components/release_block_footer_spec.js
+163
-0
spec/frontend/releases/list/components/release_block_spec.js
spec/frontend/releases/list/components/release_block_spec.js
+10
-3
spec/frontend/releases/mock_data.js
spec/frontend/releases/mock_data.js
+2
-0
No files found.
app/assets/javascripts/releases/list/components/release_block.vue
View file @
9733f3cc
...
...
@@ -10,6 +10,7 @@ import { slugify } from '~/lib/utils/text_utility';
import
{
getLocationHash
}
from
'
~/lib/utils/url_utility
'
;
import
{
scrollToElement
}
from
'
~/lib/utils/common_utils
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
ReleaseBlockFooter
from
'
./release_block_footer.vue
'
;
export
default
{
name
:
'
ReleaseBlock
'
,
...
...
@@ -19,6 +20,7 @@ export default {
GlButton
,
Icon
,
UserAvatarLink
,
ReleaseBlockFooter
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
...
...
@@ -79,6 +81,9 @@ export default {
this
.
glFeatures
.
releaseEditPage
&&
this
.
release
.
_links
&&
this
.
release
.
_links
.
edit_url
,
);
},
shouldShowFooter
()
{
return
this
.
glFeatures
.
releaseIssueSummary
;
},
},
mounted
()
{
const
hash
=
getLocationHash
();
...
...
@@ -164,7 +169,7 @@ export default {
by
<user-avatar-link
class=
"prepend-left-4"
:link-href=
"author.
path
"
:link-href=
"author.
web_url
"
:img-src=
"author.avatar_url"
:img-alt=
"userImageAltDescription"
:tooltip-text=
"author.username"
...
...
@@ -216,5 +221,16 @@ export default {
<div
v-html=
"release.description_html"
></div>
</div>
</div>
<release-block-footer
v-if=
"shouldShowFooter"
class=
"card-footer"
:commit=
"release.commit"
:commit-path=
"release.commit_path"
:tag-name=
"release.tag_name"
:tag-path=
"release.tag_path"
:author=
"release.author"
:released-at=
"release.released_at"
/>
</div>
</template>
app/assets/javascripts/releases/list/components/release_block_footer.vue
0 → 100644
View file @
9733f3cc
<
script
>
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
GlTooltipDirective
,
GlLink
}
from
'
@gitlab/ui
'
;
import
UserAvatarLink
from
'
~/vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
export
default
{
name
:
'
ReleaseBlockFooter
'
,
components
:
{
Icon
,
GlLink
,
UserAvatarLink
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
mixins
:
[
timeagoMixin
],
props
:
{
commit
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
commitPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tagName
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tagPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
author
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
releasedAt
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
computed
:
{
releasedAtTimeAgo
()
{
return
this
.
timeFormated
(
this
.
releasedAt
);
},
userImageAltDescription
()
{
return
this
.
author
&&
this
.
author
.
username
?
sprintf
(
__
(
"
%{username}'s avatar
"
),
{
username
:
this
.
author
.
username
})
:
null
;
},
},
};
</
script
>
<
template
>
<div>
<div
v-if=
"commit"
class=
"float-left mr-3 d-flex align-items-center js-commit-info"
>
<icon
ref=
"commitIcon"
name=
"commit"
class=
"mr-1"
/>
<div
v-gl-tooltip
.
bottom
:title=
"commit.title"
>
<gl-link
v-if=
"commitPath"
:href=
"commitPath"
>
{{
commit
.
short_id
}}
</gl-link>
<span
v-else
>
{{
commit
.
short_id
}}
</span>
</div>
</div>
<div
v-if=
"tagName"
class=
"float-left mr-3 d-flex align-items-center js-tag-info"
>
<icon
name=
"tag"
class=
"mr-1"
/>
<div
v-gl-tooltip
.
bottom
:title=
"__('Tag')"
>
<gl-link
v-if=
"tagPath"
:href=
"tagPath"
>
{{
tagName
}}
</gl-link>
<span
v-else
>
{{
tagName
}}
</span>
</div>
</div>
<div
v-if=
"releasedAt || author"
class=
"float-left d-flex align-items-center js-author-date-info"
>
<span
class=
"text-secondary"
>
{{
__
(
'
Created
'
)
}}
</span>
<template
v-if=
"releasedAt"
>
<span
v-gl-tooltip
.
bottom
:title=
"tooltipTitle(releasedAt)"
class=
"text-secondary flex-shrink-0"
>
{{
releasedAtTimeAgo
}}
</span>
</
template
>
<div
v-if=
"author"
class=
"d-flex"
>
<span
class=
"text-secondary"
>
{{ __('by') }}
</span>
<user-avatar-link
:link-href=
"author.web_url"
:img-src=
"author.avatar_url"
:img-alt=
"userImageAltDescription"
:tooltip-text=
"author.username"
tooltip-placement=
"bottom"
/>
</div>
</div>
</div>
</template>
app/controllers/projects/releases_controller.rb
View file @
9733f3cc
...
...
@@ -7,6 +7,7 @@ class Projects::ReleasesController < Projects::ApplicationController
before_action
:authorize_read_release!
before_action
do
push_frontend_feature_flag
(
:release_edit_page
,
project
)
push_frontend_feature_flag
(
:release_issue_summary
,
project
)
end
before_action
:authorize_update_release!
,
only:
%i[edit update]
...
...
changelogs/unreleased/nfriend-move-release-data-into-footer.yml
0 → 100644
View file @
9733f3cc
---
title
:
Move release meta-data into footer on Releases page
merge_request
:
19451
author
:
type
:
changed
spec/frontend/releases/list/components/release_block_footer_spec.js
0 → 100644
View file @
9733f3cc
import
{
mount
}
from
'
@vue/test-utils
'
;
import
ReleaseBlockFooter
from
'
~/releases/list/components/release_block_footer.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
GlLink
}
from
'
@gitlab/ui
'
;
import
{
trimText
}
from
'
helpers/text_helper
'
;
import
{
release
}
from
'
../../mock_data
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
jest
.
mock
(
'
~/vue_shared/mixins/timeago
'
,
()
=>
({
methods
:
{
timeFormated
()
{
return
'
7 fortnightes ago
'
;
},
tooltipTitle
()
{
return
'
February 30, 2401
'
;
},
},
}));
describe
(
'
Release block footer
'
,
()
=>
{
let
wrapper
;
let
releaseClone
;
const
factory
=
(
props
=
{})
=>
{
wrapper
=
mount
(
ReleaseBlockFooter
,
{
propsData
:
{
...
convertObjectPropsToCamelCase
(
releaseClone
),
...
props
,
},
sync
:
false
,
});
return
wrapper
.
vm
.
$nextTick
();
};
beforeEach
(()
=>
{
releaseClone
=
JSON
.
parse
(
JSON
.
stringify
(
release
));
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
const
commitInfoSection
=
()
=>
wrapper
.
find
(
'
.js-commit-info
'
);
const
commitInfoSectionLink
=
()
=>
commitInfoSection
().
find
(
GlLink
);
const
tagInfoSection
=
()
=>
wrapper
.
find
(
'
.js-tag-info
'
);
const
tagInfoSectionLink
=
()
=>
tagInfoSection
().
find
(
GlLink
);
const
authorDateInfoSection
=
()
=>
wrapper
.
find
(
'
.js-author-date-info
'
);
describe
(
'
with all props provided
'
,
()
=>
{
beforeEach
(()
=>
factory
());
it
(
'
renders the commit icon
'
,
()
=>
{
const
commitIcon
=
commitInfoSection
().
find
(
Icon
);
expect
(
commitIcon
.
exists
()).
toBe
(
true
);
expect
(
commitIcon
.
props
(
'
name
'
)).
toBe
(
'
commit
'
);
});
it
(
'
renders the commit SHA with a link
'
,
()
=>
{
const
commitLink
=
commitInfoSectionLink
();
expect
(
commitLink
.
exists
()).
toBe
(
true
);
expect
(
commitLink
.
text
()).
toBe
(
releaseClone
.
commit
.
short_id
);
expect
(
commitLink
.
attributes
(
'
href
'
)).
toBe
(
releaseClone
.
commit_path
);
});
it
(
'
renders the tag icon
'
,
()
=>
{
const
commitIcon
=
tagInfoSection
().
find
(
Icon
);
expect
(
commitIcon
.
exists
()).
toBe
(
true
);
expect
(
commitIcon
.
props
(
'
name
'
)).
toBe
(
'
tag
'
);
});
it
(
'
renders the tag name with a link
'
,
()
=>
{
const
commitLink
=
tagInfoSection
().
find
(
GlLink
);
expect
(
commitLink
.
exists
()).
toBe
(
true
);
expect
(
commitLink
.
text
()).
toBe
(
releaseClone
.
tag_name
);
expect
(
commitLink
.
attributes
(
'
href
'
)).
toBe
(
releaseClone
.
tag_path
);
});
it
(
'
renders the author and creation time info
'
,
()
=>
{
expect
(
trimText
(
authorDateInfoSection
().
text
())).
toBe
(
`Created 7 fortnightes ago by
${
releaseClone
.
author
.
username
}
`
,
);
});
it
(
"
renders the author's avatar image
"
,
()
=>
{
const
avatarImg
=
authorDateInfoSection
().
find
(
'
img
'
);
expect
(
avatarImg
.
exists
()).
toBe
(
true
);
expect
(
avatarImg
.
attributes
(
'
src
'
)).
toBe
(
releaseClone
.
author
.
avatar_url
);
});
it
(
"
renders a link to the author's profile
"
,
()
=>
{
const
authorLink
=
authorDateInfoSection
().
find
(
GlLink
);
expect
(
authorLink
.
exists
()).
toBe
(
true
);
expect
(
authorLink
.
attributes
(
'
href
'
)).
toBe
(
releaseClone
.
author
.
web_url
);
});
});
describe
(
'
without any commit info
'
,
()
=>
{
beforeEach
(()
=>
factory
({
commit
:
undefined
}));
it
(
'
does not render any commit info
'
,
()
=>
{
expect
(
commitInfoSection
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
without a commit URL
'
,
()
=>
{
beforeEach
(()
=>
factory
({
commitPath
:
undefined
}));
it
(
'
renders the commit SHA as plain text (instead of a link)
'
,
()
=>
{
expect
(
commitInfoSectionLink
().
exists
()).
toBe
(
false
);
expect
(
commitInfoSection
().
text
()).
toBe
(
releaseClone
.
commit
.
short_id
);
});
});
describe
(
'
without a tag name
'
,
()
=>
{
beforeEach
(()
=>
factory
({
tagName
:
undefined
}));
it
(
'
does not render any tag info
'
,
()
=>
{
expect
(
tagInfoSection
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
without a tag URL
'
,
()
=>
{
beforeEach
(()
=>
factory
({
tagPath
:
undefined
}));
it
(
'
renders the tag name as plain text (instead of a link)
'
,
()
=>
{
expect
(
tagInfoSectionLink
().
exists
()).
toBe
(
false
);
expect
(
tagInfoSection
().
text
()).
toBe
(
releaseClone
.
tag_name
);
});
});
describe
(
'
without any author info
'
,
()
=>
{
beforeEach
(()
=>
factory
({
author
:
undefined
}));
it
(
'
renders the release date without the author name
'
,
()
=>
{
expect
(
trimText
(
authorDateInfoSection
().
text
())).
toBe
(
'
Created 7 fortnightes ago
'
);
});
});
describe
(
'
without a released at date
'
,
()
=>
{
beforeEach
(()
=>
factory
({
releasedAt
:
undefined
}));
it
(
'
renders the author name without the release date
'
,
()
=>
{
expect
(
trimText
(
authorDateInfoSection
().
text
())).
toBe
(
`Created by
${
releaseClone
.
author
.
username
}
`
,
);
});
});
describe
(
'
without a release date or author info
'
,
()
=>
{
beforeEach
(()
=>
factory
({
author
:
undefined
,
releasedAt
:
undefined
}));
it
(
'
does not render any author or release date info
'
,
()
=>
{
expect
(
authorDateInfoSection
().
exists
()).
toBe
(
false
);
});
});
});
spec/frontend/releases/list/components/release_block_spec.js
View file @
9733f3cc
import
{
mount
}
from
'
@vue/test-utils
'
;
import
ReleaseBlock
from
'
~/releases/list/components/release_block.vue
'
;
import
ReleaseBlockFooter
from
'
~/releases/list/components/release_block_footer.vue
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
{
first
}
from
'
underscore
'
;
import
{
release
}
from
'
../../mock_data
'
;
...
...
@@ -21,14 +22,16 @@ describe('Release block', () => {
let
wrapper
;
let
releaseClone
;
const
factory
=
(
releaseProp
,
releaseEditPageFeatureFlag
=
true
)
=>
{
const
factory
=
(
releaseProp
,
featureFlags
=
{}
)
=>
{
wrapper
=
mount
(
ReleaseBlock
,
{
propsData
:
{
release
:
releaseProp
,
},
provide
:
{
glFeatures
:
{
releaseEditPage
:
releaseEditPageFeatureFlag
,
releaseEditPage
:
true
,
releaseIssueSummary
:
true
,
...
featureFlags
,
},
},
sync
:
false
,
...
...
@@ -142,6 +145,10 @@ describe('Release block', () => {
expect
(
milestoneLink
.
attributes
(
'
data-original-title
'
)).
toBe
(
milestone
.
description
);
});
it
(
'
renders the footer
'
,
()
=>
{
expect
(
wrapper
.
find
(
ReleaseBlockFooter
).
exists
()).
toBe
(
true
);
});
});
it
(
'
renders commit sha
'
,
()
=>
{
...
...
@@ -173,7 +180,7 @@ describe('Release block', () => {
});
it
(
'
does not render an edit button if the releaseEditPage feature flag is disabled
'
,
()
=>
factory
(
releaseClone
,
false
).
then
(()
=>
{
factory
(
releaseClone
,
{
releaseEditPage
:
false
}
).
then
(()
=>
{
expect
(
editButton
().
exists
()).
toBe
(
false
);
}));
...
...
spec/frontend/releases/mock_data.js
View file @
9733f3cc
...
...
@@ -30,6 +30,7 @@ export const milestones = [
export
const
release
=
{
name
:
'
New release
'
,
tag_name
:
'
v0.3
'
,
tag_path
:
'
/root/release-test/-/tags/v0.3
'
,
description
:
'
A super nice release!
'
,
description_html
:
'
<p data-sourcepos="1:1-1:21" dir="auto">A super nice release!</p>
'
,
created_at
:
'
2019-08-26T17:54:04.952Z
'
,
...
...
@@ -56,6 +57,7 @@ export const release = {
committer_email
:
'
admin@example.com
'
,
committed_date
:
'
2019-08-26T17:47:07.000Z
'
,
},
commit_path
:
'
/root/release-test/commit/c22b0728d1b465f82898c884d32b01aa642f96c1
'
,
upcoming_release
:
false
,
milestones
,
assets
:
{
...
...
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