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