Skip to content

Commit

Permalink
fix: prevent adding components from a different data model to the sub…
Browse files Browse the repository at this point in the history
…form table (#14442)
  • Loading branch information
lassopicasso authored Jan 22, 2025
1 parent 9b66891 commit 3d752ba
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import { useUpsertTextResourceMutation } from 'app-shared/hooks/mutations';
import { useTextIdMutation } from 'app-development/hooks/mutations';
import {
getComponentsForSubformTable,
getDefaultDataModel,
getTitleIdForColumn,
getValueOfTitleId,
} from '../../utils/editSubformTableColumnsUtils';
import { convertDataBindingToInternalFormat } from '../../../../../utils/dataModelUtils';
import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery';

export type ColumnElementProps = {
sourceColumn: TableColumn;
Expand Down Expand Up @@ -56,6 +58,7 @@ export const EditColumnElement = ({
const { mutate: upsertTextResource } = useUpsertTextResourceMutation(org, app);
const { mutate: textIdMutation } = useTextIdMutation(org, app);
const { data: formLayouts } = useFormLayoutsQuery(org, app, subformLayout);
const { data: layoutSets } = useLayoutSetsQuery(org, app);

const handleSave = () => {
upsertTextResource({ language: 'nb', textId: uniqueTitleId, translation: title });
Expand All @@ -82,7 +85,8 @@ export const EditColumnElement = ({
setTableColumn(updatedTableColumn);
};

const availableComponents = getComponentsForSubformTable(formLayouts);
const subformDefaultDataModel = getDefaultDataModel(layoutSets, subformLayout);
const availableComponents = getComponentsForSubformTable(formLayouts, subformDefaultDataModel);
const isSaveButtonDisabled = !tableColumn.headerContent || !title?.trim();

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ const formLayouts: IFormLayouts = {
...componentMocks[ComponentType.Input],
dataModelBindings: { simpleBinding: 'mockDataModelBinding3' },
},
['componentId4']: {
...componentMocks[ComponentType.Input],
textResourceBindings: { title: 'mockDescriptionId' },
dataModelBindings: {
simpleBinding: { dataType: 'mockDataModel', field: 'mockDataModelBinding4' } as any, // TODO: remove as any when https://github.com/Altinn/altinn-studio/issues/14441 is solved
},
},
},
order: {
['container1']: ['componentId1', 'componentId2', 'componentId3'],
['container1']: ['componentId1', 'componentId2', 'componentId3', 'componentId4'],
},
},
};
Expand Down Expand Up @@ -121,9 +128,11 @@ describe('editSubformTableColumnsUtils', () => {
});

describe('getComponentsForSubformTable', () => {
it('should return components with title and data model bindings', () => {
const availableComponents = getComponentsForSubformTable(formLayouts);
expect(availableComponents.length).toEqual(1);
const defaultDataModel = 'mockDataModel';

it('Should return components with a title and either a matching default data model or no data model', () => {
const availableComponents = getComponentsForSubformTable(formLayouts, defaultDataModel);
expect(availableComponents.length).toEqual(2);
});

it('should return an empty array if no components have title and data model bindings', () => {
Expand All @@ -141,7 +150,10 @@ describe('editSubformTableColumnsUtils', () => {
},
};

const availableComponents = getComponentsForSubformTable(noAvailableComponentsInFormLayouts);
const availableComponents = getComponentsForSubformTable(
noAvailableComponentsInFormLayouts,
defaultDataModel,
);
expect(availableComponents.length).toEqual(0);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { type ITextResources } from 'app-shared/types/global';
import { getAllLayoutComponents } from '@altinn/ux-editor/utils/formLayoutUtils';
import { textResourceByLanguageAndIdSelector } from '@altinn/ux-editor/selectors/textResourceSelectors';
import { getRandNumber } from '@altinn/text-editor/utils';
import { type LayoutSets } from 'app-shared/types/api/LayoutSetsResponse';
import { convertDataBindingToInternalFormat } from '@altinn/ux-editor/utils/dataModelUtils';

export const updateComponentWithSubform = (
component: FormItem<ComponentType.Subform>,
Expand All @@ -24,17 +26,34 @@ export const filterOutTableColumn = (
return tableColumns.filter((tableColumn: TableColumn) => tableColumn !== tableColumnToRemove);
};

export const getComponentsForSubformTable = (formLayouts: IFormLayouts): FormItem[] => {
export const getComponentsForSubformTable = (
formLayouts: IFormLayouts,
defaultDataModel: string,
): FormItem[] => {
const components = Object.values(formLayouts ?? {}).flatMap((layout: IInternalLayout) =>
getAllLayoutComponents(layout),
);
return componentsWithLabelAndDataModel(components);

return componentsWithTitleAndDefaultDataModel(components, defaultDataModel);
};

const componentsWithLabelAndDataModel = (components: FormItem[]): FormItem[] => {
return components.filter(
(comp) => comp.textResourceBindings?.title && comp.dataModelBindings?.simpleBinding,
);
const componentsWithTitleAndDefaultDataModel = (
components: FormItem[],
defaultDataModel: string,
): FormItem[] => {
const hasValidDataBinding = (comp: FormItem) =>
Object.keys(comp.dataModelBindings ?? {}).some((binding) => {
const { dataType, field } = convertDataBindingToInternalFormat(comp, binding);
return dataType === defaultDataModel || (dataType === '' && field !== '');
});

return components.filter((comp) => comp.textResourceBindings?.title && hasValidDataBinding(comp));
};

export const getDefaultDataModel = (layoutSets: LayoutSets, subformLayout: string): string => {
const layoutSet = layoutSets?.sets.find((layoutSet) => layoutSet.id === subformLayout);

return layoutSet?.dataType ?? '';
};

export const getValueOfTitleId = (titleId: string, textResources: ITextResources): string => {
Expand Down

0 comments on commit 3d752ba

Please sign in to comment.