Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(IDataModelBindings): Fix typing of data model bindings #14659

Merged
merged 10 commits into from
Feb 17, 2025
37 changes: 18 additions & 19 deletions frontend/packages/shared/src/types/ComponentSpecificConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,43 @@ import type { ActionButtonAction } from 'app-shared/types/ActionButtonAction';
import type { GridRow } from 'app-shared/types/GridRow';
import type { HTMLAutoCompleteValue } from 'app-shared/types/HTMLAutoCompleteValue';
import type { BooleanExpression, StringExpression } from '@studio/components';
import type { InternalBindingFormat } from '@altinn/ux-editor/utils/dataModelUtils';
import type {
IDataModelBindings,
IDataModelBindingsKeyValue,
} from '@altinn/ux-editor/types/global';

type DataModelBindingsForAddress = {
address: string;
zipCode: string;
postPlace: string;
careOf?: string;
houseNumber?: string;
address: IDataModelBindings;
zipCode: IDataModelBindings;
postPlace: IDataModelBindings;
careOf?: IDataModelBindings;
houseNumber?: IDataModelBindings;
};

type DataModelBindingsForCustom = {
[id: string]: string;
};
type DataModelBindingsForCustom = IDataModelBindingsKeyValue;

type DataModelBindingsForGroup = {
group: string;
group: IDataModelBindings;
};

type DataModelBindingsForList = {
[id: string]: string;
};
type DataModelBindingsForList = IDataModelBindingsKeyValue;

type DataModelBindingsLikert = {
answer: string;
questions: string;
answer: IDataModelBindings;
questions: IDataModelBindings;
};

type DataModelBindingsList = {
list: string;
list: IDataModelBindings;
};

type DataModelBindingsOptionsSimple = {
simpleBinding: string | InternalBindingFormat;
metadata?: string;
simpleBinding: IDataModelBindings;
metadata?: IDataModelBindings;
};

export type DataModelBindingsSimple = {
simpleBinding: string | InternalBindingFormat;
simpleBinding: IDataModelBindings;
};

type DataModelBindingsForFileUpload = DataModelBindingsSimple | DataModelBindingsList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { KeyValuePairs } from 'app-shared/types/KeyValuePairs';
import type { ComponentType } from 'app-shared/types/ComponentType';
import type { ComponentSpecificConfig } from 'app-shared/types/ComponentSpecificConfig';
import type { Expression } from '@studio/components';
import type { IDataModelBindingsKeyValue } from '@altinn/ux-editor/types/global';

export type FormLayoutsResponse = KeyValuePairs<ExternalFormLayout>;

Expand All @@ -20,7 +21,7 @@ export interface ExternalData {
export type ExternalComponentBase<T extends ComponentType = ComponentType> = {
id: string;
type: T;
dataModelBindings?: KeyValuePairs<string>;
dataModelBindings?: IDataModelBindingsKeyValue;
textResourceBindings?: KeyValuePairs<string>;
[key: string]: any;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import { layoutSet3SubformNameMock } from '../../../../testing/layoutSetsMock';
import { QueryKey } from 'app-shared/types/QueryKey';
import { app, org } from '@studio/testing/testids';
import { subformLayoutMock } from '../../../../testing/subformLayoutMock';
import { convertDataBindingToInternalFormat } from '@altinn/ux-editor/utils/dataModelUtils';

const headerContentMock: string = 'Header';
const cellContentQueryMock: string = 'Query';
const cellContentDefaultMock: string = 'Default';
const columnNumberMock: number = 1;
const addressDataField = convertDataBindingToInternalFormat(
subformLayoutMock.component4.dataModelBindings['address'],
).field;
mlqn marked this conversation as resolved.
Show resolved Hide resolved

const mockTableColumn: TableColumn = {
headerContent: headerContentMock,
Expand Down Expand Up @@ -47,7 +51,7 @@ describe('ColumnElement', () => {
onChange: onChangeMock,
tableColumn: {
headerContent: subformLayoutMock.component4.textResourceBindings.title,
cellContent: { query: subformLayoutMock.component4.dataModelBindings.address },
cellContent: { query: addressDataField },
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useState } from 'react';
import { StudioCombobox } from '@studio/components';
import { useTranslation } from 'react-i18next';
import type { IDataModelBindings } from '../../../../../types/global';
import type { IDataModelBindingsKeyValue } from '../../../../../types/global';
import { convertDataBindingToInternalFormat } from '../../../../../utils/dataModelUtils';

type DataModelBindingsComboboxProps = {
componentType: string;
dataModelBindings?: IDataModelBindings;
dataModelBindings?: IDataModelBindingsKeyValue;
onDataModelBindingChange: (dataModelBindingKey: string) => void;
initialDataModelBindingKey: string;
};
Expand Down Expand Up @@ -40,7 +40,7 @@ export const DataModelBindingsCombobox = ({
onValueChange={(values) => onValueChange(values[0])}
>
{Object.keys(dataModelBindings).map((key) => {
const { field } = convertDataBindingToInternalFormat(dataModelBindings, key);
const { field } = convertDataBindingToInternalFormat(dataModelBindings?.[key]);
return (
lassopicasso marked this conversation as resolved.
Show resolved Hide resolved
field && (
<StudioCombobox.Option key={key} value={key} description={field}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { renderWithProviders } from '../../../../../testing/mocks';
import { createQueryClientMock } from 'app-shared/mocks/queryClientMock';
import { QueryKey } from 'app-shared/types/QueryKey';
import { app, org } from '@studio/testing/testids';
import { convertDataBindingToInternalFormat } from '@altinn/ux-editor/utils/dataModelUtils';

const subformComponentMock = componentMocks[ComponentType.Subform];

Expand All @@ -23,6 +24,12 @@ const defaultProps: EditColumnElementProps = {
};
const textKeyMock = 'textkeymock1';
const textValueMock = 'textkeymock1';
const { field: addressDataField } = convertDataBindingToInternalFormat(
subformLayoutMock.component4.dataModelBindings['address'],
);
const { field: postPlaceDataField } = convertDataBindingToInternalFormat(
subformLayoutMock.component4.dataModelBindings['postPlace'],
);

describe('EditColumnElementComponentSelect', () => {
afterEach(() => {
Expand Down Expand Up @@ -128,7 +135,7 @@ describe('EditColumnElementComponentSelect', () => {
renderEditColumnElement({
tableColumn: {
headerContent: subformLayoutMock.component4.textResourceBindings.title,
cellContent: { query: subformLayoutMock.component4.dataModelBindings.address },
cellContent: { query: addressDataField },
},
});
const componentSelect = screen.getByRole('combobox', {
Expand All @@ -154,7 +161,7 @@ describe('EditColumnElementComponentSelect', () => {
renderEditColumnElement({
tableColumn: {
headerContent: subformLayoutMock.component4.textResourceBindings.title,
cellContent: { query: subformLayoutMock.component4.dataModelBindings.address },
cellContent: { query: addressDataField },
},
});
const componentSelect = screen.getByRole('combobox', {
Expand Down Expand Up @@ -265,7 +272,7 @@ describe('EditColumnElementComponentSelect', () => {
onChange: onChangeMock,
tableColumn: {
headerContent: subformLayoutMock.component4.textResourceBindings.title,
cellContent: { query: subformLayoutMock.component4.dataModelBindings.address },
cellContent: { query: addressDataField },
},
});

Expand Down Expand Up @@ -303,7 +310,7 @@ describe('EditColumnElementComponentSelect', () => {
onChange: onChangeMock,
tableColumn: {
headerContent: subformLayoutMock.component4.textResourceBindings.title,
cellContent: { query: subformLayoutMock.component4.dataModelBindings.address },
cellContent: { query: addressDataField },
},
});
const componentSelect = screen.getByRole('combobox', {
Expand All @@ -326,7 +333,7 @@ describe('EditColumnElementComponentSelect', () => {
});
await user.click(
screen.getByRole('option', {
name: new RegExp(subformLayoutMock.component4.dataModelBindings.postPlace),
name: new RegExp(postPlaceDataField),
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { convertDataBindingToInternalFormat } from '../../../../../utils/dataModelUtils';
import { DataModelBindingsCombobox } from './DataModelBindingsCombobox';
import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery';
import type { IDataModelBindings } from '../../../../../types/global';
import type { IDataModelBindingsKeyValue } from '../../../../../types/global';

export type EditColumnElementProps = {
tableColumn: TableColumn;
Expand Down Expand Up @@ -56,8 +56,7 @@ export const EditColumnElement = ({
const bindingKey = Object.keys(selectedComponent.dataModelBindings)[0];

const binding = convertDataBindingToInternalFormat(
selectedComponent?.dataModelBindings,
bindingKey,
selectedComponent?.dataModelBindings?.[bindingKey],
);

onChange({
Expand All @@ -68,10 +67,10 @@ export const EditColumnElement = ({
};

const handleBindingChange = (
dataModelBindings: IDataModelBindings,
dataModelBindings: IDataModelBindingsKeyValue,
dataModelBindingKey: string,
) => {
const { field } = convertDataBindingToInternalFormat(dataModelBindings, dataModelBindingKey);
const { field } = convertDataBindingToInternalFormat(dataModelBindings[dataModelBindingKey]);
const updatedTableColumn = {
...tableColumn,
cellContent: { query: field },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const formLayouts: IFormLayouts = {
...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
simpleBinding: { dataType: 'mockDataModel', field: 'mockDataModelBinding4' },
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ const componentsWithTitleAndDefaultDataModel = (
const hasValidDataBinding = (comp: FormItem) =>
Object.keys(comp.dataModelBindings ?? {}).some((binding) => {
const { dataType, field } = convertDataBindingToInternalFormat(
comp?.dataModelBindings,
binding,
comp?.dataModelBindings?.[binding],
);
return dataType === defaultDataModel || (dataType === '' && field !== '');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { useTranslation } from 'react-i18next';
import {
getDataModelFields,
validateSelectedDataField,
type InternalBindingFormat,
} from '@altinn/ux-editor/utils/dataModelUtils';
import type { ComponentType } from 'app-shared/types/ComponentType';
import { useValidDataModels } from '@altinn/ux-editor/hooks/useValidDataModels';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';

export type DefinedBindingProps = {
onClick: () => void;
label: string;
internalBindingFormat: InternalBindingFormat;
internalBindingFormat: ExplicitDataModelBinding;
componentType: ComponentType;
bindingKey: string;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext';
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import { textMock } from '@studio/testing/mocks/i18nMock';
import userEvent from '@testing-library/user-event';
import type { InternalBindingFormat } from '@altinn/ux-editor/utils/dataModelUtils';
import { layoutSet1NameMock } from '../../../../../testing/layoutSetsMock';
import { QueryKey } from 'app-shared/types/QueryKey';
import { app, org } from '@studio/testing/testids';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';
import { convertDataBindingToInternalFormat } from '@altinn/ux-editor/utils/dataModelUtils';

const defaultLabel = 'label';
const defaultBindingKey = 'simpleBinding';
Expand All @@ -37,15 +38,18 @@ type MockedParentComponentProps = EditBindingProps;

const MockedParentComponent = (props: MockedParentComponentProps) => {
const [newInternalBindingFormat, setNewInternalBindingFormat] =
React.useState<InternalBindingFormat>(props.internalBindingFormat);
React.useState<ExplicitDataModelBinding>(props.internalBindingFormat);

return (
<EditBinding
{...props}
handleComponentChange={(formItem) => {
const fieldBinding = formItem.dataModelBindings[defaultBindingKey] as InternalBindingFormat;
const { field } = convertDataBindingToInternalFormat(
props.component.dataModelBindings[props.bindingKey],
);
setNewInternalBindingFormat((prev) => ({
...prev,
field: fieldBinding.field,
field,
}));
}}
internalBindingFormat={newInternalBindingFormat}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
getMaxOccursFromDataModelFields,
getMinOccursFromDataModelFields,
getXsdDataTypeFromDataModelFields,
type InternalBindingFormat,
} from '@altinn/ux-editor/utils/dataModelUtils';
import { useAppContext } from '@altinn/ux-editor/hooks';
import type { UpdateFormMutateOptions } from '@altinn/ux-editor/containers/FormItemContext';
Expand All @@ -17,14 +16,15 @@ import { useValidDataModels } from '@altinn/ux-editor/hooks/useValidDataModels';
import { StudioSpinner } from '@studio/components';
import { useTranslation } from 'react-i18next';
import { formItemConfigs } from '@altinn/ux-editor/data/formItemConfig';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';

export type EditBindingProps = {
bindingKey: string;
component: FormItem;
label: string;
handleComponentChange: (component: FormItem, mutateOptions?: UpdateFormMutateOptions) => void;
onSetDataModelSelectVisible: (visible: boolean) => void;
internalBindingFormat: InternalBindingFormat;
internalBindingFormat: ExplicitDataModelBinding;
};

export const EditBinding = ({
Expand All @@ -41,7 +41,7 @@ export const EditBinding = ({
internalBindingFormat.dataType,
);

const handleBindingChange = (updatedBinding?: InternalBindingFormat) => {
const handleBindingChange = (updatedBinding?: ExplicitDataModelBinding) => {
const selectedDataFieldElement = updatedBinding?.field;

const value =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { StudioButton, StudioDeleteButton } from '@studio/components';
import { XMarkIcon } from '@studio/icons';
import classes from './EditBindingButtons.module.css';
import { useTranslation } from 'react-i18next';
import type { InternalBindingFormat } from '@altinn/ux-editor/utils/dataModelUtils';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';

export type EditBindingButtons = {
handleBindingChange: (binding: InternalBindingFormat) => void;
handleBindingChange: (binding: ExplicitDataModelBinding) => void;
onSetDataModelSelectVisible: (visible: boolean) => void;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import {
getDataModelFields,
validateSelectedDataField,
type InternalBindingFormat,
} from '@altinn/ux-editor/utils/dataModelUtils';
import { useTranslation } from 'react-i18next';
import { FormField } from 'app-shared/components/FormField';
Expand All @@ -11,10 +10,11 @@ import { useValidDataModels } from '@altinn/ux-editor/hooks/useValidDataModels';
import type { ComponentType } from 'app-shared/types/ComponentType';
import classes from './SelectDataFieldBinding.module.css';
import { useComponentPropertyHelpText } from '../../../../../hooks';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';

type SelectDataFieldProps = {
internalBindingFormat: InternalBindingFormat;
handleBindingChange: (dataModelBindings: InternalBindingFormat) => void;
internalBindingFormat: ExplicitDataModelBinding;
handleBindingChange: (dataModelBindings: ExplicitDataModelBinding) => void;
bindingKey: string;
componentType: ComponentType;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import classes from './SelectDataModelBinding.module.css';
import { FormField } from 'app-shared/components/FormField';
import { StudioNativeSelect } from '@studio/components';
import { useTranslation } from 'react-i18next';
import type { InternalBindingFormat } from '@altinn/ux-editor/utils/dataModelUtils';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import { useAppContext } from '../../../../../hooks';
import { useGetBindableDataTypes } from '../../../../../hooks/useGetBindableDataTypes';
import { useValidDataModels } from '../../../../../hooks/useValidDataModels';
import type { ExplicitDataModelBinding } from '@altinn/ux-editor/types/global';

type SelectDataModelProps = {
currentDataModel: string;
bindingKey: string;
handleBindingChange: (dataModelBindings: InternalBindingFormat) => void;
handleBindingChange: (dataModelBindings: ExplicitDataModelBinding) => void;
};

export const SelectDataModelBinding = ({
Expand Down
Loading