Commit cec99db0 authored by Brandon Labuschagne's avatar Brandon Labuschagne Committed by Martin Wortschack

DevOps Report: Add tooltips to table headings

parent 5559a68e
<script>
import { GlTable, GlButton, GlPopover, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import {
GlTable,
GlButton,
GlPopover,
GlModalDirective,
GlTooltipDirective,
GlIcon,
} from '@gitlab/ui';
import DevopsAdoptionTableCellFlag from './devops_adoption_table_cell_flag.vue';
import DevopsAdoptionDeleteModal from './devops_adoption_delete_modal.vue';
import {
......@@ -15,6 +21,19 @@ const fieldOptions = {
thAttr: { 'data-testid': DEVOPS_ADOPTION_TABLE_TEST_IDS.TABLE_HEADERS },
};
const { table: i18n } = DEVOPS_ADOPTION_STRINGS;
const headers = [
'name',
'issueOpened',
'mergeRequestOpened',
'mergeRequestApproved',
'runnerConfigured',
'pipelineSucceeded',
'deploySucceeded',
'securityScanSucceeded',
].map(key => ({ key, ...i18n.headers[key], ...fieldOptions }));
export default {
name: 'DevopsAdoptionTable',
components: {
......@@ -23,57 +42,19 @@ export default {
GlButton,
GlPopover,
DevopsAdoptionDeleteModal,
GlIcon,
},
i18n: DEVOPS_ADOPTION_STRINGS.table,
i18n,
devopsSegmentModalId: DEVOPS_ADOPTION_SEGMENT_MODAL_ID,
devopsSegmentDeleteModalId: DEVOPS_ADOPTION_SEGMENT_DELETE_MODAL_ID,
directives: {
GlTooltip: GlTooltipDirective,
GlModal: GlModalDirective,
},
tableHeaderFields: [
{
key: 'name',
label: s__('DevopsAdoption|Segment'),
...fieldOptions,
},
{
key: 'issueOpened',
label: s__('DevopsAdoption|Issues'),
...fieldOptions,
},
{
key: 'mergeRequestOpened',
label: s__('DevopsAdoption|MRs'),
...fieldOptions,
},
{
key: 'mergeRequestApproved',
label: s__('DevopsAdoption|Approvals'),
...fieldOptions,
},
{
key: 'runnerConfigured',
label: s__('DevopsAdoption|Runners'),
...fieldOptions,
},
{
key: 'pipelineSucceeded',
label: s__('DevopsAdoption|Pipelines'),
...fieldOptions,
},
{
key: 'deploySucceeded',
label: s__('DevopsAdoption|Deploys'),
...fieldOptions,
},
{
key: 'securityScanSucceeded',
label: s__('DevopsAdoption|Scanning'),
...fieldOptions,
},
...headers,
{
key: 'actions',
label: '',
tdClass: 'actions-cell',
...fieldOptions,
},
......@@ -100,6 +81,9 @@ export default {
setSelectedSegment(segment) {
this.$emit('set-selected-segment', segment);
},
slotName(key) {
return `head(${key})`;
},
},
};
</script>
......@@ -111,6 +95,19 @@ export default {
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)]>
<div :key="header.key" class="gl-display-flex gl-align-items-center">
<span>{{ header.label }}</span>
<gl-icon
v-if="header.tooltip"
v-gl-tooltip.hover="header.tooltip"
name="information-o"
class="gl-text-gray-200 gl-ml-1"
:size="14"
/>
</div>
</template>
<template #cell(name)="{ item }">
<div :data-testid="$options.testids.SEGMENT">
<strong>{{ item.name }}</strong>
......
......@@ -52,6 +52,39 @@ export const DEVOPS_ADOPTION_STRINGS = {
table: {
editButton: s__('DevopsAdoption|Edit segment'),
deleteButton: s__('DevopsAdoption|Delete segment'),
headers: {
name: {
label: s__('DevopsAdoption|Segment'),
},
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 delete segment'),
......
import { GlTable, GlButton } from '@gitlab/ui';
import { GlTable, GlButton, GlIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import DevopsAdoptionTable from 'ee/admin/dev_ops_report/components/devops_adoption_table.vue';
import DevopsAdoptionTableCellFlag from 'ee/admin/dev_ops_report/components/devops_adoption_table_cell_flag.vue';
import { DEVOPS_ADOPTION_TABLE_TEST_IDS as TEST_IDS } from 'ee/admin/dev_ops_report/constants';
......@@ -13,6 +14,9 @@ describe('DevopsAdoptionTable', () => {
propsData: {
segments: devopsAdoptionSegmentsData.nodes,
},
directives: {
GlTooltip: createMockDirective(),
},
});
};
......@@ -32,13 +36,48 @@ describe('DevopsAdoptionTable', () => {
const findColSubComponent = (colTestId, childComponent) =>
findCol(colTestId).find(childComponent);
it('displays the correct table headers', () => {
const headers = findTable().findAll(`[data-testid="${TEST_IDS.TABLE_HEADERS}"]`);
describe('table headings', () => {
let headers;
beforeEach(() => {
headers = findTable().findAll(`[data-testid="${TEST_IDS.TABLE_HEADERS}"]`);
});
it('displays the correct number of headings', () => {
expect(headers).toHaveLength(devopsAdoptionTableHeaders.length);
});
describe.each(devopsAdoptionTableHeaders)(
'header fields',
({ label, tooltip: tooltipText, index }) => {
let headerWrapper;
expect(headers).toHaveLength(devopsAdoptionTableHeaders.length);
beforeEach(() => {
headerWrapper = headers.at(index);
});
devopsAdoptionTableHeaders.forEach((headerText, i) =>
expect(headers.at(i).text()).toEqual(headerText),
it(`displays the correct table heading text for "${label}"`, () => {
expect(headerWrapper.text()).toBe(label);
});
describe(`helper information for "${label}"`, () => {
const expected = Boolean(tooltipText);
it(`${expected ? 'displays' : "doesn't display"} an information icon`, () => {
expect(headerWrapper.find(GlIcon).exists()).toBe(expected);
});
if (expected) {
it('includes a tooltip', () => {
const icon = headerWrapper.find(GlIcon);
const tooltip = getBinding(icon.element, 'gl-tooltip');
expect(tooltip).toBeDefined();
expect(tooltip.value).toBe(tooltipText);
});
}
});
},
);
});
......
......@@ -66,15 +66,51 @@ export const devopsAdoptionSegmentsDataEmpty = {
};
export const devopsAdoptionTableHeaders = [
'Segment',
'Issues',
'MRs',
'Approvals',
'Runners',
'Pipelines',
'Deploys',
'Scanning',
'',
{
index: 0,
label: 'Segment',
tooltip: null,
},
{
index: 1,
label: 'Issues',
tooltip: 'At least 1 issue opened',
},
{
index: 2,
label: 'MRs',
tooltip: 'At least 1 MR opened',
},
{
index: 3,
label: 'Approvals',
tooltip: 'At least 1 approval on an MR',
},
{
index: 4,
label: 'Runners',
tooltip: 'Runner configured for project/group',
},
{
index: 5,
label: 'Pipelines',
tooltip: 'At least 1 pipeline successfully run',
},
{
index: 6,
label: 'Deploys',
tooltip: 'At least 1 deploy',
},
{
index: 7,
label: 'Scanning',
tooltip: 'At least 1 security scan of any type run in pipeline',
},
{
index: 8,
label: '',
tooltip: null,
},
];
export const segmentName = 'Foooo';
......
......@@ -9619,6 +9619,24 @@ msgstr ""
msgid "DevopsAdoption|Are you sure that you would like to delete %{name}?"
msgstr ""
msgid "DevopsAdoption|At least 1 MR opened"
msgstr ""
msgid "DevopsAdoption|At least 1 approval on an MR"
msgstr ""
msgid "DevopsAdoption|At least 1 deploy"
msgstr ""
msgid "DevopsAdoption|At least 1 issue opened"
msgstr ""
msgid "DevopsAdoption|At least 1 pipeline successfully run"
msgstr ""
msgid "DevopsAdoption|At least 1 security scan of any type run in pipeline"
msgstr ""
msgid "DevopsAdoption|Confirm delete segment"
msgstr ""
......@@ -9664,6 +9682,9 @@ msgstr ""
msgid "DevopsAdoption|Pipelines"
msgstr ""
msgid "DevopsAdoption|Runner configured for project/group"
msgstr ""
msgid "DevopsAdoption|Runners"
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