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

Tech debt: Language variables rewrite #1444

Merged
merged 27 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8c13f67
fix(TextResources): use useLanguage hook to replace variables in text…
mikaelrss Sep 5, 2023
6e3377f
Removing unused redux actions
Sep 5, 2023
4777cd9
Removing commented-out implementation of the old function
Sep 5, 2023
514d031
Adding back support for instanceContext/applicationSettings
Sep 5, 2023
7e30d53
Merge branch 'main' into fix/1218-language-support-tech-debt
Sep 5, 2023
990afe6
Moving and unexporting code only used from useLanguage.ts
Sep 5, 2023
77d76b9
Fixing lookups for the Likert component, and summaries for the Likert…
Sep 5, 2023
b029861
Fixing data model lookups in instances where you don't have a node ob…
Sep 5, 2023
4234e5f
Fix issue with returning object from instance context selector, resul…
mikaelrss Sep 6, 2023
6c24148
Rewriting the text resources state to use a map (most changes here ar…
Sep 6, 2023
6586fb6
wip: useSourceOptions
mikaelrss Sep 6, 2023
8f1bb75
Rewriting source-options (from repeating groups) by fetching directly…
Sep 6, 2023
bf6c7c7
add helpText and description to useSourceOptions. Prioritize sourceOp…
mikaelrss Sep 6, 2023
b341178
fix textResourceMap test data for GroupContainer
mikaelrss Sep 6, 2023
59f20b9
fix issue with infinite re-render in ReceiptContainer
mikaelrss Sep 6, 2023
d17a790
Fixing GroupContainer.test.tsx
Sep 6, 2023
ff6bb89
fix: unit tests for infoTaskQueueSaga
mikaelrss Sep 6, 2023
0b2f7cf
Merge remote-tracking branch 'origin/fix/1218-language-support-tech-d…
Sep 6, 2023
86b6cb4
Fixing issues with validation text resources needing a node object to…
Sep 6, 2023
ad138f2
fix issue with textResources with variables in rowsAfter for repeatin…
mikaelrss Sep 7, 2023
d66fa55
Merge remote-tracking branch 'origin/fix/1218-language-support-tech-d…
Sep 7, 2023
7750159
Running cypress tests on merge to other branches than main
Sep 7, 2023
ed82a28
remove unused util function
mikaelrss Sep 11, 2023
d4931eb
chore: remove unused test setupSourceOptions
mikaelrss Sep 11, 2023
1d62d50
Merge branch 'main' into fix/1218-language-support-tech-debt
Sep 11, 2023
c139de2
Merge remote-tracking branch 'origin/fix/1218-language-support-tech-d…
Sep 11, 2023
80a6172
Merge branch 'main' into fix/1218-language-support-tech-debt
Sep 13, 2023
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
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