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

feat: Remove featureflag multiple data models per task #14171

Merged
merged 17 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading