Skip to content

Commit

Permalink
🚸 Declutter variables table a bit more
Browse files Browse the repository at this point in the history
The component variables are now grouped by the step they occur in, and
the column with the form definition name is removed. Variables are
sorted alphabetically, which should give a stable ordering of variables
inside of a step (or other tab). The steps are of course rendered in
order of definition.

The key of a component is now properly marked up as code, as it is a
system identifier and can help with quickly visual scanning which key
is required in logic rules.
  • Loading branch information
sergei-maertens committed Mar 11, 2025
1 parent 4d80299 commit 65a9ce5
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const PluginVariables = ({
<tr className={`row${(index % 2) + 1}`} key={variable.key}>
<td />
<td>{variable.name}</td>
<td>{variable.key}</td>
<td>
<code>{variable.key}</code>
</td>
<td>
<RegistrationSummaryList
variable={variable}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ const StaticData = ({onFieldChange}) => {
<tr className={`row${(index % 2) + 1}`} key={item.key}>
<td />
<td>{item.name}</td>
<td>{item.key}</td>
<td>
<code>{item.key}</code>
</td>
<td>
<RegistrationSummaryList variable={item} onFieldChange={onFieldChange} />
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ const AVAILABLE_FORM_STEPS = [
validationErrors: [],
},
{
formDefinition: 'http://localhost:8000/api/v2/form-definitions/fe599c97',
formDefinition: '',
configuration: {display: 'form', components: []},
slug: 'step-2',
name: 'Step 2',
url: 'http://localhost:8000/api/v2/forms/ae26e20c-f059-4fdf-bb82-afc377869bb5/steps/fe599c97',
uuid: 'fe599c97',
_generatedId: '',
isNew: false,
_generatedId: 'unsaved-step',
isNew: true,
validationErrors: [],
},
];
Expand Down Expand Up @@ -81,7 +81,7 @@ const VARIABLES = [
},
{
form: 'http://localhost:8000/api/v2/forms/36612390',
formDefinition: 'http://localhost:8000/api/v2/form-definitions/fe599c97',
formDefinition: 'unsaved-step',
name: 'Multiple File',
key: 'aMultipleFile',
source: 'component',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import classNames from 'classnames';
import groupBy from 'lodash/groupBy';
import PropTypes from 'prop-types';
import React, {useContext, useState} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
Expand Down Expand Up @@ -35,11 +36,10 @@ const SensitiveData = ({isSensitive}) => {
);
};

const Td = ({variable, fieldName}) => {
const KeyDisplay = ({variable}) => {
const intl = useIntl();

const field = variable[fieldName];
let fieldErrors = variable?.errors?.[fieldName] ?? [];
let fieldErrors = variable?.errors?.key ?? [];

if (!Array.isArray(fieldErrors)) fieldErrors = [fieldErrors];

Expand All @@ -51,41 +51,28 @@ const Td = ({variable, fieldName}) => {
});

return (
<td>
<Field name={fieldName} errors={fieldErrors}>
<div>{field}</div>
</Field>
</td>
<Field name="key" errors={fieldErrors}>
<code>{variable.key}</code>
</Field>
);
};

Td.propTypes = {
KeyDisplay.propTypes = {
variable: Variable.isRequired,
fieldName: PropTypes.string.isRequired,
};

const VariableRow = ({index, variable, onFieldChange}) => {
const formContext = useContext(FormContext);
const formSteps = formContext.formSteps;

const getFormDefinitionName = formDefinition => {
for (const step of formSteps) {
if (step.formDefinition === formDefinition || step._generatedId === formDefinition)
return step.name;
}
return '';
};

const rowClassnames = classNames(`row${(index % 2) + 1}`, 'variables-table__row', {
const VariableRow = ({variable, onFieldChange}) => {
const rowClassnames = classNames('variables-table__row', {
'variables-table__row--errors': variableHasErrors(variable),
});

return (
<tr className={rowClassnames}>
<td />
<td>{variable.name}</td>
<Td variable={variable} fieldName="key" />
<td>{getFormDefinitionName(variable.formDefinition)}</td>
<td>
<KeyDisplay variable={variable} fieldName="key" />
</td>
<td>
<PrefillSummary
plugin={variable.prefillPlugin}
Expand Down Expand Up @@ -131,7 +118,7 @@ const EditableVariableRow = ({index, variable, onDelete, onChange, onFieldChange

return (
<tr
className={classNames('variables-table__row', `row${(index % 2) + 1}`, {
className={classNames('variables-table__row', {
'variables-table__row--errors': variableHasErrors(variable),
})}
>
Expand Down Expand Up @@ -219,6 +206,8 @@ const EditableVariableRow = ({index, variable, onDelete, onChange, onFieldChange
};

const VariablesTable = ({variables, editable, onDelete, onChange, onFieldChange}) => {
const {formSteps} = useContext(FormContext);

const headColumns = (
<>
<HeadColumn content="" />
Expand All @@ -228,16 +217,6 @@ const VariablesTable = ({variables, editable, onDelete, onChange, onFieldChange}
<HeadColumn
content={<FormattedMessage defaultMessage="Key" description="Variable table key title" />}
/>
{!editable && (
<HeadColumn
content={
<FormattedMessage
defaultMessage="Form definition"
description="Variable table form definition title"
/>
}
/>
)}
<HeadColumn
content={
<FormattedMessage defaultMessage="Prefill" description="Variable table prefill title" />
Expand Down Expand Up @@ -278,27 +257,62 @@ const VariablesTable = ({variables, editable, onDelete, onChange, onFieldChange}
</>
);

// first, sort the variables alphabetically
const sortedVariables = variables.toSorted((var1, var2) => var1.name.localeCompare(var2.name));
// then, group the variables by their step so that we display them grouped in the table,
// which cuts down on the number of columns to display
const variablesGroupedByFormStep = groupBy(
sortedVariables,
variable => variable.formDefinition ?? ''
);

// convert back to an ordered array, in order of steps, as Objects don't have a
// guaranteed insert order
const variableGroups = formSteps.map(step => {
const key = step.formDefinition || step._generatedId;
return [step, variablesGroupedByFormStep?.[key]];
});
// and add the variables not attached to a step (the user defined vars)
const varsNotRelatedToStep = variablesGroupedByFormStep[''];
if (varsNotRelatedToStep) {
variableGroups.push([{name: '', _generatedId: 'userDefined'}, varsNotRelatedToStep]);
}

return (
<div className="variables-table">
<ChangelistTableWrapper headColumns={headColumns} extraModifiers={['fixed']}>
{variables.map((variable, index) =>
editable ? (
<EditableVariableRow
key={`${variable.key}-${index}`}
index={index}
variable={variable}
onDelete={onDelete}
onChange={onChange}
onFieldChange={onFieldChange}
/>
) : (
<VariableRow
key={`${variable.key}-${index}`}
index={index}
variable={variable}
onFieldChange={onFieldChange}
/>
)
{variableGroups.map(
([step, stepVariables]) =>
stepVariables && (
<React.Fragment key={step.uuid || step._generatedId}>
{step.name && (
<tr>
<td />
<th colSpan={7} className="variables-table__step-name">
{step.name}
</th>
</tr>
)}
{stepVariables.map((variable, index) =>
editable ? (
<EditableVariableRow
key={`${variable.key}-${index}`}
index={index}
variable={variable}
onDelete={onDelete}
onChange={onChange}
onFieldChange={onFieldChange}
/>
) : (
<VariableRow
key={`${variable.key}-${index}`}
variable={variable}
onFieldChange={onFieldChange}
/>
)
)}
</React.Fragment>
)
)}
</ChangelistTableWrapper>
</div>
Expand Down
17 changes: 15 additions & 2 deletions src/openforms/scss/components/admin/_variables-table.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@use 'microscope-sass/lib/bem';

@import '../../../ui/static/ui/scss/settings';

.variables-table {
Expand All @@ -19,8 +21,15 @@
padding-left: 0 !important;
}

&__row {
&--errors {
@include bem.element('step-name') {
text-decoration: underline;
text-decoration-style: dashed;
text-underline-offset: 5px;
text-decoration-thickness: 0.5px;
}

@include bem.element('row') {
@include bem.modifier('errors') {
td {
vertical-align: bottom !important;
}
Expand All @@ -29,5 +38,9 @@
.checkbox-row {
padding: $grid-margin-1; // Same padding as the icon
}

code {
font-size: 100%;
}
}
}

0 comments on commit 65a9ce5

Please sign in to comment.