Skip to content

Commit

Permalink
Merge pull request #147 from mercedes-benz/VULCAN-947/ActionRules
Browse files Browse the repository at this point in the history
Vulcan 947/Checkbox Disable Pre Condition
  • Loading branch information
m-o-n-i-s-h authored Nov 21, 2024
2 parents 4f1710c + e45c07d commit 958cd79
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/card/settings/CardSettingsFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const NeoCardSettingsFooter = ({
settingValue={reportSettings[actionsToCustomize]}
type={type}
fields={fields}
preConditionsSetting={reportSettings?.preConditions}
customReportActionsModalOpen={customReportActionsModalOpen}
setCustomReportActionsModalOpen={setCustomReportActionsModalOpen}
onReportSettingUpdate={onReportSettingUpdate}
Expand Down
42 changes: 42 additions & 0 deletions src/chart/table/TableActionsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,48 @@ export const hasCheckboxes = (actionsRules) => {
return rules.length > 0;
};

export const hasPreCondition = (preConditions) => {
return preConditions.length > 0;
};

const groupConditionsByField = (conditions) => {
return conditions.reduce((acc, condition) => {
if (!acc[condition.field]) {
acc[condition.field] = [];
}
acc[condition.field].push(condition);
return acc;
}, {});
};

const evaluateGroupedConditions = (groupedConditions, row) => {
return Object.keys(groupedConditions).every((field) => {
// Logical OR between conditions for the same field
return groupedConditions[field].some((condition) => evaluateCondition(condition, row));
});
};

export const convertConditionsToExpression = (conditions, row) => {
const groupedConditions = groupConditionsByField(conditions);
return !evaluateGroupedConditions(groupedConditions, row);
};

const evaluateCondition = (condition, row) => {
const fieldValue = row[condition.field];
switch (condition.condition) {
case '=':
return fieldValue === condition.value;
case '!=':
return fieldValue !== condition.value;
case 'contains':
return typeof fieldValue === 'string' && fieldValue.includes(condition.value);
case 'not_contains':
return typeof fieldValue === 'string' && !fieldValue.includes(condition.value);
default:
return false;
}
};

export const getCheckboxes = (actionsRules, rows, getGlobalParameter) => {
let rules = actionsRules.filter((rule) => rule.condition && rule.condition == 'rowCheck');
const params = rules.map((rule) => `neodash_${rule.customizationValue}`);
Expand Down
22 changes: 20 additions & 2 deletions src/chart/table/TableChart.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { DataGrid, GridColumnVisibilityModel } from '@mui/x-data-grid';
import { DataGrid, GridColumnVisibilityModel, GridRowId } from '@mui/x-data-grid';
import { ChartProps } from '../Chart';
import {
evaluateRulesOnDict,
Expand All @@ -22,7 +22,13 @@ import { ThemeProvider, createTheme } from '@mui/material/styles';
import Button from '@mui/material/Button';
import { extensionEnabled } from '../../utils/ReportUtils';
import { renderCellExpand } from '../../component/misc/DataGridExpandRenderer';
import { getCheckboxes, hasCheckboxes, updateCheckBoxes } from './TableActionsHelper';
import {
convertConditionsToExpression,
getCheckboxes,
hasCheckboxes,
hasPreCondition,
updateCheckBoxes,
} from './TableActionsHelper';
import ApiService from '../../utils/apiService';
import { AxiosResponse } from 'axios';
import Notification from '../../component/custom/Notification';
Expand Down Expand Up @@ -97,6 +103,10 @@ export const NeoTableChart = (props: ChartProps) => {
extensionEnabled(props.extensions, 'actions') && props.settings && props.settings.actionsRules
? props.settings.actionsRules
: [];
const preConditions =
extensionEnabled(props.extensions, 'actions') && props.settings && props.settings.preConditions
? props.settings.preConditions
: [];
const compact = props.settings && props.settings.compact !== undefined ? props.settings.compact : false;
const styleRules = useStyleRules(
extensionEnabled(props.extensions, 'styling'),
Expand Down Expand Up @@ -413,6 +423,13 @@ export const NeoTableChart = (props: ChartProps) => {
? { marginTop: 10, height: '90%', width: '100%', position: 'relative' }
: { height: '100%', width: '100%', position: 'relative' };

const isRowSelectable = (params: { id: GridRowId; row: any }) => {
if (hasPreCondition(preConditions)) {
return convertConditionsToExpression(preConditions, params.row);
}
return true;
};

return (
<ThemeProvider theme={theme}>
<Notification
Expand Down Expand Up @@ -489,6 +506,7 @@ export const NeoTableChart = (props: ChartProps) => {
onSelectionModelChange={(selection) =>
updateCheckBoxes(actionsRules, rows, selection, props.setGlobalParameter)
}
isRowSelectable={isRowSelectable}
autoPageSize
pagination
disableSelectionOnClick
Expand Down
156 changes: 153 additions & 3 deletions src/extensions/actions/ActionsRuleCreationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,34 @@ import {
} from '@neo4j-ndl/react/icons';
import { getPageNumbersAndNamesList } from '../advancedcharts/Utils';
import { IconButton, Button, Dialog, Dropdown, TextInput } from '@neo4j-ndl/react';
import { Autocomplete, TextField } from '@mui/material';
import { Autocomplete, TextField, Typography } from '@mui/material';

// Pre conditions

const PRE_CONDITIONS_RULES = [
{
value: '=',
label: '=',
},
{
value: '!=',
label: '!=',
},
{
value: 'contains',
label: 'contains',
},
{
value: 'not_contains',
label: 'not_contains',
},
];

const defaultPreCondition = {
condition: '=',
field: '',
value: '',
};

// The set of conditional checks that are included in the rule specification.
const RULE_CONDITIONS = {
Expand Down Expand Up @@ -166,12 +193,17 @@ export const NeoCustomReportActionsModal = ({
fields,
setCustomReportActionsModalOpen,
onReportSettingUpdate,
preConditionsSetting,
}) => {
// The rule set defined in this modal is updated whenever the setting value is externally changed.
const [rules, setRules] = React.useState([]);
const [preConditions, setPreConditions] = React.useState([defaultPreCondition]);
useEffect(() => {
if (settingValue) {
setRules(settingValue);
if (preConditionsSetting) {
setPreConditions(preConditionsSetting);
}
}
}, [settingValue]);

Expand All @@ -183,6 +215,12 @@ export const NeoCustomReportActionsModal = ({
} else {
onReportSettingUpdate(settingName, rules);
}

if (preConditions.length === 0) {
onReportSettingUpdate('preConditions', undefined);
} else {
onReportSettingUpdate('preConditions', preConditions);
}
setCustomReportActionsModalOpen(false);
};

Expand All @@ -193,6 +231,10 @@ export const NeoCustomReportActionsModal = ({
setRules(newRules);
};

const updatePreConditionFieldById = (j, field, value) => {
setPreConditions((prevItems) => prevItems.map((item, i) => (i === j ? { ...item, [field]: value } : item)));
};

/**
* Create the list of suggestions used in the autocomplete box of the rule specification window.
* This will be dynamic based on the type of report we are customizing.
Expand Down Expand Up @@ -333,7 +375,7 @@ export const NeoCustomReportActionsModal = ({
const td2Styling = (type) => ({ width: type === 'bar' ? '15%' : '30%' });
const td2DropdownClassname = (type) => `n-align-middle n-pr-1 ${type === 'bar' ? 'n-w-full' : 'n-w-2/5'}`;
const td2Autocomplete = (type, index, rule) =>
(type !== 'bar' && rule.condition !== 'rowCheck' ? (
type !== 'bar' && rule.condition !== 'rowCheck' ? (
<Autocomplete
className='n-align-middle n-inline-block n-w-/5'
disableClearable={true}
Expand Down Expand Up @@ -364,7 +406,7 @@ export const NeoCustomReportActionsModal = ({
/>
) : (
<></>
));
);
const td4Styling = (type) => ({ width: type === 'bar' ? '45%' : '40%' });
const td4DropdownClassname = 'n-align-middle, n-w-1/3';
const td6Styling = (type) => ({ width: type === 'bar' ? '30%' : '20%' });
Expand Down Expand Up @@ -535,6 +577,114 @@ export const NeoCustomReportActionsModal = ({
</td>
</tr>
</table>

<table>
<tr>
<td colSpan={7}>
<tr>
<th colSpan={7} className='n-text-center n-font-bold n-py-2'>
Report Pre Conditions
</th>
</tr>
</td>
</tr>
{preConditions.map((con, i) => {
return (
<tr>
<td width='2.5%' className='n-pr-1'>
<span className='n-pr-1'>{i + 1}.</span>
<span className='n-font-bold'>IF</span>
</td>
<td width='100%'>
<div style={{ border: '2px dashed grey' }} className='n-p-1'>
<Autocomplete
className='n-align-middle n-inline-block n-w-5/12 n-pr-1'
disableClearable={true}
id={`autocomplete-label-type${i}`}
size='small'
noOptionsText='*Specify an exact field name'
options={createFieldVariableSuggestions(null, null, null).filter((e) =>
e.toLowerCase().includes(con.field.toLowerCase())
)}
value={con.field ? con.field : ''}
inputValue={con.field ? con.field : ''}
popupIcon={<></>}
style={{ minWidth: 125 }}
onInputChange={(event, value) => {
updatePreConditionFieldById(i, 'field', value);
}}
onChange={(event, newValue) => {
updatePreConditionFieldById(i, 'field', newValue);
}}
renderInput={(params) => (
<TextField
{...params}
placeholder='Field name...'
InputLabelProps={{ shrink: true }}
style={{ padding: '6px 0 7px' }}
size={'small'}
/>
)}
/>
<Dropdown
type='select'
className='n-align-middle n-w-2/12 n-pr-1'
selectProps={{
onChange: (newValue) => updatePreConditionFieldById(i, 'condition', newValue?.value),
options: PRE_CONDITIONS_RULES.map((option) => ({
label: option.label,
value: option.value,
})),
value: { label: con.condition, value: con.condition },
}}
style={{ minWidth: 70, display: 'inline-block' }}
fluid
/>
<TextInput
className='n-align-middle n-inline-block n-w-5/12'
style={{ minWidth: 100 }}
placeholder='Value...'
value={con.value}
onChange={(e) => updatePreConditionFieldById(i, 'value', e.target.value)}
fluid
></TextInput>
</div>
</td>

<td width='5%'>
<IconButton
aria-label='remove rule'
size='medium'
style={{ marginLeft: 10 }}
floating
onClick={() => {
setPreConditions((prevItems) => prevItems.filter((_, j) => j !== i));
}}
>
<XMarkIconOutline />
</IconButton>
</td>
</tr>
);
})}

<tr>
<td colSpan={7}>
<div className='n-text-center n-mt-1'>
<IconButton
aria-label='add'
size='medium'
floating
onClick={() => {
setPreConditions([...preConditions, defaultPreCondition]);
}}
>
<PlusIconOutline />
</IconButton>
</div>
</td>
</tr>
</table>
</div>
</Dialog.Content>
<Dialog.Actions>
Expand Down

0 comments on commit 958cd79

Please sign in to comment.