Skip to content

Commit

Permalink
Use explicit method to get properties defined as enums
Browse files Browse the repository at this point in the history
  • Loading branch information
standeren committed Jul 15, 2024
1 parent 20d784f commit 3927b0c
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 5 deletions.
50 changes: 49 additions & 1 deletion frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,7 @@
"ux_editor.component_properties.addButton": "'Legg til'-knapp",
"ux_editor.component_properties.alertOnChange": "Bruker skal få advarsel når de gjør endring",
"ux_editor.component_properties.alertOnDelete": "Bruker skal få advarsel når de sletter",
"ux_editor.component_properties.align": "Plassering*",
"ux_editor.component_properties.align": "Plassering av tekstinnhold",
"ux_editor.component_properties.alwaysShowAddButton": "Vis alltid 'Legg til'-knapp",
"ux_editor.component_properties.attribution": "Opphav",
"ux_editor.component_properties.autocomplete": "HTML autofullfør",
Expand All @@ -1661,6 +1661,7 @@
"ux_editor.component_properties.compact": "Bruk kompakt visning",
"ux_editor.component_properties.componentRef": "ID på komponenten det gjelder (componentRef)",
"ux_editor.component_properties.config_is_expression_message": "Denne egenskapen er konfigurert som et uttrykk, og kan foreløpig ikke redigeres her.",
"ux_editor.component_properties.currency": "Valuta",
"ux_editor.component_properties.current_task": "Kun gjeldende oppgave",
"ux_editor.component_properties.dataListId": "Id på dataliste",
"ux_editor.component_properties.dataTypeIds": "Liste med ID på datatyper som skal vises",
Expand All @@ -1671,6 +1672,51 @@
"ux_editor.component_properties.edit": "Redigeringsvalg",
"ux_editor.component_properties.editButton": "'Endre'-knapp",
"ux_editor.component_properties.elements": "Elementer som skal vises (når ingen er satt vises alle)",
"ux_editor.component_properties.enum_All": "Alt",
"ux_editor.component_properties.enum_AllExceptRequired": "Alle utenom påkrevd",
"ux_editor.component_properties.enum_Component": "Komponent",
"ux_editor.component_properties.enum_CustomBackend": "Egendefinert i kode",
"ux_editor.component_properties.enum_Expression": "Uttrykk",
"ux_editor.component_properties.enum_Required": "Påkrevd",
"ux_editor.component_properties.enum_Schema": "Skjema",
"ux_editor.component_properties.enum_always": "Alltid",
"ux_editor.component_properties.enum_asc": "Alfabetisk",
"ux_editor.component_properties.enum_auto": "Automatisk",
"ux_editor.component_properties.enum_avoid": "Unngå sideskift",
"ux_editor.component_properties.enum_bottom": "Bunn",
"ux_editor.component_properties.enum_celsius": "Celsius",
"ux_editor.component_properties.enum_center": "Senter",
"ux_editor.component_properties.enum_centimeter": "Centimeter",
"ux_editor.component_properties.enum_day": "Dag",
"ux_editor.component_properties.enum_degree": "Grader",
"ux_editor.component_properties.enum_desc": "Motsatt alfabetisk",
"ux_editor.component_properties.enum_foot": "Fot",
"ux_editor.component_properties.enum_gram": "Gram",
"ux_editor.component_properties.enum_hectare": "Hekto",
"ux_editor.component_properties.enum_hour": "Time",
"ux_editor.component_properties.enum_inch": "Tomme",
"ux_editor.component_properties.enum_kilogram": "Kilogram",
"ux_editor.component_properties.enum_kilometer": "Kilometer",
"ux_editor.component_properties.enum_left": "Venstre",
"ux_editor.component_properties.enum_liter": "Liter",
"ux_editor.component_properties.enum_meter": "Meter",
"ux_editor.component_properties.enum_milliliter": "Milliliter",
"ux_editor.component_properties.enum_millimeter": "Millimeter",
"ux_editor.component_properties.enum_millisecond": "Millisekund",
"ux_editor.component_properties.enum_minute": "Minutt",
"ux_editor.component_properties.enum_month": "Måned",
"ux_editor.component_properties.enum_neutral": "Nøytral",
"ux_editor.component_properties.enum_percent": "Prosent",
"ux_editor.component_properties.enum_prefix": "Prefiks (Før tall)",
"ux_editor.component_properties.enum_right": "Høyre",
"ux_editor.component_properties.enum_search": "Søk",
"ux_editor.component_properties.enum_second": "Sekund",
"ux_editor.component_properties.enum_subtle": "Forsiktig",
"ux_editor.component_properties.enum_suffix": "Suffiks (Etter tall)",
"ux_editor.component_properties.enum_text": "Tekst",
"ux_editor.component_properties.enum_top": "Topp",
"ux_editor.component_properties.enum_week": "Uke",
"ux_editor.component_properties.enum_year": "År",
"ux_editor.component_properties.excludedChildren": "Komponenter som skal ekskluderes fra gruppens oppsummering",
"ux_editor.component_properties.filter": "Filter",
"ux_editor.component_properties.format": "Format",
Expand Down Expand Up @@ -1710,6 +1756,7 @@
"ux_editor.component_properties.pageBreak": "PDF-innstillinger (pageBreak)",
"ux_editor.component_properties.pageRef": "Navnet til siden det gjelder (pageRef)",
"ux_editor.component_properties.pagination": "Paginering",
"ux_editor.component_properties.position": "Plassering av valuta",
"ux_editor.component_properties.preselectedOptionIndex": "Indeks/plassering av forhåndsvalgt verdi (preselectedOptionIndex)",
"ux_editor.component_properties.queryParameters": "Parametere i spørringen",
"ux_editor.component_properties.readOnly": "Feltet skal være skrivebeskyttet (readOnly)",
Expand Down Expand Up @@ -1751,6 +1798,7 @@
"ux_editor.component_properties.taskId": "Oppgave-ID",
"ux_editor.component_properties.timeStamp": "Inkluder tidsstempel i dato (på som standard)",
"ux_editor.component_properties.triggers": "Feltet skal trigge:",
"ux_editor.component_properties.unit": "Enhet",
"ux_editor.component_properties.url": "Lenke (URL)",
"ux_editor.component_properties.useComponentGrid": "Bruk komponentens grid-oppsett",
"ux_editor.component_properties.validFileEndings": "Skriv inn gyldige filtyper (Eksempel: .jpeg, .pdf, .png)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function LayoutSetsContainer() {
onChange={(event) => onLayoutSetClick(event.target.value)}
value={selectedFormLayoutSetName}
className={classes.layoutSetsDropDown}
size='small'
>
{layoutSetNames.map((set: string) => {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.objectPropertyContainer {
gap: 0.5rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {
PropertyTypes,
propertyKeysToExcludeFromComponentConfig,
getSupportedPropertyKeysForPropertyType,
getEnumPropertyKeys,
} from '../../utils/component';
import { EditGrid } from './editModal/EditGrid';
import type { FormItem } from '../../types/FormItem';
import type { UpdateFormMutateOptions } from '../../containers/FormItemContext';
import { useComponentPropertyDescription } from '../../hooks/useComponentPropertyDescription';
import classes from './FormComponentConfig.module.css';

export interface IEditFormComponentProps {
editFormId: string;
Expand Down Expand Up @@ -76,6 +78,10 @@ export const FormComponentConfig = ({
[PropertyTypes.object],
[...customProperties, 'source'],
);
const enumPropertyKeys: string[] = getEnumPropertyKeys(
schema.properties,
customProperties.concat(stringPropertyKeys),
);

const unsupportedPropertyKeys: string[] = Object.keys(properties).filter((key) => {
return (
Expand Down Expand Up @@ -165,6 +171,20 @@ export const FormComponentConfig = ({
);
})}

{/** Enum properties */}
{enumPropertyKeys.map((propertyKey) => {
return (
<EditStringValue
component={component}
handleComponentChange={handleComponentUpdate}
propertyKey={propertyKey}
key={propertyKey}
helpText={properties[propertyKey]?.description}
enumValues={properties[propertyKey]?.enum || properties[propertyKey]?.examples}
/>
);
})}

{/** Number properties (number and integer types) */}
{numberPropertyKeys.map((propertyKey) => {
return (
Expand Down Expand Up @@ -196,7 +216,7 @@ export const FormComponentConfig = ({
{/** Object properties */}
{objectPropertyKeys.map((propertyKey) => {
return (
<Card key={propertyKey}>
<Card key={propertyKey} className={classes.objectPropertyContainer}>
<Heading level={3} size='xxsmall'>
{componentPropertyLabel(propertyKey)}
</Heading>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FormField } from '../../FormField';
import { Textfield } from '@digdir/designsystemet-react';
import { LegacySelect } from '@digdir/design-system-react';
import { useComponentPropertyLabel } from '../../../hooks/useComponentPropertyLabel';
import { useComponentPropertyEnumValue } from '@altinn/ux-editor/hooks/useComponentPropertyEnumValue';

export interface EditStringValueProps extends IGenericEditComponent {
propertyKey: string;
Expand All @@ -23,6 +24,7 @@ export const EditStringValue = ({
}: EditStringValueProps) => {
const { t } = useTranslation();
const componentPropertyLabel = useComponentPropertyLabel();
const componentEnumValue = useComponentPropertyEnumValue();

const handleValueChange = (newValue: string) => {
handleComponentChange({
Expand All @@ -49,7 +51,7 @@ export const EditStringValue = ({
<LegacySelect
{...fieldProps}
options={enumValues.map((value) => ({
label: value,
label: componentEnumValue(value),
value: value,
}))}
onChange={(e: any) => fieldProps.onChange(e)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { renderHook } from '@testing-library/react';
import { textMock } from '@studio/testing/mocks/i18nMock';
import { useComponentPropertyEnumValue } from '@altinn/ux-editor/hooks/useComponentPropertyEnumValue';
import type { KeyValuePairs } from 'app-shared/types/KeyValuePairs';

const someEnumValue = 'someEnumValue';
const customTextMockToHandleUndefined = (
keys: string | string[],
variables?: KeyValuePairs<string>,
) => {
const key = Array.isArray(keys) ? keys[0] : keys;
if (key === `ux_editor.component_properties.enum_${someEnumValue}`) return key;
return variables
? '[mockedText(' + key + ', ' + JSON.stringify(variables) + ')]'
: '[mockedText(' + key + ')]';
};

jest.mock('react-i18next', () => ({
useTranslation: () => ({
t: customTextMockToHandleUndefined,
}),
}));

describe('useComponentPropertyEnumValue', () => {
it('Returns a function that returns the enum value', () => {
const result = renderHook(() => useComponentPropertyEnumValue()).result.current;
const propertyEnumValue = result('testEnumValue');
expect(propertyEnumValue).toEqual(
textMock('ux_editor.component_properties.enum_testEnumValue'),
);
});
it('Returns a function that returns the enum value if there was no text key for the description', () => {
const result = renderHook(() => useComponentPropertyEnumValue()).result.current;
const propertyEnumValue = result(someEnumValue);
expect(propertyEnumValue).toEqual(someEnumValue);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useTranslation } from 'react-i18next';
import { useCallback } from 'react';

export const useComponentPropertyEnumValue = () => {
const { t } = useTranslation();
return useCallback(
(value: string) => {
const translationKey: string = `ux_editor.component_properties.enum_${value}`;
const translation = t(translationKey);
return translation === translationKey ? value : translation;
},
[t],
);
};
40 changes: 40 additions & 0 deletions frontend/packages/ux-editor/src/utils/component.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
PropertyTypes,
propertyTypeMatcher,
getSupportedPropertyKeysForPropertyType,
getEnumPropertyKeys,
} from './component';
import { ComponentType } from 'app-shared/types/ComponentType';
import type {
Expand Down Expand Up @@ -438,4 +439,43 @@ describe('Component utils', () => {
).toEqual(['testProperty1']);
});
});

describe('getEnumPropertyKeys', () => {
it('should return empty array if no properties are provided', () => {
expect(getEnumPropertyKeys({})).toEqual([]);
});

it('should return array of property keys of the expected properties with enums', () => {
expect(
getEnumPropertyKeys({
testProperty: {
enum: ['enum1', 'enum2'],
},
testProperty2: {
type: 'string',
},
}),
).toEqual(['testProperty']);
});

it('should only return property keys that are not in the excludeKeys array', () => {
expect(
getEnumPropertyKeys(
{
testProperty: {
enum: ['enum1', 'enum2'],
type: 'string',
},
testProperty1: {
enum: ['enum1', 'enum2'],
},
testProperty2: {
type: 'number',
},
},
['testProperty'],
),
).toEqual(['testProperty1']);
});
});
});
17 changes: 15 additions & 2 deletions frontend/packages/ux-editor/src/utils/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ export const propertyTypeMatcher = (property: KeyValuePairs, propertyType: Prope
switch (propertyType) {
case PropertyTypes.string:
// Not all schemas with enum value explicitly specifies type as string
return baseMatch || !!property.enum;
return baseMatch;
case PropertyTypes.array:
// Currently only supporting array of strings with specified enum values
return baseMatch && !!property.items?.enum;
case PropertyTypes.object:
// Currently only supporting object with specifiec properties and no additional properties
// Currently only supporting object with specific properties and no additional properties
return baseMatch && !!property.properties && !property.additionalProperties;
default:
return baseMatch;
Expand Down Expand Up @@ -127,6 +127,19 @@ export const getSupportedPropertyKeysForPropertyType = (
});
};

export const getEnumPropertyKeys = (properties: KeyValuePairs, excludeKeys: string[] = []) => {
return Object.keys(properties).filter((key) => {
if (
!properties[key] ||
excludeKeys.includes(key) ||
propertyKeysToExcludeFromComponentConfig.includes(key)
)
return false;

if (properties[key].enum) return properties[key];
});
};

export const changeTitleBinding = (component: FormComponent, resourceKey: string): FormComponent =>
changeTextResourceBinding(component, 'title', resourceKey);

Expand Down

0 comments on commit 3927b0c

Please sign in to comment.