Skip to content

Commit

Permalink
12600 process receipt fixes (#12884)
Browse files Browse the repository at this point in the history
* Fixing UI issues#

* fixing logic for custom receipt

* refactor code

* fixing typecheck

* fixing some comments

* trying to fix issue

* trying to fix issue

* Delete dataType connection in LayoutSets based on dataTypeId directly when deleting a data model

* Fixing tests

* Fixing tests

* Remove comment

* PR feedback

---------

Co-authored-by: andreastanderen <andreastanderen@gmail.com>
  • Loading branch information
WilliamThorenfeldt and standeren authored Jun 3, 2024
1 parent fea8a6b commit c91bfd7
Show file tree
Hide file tree
Showing 20 changed files with 113 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,8 @@ private static async Task DeleteDatatypeFromApplicationMetadataAndLayoutSets(Alt
if (altinnAppGitRepository.AppUsesLayoutSets())
{
var layoutSets = await altinnAppGitRepository.GetLayoutSetsFile();
List<LayoutSetConfig> layoutSetsWithDeletedDataType = layoutSets.Sets.FindAll(set => set.DataType == dataTypeToDelete.Id);
foreach (LayoutSetConfig layoutSet in layoutSetsWithDeletedDataType)
List<LayoutSetConfig> layoutSetsWithDataTypeToDelete = layoutSets.Sets.FindAll(set => set.DataType == id);
foreach (LayoutSetConfig layoutSet in layoutSetsWithDataTypeToDelete)
{
layoutSet.DataType = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ export const ProcessEditor = (): React.ReactElement => {

const { data: availableDataModelIds, isPending: availableDataModelIdsPending } =
useAppMetadataModelIdsQuery(org, app);
const { data: allDataModelIds, isPending: allDataModelIdsPending } = useAppMetadataModelIdsQuery(
org,
app,
false,
);
const { data: layoutSets } = useLayoutSetsQuery(org, app);

const pendingApiOperations: boolean =
Expand All @@ -74,6 +79,7 @@ export const ProcessEditor = (): React.ReactElement => {
deleteLayoutSetPending ||
updateDataTypePending ||
availableDataModelIdsPending ||
allDataModelIdsPending ||
isPendingCurrentPolicy;

const { onWSMessageReceived } = useWebSocket({
Expand Down Expand Up @@ -139,6 +145,7 @@ export const ProcessEditor = (): React.ReactElement => {
return (
<ProcessEditorImpl
availableDataModelIds={availableDataModelIds}
allDataModelIds={allDataModelIds}
layoutSets={layoutSets}
pendingApiOperations={pendingApiOperations}
existingCustomReceiptLayoutSetId={existingCustomReceiptId}
Expand Down
2 changes: 1 addition & 1 deletion frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@
"process_editor.configuration_panel_layout_set_id_not_valid_format": "Sidegruppenavnet må være unikt",
"process_editor.configuration_panel_missing_task": "Oppgave",
"process_editor.configuration_panel_name_label": "Navn: ",
"process_editor.configuration_panel_no_data_model_to_select": "Du må ha ingen tilgjengelige datamodeller du kan knytte mot dette steget.",
"process_editor.configuration_panel_no_data_model_to_select": "Du må ha tilgjengelige datamodeller du kan knytte mot dette steget.",
"process_editor.configuration_panel_no_task_message": "Velg en oppgave i diagrammet til venstre for å se detaljer om valgt oppgave.",
"process_editor.configuration_panel_no_task_title": "Ingen oppgave er valgt",
"process_editor.configuration_panel_payment_task": "Oppgave: Betaling",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const defaultProps: ProcessEditorProps = {
saveBpmn: jest.fn(),
appLibVersion: mockAppLibVersion8,
availableDataModelIds: [],
allDataModelIds: [],
layoutSets: { sets: [] },
pendingApiOperations: false,
existingCustomReceiptLayoutSetId: undefined,
Expand Down
3 changes: 3 additions & 0 deletions frontend/packages/process-editor/src/ProcessEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type ProcessEditorProps = {
appLibVersion: string;
bpmnXml: string | undefined | null;
availableDataModelIds: BpmnApiContextProps['availableDataModelIds'];
allDataModelIds: BpmnApiContextProps['allDataModelIds'];
layoutSets: BpmnApiContextProps['layoutSets'];
pendingApiOperations: boolean;
existingCustomReceiptLayoutSetId: BpmnApiContextProps['existingCustomReceiptLayoutSetId'];
Expand All @@ -36,6 +37,7 @@ export const ProcessEditor = ({
appLibVersion,
bpmnXml,
availableDataModelIds,
allDataModelIds,
layoutSets,
pendingApiOperations,
existingCustomReceiptLayoutSetId,
Expand Down Expand Up @@ -64,6 +66,7 @@ export const ProcessEditor = ({
<BpmnContextProvider bpmnXml={bpmnXml} appLibVersion={appLibVersion}>
<BpmnApiContextProvider
availableDataModelIds={availableDataModelIds}
allDataModelIds={allDataModelIds}
layoutSets={layoutSets}
pendingApiOperations={pendingApiOperations}
existingCustomReceiptLayoutSetId={existingCustomReceiptLayoutSetId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import { useTranslation } from 'react-i18next';
import { useBpmnContext } from '../../../contexts/BpmnContext';
import { EditTaskId } from './EditTaskId/EditTaskId';
import { StudioDisplayTile, StudioSectionHeader } from '@studio/components';
import {
getConfigTitleKey,
getConfigTitleHelpTextKey,
getDataModelOptions,
} from '../../../utils/configPanelUtils';
import { getConfigTitleKey, getConfigTitleHelpTextKey } from '../../../utils/configPanelUtils';
import { ConfigIcon } from './ConfigIcon';
import { EditDataType } from '../EditDataType';
import { useBpmnApiContext } from '../../../contexts/BpmnApiContext';
Expand All @@ -27,8 +23,6 @@ export const ConfigContent = (): React.ReactElement => {
const layoutSet = layoutSets?.sets.find((set) => set.tasks.includes(bpmnDetails.id));
const existingDataTypeForTask = layoutSet?.dataType;

const dataModelIds = getDataModelOptions(availableDataModelIds, existingDataTypeForTask);

const taskHasConnectedLayoutSet = layoutSets?.sets?.some((set) => set.tasks[0] == bpmnDetails.id);

return (
Expand All @@ -53,7 +47,7 @@ export const ConfigContent = (): React.ReactElement => {
{taskHasConnectedLayoutSet && (
<EditDataType
connectedTaskId={layoutSet.tasks[0]}
dataModelIds={dataModelIds}
dataModelIds={availableDataModelIds}
existingDataTypeForTask={existingDataTypeForTask}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@ import { queryOptionMock } from 'app-shared/mocks/queryOptionMock';
import { PROTECTED_TASK_NAME_CUSTOM_RECEIPT } from 'app-shared/constants';

const mockAddLayoutSet = jest.fn().mockImplementation(queryOptionMock);
const mockMutateDataType = jest.fn().mockImplementation(queryOptionMock);

const mockOnCloseForm = jest.fn();
const mockAvailableDataModelIds: string[] = ['model1', 'model2'];
const mockAllDataModelIds: string[] = ['model1', 'model2'];

const defaultProps: CreateCustomReceiptFormProps = {
onCloseForm: mockOnCloseForm,
};

const defaultBpmnApiContextProps: BpmnApiContextProps = {
...mockBpmnApiContextValue,
availableDataModelIds: mockAvailableDataModelIds,
allDataModelIds: mockAllDataModelIds,
addLayoutSet: mockAddLayoutSet,
mutateDataType: mockMutateDataType,
};

describe('CreateCustomReceiptForm', () => {
Expand All @@ -46,13 +44,14 @@ describe('CreateCustomReceiptForm', () => {
const newId: string = 'newLayoutSetId';
await user.type(layoutSetInput, newId);

const selectElement = screen.getByLabelText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
);
await user.click(selectElement);
const combobox = screen.getByRole('combobox', {
name: textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
});
await user.click(combobox);

const optionElement = screen.getByRole('option', { name: mockAvailableDataModelIds[0] });
await user.selectOptions(selectElement, optionElement);
const optionElement = screen.getByRole('option', { name: mockAllDataModelIds[0] });
await user.click(optionElement);
await user.keyboard('{Escape}');

const createButton = screen.getByRole('button', {
name: textMock('process_editor.configuration_panel_custom_receipt_create_button'),
Expand All @@ -65,6 +64,7 @@ describe('CreateCustomReceiptForm', () => {
{
layoutSetConfig: {
id: newId,
dataType: mockAllDataModelIds[0],
tasks: [PROTECTED_TASK_NAME_CUSTOM_RECEIPT],
},
layoutSetIdToUpdate: newId,
Expand All @@ -75,33 +75,21 @@ describe('CreateCustomReceiptForm', () => {
),
);

await waitFor(() => expect(mockMutateDataType).toHaveBeenCalledTimes(1));
await waitFor(() =>
expect(mockMutateDataType).toHaveBeenCalledWith(
{
connectedTaskId: PROTECTED_TASK_NAME_CUSTOM_RECEIPT,
newDataType: mockAvailableDataModelIds[0],
},
{
onSuccess: expect.any(Function),
},
),
);

expect(mockOnCloseForm).toHaveBeenCalled();
});

it('displays error when there are no value present for layout id', async () => {
const user = userEvent.setup();
renderCreateCustomReceiptForm();

const selectElement = screen.getByLabelText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
);
await user.click(selectElement);
const combobox = screen.getByRole('combobox', {
name: textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
});
await user.click(combobox);

const optionElement = screen.getByRole('option', { name: mockAvailableDataModelIds[0] });
await user.selectOptions(selectElement, optionElement);
const optionElement = screen.getByRole('option', { name: mockAllDataModelIds[0] });
await user.click(optionElement);
await user.keyboard('{Escape}');

const createButton = screen.getByRole('button', {
name: textMock('process_editor.configuration_panel_custom_receipt_create_button'),
Expand Down Expand Up @@ -190,18 +178,15 @@ describe('CreateCustomReceiptForm', () => {

it('displays error when there are no value present for data model id', async () => {
const user = userEvent.setup();
renderCreateCustomReceiptForm({ bpmnApiContextProps: mockBpmnApiContextValue });
renderCreateCustomReceiptForm({
bpmnApiContextProps: { allDataModelIds: mockAllDataModelIds },
});

const layoutSetInput = screen.getByLabelText(
textMock('process_editor.configuration_panel_custom_receipt_textfield_label'),
);
await user.type(layoutSetInput, 'newLayoutSetId');

const selectElement = screen.getByLabelText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
);
await user.click(selectElement);

const createButton = screen.getByRole('button', {
name: textMock('process_editor.configuration_panel_custom_receipt_create_button'),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next';
import { StudioButton, StudioTextfield } from '@studio/components';
import { useBpmnApiContext } from '../../../../../contexts/BpmnApiContext';
import { type CustomReceiptType } from '../../../../../types/CustomReceiptType';
import { type DataTypeChange } from 'app-shared/types/api/DataTypeChange';
import { PROTECTED_TASK_NAME_CUSTOM_RECEIPT } from 'app-shared/constants';
import { type LayoutSetConfig } from 'app-shared/types/api/LayoutSetsResponse';
import { SelectCustomReceiptDataModelId } from './SelectCustomReceiptDataModelId';
Expand All @@ -18,9 +17,11 @@ export const CreateCustomReceiptForm = ({
onCloseForm,
}: CreateCustomReceiptFormProps): React.ReactElement => {
const { t } = useTranslation();
const { layoutSets, existingCustomReceiptLayoutSetId, addLayoutSet, mutateDataType } =
const { allDataModelIds, layoutSets, existingCustomReceiptLayoutSetId, addLayoutSet } =
useBpmnApiContext();

const allDataModelIdsEmpty: boolean = allDataModelIds.length === 0;

const [layoutSetError, setLayoutSetError] = useState<string>(null);
const [dataModelError, setDataModelError] = useState<string>(null);

Expand All @@ -46,6 +47,7 @@ export const CreateCustomReceiptForm = ({
const updateErrors = (customReceiptForm: CustomReceiptType) => {
const { layoutSetId, dataModelId } = customReceiptForm;
setLayoutSetError(!layoutSetId ? t('validation_errors.required') : null);

setDataModelError(
!dataModelId
? t('process_editor.configuration_panel_custom_receipt_create_data_model_error')
Expand All @@ -56,6 +58,7 @@ export const CreateCustomReceiptForm = ({
const createNewCustomReceipt = (customReceipt: CustomReceiptType) => {
const customReceiptLayoutSetConfig: LayoutSetConfig = {
id: customReceipt.layoutSetId,
dataType: customReceipt.dataModelId,
tasks: [PROTECTED_TASK_NAME_CUSTOM_RECEIPT],
};
addLayoutSet(
Expand All @@ -64,21 +67,11 @@ export const CreateCustomReceiptForm = ({
layoutSetConfig: customReceiptLayoutSetConfig,
},
{
onSuccess: () => saveDataModel(customReceipt.dataModelId),
onSuccess: onCloseForm,
},
);
};

const saveDataModel = (dataModelId: string) => {
const dataTypeChange: DataTypeChange = {
newDataType: dataModelId,
connectedTaskId: PROTECTED_TASK_NAME_CUSTOM_RECEIPT,
};
mutateDataType(dataTypeChange, {
onSuccess: onCloseForm,
});
};

const handleValidateLayoutSetId = (event: React.ChangeEvent<HTMLInputElement>) => {
const validationResult = getLayoutSetIdValidationErrorKey(
layoutSets,
Expand All @@ -103,7 +96,7 @@ export const CreateCustomReceiptForm = ({
onChange={() => setDataModelError(null)}
/>
<div className={classes.buttonWrapper}>
<StudioButton size='small' type='submit' variant='primary'>
<StudioButton disabled={allDataModelIdsEmpty} size='small' type='submit' variant='primary'>
{t('process_editor.configuration_panel_custom_receipt_create_button')}
</StudioButton>
<StudioButton size='small' onClick={onCloseForm} variant='secondary'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {

const mockError: string = 'Error';
const mockOnChange = jest.fn();
const mockAvailableDataModelIds: string[] = ['model1', 'model2'];
const mockAllDataModelIds: string[] = ['model1', 'model2'];

const defaultProps: SelectCustomReceiptDataModelIdProps = {
error: mockError,
Expand All @@ -32,38 +32,37 @@ describe('SelectCustomReceiptDataModelId', () => {
it('calls onChange function when an option is selected', async () => {
const user = userEvent.setup();
renderSelectCustomReceiptDataModelId({
availableDataModelIds: mockAvailableDataModelIds,
allDataModelIds: mockAllDataModelIds,
});

const selectElement = screen.getByLabelText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
);
await user.click(selectElement);
const combobox = screen.getByRole('combobox', {
name: textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
});
await user.click(combobox);

const optionElement = screen.getByRole('option', { name: mockAvailableDataModelIds[0] });
await user.selectOptions(selectElement, optionElement);
const optionElement = screen.getByRole('option', { name: mockAllDataModelIds[0] });
await user.click(optionElement);

expect(mockOnChange).toHaveBeenCalledTimes(1);
});

it('displays the description when there are no available data model ids', () => {
renderSelectCustomReceiptDataModelId();

const description = screen.getByText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_description'),
);
expect(description).toBeInTheDocument();
});

it('hides the description when there are available data model ids', () => {
it('should display a combobox without value and an empty combobox element informing that data models are missing when clicking "add data model" when there are no data models', async () => {
const user = userEvent.setup();
renderSelectCustomReceiptDataModelId({
availableDataModelIds: mockAvailableDataModelIds,
allDataModelIds: [],
});

const description = screen.queryByText(
textMock('process_editor.configuration_panel_custom_receipt_select_data_model_description'),
const combobox = screen.getByRole('combobox', {
name: textMock('process_editor.configuration_panel_custom_receipt_select_data_model_label'),
});

await user.click(combobox);
expect(combobox).not.toHaveValue();

const noAvailableModelsOption = screen.getByText(
textMock('process_editor.configuration_panel_no_data_model_to_select'),
);
expect(description).not.toBeInTheDocument();
expect(noAvailableModelsOption).toBeInTheDocument();
});
});

Expand Down
Loading

0 comments on commit c91bfd7

Please sign in to comment.