Commit 89e2ee15 authored by Sincheol (David) Kim's avatar Sincheol (David) Kim

Merge branch '215290-vsa-display-project-for-each-record-in-group-level-feature' into 'master'

[VSA] Display project for each record in group level feature

See merge request gitlab-org/gitlab!77841
parents d1ac31ec 2277b124
...@@ -89,6 +89,11 @@ export default { ...@@ -89,6 +89,11 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
includeProjectName: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
if (this.pagination) { if (this.pagination) {
...@@ -144,8 +149,13 @@ export default { ...@@ -144,8 +149,13 @@ export default {
isMrLink(url = '') { isMrLink(url = '') {
return url.includes('/merge_request'); return url.includes('/merge_request');
}, },
itemId({ url, iid }) { itemId({ iid, projectPath }, separator = '#') {
return this.isMrLink(url) ? `!${iid}` : `#${iid}`; const prefix = this.includeProjectName ? projectPath : '';
return `${prefix}${separator}${iid}`;
},
itemDisplayName(item) {
const separator = this.isMrLink(item.url) ? '!' : '#';
return this.itemId(item, separator);
}, },
itemTitle(item) { itemTitle(item) {
return item.title || item.name; return item.title || item.name;
...@@ -201,8 +211,11 @@ export default { ...@@ -201,8 +211,11 @@ export default {
<div data-testid="vsa-stage-event"> <div data-testid="vsa-stage-event">
<div v-if="item.id" data-testid="vsa-stage-content"> <div v-if="item.id" data-testid="vsa-stage-content">
<p class="gl-m-0"> <p class="gl-m-0">
<gl-link class="gl-text-black-normal pipeline-id" :href="item.url" <gl-link
>#{{ item.id }}</gl-link data-testid="vsa-stage-event-link"
class="gl-text-black-normal pipeline-id"
:href="item.url"
>{{ itemId(item.id, '#') }}</gl-link
> >
<gl-icon :size="16" name="fork" /> <gl-icon :size="16" name="fork" />
<gl-link <gl-link
...@@ -240,7 +253,12 @@ export default { ...@@ -240,7 +253,12 @@ export default {
<gl-link class="gl-text-black-normal" :href="item.url">{{ itemTitle(item) }}</gl-link> <gl-link class="gl-text-black-normal" :href="item.url">{{ itemTitle(item) }}</gl-link>
</h5> </h5>
<p class="gl-m-0"> <p class="gl-m-0">
<gl-link class="gl-text-black-normal" :href="item.url">{{ itemId(item) }}</gl-link> <gl-link
data-testid="vsa-stage-event-link"
class="gl-text-black-normal"
:href="item.url"
>{{ itemDisplayName(item) }}</gl-link
>
<span class="gl-font-lg">&middot;</span> <span class="gl-font-lg">&middot;</span>
<span data-testid="vsa-stage-event-date"> <span data-testid="vsa-stage-event-date">
{{ s__('OpenedNDaysAgo|Opened') }} {{ s__('OpenedNDaysAgo|Opened') }}
......
...@@ -9,6 +9,9 @@ class AnalyticsBuildEntity < Grape::Entity ...@@ -9,6 +9,9 @@ class AnalyticsBuildEntity < Grape::Entity
expose :ref, as: :branch expose :ref, as: :branch
expose :short_sha expose :short_sha
expose :author, using: UserEntity expose :author, using: UserEntity
expose :project_path do |build|
build.project.path
end
expose :started_at, as: :date do |build| expose :started_at, as: :date do |build|
interval_in_words(build[:started_at]) interval_in_words(build[:started_at])
......
...@@ -6,6 +6,9 @@ class AnalyticsIssueEntity < Grape::Entity ...@@ -6,6 +6,9 @@ class AnalyticsIssueEntity < Grape::Entity
expose :title expose :title
expose :author, using: UserEntity expose :author, using: UserEntity
expose :project_path do |object|
object[:project_path]
end
expose :iid do |object| expose :iid do |object|
object[:iid].to_s object[:iid].to_s
......
...@@ -213,6 +213,7 @@ export default { ...@@ -213,6 +213,7 @@ export default {
:empty-state-message="selectedStageError" :empty-state-message="selectedStageError"
:no-data-svg-path="noDataSvgPath" :no-data-svg-path="noDataSvgPath"
:pagination="pagination" :pagination="pagination"
include-project-name
@handleUpdatePagination="onHandleUpdatePagination" @handleUpdatePagination="onHandleUpdatePagination"
/> />
<url-sync v-if="selectedStageReady" :query="query" /> <url-sync v-if="selectedStageReady" :query="query" />
......
...@@ -319,6 +319,10 @@ describe('EE Value Stream Analytics component', () => { ...@@ -319,6 +319,10 @@ describe('EE Value Stream Analytics component', () => {
displaysStageTable(true); displaysStageTable(true);
}); });
it('sets the `includeProjectName` prop on stage table', () => {
expect(findStageTable().props('includeProjectName')).toBe(true);
});
it('displays the path navigation', () => { it('displays the path navigation', () => {
displaysPathNavigation(true); displaysPathNavigation(true);
}); });
......
...@@ -24,6 +24,7 @@ const findTable = () => wrapper.findComponent(GlTable); ...@@ -24,6 +24,7 @@ const findTable = () => wrapper.findComponent(GlTable);
const findTableHead = () => wrapper.find('thead'); const findTableHead = () => wrapper.find('thead');
const findTableHeadColumns = () => findTableHead().findAll('th'); const findTableHeadColumns = () => findTableHead().findAll('th');
const findStageEventTitle = (ev) => extendedWrapper(ev).findByTestId('vsa-stage-event-title'); const findStageEventTitle = (ev) => extendedWrapper(ev).findByTestId('vsa-stage-event-title');
const findStageEventLink = (ev) => extendedWrapper(ev).findByTestId('vsa-stage-event-link');
const findStageTime = () => wrapper.findByTestId('vsa-stage-event-time'); const findStageTime = () => wrapper.findByTestId('vsa-stage-event-time');
const findIcon = (name) => wrapper.findByTestId(`${name}-icon`); const findIcon = (name) => wrapper.findByTestId(`${name}-icon`);
...@@ -86,6 +87,15 @@ describe('StageTable', () => { ...@@ -86,6 +87,15 @@ describe('StageTable', () => {
expect(titles[index]).toBe(ev.title); expect(titles[index]).toBe(ev.title);
}); });
}); });
it('will not display the project name in the record link', () => {
const evs = findStageEvents();
const links = evs.wrappers.map((ev) => findStageEventLink(ev).text());
issueEventItems.forEach((ev, index) => {
expect(links[index]).toBe(`#${ev.iid}`);
});
});
}); });
describe('default event', () => { describe('default event', () => {
...@@ -187,6 +197,21 @@ describe('StageTable', () => { ...@@ -187,6 +197,21 @@ describe('StageTable', () => {
}); });
}); });
describe('includeProjectName set', () => {
beforeEach(() => {
wrapper = createComponent({ includeProjectName: true });
});
it('will display the project name in the record link', () => {
const evs = findStageEvents();
const links = evs.wrappers.map((ev) => findStageEventLink(ev).text());
issueEventItems.forEach((ev, index) => {
expect(links[index]).toBe(`${ev.projectPath}#${ev.iid}`);
});
});
});
describe('Pagination', () => { describe('Pagination', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createComponent(); wrapper = createComponent();
......
...@@ -27,6 +27,10 @@ RSpec.describe AnalyticsBuildEntity do ...@@ -27,6 +27,10 @@ RSpec.describe AnalyticsBuildEntity do
expect(subject).to include(:author) expect(subject).to include(:author)
end end
it 'contains the project path' do
expect(subject).to include(:project_path)
end
it 'does not contain sensitive information' do it 'does not contain sensitive information' do
expect(subject).not_to include(/token/) expect(subject).not_to include(/token/)
expect(subject).not_to include(/variables/) expect(subject).not_to include(/variables/)
......
...@@ -32,6 +32,10 @@ RSpec.describe AnalyticsIssueEntity do ...@@ -32,6 +32,10 @@ RSpec.describe AnalyticsIssueEntity do
expect(subject).to include(:author) expect(subject).to include(:author)
end end
it 'contains the project path' do
expect(subject).to include(:project_path)
end
it 'does not contain sensitive information' do it 'does not contain sensitive information' do
expect(subject).not_to include(/token/) expect(subject).not_to include(/token/)
expect(subject).not_to include(/variables/) expect(subject).not_to include(/variables/)
......
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