From 397a388d93d1fd6ce91569d922db7314602e334b Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Wed, 10 Apr 2024 10:52:08 +0200 Subject: [PATCH] Add: New multi_selection report format param type A new parameter type for report formats and report configs is added that allows selecting multiple predefined options. Some small style changes have been made to make params with multi-line values more readable and to make the params in report formats and report configs more consistent. The new param type can later be used to add new customization options to report formats like a column selection for CSV. --- src/gmp/commands/__tests__/reportconfig.js | 18 ++++++ src/gmp/commands/reportconfigs.js | 24 +++++-- src/gmp/models/reportconfig.js | 3 + src/gmp/models/reportformat.js | 3 + .../__tests__/__snapshots__/details.jsx.snap | 24 +++++-- .../__snapshots__/detailspage.jsx.snap | 24 +++++-- .../__tests__/__snapshots__/dialog.jsx.snap | 5 +- .../reportconfigs/__tests__/component.jsx | 6 ++ .../pages/reportconfigs/__tests__/dialog.jsx | 29 +++++++++ src/web/pages/reportconfigs/details.jsx | 16 ++++- src/web/pages/reportconfigs/dialog.jsx | 27 +++++++- src/web/pages/reportformats/detailspage.jsx | 62 ++++++++++++++++++- 12 files changed, 218 insertions(+), 23 deletions(-) diff --git a/src/gmp/commands/__tests__/reportconfig.js b/src/gmp/commands/__tests__/reportconfig.js index 43d6ec9d33..7446eaaaca 100644 --- a/src/gmp/commands/__tests__/reportconfig.js +++ b/src/gmp/commands/__tests__/reportconfig.js @@ -64,11 +64,19 @@ describe('ReportConfigCommand tests', () => { 'param 1': 'value 1', 'param 2': 'value 2', 'param 3': ['report-format-1', 'report-format-2'], + 'param 4': ['option-1', 'option-2'], }, params_using_default: { 'param 1': false, 'param 2': true, 'param 3': false, + 'param 4': false, + }, + param_types: { + 'param 1': 'string', + 'param 2': 'text', + 'param 3': 'report_format_list', + 'param 4': 'multi_selection', }, }) .then(resp => { @@ -81,6 +89,7 @@ describe('ReportConfigCommand tests', () => { 'param:param 1': 'value 1', 'param:param 2': 'value 2', 'param:param 3': 'report-format-1,report-format-2', + 'param:param 4': '["option-1","option-2"]', 'param_using_default:param 2': 1, }, }); @@ -106,11 +115,19 @@ describe('ReportConfigCommand tests', () => { 'param 1': 'value A', 'param 2': 'value B', 'param 3': ['report-format-A', 'report-format-B'], + 'param 4': ['option-1', 'option-2'], }, params_using_default: { 'param 1': true, 'param 2': false, 'param 3': false, + 'param 4': false, + }, + param_types: { + 'param 1': 'string', + 'param 2': 'text', + 'param 3': 'report_format_list', + 'param 4': 'multi_selection', }, }) .then(resp => { @@ -122,6 +139,7 @@ describe('ReportConfigCommand tests', () => { 'param:param 1': 'value A', 'param:param 2': 'value B', 'param:param 3': 'report-format-A,report-format-B', + 'param:param 4': '["option-1","option-2"]', 'param_using_default:param 1': 1, }, }); diff --git a/src/gmp/commands/reportconfigs.js b/src/gmp/commands/reportconfigs.js index a642deae66..d6c0695223 100644 --- a/src/gmp/commands/reportconfigs.js +++ b/src/gmp/commands/reportconfigs.js @@ -41,6 +41,7 @@ export class ReportConfigCommand extends EntityCommand { report_format_id, params = {}, params_using_default = {}, + param_types = {}, } = args; const data = { @@ -52,8 +53,12 @@ export class ReportConfigCommand extends EntityCommand { for (const prefname in params) { let value = params[prefname]; - if (isArray(params[prefname])) { - value = params[prefname].join(','); + if (isArray(value)) { + if (param_types[prefname] === 'report_format_list') { + value = params[prefname].join(','); + } else { + value = JSON.stringify(params[prefname]); + } } data['param:' + prefname] = value; } @@ -71,7 +76,14 @@ export class ReportConfigCommand extends EntityCommand { } save(args) { - const {id, comment, name, params = {}, params_using_default = {}} = args; + const { + id, + comment, + name, + params = {}, + params_using_default = {}, + param_types = {}, + } = args; const data = { cmd: 'save_report_config', @@ -91,7 +103,11 @@ export class ReportConfigCommand extends EntityCommand { for (const prefname in params) { let value = params[prefname]; if (isArray(params[prefname])) { - value = params[prefname].join(','); + if (param_types[prefname] === 'report_format_list') { + value = params[prefname].join(','); + } else { + value = JSON.stringify(params[prefname]); + } } data['param:' + prefname] = value; } diff --git a/src/gmp/models/reportconfig.js b/src/gmp/models/reportconfig.js index c43e602d96..100d9c8e73 100644 --- a/src/gmp/models/reportconfig.js +++ b/src/gmp/models/reportconfig.js @@ -56,6 +56,9 @@ class Param { forEach(other.default.report_format, format => { this.default_labels[format._id] = format.name; }); + } else if (this.type === 'multi_selection') { + this.value = JSON.parse(get_value(value)); + this.default = JSON.parse(get_value(other.default)); } else if (this.type === 'integer') { this.value = parseInt(get_value(value)); this.default = parseInt(get_value(other.default)); diff --git a/src/gmp/models/reportformat.js b/src/gmp/models/reportformat.js index b74363873f..be955c4136 100644 --- a/src/gmp/models/reportformat.js +++ b/src/gmp/models/reportformat.js @@ -48,6 +48,9 @@ class Param { if (this.type === 'report_format_list') { this.value = map(value.report_format, format => format._id); + } else if (this.type === 'multi_selection') { + this.value = JSON.parse(get_value(value)); + this.default = JSON.parse(get_value(other.default)); } else { this.value = get_value(value); } diff --git a/src/web/pages/reportconfigs/__tests__/__snapshots__/details.jsx.snap b/src/web/pages/reportconfigs/__tests__/__snapshots__/details.jsx.snap index ee263d7431..8bdcd9756c 100644 --- a/src/web/pages/reportconfigs/__tests__/__snapshots__/details.jsx.snap +++ b/src/web/pages/reportconfigs/__tests__/__snapshots__/details.jsx.snap @@ -167,7 +167,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` class="" > - +
@@ -183,7 +185,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` - +
@@ -201,7 +205,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` - +
@@ -217,7 +223,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` - +
@@ -233,7 +241,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` - +
@@ -249,7 +259,9 @@ exports[`Report Config Details tests > should render full Details 1`] = ` - +
diff --git a/src/web/pages/reportconfigs/__tests__/__snapshots__/detailspage.jsx.snap b/src/web/pages/reportconfigs/__tests__/__snapshots__/detailspage.jsx.snap index d2fc55799d..4406a4ff0a 100644 --- a/src/web/pages/reportconfigs/__tests__/__snapshots__/detailspage.jsx.snap +++ b/src/web/pages/reportconfigs/__tests__/__snapshots__/detailspage.jsx.snap @@ -876,7 +876,9 @@ exports[`Report Config Details Page tests > should render full Details page with class="" > - +
@@ -892,7 +894,9 @@ exports[`Report Config Details Page tests > should render full Details page with - +
@@ -910,7 +914,9 @@ exports[`Report Config Details Page tests > should render full Details page with - +
@@ -926,7 +932,9 @@ exports[`Report Config Details Page tests > should render full Details page with - +
@@ -942,7 +950,9 @@ exports[`Report Config Details Page tests > should render full Details page with - +
@@ -958,7 +968,9 @@ exports[`Report Config Details Page tests > should render full Details page with - +
diff --git a/src/web/pages/reportconfigs/__tests__/__snapshots__/dialog.jsx.snap b/src/web/pages/reportconfigs/__tests__/__snapshots__/dialog.jsx.snap index 6a417e9a83..9096afa858 100644 --- a/src/web/pages/reportconfigs/__tests__/__snapshots__/dialog.jsx.snap +++ b/src/web/pages/reportconfigs/__tests__/__snapshots__/dialog.jsx.snap @@ -1354,11 +1354,12 @@ exports[`Edit Report Config Dialog component tests > should render dialog with d class="c13 c34" > should render dialog with d data-testid="radio-input" name="BooleanParam" type="radio" - value="0" + value="false" /> { entityType: 'reportconfig', id: 'rc123', name: 'test report config', + param_types: { + 'test param': 'string', + }, params: { 'test param': 'ABC', }, @@ -224,6 +227,9 @@ describe('Report Config Component tests', () => { expect(createReportConfig).toHaveBeenCalledWith({ name: 'Unnamed', comment: '', + param_types: { + 'test param': 'string', + }, params: { 'test param': 'ABC', }, diff --git a/src/web/pages/reportconfigs/__tests__/dialog.jsx b/src/web/pages/reportconfigs/__tests__/dialog.jsx index f2bae65fdf..2dfecb3fed 100644 --- a/src/web/pages/reportconfigs/__tests__/dialog.jsx +++ b/src/web/pages/reportconfigs/__tests__/dialog.jsx @@ -94,6 +94,14 @@ describe('Edit Report Config Dialog component tests', () => { expect(handleSave).toHaveBeenCalledWith({ ...config, + param_types: { + BooleanParam: 'boolean', + IntegerParam: 'integer', + ReportFormatListParam: 'report_format_list', + SelectionParam: 'selection', + StringParam: 'string', + TextParam: 'text', + }, params: { BooleanParam: true, IntegerParam: 12, @@ -210,6 +218,14 @@ describe('Edit Report Config Dialog component tests', () => { ...config, name: 'lorem', comment: 'ipsum', + param_types: { + BooleanParam: 'boolean', + IntegerParam: 'integer', + ReportFormatListParam: 'report_format_list', + SelectionParam: 'selection', + StringParam: 'string', + TextParam: 'text', + }, params: { BooleanParam: false, IntegerParam: 7, @@ -279,6 +295,14 @@ describe('Edit Report Config Dialog component tests', () => { expect(handleSave).toHaveBeenCalledWith({ ...config, + param_types: { + BooleanParam: 'boolean', + IntegerParam: 'integer', + ReportFormatListParam: 'report_format_list', + SelectionParam: 'selection', + StringParam: 'string', + TextParam: 'text', + }, params: { BooleanParam: true, IntegerParam: 12, @@ -435,6 +459,11 @@ describe('New Report Config Dialog component tests', () => { name: 'lorem', comment: 'ipsum', report_format_id: '1234567', + param_types: { + Param1: 'string', + Param2: 'string', + ReportFormatListParam: 'report_format_list', + }, params: { Param1: 'ABC', Param2: 'XYZ', diff --git a/src/web/pages/reportconfigs/details.jsx b/src/web/pages/reportconfigs/details.jsx index cb360fbf83..c787ff5732 100644 --- a/src/web/pages/reportconfigs/details.jsx +++ b/src/web/pages/reportconfigs/details.jsx @@ -36,6 +36,8 @@ import {map} from 'gmp/utils/array'; import {isDefined} from 'gmp/utils/identity'; import {renderYesNo} from 'web/utils/render'; +import styled from 'styled-components'; + export const ReportConfigParamValue = ({ param, value = param.value, @@ -58,6 +60,18 @@ export const ReportConfigParamValue = ({ ); }); + } else if (param.type === 'multi_selection') { + const OptionsList = styled.ul` + margin: 0; + padding-left: 1em; + `; + return ( + + {param.value.map(option => ( +
  • {value}; } else if (param.type === 'boolean') { @@ -94,7 +108,7 @@ const ReportConfigDetails = ({entity, links = true}) => { params.map(param => { return ( - {param.name} + {param.name} diff --git a/src/web/pages/reportconfigs/dialog.jsx b/src/web/pages/reportconfigs/dialog.jsx index 252633d3d0..4b3fb1d4f8 100644 --- a/src/web/pages/reportconfigs/dialog.jsx +++ b/src/web/pages/reportconfigs/dialog.jsx @@ -68,6 +68,8 @@ const Param = ({ field = ( ); + } else if (type === 'multi_selection') { + const typeOptions = map(value.options, opt => ({ + label: opt.name, + value: opt.value, + })); + field = ( + + ); } else if (type === 'string') { field = ( { + param_types[param_item.name] = param_item.type; + }); onSave({ ...data, params, params_using_default, + param_types, report_format_id, }); } diff --git a/src/web/pages/reportformats/detailspage.jsx b/src/web/pages/reportformats/detailspage.jsx index 83858dc04f..97523a35ce 100644 --- a/src/web/pages/reportformats/detailspage.jsx +++ b/src/web/pages/reportformats/detailspage.jsx @@ -40,7 +40,7 @@ import Tabs from 'web/components/tab/tabs'; import Table from 'web/components/table/stripedtable'; import TableBody from 'web/components/table/body'; -import TableData from 'web/components/table/data'; +import TableData, {TableDataAlignTop} from 'web/components/table/data'; import TableHeader from 'web/components/table/header'; import TableHead from 'web/components/table/head'; import TableRow from 'web/components/table/row'; @@ -66,6 +66,11 @@ import withCapabilities from 'web/utils/withCapabilities'; import ReportFormatComponent from './component'; import ReportFormatDetails from './details'; +import DetailsLink from 'web/components/link/detailslink'; +import {map} from 'gmp/utils/array'; +import {isDefined} from 'gmp/utils/identity'; +import {renderYesNo} from 'web/utils/render'; +import styled from 'styled-components'; const ToolBarIcons = withCapabilities( ({ @@ -125,6 +130,55 @@ Details.propTypes = { entity: PropTypes.model.isRequired, links: PropTypes.bool, }; +const ReportFormatParamValue = ({ + param, + value = param.value, + value_labels = param.value_labels, + links = true, +}) => { + if (param.type === 'report_format_list') { + return map(value, report_format_id => { + const label = isDefined(value_labels[report_format_id]) + ? value_labels[report_format_id] + : report_format_id; + return ( + + {label} + + ); + }); + } else if (param.type === 'multi_selection') { + const OptionsList = styled.ul` + margin: 0; + padding-left: 1em; + `; + return ( + + {param.value.map(option => ( +
  • {value}; + } else if (param.type === 'boolean') { + return renderYesNo(value); + } + + return value; +}; + +ReportFormatParamValue.propTypes = { + links: PropTypes.bool, + param: PropTypes.any.isRequired, + value: PropTypes.any, + value_labels: PropTypes.object, +}; const Parameters = ({entity}) => { const {params = []} = entity; @@ -143,8 +197,10 @@ const Parameters = ({entity}) => { {params.map(param => ( - {param.name} - {param.value} + {param.name} + + + ))}