Commit 2f84e94d authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '326480-devops-adoption-add-devsecops-tabs-to-table-2' into 'master'

Resolve "[DevOps Adoption] Migrate table to a configuration object"

See merge request gitlab-org/gitlab!61148
parents 1590ddb7 938d55d2
......@@ -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