Commit 65a01d5e authored by Brandon Labuschagne's avatar Brandon Labuschagne Committed by Jose Ivan Vargas

DevOps Adoption - Link group titles to group

parent a0d10fed
......@@ -7,6 +7,7 @@ import {
GlIcon,
GlBadge,
GlProgressBar,
GlLink,
} from '@gitlab/ui';
import { uniqueId } from 'lodash';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
......@@ -22,6 +23,7 @@ import {
OVERVIEW_TABLE_SORT_DESC_STORAGE_KEY,
OVERVIEW_TABLE_NAME_KEY,
} from '../constants';
import { getGroupAdoptionPath } from '../utils/helpers';
import DevopsAdoptionDeleteModal from './devops_adoption_delete_modal.vue';
const thClass = ['gl-bg-white!', 'gl-text-gray-400'];
......@@ -52,6 +54,7 @@ export default {
GlProgressBar,
DevopsAdoptionDeleteModal,
LocalStorageSync,
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -146,6 +149,9 @@ export default {
cellSlotName(key) {
return `cell(${key})`;
},
getGroupAdoptionPath(fullPath) {
return getGroupAdoptionPath(fullPath);
},
},
};
</script>
......@@ -168,16 +174,25 @@ export default {
<template #cell(name)="{ item }">
<div data-testid="namespace">
<span v-if="item.group.latestSnapshot" class="gl-font-weight-bold">{{
item.group.namespace.fullName
}}</span>
<template v-if="item.group.latestSnapshot">
<template v-if="isCurrentGroup(item.group)">
<span class="gl-text-gray-500 gl-font-weight-bold">{{
item.group.namespace.fullName
}}</span>
<gl-badge class="gl-ml-1" variant="info">{{ __('This group') }}</gl-badge>
</template>
<gl-link
v-else
:href="getGroupAdoptionPath(item.group.namespace.fullPath)"
class="gl-text-gray-500 gl-font-weight-bold"
>
{{ item.group.namespace.fullName }}
</gl-link>
</template>
<template v-else>
<span class="gl-text-gray-400">{{ item.group.namespace.fullName }}</span>
<gl-icon name="hourglass" class="gl-text-gray-400" />
</template>
<gl-badge v-if="isCurrentGroup(item.group)" class="gl-ml-1" variant="info">{{
__('This group')
}}</gl-badge>
</div>
</template>
......
......@@ -6,6 +6,7 @@ import {
GlTooltipDirective,
GlIcon,
GlBadge,
GlLink,
} from '@gitlab/ui';
import { uniqueId } from 'lodash';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
......@@ -16,6 +17,7 @@ import {
I18N_TABLE_REMOVE_BUTTON_DISABLED,
I18N_GROUP_COL_LABEL,
} from '../constants';
import { getGroupAdoptionPath } from '../utils/helpers';
import DevopsAdoptionDeleteModal from './devops_adoption_delete_modal.vue';
import DevopsAdoptionTableCellFlag from './devops_adoption_table_cell_flag.vue';
......@@ -55,6 +57,7 @@ export default {
DevopsAdoptionDeleteModal,
GlIcon,
GlBadge,
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -129,6 +132,9 @@ export default {
? this.$options.i18n.removeButtonDisabled
: this.$options.i18n.removeButton;
},
getGroupAdoptionPath(fullPath) {
return getGroupAdoptionPath(fullPath);
},
},
};
</script>
......@@ -159,14 +165,25 @@ export default {
<template #cell(name)="{ item }">
<div data-testid="namespace">
<strong v-if="item.latestSnapshot">{{ item.namespace.fullName }}</strong>
<template v-if="item.latestSnapshot">
<template v-if="isCurrentGroup(item)">
<span class="gl-text-gray-500 gl-font-weight-bold">{{
item.namespace.fullName
}}</span>
<gl-badge class="gl-ml-1" variant="info">{{ __('This group') }}</gl-badge>
</template>
<gl-link
v-else
:href="getGroupAdoptionPath(item.namespace.fullPath)"
class="gl-text-gray-500 gl-font-weight-bold"
>
{{ item.namespace.fullName }}
</gl-link>
</template>
<template v-else>
<span class="gl-text-gray-400">{{ item.namespace.fullName }}</span>
<gl-icon name="hourglass" class="gl-text-gray-400" />
</template>
<gl-badge v-if="isCurrentGroup(item)" class="gl-ml-1" variant="info">{{
__('This group')
}}</gl-badge>
</div>
</template>
......
......@@ -5,6 +5,7 @@ export const PER_PAGE = 20;
export const DEBOUNCE_DELAY = 500;
export const PROGRESS_BAR_HEIGHT = '8px';
export const DATE_TIME_FORMAT = 'yyyy-mm-dd HH:MM';
export const GROUP_DEVOPS_PATH = '/groups/%{fullPath}/-/analytics/devops_adoption';
export const OVERVIEW_TABLE_NAME_KEY = 'name';
......
#import "../fragments/latest_snapshot.fragment.graphql"
#import "../fragments/namespace.fragment.graphql"
mutation($namespaceIds: [NamespaceID!]!, $displayNamespaceId: NamespaceID) {
bulkEnableDevopsAdoptionNamespaces(
......@@ -10,8 +11,7 @@ mutation($namespaceIds: [NamespaceID!]!, $displayNamespaceId: NamespaceID) {
...LatestSnapshot
}
namespace {
fullName
id
...Namespace
}
}
errors
......
#import "../fragments/latest_snapshot.fragment.graphql"
#import "../fragments/namespace.fragment.graphql"
query devopsAdoptionEnabledNamespaces($displayNamespaceId: NamespaceID) {
devopsAdoptionEnabledNamespaces(displayNamespaceId: $displayNamespaceId) {
......@@ -8,8 +9,7 @@ query devopsAdoptionEnabledNamespaces($displayNamespaceId: NamespaceID) {
...LatestSnapshot
}
namespace {
fullName
id
...Namespace
}
}
}
......
import { sprintf } from '~/locale';
import { GROUP_DEVOPS_PATH } from '../constants';
/**
* A helper function which accepts the enabledNamespaces,
*
......@@ -37,3 +40,15 @@ export const getAdoptedCountsByCols = (snapshots, cols) => {
return [...acc, adoptedCount];
}, []);
};
/**
* A helper function which computes the DevOps Adoption feature path
* given a specific group path
*
* @param { String } fullPath the full path for the group
*
* @return { String } the path for the group level DevOps Adoption feature
*/
export const getGroupAdoptionPath = (fullPath) => {
return fullPath ? sprintf(GROUP_DEVOPS_PATH, { fullPath }) : null;
};
import { GlButton, GlIcon, GlBadge, GlProgressBar } from '@gitlab/ui';
import { GlButton, GlIcon, GlBadge, GlProgressBar, GlLink } from '@gitlab/ui';
import DevopsAdoptionDeleteModal from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_delete_modal.vue';
import DevopsAdoptionOverviewTable from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_overview_table.vue';
import { DEVOPS_ADOPTION_TABLE_CONFIGURATION } from 'ee/analytics/devops_report/devops_adoption/constants';
......@@ -78,6 +78,17 @@ describe('DevopsAdoptionOverviewTable', () => {
);
});
it('includes a link to the group DevOps page', () => {
createComponent();
const link = findColSubComponent(TABLE_TEST_IDS_NAMESPACE, GlLink);
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe(
`/groups/${devopsAdoptionNamespaceData.nodes[0].namespace.fullPath}/-/analytics/devops_adoption`,
);
});
describe('"This group" badge', () => {
const thisGroupGid = devopsAdoptionNamespaceData.nodes[0].namespace.id;
......@@ -106,6 +117,12 @@ describe('DevopsAdoptionOverviewTable', () => {
expect(name.classes()).toStrictEqual(['gl-text-gray-400']);
});
it('does not include a link to the group DevOps page', () => {
const link = findColRowChild(TABLE_TEST_IDS_NAMESPACE, 1, GlLink);
expect(link.exists()).toBe(false);
});
describe('hourglass icon', () => {
let icon;
......
import { GlTable, GlButton, GlIcon, GlBadge } from '@gitlab/ui';
import { GlTable, GlButton, GlIcon, GlBadge, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import DevopsAdoptionDeleteModal from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_delete_modal.vue';
......@@ -102,10 +102,6 @@ describe('DevopsAdoptionTable', () => {
describe('table fields', () => {
describe('enabled namespace name', () => {
beforeEach(() => {
createComponent();
});
it('displays the correct name', () => {
createComponent();
......@@ -114,6 +110,17 @@ describe('DevopsAdoptionTable', () => {
);
});
it('includes a link to the group DevOps page', () => {
createComponent();
const link = findColSubComponent(TABLE_TEST_IDS_NAMESPACE, GlLink);
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe(
`/groups/${devopsAdoptionNamespaceData.nodes[0].namespace.fullPath}/-/analytics/devops_adoption`,
);
});
describe('"This group" badge', () => {
const thisGroupGid = devopsAdoptionNamespaceData.nodes[0].namespace.id;
......@@ -142,6 +149,12 @@ describe('DevopsAdoptionTable', () => {
expect(name.classes()).toStrictEqual(['gl-text-gray-400']);
});
it('does not include a link to the group DevOps page', () => {
const link = findColRowChild(TABLE_TEST_IDS_NAMESPACE, 1, GlLink);
expect(link.exists()).toBe(false);
});
describe('hourglass icon', () => {
let icon;
......
import {
shouldPollTableData,
getAdoptedCountsByCols,
getGroupAdoptionPath,
} from 'ee/analytics/devops_report/devops_adoption/utils/helpers';
import { DEVOPS_ADOPTION_TABLE_CONFIGURATION } from 'ee/analytics/devops_report/devops_adoption/constants';
import { devopsAdoptionNamespaceData, namespaceWithSnapotsData } from '../mock_data';
......@@ -43,3 +44,13 @@ describe('getAdoptedCountsByCols', () => {
},
);
});
describe('getGroupAdoptionPath', () => {
it.each`
fullPath | expected
${'gitlab-org'} | ${'/groups/gitlab-org/-/analytics/devops_adoption'}
${null} | ${null}
`('returns the correct value based on the group full path', ({ fullPath, expected }) => {
expect(getGroupAdoptionPath(fullPath)).toBe(expected);
});
});
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