Commit 938d55d2 authored by Brandon Labuschagne's avatar Brandon Labuschagne

Migrate DA to table config render

Instead of hard coding the data for the
devops adoption table, we want to make this
configurable by an object.

This will enable us to easily configur multiple
tables when we move to the tab model.

Changelog: changed
parent d861f7ac
......@@ -18,6 +18,7 @@ import {
DEVOPS_ADOPTION_SEGMENT_MODAL_ID,
DEFAULT_POLLING_INTERVAL,
DEVOPS_ADOPTION_GROUP_LEVEL_LABEL,
DEVOPS_ADOPTION_TABLE_CONFIGURATION,
} from '../constants';
import bulkFindOrCreateDevopsAdoptionSegmentsMutation from '../graphql/mutations/bulk_find_or_create_devops_adoption_segments.mutation.graphql';
import devopsAdoptionSegmentsQuery from '../graphql/queries/devops_adoption_segments.query.graphql';
......@@ -57,6 +58,7 @@ export default {
},
maxSegments: MAX_SEGMENTS,
devopsSegmentModalId: DEVOPS_ADOPTION_SEGMENT_MODAL_ID,
devopsAdoptionTableConfiguration: DEVOPS_ADOPTION_TABLE_CONFIGURATION,
data() {
return {
isLoadingGroups: false,
......@@ -288,6 +290,7 @@ export default {
>
</div>
<devops-adoption-table
:cols="$options.devopsAdoptionTableConfiguration[0].cols"
:segments="devopsAdoptionSegments.nodes"
:selected-segment="selectedSegment"
@set-selected-segment="setSelectedSegment"
......
......@@ -16,6 +16,7 @@ import {
DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_BY_STORAGE_KEY,
DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_DESC_STORAGE_KEY,
DEVOPS_ADOPTION_TABLE_REMOVE_BUTTON_DISABLED,
DEVOPS_ADOPTION_GROUP_COL_LABEL,
} from '../constants';
import DevopsAdoptionDeleteModal from './devops_adoption_delete_modal.vue';
import DevopsAdoptionTableCellFlag from './devops_adoption_table_cell_flag.vue';
......@@ -46,17 +47,6 @@ const fieldOptions = {
const { table: i18n } = DEVOPS_ADOPTION_STRINGS;
const headers = [
NAME_HEADER,
'issueOpened',
'mergeRequestOpened',
'mergeRequestApproved',
'runnerConfigured',
'pipelineSucceeded',
'deploySucceeded',
'securityScanSucceeded',
].map((key) => ({ key, ...i18n.headers[key], ...fieldOptions }));
export default {
name: 'DevopsAdoptionTable',
components: {
......@@ -83,15 +73,6 @@ export default {
},
devopsSegmentModalId: DEVOPS_ADOPTION_SEGMENT_MODAL_ID,
devopsSegmentDeleteModalId: DEVOPS_ADOPTION_SEGMENT_DELETE_MODAL_ID,
tableHeaderFields: [
...headers,
{
key: 'actions',
tdClass: 'actions-cell',
...fieldOptions,
sortable: false,
},
],
testids: DEVOPS_ADOPTION_TABLE_TEST_IDS,
sortByStorageKey: DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_BY_STORAGE_KEY,
sortDescStorageKey: DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_DESC_STORAGE_KEY,
......@@ -105,6 +86,10 @@ export default {
required: false,
default: null,
},
cols: {
type: Array,
required: true,
},
},
data() {
return {
......@@ -112,13 +97,37 @@ export default {
sortDesc: false,
};
},
computed: {
tableHeaderFields() {
return [
{
key: 'name',
label: DEVOPS_ADOPTION_GROUP_COL_LABEL,
...fieldOptions,
},
...this.cols.map((item) => ({
...item,
...fieldOptions,
})),
{
key: 'actions',
tdClass: 'actions-cell',
...fieldOptions,
sortable: false,
},
];
},
},
methods: {
setSelectedSegment(segment) {
this.$emit('set-selected-segment', segment);
},
slotName(key) {
headerSlotName(key) {
return `head(${key})`;
},
cellSlotName(key) {
return `cell(${key})`;
},
isCurrentGroup(item) {
return item.namespace?.id === this.groupGid;
},
......@@ -145,14 +154,14 @@ export default {
as-json
/>
<gl-table
:fields="$options.tableHeaderFields"
:fields="tableHeaderFields"
:items="segments"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
thead-class="gl-border-t-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-100"
stacked="sm"
>
<template v-for="header in $options.tableHeaderFields" #[slotName(header.key)]>
<template v-for="header in tableHeaderFields" #[headerSlotName(header.key)]>
<div :key="header.key" class="gl-display-flex gl-align-items-center">
<span>{{ header.label }}</span>
<gl-icon
......@@ -178,59 +187,12 @@ export default {
</div>
</template>
<template #cell(issueOpened)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.ISSUES"
:enabled="item.latestSnapshot.issueOpened"
/>
</template>
<template #cell(mergeRequestOpened)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.MRS"
:enabled="item.latestSnapshot.mergeRequestOpened"
/>
</template>
<template #cell(mergeRequestApproved)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.APPROVALS"
:enabled="item.latestSnapshot.mergeRequestApproved"
/>
</template>
<template #cell(runnerConfigured)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.RUNNERS"
:enabled="item.latestSnapshot.runnerConfigured"
/>
</template>
<template #cell(pipelineSucceeded)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.PIPELINES"
:enabled="item.latestSnapshot.pipelineSucceeded"
/>
</template>
<template #cell(deploySucceeded)="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.DEPLOYS"
:enabled="item.latestSnapshot.deploySucceeded"
/>
</template>
<template #cell(securityScanSucceeded)="{ item }">
<template v-for="col in cols" #[cellSlotName(col.key)]="{ item }">
<devops-adoption-table-cell-flag
v-if="item.latestSnapshot"
:data-testid="$options.testids.SCANNING"
:enabled="item.latestSnapshot.securityScanSucceeded"
:key="col.key"
:data-testid="col.testId"
:enabled="item.latestSnapshot[col.key]"
/>
</template>
......
......@@ -63,39 +63,6 @@ export const DEVOPS_ADOPTION_STRINGS = {
},
table: {
removeButton: s__('DevopsAdoption|Remove Group from the table.'),
headers: {
name: {
label: __('Group'),
},
issueOpened: {
label: s__('DevopsAdoption|Issues'),
tooltip: s__('DevopsAdoption|At least 1 issue opened'),
},
mergeRequestOpened: {
label: s__('DevopsAdoption|MRs'),
tooltip: s__('DevopsAdoption|At least 1 MR opened'),
},
mergeRequestApproved: {
label: s__('DevopsAdoption|Approvals'),
tooltip: s__('DevopsAdoption|At least 1 approval on an MR'),
},
runnerConfigured: {
label: s__('DevopsAdoption|Runners'),
tooltip: s__('DevopsAdoption|Runner configured for project/group'),
},
pipelineSucceeded: {
label: s__('DevopsAdoption|Pipelines'),
tooltip: s__('DevopsAdoption|At least 1 pipeline successfully run'),
},
deploySucceeded: {
label: s__('DevopsAdoption|Deploys'),
tooltip: s__('DevopsAdoption|At least 1 deploy'),
},
securityScanSucceeded: {
label: s__('DevopsAdoption|Scanning'),
tooltip: s__('DevopsAdoption|At least 1 security scan of any type run in pipeline'),
},
},
},
deleteModal: {
title: s__('DevopsAdoption|Confirm remove Group'),
......@@ -115,14 +82,7 @@ export const DEVOPS_ADOPTION_STRINGS = {
export const DEVOPS_ADOPTION_TABLE_TEST_IDS = {
TABLE_HEADERS: 'header',
SEGMENT: 'segmentCol',
ISSUES: 'issuesCol',
MRS: 'mrsCol',
APPROVALS: 'approvalsCol',
RUNNERS: 'runnersCol',
PIPELINES: 'pipelinesCol',
DEPLOYS: 'deploysCol',
ACTIONS: 'actionsCol',
SCANNING: 'scanningCol',
LOCAL_STORAGE_SORT_BY: 'localStorageSortBy',
LOCAL_STORAGE_SORT_DESC: 'localStorageSortDesc',
};
......@@ -132,3 +92,55 @@ export const DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_BY_STORAGE_KEY =
export const DEVOPS_ADOPTION_SEGMENTS_TABLE_SORT_DESC_STORAGE_KEY =
'devops_adoption_segments_table_sort_desc';
export const DEVOPS_ADOPTION_GROUP_COL_LABEL = __('Group');
export const DEVOPS_ADOPTION_TABLE_CONFIGURATION = [
{
title: s__('DevopsAdoption|Adoption'),
cols: [
{
key: 'issueOpened',
label: s__('DevopsAdoption|Issues'),
tooltip: s__('DevopsAdoption|At least 1 issue opened'),
testId: 'issuesCol',
},
{
key: 'mergeRequestOpened',
label: s__('DevopsAdoption|MRs'),
tooltip: s__('DevopsAdoption|At least 1 MR opened'),
testId: 'mrsCol',
},
{
key: 'mergeRequestApproved',
label: s__('DevopsAdoption|Approvals'),
tooltip: s__('DevopsAdoption|At least 1 approval on an MR'),
testId: 'approvalsCol',
},
{
key: 'runnerConfigured',
label: s__('DevopsAdoption|Runners'),
tooltip: s__('DevopsAdoption|Runner configured for project/group'),
testId: 'runnersCol',
},
{
key: 'pipelineSucceeded',
label: s__('DevopsAdoption|Pipelines'),
tooltip: s__('DevopsAdoption|At least 1 pipeline successfully run'),
testId: 'pipelinesCol',
},
{
key: 'deploySucceeded',
label: s__('DevopsAdoption|Deploys'),
tooltip: s__('DevopsAdoption|At least 1 deploy'),
testId: 'deploysCol',
},
{
key: 'securityScanSucceeded',
label: s__('DevopsAdoption|Scanning'),
tooltip: s__('DevopsAdoption|At least 1 security scan of any type run in pipeline'),
testId: 'scanningCol',
},
],
},
];
......@@ -4,7 +4,10 @@ import { nextTick } from 'vue';
import DevopsAdoptionDeleteModal from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_delete_modal.vue';
import DevopsAdoptionTable from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_table.vue';
import DevopsAdoptionTableCellFlag from 'ee/analytics/devops_report/devops_adoption/components/devops_adoption_table_cell_flag.vue';
import { DEVOPS_ADOPTION_TABLE_TEST_IDS as TEST_IDS } from 'ee/analytics/devops_report/devops_adoption/constants';
import {
DEVOPS_ADOPTION_TABLE_TEST_IDS as TEST_IDS,
DEVOPS_ADOPTION_TABLE_CONFIGURATION,
} from 'ee/analytics/devops_report/devops_adoption/constants';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import { devopsAdoptionSegmentsData, devopsAdoptionTableHeaders } from '../mock_data';
......@@ -17,6 +20,7 @@ describe('DevopsAdoptionTable', () => {
wrapper = mount(DevopsAdoptionTable, {
propsData: {
cols: DEVOPS_ADOPTION_TABLE_CONFIGURATION[0].cols,
segments: devopsAdoptionSegmentsData.nodes,
selectedSegment: devopsAdoptionSegmentsData.nodes[0],
},
......@@ -152,21 +156,14 @@ describe('DevopsAdoptionTable', () => {
});
});
it.each`
id | field | flag
${TEST_IDS.ISSUES} | ${'issues'} | ${true}
${TEST_IDS.MRS} | ${'MRs'} | ${true}
${TEST_IDS.APPROVALS} | ${'approvals'} | ${false}
${TEST_IDS.RUNNERS} | ${'runners'} | ${true}
${TEST_IDS.PIPELINES} | ${'pipelines'} | ${false}
${TEST_IDS.DEPLOYS} | ${'deploys'} | ${false}
${TEST_IDS.SCANNING} | ${'scanning'} | ${false}
`('displays the correct $field snapshot value', ({ id, flag }) => {
const testCols = DEVOPS_ADOPTION_TABLE_CONFIGURATION[0].cols.map((col) => [col.label, col]);
it.each(testCols)('displays the cell flag component for %s', (label, { testId }) => {
createComponent();
const booleanFlag = findColSubComponent(id, DevopsAdoptionTableCellFlag);
const booleanFlag = findColSubComponent(testId, DevopsAdoptionTableCellFlag);
expect(booleanFlag.props('enabled')).toBe(flag);
expect(booleanFlag.exists()).toBe(true);
});
describe.each`
......
......@@ -11265,6 +11265,9 @@ msgstr ""
msgid "DevopsAdoption|Adopted"
msgstr ""
msgid "DevopsAdoption|Adoption"
msgstr ""
msgid "DevopsAdoption|An error occurred while removing the group. Please try again."
msgstr ""
......
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