Skip to content

Commit

Permalink
Tech debt: Language variables rewrite (#1444)
Browse files Browse the repository at this point in the history
Co-authored-by: Mikael Solstad <mikaelrinosolstad@gmail.com>
Co-authored-by: Ole Martin Handeland <git@olemartin.org>
  • Loading branch information
3 people authored Sep 13, 2023
1 parent 52cc193 commit b2db236
Show file tree
Hide file tree
Showing 72 changed files with 578 additions and 1,068 deletions.
27 changes: 8 additions & 19 deletions src/__mocks__/initialStateMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,67 +111,56 @@ export function getInitialStateMock(customStates?: Partial<IRuntimeState>): IRun
userTask: { error: null, isDone: null },
},
textResources: {
resources: [
{
id: 'option.from.rep.group.label',
resourceMap: {
'option.from.rep.group.label': {
value: 'The value from the group is: {0}',
unparsedValue: 'The value from the group is: {0}',
variables: [
{
dataSource: 'dataModel.skjema',
key: 'someGroup[{0}].labelField',
},
],
},
{
id: 'option.from.rep.group.description',
'option.from.rep.group.description': {
value: 'Description: The value from the group is: {0}',
unparsedValue: 'Description: The value from the group is: {0}',
variables: [
{
dataSource: 'dataModel.skjema',
key: 'someGroup[{0}].labelField',
},
],
},
{
id: 'option.from.rep.group.helpText',
'option.from.rep.group.helpText': {
value: 'Help Text: The value from the group is: {0}',
unparsedValue: 'Help Text: The value from the group is: {0}',
variables: [
{
dataSource: 'dataModel.skjema',
key: 'someGroup[{0}].labelField',
},
],
},
{
id: 'group.input.title',
'group.input.title': {
value: 'The value from group is: {0}',
unparsedValue: 'The value from group is: {0}',
variables: [
{
dataSource: 'dataModel.skjema',
key: 'referencedGroup[{0}].inputField',
},
],
},
{
id: 'group.input.title-2',
'group.input.title-2': {
value: 'The value from the group is: Value from input field [2]',
unparsedValue: 'The value from group is: {0}',
variables: [
{
dataSource: 'dataModel.skjema',
key: 'referencedGroup[2].inputField',
},
],
},
{
id: 'accordion.title',
'accordion.title': {
value: 'This is a title',
},
],
},
error: null,
language: 'nb',
},
Expand Down
21 changes: 9 additions & 12 deletions src/components/presentation/NavBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getProfileStateMock } from 'src/__mocks__/profileStateMock';
import { getUiConfigStateMock } from 'src/__mocks__/uiConfigStateMock';
import { NavBar } from 'src/components/presentation/NavBar';
import { renderWithProviders } from 'src/testUtils';
import type { ITextResource } from 'src/types';
import type { TextResourceMap } from 'src/features/textResources';
import type { IAppLanguage } from 'src/types/shared';

afterEach(() => mockAxios.reset());
Expand All @@ -19,15 +19,15 @@ interface RenderNavBarProps {
hideCloseButton: boolean;
showLanguageSelector: boolean;
languageResponse?: IAppLanguage[];
textResources?: ITextResource[];
textResources?: TextResourceMap;
}

const renderNavBar = ({
hideCloseButton,
showBackArrow,
showLanguageSelector,
languageResponse,
textResources = [],
textResources = {},
}: RenderNavBarProps) => {
const mockClose = jest.fn();
const mockBack = jest.fn();
Expand All @@ -43,7 +43,7 @@ const renderNavBar = ({
preloadedState: {
profile: getProfileStateMock({ selectedAppLanguage: 'nb' }),
textResources: {
resources: textResources,
resourceMap: textResources,
language: 'nb',
error: null,
},
Expand Down Expand Up @@ -131,20 +131,17 @@ describe('NavBar', () => {
hideCloseButton: false,
showBackArrow: true,
showLanguageSelector: true,
textResources: [
{
id: 'language.selector.label',
textResources: {
'language.selector.label': {
value: 'Velg språk test',
},
{
id: 'language.full_name.nb',
'language.full_name.nb': {
value: 'Norsk test',
},
{
id: 'language.full_name.en',
'language.full_name.en': {
value: 'Engelsk test',
},
],
},
languageResponse: [{ language: 'en' }, { language: 'nb' }],
});
await waitForElementToBeRemoved(screen.queryByRole('progressbar'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('returnConfirmSummaryObject', () => {

it('should return custom value for confirm.sender if key is supplied in text resources', () => {
const result = returnConfirmSummaryObject({
langTools: staticUseLanguageForTests({ textResources: [{ id: 'confirm.sender', value: 'Some custom value' }] }),
langTools: staticUseLanguageForTests({ textResources: { 'confirm.sender': { value: 'Some custom value' } } }),
instanceOwnerParty: {
partyId: '50001',
name: 'Ola Privatperson',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface Props {
}

export function NodeInspectorTextResourceBindings({ node, textResourceBindings }: Props) {
const textResources = useAppSelector((state) => state.textResources.resources);
const textResources = useAppSelector((state) => state.textResources.resourceMap);
const { langAsString } = useLanguage();

let actualTextResourceBindings = textResourceBindings || {};
Expand Down Expand Up @@ -44,7 +44,7 @@ export function NodeInspectorTextResourceBindings({ node, textResourceBindings }
</div>
)}
{Object.keys(actualTextResourceBindings).map((key) => {
const inResources = textResources.find((resource) => resource.id === actualTextResourceBindings[key]);
const inResources = textResources[actualTextResourceBindings[key]];
const value = actualTextResourceBindings[key];
const isExpression = canBeExpression(value, true);

Expand Down
1 change: 0 additions & 1 deletion src/features/expressions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,6 @@ export const ExprFunctions = {
formData: this.dataSources.formData,
attachments: this.dataSources.attachments,
options: this.dataSources.options,
uiConfig: this.dataSources.uiConfig,
langTools: this.dataSources.langTools,
});
},
Expand Down
3 changes: 2 additions & 1 deletion src/features/expressions/shared.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { evalExpr } from 'src/features/expressions';
import { NodeNotFoundWithoutContext } from 'src/features/expressions/errors';
import { convertLayouts, getSharedTests } from 'src/features/expressions/shared';
import { asExpression } from 'src/features/expressions/validation';
import { resourcesAsMap } from 'src/features/textResources/resourcesAsMap';
import { staticUseLanguageForTests } from 'src/hooks/useLanguage';
import { getLayoutComponentObject } from 'src/layout';
import { buildAuthContext } from 'src/utils/authContext';
Expand Down Expand Up @@ -80,7 +81,7 @@ describe('Expressions shared function tests', () => {
applicationSettings: frontendSettings || ({} as IApplicationSettings),
authContext: buildAuthContext(permissions),
langTools: staticUseLanguageForTests({
textResources: textResources || [],
textResources: textResources ? resourcesAsMap(textResources) : {},
profileLanguage: profileSettings?.language,
}),
};
Expand Down
4 changes: 2 additions & 2 deletions src/features/expressions/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { IAttachments } from 'src/features/attachments';
import type { Expression } from 'src/features/expressions/types';
import type { IProcessPermissions } from 'src/features/process';
import type { IProfileState } from 'src/features/profile';
import type { IRawTextResource } from 'src/features/textResources';
import type { ILayout, ILayouts } from 'src/layout/layout';
import type { ITextResource } from 'src/types';
import type { IApplicationSettings, IInstance } from 'src/types/shared';

export interface Layouts {
Expand All @@ -27,7 +27,7 @@ export interface SharedTest {
instance?: IInstance;
permissions?: IProcessPermissions;
frontendSettings?: IApplicationSettings;
textResources?: ITextResource[];
textResources?: IRawTextResource[];
profileSettings?: Pick<IProfileState['profile']['profileSettingPreference'], 'language'>;
}

Expand Down
2 changes: 1 addition & 1 deletion src/features/formData/submit/submitFormDataSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function* submitFormSaga(): SagaIterator {
try {
const state: IRuntimeState = yield select();
const resolvedNodes: LayoutPages = yield select(ResolvedNodesSelector);
const validationObjects = resolvedNodes.runValidations(validationContextFromState(state));
const validationObjects = resolvedNodes.runValidations((node) => validationContextFromState(state, node));
const validationResult = createValidationResult(validationObjects);
if (containsErrors(validationObjects)) {
yield put(ValidationActions.updateValidations({ validationResult, merge: false }));
Expand Down
2 changes: 1 addition & 1 deletion src/features/formData/update/updateFormDataSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function* runValidations(field: string, data: any, componentId: string | undefin
const overrideFormData = { [field]: data?.length ? data : undefined };

if (implementsAnyValidation(node.def)) {
const validationObjects = node.runValidations(validationContextFromState(state), {
const validationObjects = node.runValidations((node) => validationContextFromState(state, node), {
overrideFormData,
skipEmptyFieldValidation: true,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function* updateRepeatingGroupEditIndexSaga({
if (validate && groupNode?.isType('Group') && typeof rowIndex === 'number' && rowIndex > -1) {
const frontendValidationObjects = groupNode.def.runGroupValidations(
groupNode,
validationContextFromState(state),
(node) => validationContextFromState(state, node),
validate === Triggers.ValidateRow ? rowIndex : undefined,
);

Expand Down
3 changes: 2 additions & 1 deletion src/features/layout/update/updateFormLayoutSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export function* updateCurrentViewSaga({
);
} else {
const currentView = state.formLayout.uiConfig.currentView;
const frontendValidationObjects = resolvedNodes?.runValidations(validationContextFromState(state)) ?? [];
const frontendValidationObjects =
resolvedNodes?.runValidations((node) => validationContextFromState(state, node)) ?? [];

const options: AxiosRequestConfig = {
headers: {
Expand Down
34 changes: 15 additions & 19 deletions src/features/options/getOptionList.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { getOptionLookupKey, getRelevantFormDataForOptionSource, setupSourceOptions } from 'src/utils/options';
import { getSourceOptions } from 'src/hooks/useSourceOptions';
import { getOptionLookupKey } from 'src/utils/options';
import type { IFormData } from 'src/features/formData';
import type { IUseLanguage } from 'src/hooks/useLanguage';
import type { IOption, ISelectionComponent } from 'src/layout/common.generated';
import type { IOptions, IRepeatingGroups, ITextResource } from 'src/types';
import type { IOptions } from 'src/types';
import type { LayoutNode } from 'src/utils/layout/LayoutNode';

export function getOptionList(
component: ISelectionComponent,
textResources: ITextResource[],
formData: IFormData,
repeatingGroups: IRepeatingGroups | null,
options: IOptions,
langTools: IUseLanguage,
node: LayoutNode,
formData: IFormData,
): IOption[] {
if (component.options) {
return component.options;
Expand All @@ -21,21 +24,14 @@ export function getOptionList(
return options[key]?.options || [];
}
if (component.source) {
const relevantTextResourceLabel = textResources.find(
(resourceLabel) => resourceLabel.id === component.source?.label,
);
const reduxOptions =
relevantTextResourceLabel &&
setupSourceOptions({
return (
getSourceOptions({
source: component.source,
relevantTextResources: { label: relevantTextResourceLabel },
relevantFormData: getRelevantFormDataForOptionSource(formData, component.source),
repeatingGroups,
dataSources: {
dataModel: formData,
},
});
return reduxOptions || [];
langTools,
node,
formData,
}) || []
);
}

return [];
Expand Down
20 changes: 8 additions & 12 deletions src/features/queue/infoTask/infoTaskQueueSaga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,18 @@ import {
TextResourceSelector,
} from 'src/features/queue/infoTask/infoTaskQueueSaga';
import { QueueActions } from 'src/features/queue/queueSlice';
import { TextResourcesActions } from 'src/features/textResources/textResourcesSlice';
import type { IApplicationMetadata } from 'src/features/applicationMetadata';
import type { ITextResource } from 'src/types';
import type { TextResourceMap } from 'src/features/textResources';

describe('infoTaskQueueSaga', () => {
let textResources: ITextResource[];
let textResources: TextResourceMap;

beforeAll(() => {
textResources = [
{
id: 'text1',
textResources = {
text1: {
value: 'some text',
},
];
};
});

it('startInitialInfoTaskQueueSaga, text resources with no variables', () =>
Expand All @@ -41,10 +39,9 @@ describe('infoTaskQueueSaga', () => {
.run());

it('startInitialInfoTaskQueueSaga, text resources with variables should load form data', () => {
const textsWithVariables = [
const textsWithVariables = {
...textResources,
{
id: 'someTextWithVariable',
someTextWithVariable: {
value: '{0}',
variables: [
{
Expand All @@ -53,7 +50,7 @@ describe('infoTaskQueueSaga', () => {
},
],
},
];
};
const applicationMetadata: IApplicationMetadata = {
...applicationMetadataMock,
dataTypes: [
Expand All @@ -76,7 +73,6 @@ describe('infoTaskQueueSaga', () => {
.put(IsLoadingActions.startDataTaskIsLoading())
.put(QueueActions.startInitialInfoTaskQueueFulfilled())
.put(FormDataActions.fetchFulfilled({ formData: {} }))
.put(TextResourcesActions.replace())
.put(IsLoadingActions.finishDataTaskIsLoading())
.run();
});
Expand Down
12 changes: 7 additions & 5 deletions src/features/queue/infoTask/infoTaskQueueSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,31 @@ import { FormDataActions } from 'src/features/formData/formDataSlice';
import { InstanceDataActions } from 'src/features/instanceData/instanceDataSlice';
import { IsLoadingActions } from 'src/features/isLoading/isLoadingSlice';
import { QueueActions } from 'src/features/queue/queueSlice';
import { mapAsResources } from 'src/features/textResources/resourcesAsMap';
import { TextResourcesActions } from 'src/features/textResources/textResourcesSlice';
import { convertModelToDataBinding } from 'src/utils/databindings';
import { httpGet } from 'src/utils/network/sharedNetworking';
import { getFetchFormDataUrl } from 'src/utils/urls/appUrlHelper';
import type { IApplicationMetadata } from 'src/features/applicationMetadata';
import type { IRuntimeState, ITextResource } from 'src/types';
import type { TextResourceMap } from 'src/features/textResources';
import type { IRuntimeState } from 'src/types';
import type { IInstance } from 'src/types/shared';

export const ApplicationMetadataSelector = (state: IRuntimeState) => state.applicationMetadata.applicationMetadata;
export const TextResourceSelector = (state: IRuntimeState) => state.textResources.resources;
export const TextResourceSelector = (state: IRuntimeState) => state.textResources.resourceMap;
export const InstanceDataSelector = (state: IRuntimeState) => state.instanceData.instance;

export function* startInitialInfoTaskQueueSaga(): SagaIterator {
const appMetadata: IApplicationMetadata = yield select(ApplicationMetadataSelector);
const textResources: ITextResource[] = yield select(TextResourceSelector);
const textResourceMap: TextResourceMap = yield select(TextResourceSelector);
const instance: IInstance = yield select(InstanceDataSelector);

yield put(IsLoadingActions.startDataTaskIsLoading());

const textResourcesWithVariables = textResources.filter(
const textResourcesWithVariables = mapAsResources(textResourceMap).filter(
(resource) => resource.variables && resource.variables.length > 0,
);

if (textResourcesWithVariables && textResourcesWithVariables.length > 0) {
const dataElements: string[] = [];
textResourcesWithVariables.forEach((resource) => {
Expand Down Expand Up @@ -55,7 +58,6 @@ export function* startInitialInfoTaskQueueSaga(): SagaIterator {
}

yield put(FormDataActions.fetchFulfilled({ formData }));
yield put(TextResourcesActions.replace());
}

yield put(QueueActions.startInitialInfoTaskQueueFulfilled());
Expand Down
Loading

0 comments on commit b2db236

Please sign in to comment.