Skip to content

Commit

Permalink
feat: Remove featureflag multiple data models per task (#14171)
Browse files Browse the repository at this point in the history
  • Loading branch information
lassopicasso authored Jan 16, 2025
1 parent a305c40 commit 0ba2d73
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 162 deletions.
5 changes: 3 additions & 2 deletions frontend/packages/shared/src/types/ComponentSpecificConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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';

type DataModelBindingsForAddress = {
address: string;
Expand Down Expand Up @@ -38,12 +39,12 @@ type DataModelBindingsList = {
};

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

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

type DataModelBindingsForFileUpload = DataModelBindingsSimple | DataModelBindingsList;
Expand Down
1 change: 0 additions & 1 deletion frontend/packages/shared/src/utils/featureToggleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export enum FeatureFlag {
ComponentConfigBeta = 'componentConfigBeta',
ExportForm = 'exportForm',
Maskinporten = 'maskinporten',
MultipleDataModelsPerTask = 'multipleDataModelsPerTask',
OptionListEditor = 'optionListEditor',
AccessPackages = 'accessPackages',
ShouldOverrideAppLibCheck = 'shouldOverrideAppLibCheck',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { layoutSet1NameMock } from '@altinn/ux-editor/testing/layoutSetsMock';
import { app, org } from '@studio/testing/testids';
import type { DataModelMetadataResponse } from 'app-shared/types/api';

const defaultModel = 'testModel';
const defaultModel = 'testModelField';

const defaultDataModel = 'testModel';
const secondDataModel = 'secondDataModel';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { ComponentType } from 'app-shared/types/ComponentType';
import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext';
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import { textMock } from '@studio/testing/mocks/i18nMock';
import { typedLocalStorage } from '@studio/pure-functions';
import userEvent from '@testing-library/user-event';
import type { InternalBindingFormat } from '@altinn/ux-editor/utils/dataModelUtils';
import { layoutSet1NameMock } from '../../../../../testing/layoutSetsMock';
Expand All @@ -18,6 +17,7 @@ import { app, org } from '@studio/testing/testids';
const defaultLabel = 'label';
const defaultBindingKey = 'simpleBinding';
const defaultDataModelField = 'field1';
const secondDataModelField = 'field2';
const defaultDataModel = 'defaultModel';
const secondDataModel = 'secondModel';

Expand All @@ -43,9 +43,10 @@ const MockedParentComponent = (props: MockedParentComponentProps) => {
<EditBinding
{...props}
handleComponentChange={(formItem) => {
const fieldBinding = formItem.dataModelBindings[defaultBindingKey] as InternalBindingFormat;
setNewInternalBindingFormat((prev) => ({
...prev,
field: formItem.dataModelBindings[defaultBindingKey],
field: fieldBinding.field,
}));
}}
internalBindingFormat={newInternalBindingFormat}
Expand Down Expand Up @@ -97,7 +98,7 @@ const getDataModelMetadataMock = jest
.fn()
.mockImplementation(() => Promise.resolve(dataModelMetadataResponseMock));

describe('EditBinding without featureFlag', () => {
describe('EditBinding', () => {
it('should render loading spinner', async () => {
renderEditBinding({});

Expand All @@ -120,7 +121,7 @@ describe('EditBinding without featureFlag', () => {
expect(fieldSet).toBeInTheDocument();
});

it('should render correct elements in field set', async () => {
it('should display two selectors: data model and a data model field', async () => {
renderEditBinding({
queries: {
getAppMetadataModelIds: getAppMetadataModelIdsMock,
Expand All @@ -132,18 +133,15 @@ describe('EditBinding without featureFlag', () => {
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const label = screen.getByText(defaultEditBinding.label);
expect(label).toBeInTheDocument();

const selectedModel = screen.getByText(defaultDataModel);
const noneExistingDataModelSelector = screen.queryByRole('combobox', {
const dataModelSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_binding'),
});
expect(selectedModel).toBeInTheDocument();
expect(noneExistingDataModelSelector).not.toBeInTheDocument();
expect(dataModelSelector).toBeInTheDocument();

const selectedField = screen.getByRole('combobox');
expect(selectedField).toBeInTheDocument();
const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});
expect(dataModelFieldSelector).toBeInTheDocument();
});

it('should display default data model and "choose datafield" when no bindings', async () => {
Expand All @@ -165,7 +163,10 @@ describe('EditBinding without featureFlag', () => {
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

expect(screen.getByText(defaultDataModel)).toBeInTheDocument();
const dataModelSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_binding'),
});
expect(dataModelSelector).toHaveValue(defaultDataModel);

const chooseDataFieldOption: HTMLOptionElement = screen.getByRole('option', {
name: textMock('ux_editor.modal_properties_data_model_field_choose'),
Expand Down Expand Up @@ -226,14 +227,15 @@ describe('EditBinding without featureFlag', () => {
);
expect(errorMessage).toBeInTheDocument();

const dataModelFieldSelector = screen.getByRole('combobox');
const option2 = screen.getByRole('option', { name: defaultDataModelField });
const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});
const option2 = screen.getByRole('option', { name: secondDataModelField });
await user.selectOptions(dataModelFieldSelector, option2);

expect(errorMessage).not.toBeInTheDocument();
});

it('should call handleComponentChange with old binding format when data model field is changed', async () => {
it('should call handleComponentChange with new binding format when data model field is changed', async () => {
const user = userEvent.setup();
const handleComponentChange = jest.fn();
renderEditBinding({
Expand All @@ -251,7 +253,9 @@ describe('EditBinding without featureFlag', () => {
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const dataModelFieldSelector = screen.getByRole('combobox');
const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});
const option2 = screen.getByRole('option', { name: 'field2' });
await user.selectOptions(dataModelFieldSelector, option2);

Expand All @@ -260,7 +264,10 @@ describe('EditBinding without featureFlag', () => {
{
...componentMocks[ComponentType.Input],
dataModelBindings: {
[defaultEditBinding.bindingKey]: 'field2',
[defaultEditBinding.bindingKey]: {
field: 'field2',
dataType: defaultDataModel,
},
},
maxCount: undefined,
required: true,
Expand All @@ -272,8 +279,7 @@ describe('EditBinding without featureFlag', () => {
);
});

it('should set the data model binding to the default value when click on delete button', async () => {
window.confirm = jest.fn(() => true);
it('should call handleComponentChange with new binding format when data model is changed', async () => {
const user = userEvent.setup();
const handleComponentChange = jest.fn();
renderEditBinding({
Expand All @@ -291,17 +297,21 @@ describe('EditBinding without featureFlag', () => {
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const deleteButton = screen.getByRole('button', {
name: textMock('general.delete'),
const dataModelSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_binding'),
});
await user.click(deleteButton);
const option2 = screen.getByRole('option', { name: secondDataModel });
await user.selectOptions(dataModelSelector, option2);

expect(handleComponentChange).toHaveBeenCalledTimes(1);
expect(handleComponentChange).toHaveBeenCalledWith(
{
...componentMocks[ComponentType.Input],
dataModelBindings: {
simpleBinding: '',
[defaultEditBinding.bindingKey]: {
field: '',
dataType: secondDataModel,
},
},
maxCount: undefined,
required: undefined,
Expand All @@ -313,14 +323,13 @@ describe('EditBinding without featureFlag', () => {
);
});

it('should delete the data model binding when click on delete button and no default value is defined', async () => {
it('should call handleComponentChange when click on delete button', async () => {
window.confirm = jest.fn(() => true);
const user = userEvent.setup();
const handleComponentChange = jest.fn();
renderEditBinding({
editBindingProps: {
...defaultEditBinding,
component: componentMocks[ComponentType.FileUpload],
handleComponentChange,
},
queries: {
Expand All @@ -338,120 +347,12 @@ describe('EditBinding without featureFlag', () => {
});
await user.click(deleteButton);

expect(handleComponentChange).toHaveBeenCalledTimes(1);
expect(handleComponentChange).toHaveBeenCalledWith(componentMocks[ComponentType.FileUpload], {
onSuccess: expect.any(Function),
});
});
});

describe('EditBinding with featureFlag', () => {
beforeEach(() => {
typedLocalStorage.removeItem('featureFlags');
});
it('should display two selectors: data model and a data model field, when the feature flag is enabled', async () => {
typedLocalStorage.setItem<string[]>('featureFlags', ['multipleDataModelsPerTask']);
renderEditBinding({
queries: {
getAppMetadataModelIds: getAppMetadataModelIdsMock,
getDataModelMetadata: getDataModelMetadataMock,
},
});

await waitForElementToBeRemoved(() =>
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const dataModelSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_binding'),
});
expect(dataModelSelector).toBeInTheDocument();

const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});
expect(dataModelFieldSelector).toBeInTheDocument();
});

it('should call handleComponentChange with new binding format when data model field is changed', async () => {
typedLocalStorage.setItem<string[]>('featureFlags', ['multipleDataModelsPerTask']);
const user = userEvent.setup();
const handleComponentChange = jest.fn();
renderEditBinding({
editBindingProps: {
...defaultEditBinding,
handleComponentChange,
},
queries: {
getAppMetadataModelIds: getAppMetadataModelIdsMock,
getDataModelMetadata: getDataModelMetadataMock,
},
});

await waitForElementToBeRemoved(() =>
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});
const option2 = screen.getByRole('option', { name: 'field2' });
await user.selectOptions(dataModelFieldSelector, option2);

expect(handleComponentChange).toHaveBeenCalledTimes(1);
expect(handleComponentChange).toHaveBeenCalledWith(
{
...componentMocks[ComponentType.Input],
dataModelBindings: {
[defaultEditBinding.bindingKey]: {
field: 'field2',
dataType: defaultDataModel,
},
},
maxCount: undefined,
required: true,
timeStamp: undefined,
},
{
onSuccess: expect.any(Function),
},
);
});

it('should call handleComponentChange with new binding format when data model is changed', async () => {
typedLocalStorage.setItem<string[]>('featureFlags', ['multipleDataModelsPerTask']);
const user = userEvent.setup();
const handleComponentChange = jest.fn();
renderEditBinding({
editBindingProps: {
...defaultEditBinding,
handleComponentChange,
},
queries: {
getAppMetadataModelIds: getAppMetadataModelIdsMock,
getDataModelMetadata: getDataModelMetadataMock,
},
});

await waitForElementToBeRemoved(() =>
screen.queryByTitle(textMock('ux_editor.modal_properties_loading')),
);

const dataModelSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_binding'),
});
const option2 = screen.getByRole('option', { name: secondDataModel });
await user.selectOptions(dataModelSelector, option2);

expect(handleComponentChange).toHaveBeenCalledTimes(1);
expect(handleComponentChange).toHaveBeenCalledWith(
{
...componentMocks[ComponentType.Input],
dataModelBindings: {
[defaultEditBinding.bindingKey]: {
field: '',
dataType: secondDataModel,
},
simpleBinding: '',
},
maxCount: undefined,
required: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
getXsdDataTypeFromDataModelFields,
type InternalBindingFormat,
} from '@altinn/ux-editor/utils/dataModelUtils';
import { shouldDisplayFeature, FeatureFlag } from 'app-shared/utils/featureToggleUtils';
import { useAppContext } from '@altinn/ux-editor/hooks';
import type { UpdateFormMutateOptions } from '@altinn/ux-editor/containers/FormItemContext';
import { EditBindingButtons } from './EditBindingButtons';
Expand Down Expand Up @@ -48,9 +47,7 @@ export const EditBinding = ({
const selectedDataFieldElement = updatedBinding?.field;

const value =
(shouldDisplayFeature(FeatureFlag.MultipleDataModelsPerTask)
? updatedBinding
: selectedDataFieldElement) ??
updatedBinding ??
formItemConfigs[component.type]?.defaultProperties?.['dataModelBindings']?.[bindingKey];

const dataModelBindings = { ...component.dataModelBindings };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useId } from 'react';
import classes from './SelectDataModelBinding.module.css';
import { FormField } from 'app-shared/components/FormField';
import { shouldDisplayFeature, FeatureFlag } from 'app-shared/utils/featureToggleUtils';
import { StudioDisplayTile, StudioNativeSelect } from '@studio/components';
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';
Expand Down Expand Up @@ -41,7 +40,7 @@ export const SelectDataModelBinding = ({
handleBindingChange(dataModelBinding);
};

return shouldDisplayFeature(FeatureFlag.MultipleDataModelsPerTask) ? (
return (
<FormField
id={id}
onChange={handleDataModelChange}
Expand Down Expand Up @@ -70,10 +69,5 @@ export const SelectDataModelBinding = ({
</StudioNativeSelect>
)}
/>
) : (
<StudioDisplayTile
label={t('ux_editor.modal_properties_data_model_binding')}
value={selectedDataModel}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ describe('EditDataModelBinding', () => {
await user.click(bindingButton);
expect(bindingButton).not.toBeInTheDocument();

const dataModelFieldSelector = screen.getByRole('combobox');
const dataModelFieldSelector = screen.getByRole('combobox', {
name: textMock('ux_editor.modal_properties_data_model_field_binding'),
});

expect(dataModelFieldSelector).toBeInTheDocument();
};
Expand Down
Loading

0 comments on commit 0ba2d73

Please sign in to comment.