diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 09346485b3b..647c19fcbc7 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -1032,6 +1032,7 @@ "right_menu.rules_conditional_rendering_add_alt": "Legg til regel for vis/skjul felt", "right_menu.rules_empty": "Ingen regler lagt til...", "right_menu.show_old_dynamics": "Vis gammelt verktøy for dynamikk", + "right_menu.text": "Tekst", "right_menu.warning_dynamics_deprecated": "Denne funksjonaliteten utgår og vi kommer ikke til å vedlikeholde den. Vi anbefaler å bruke <0 href=\"{{expressionDocs}}\" >dynamiske uttrykk.0>", "schema_editor.active_languages": "Aktive språk:", "schema_editor.add": "Legg til", @@ -1480,7 +1481,7 @@ "ux_editor.component_unknown": "Ukjent komponent", "ux_editor.conditional_rendering_connection_header": "Betingede renderingstilkoblinger", "ux_editor.container_empty": "Tomt, dra noe inn her...", - "ux_editor.container_not_editable_info": "Noen egenskaper for denne komponenten er ikke redigerbare for øyeblikket. Du kan legge til underkomponenter i kolonnen til venstre.", + "ux_editor.container_not_editable_info": "Noen egenskaper for denne komponenten er ikke redigerbare for øyeblikket. Du kan legge til underkomponenter i kolonnen til venstre og redigere tekster.", "ux_editor.edit_component.show_beta_func": "Vis ny konfigurasjon (BETA)", "ux_editor.edit_component.show_beta_func_help_text": "Vi jobber med å få på plass støtte for å redigere alle innstillinger. Ved å huke av her kan du ta i bruk den nye konfigurasjonsvisningen, som støtter flere innstillinger. Merk at denne visningen fortsatt er under utvikling, og vil kunne oppleves som noe ustabil.", "ux_editor.edit_component.unknown_component": "Komponenten {{componentName}} gjenkjennes ikke av Studio og kan derfor ikke konfigureres.", @@ -1547,6 +1548,7 @@ "ux_editor.modal_new_option": "Legg til flere", "ux_editor.modal_options": "Valg", "ux_editor.modal_properties_add_check_box_options": "Hvordan vil du legge til avkrysningsbokser?", + "ux_editor.modal_properties_add_options": "Hvordan vil du legge til alternativer?", "ux_editor.modal_properties_add_radio_button_options": "Hvordan vil du legge til radioknapper?", "ux_editor.modal_properties_button_helper": "Søk etter tekst til knappen", "ux_editor.modal_properties_button_type_ActionButton": "ActionButton", @@ -1615,6 +1617,8 @@ "ux_editor.modal_properties_read_only": "Read-only.", "ux_editor.modal_properties_read_only_description": "Om dette feltet ikke skal kunne redigeres, kan du skru på read-only.", "ux_editor.modal_properties_tag_helper": "Søk etter merkebeskrivelse", + "ux_editor.modal_properties_textResourceBindings_add_button": "'Legg til ny'-knapp", + "ux_editor.modal_properties_textResourceBindings_add_button_add": "Legg til tekst for 'Legg til ny'-knapp", "ux_editor.modal_properties_textResourceBindings_altTextImg": "Alternativ tekst for bilde", "ux_editor.modal_properties_textResourceBindings_altTextImg_add": "Legg til alternativ tekst for bilde", "ux_editor.modal_properties_textResourceBindings_back": "Tekst på tilbake-knapp", @@ -1623,16 +1627,24 @@ "ux_editor.modal_properties_textResourceBindings_body_add": "Legg til tekstinnhold", "ux_editor.modal_properties_textResourceBindings_description": "Beskrivelse", "ux_editor.modal_properties_textResourceBindings_description_add": "Legg til beskrivelse", + "ux_editor.modal_properties_textResourceBindings_edit_button_close": "'Rediger'-knapp (lukket gruppe)", + "ux_editor.modal_properties_textResourceBindings_edit_button_close_add": "Legg til tekst for 'Rediger'-knapp (lukket gruppe)", + "ux_editor.modal_properties_textResourceBindings_edit_button_open": "'Rediger'-knapp (åpen gruppe)", + "ux_editor.modal_properties_textResourceBindings_edit_button_open_add": "Legg til tekst for 'Rediger'-knapp (åpen gruppe)", "ux_editor.modal_properties_textResourceBindings_help": "Hjelpetekst", "ux_editor.modal_properties_textResourceBindings_help_add": "Legg til hjelpetekst", "ux_editor.modal_properties_textResourceBindings_next": "Tekst på neste-knapp", "ux_editor.modal_properties_textResourceBindings_next_add": "Legg til tekst på neste-knapp", + "ux_editor.modal_properties_textResourceBindings_save_and_next_button": "'Lagre og neste'-knapp", + "ux_editor.modal_properties_textResourceBindings_save_and_next_button_add": "Legg til tekst for 'Lagre og neste'-knapp", + "ux_editor.modal_properties_textResourceBindings_save_button": "'Lagre'-knapp", + "ux_editor.modal_properties_textResourceBindings_save_button_add": "'Legg til tekst for Lagre'-knapp", "ux_editor.modal_properties_textResourceBindings_shortName": "Kortnavn", "ux_editor.modal_properties_textResourceBindings_shortName_add": "Legg til kortnavn", "ux_editor.modal_properties_textResourceBindings_tableTitle": "Tittel i tabell", "ux_editor.modal_properties_textResourceBindings_tableTitle_add": "Legg til tittel i tabell", - "ux_editor.modal_properties_textResourceBindings_tag": "Merkebeskrivelse:", - "ux_editor.modal_properties_textResourceBindings_tag_add": "Legg til merkebeskrivelse", + "ux_editor.modal_properties_textResourceBindings_tagTitle": "Merkebeskrivelse", + "ux_editor.modal_properties_textResourceBindings_tagTitle_add": "Legg til merkebeskrivelse", "ux_editor.modal_properties_textResourceBindings_title": "Ledetekst", "ux_editor.modal_properties_textResourceBindings_title_add": "Legg til ledetekst", "ux_editor.modal_properties_trigger_validation_label": "Skal feltet trigge en validering?", @@ -1667,6 +1679,14 @@ "ux_editor.pages_error_length": "Navnet kan ikke være lengre enn 30 tegn.", "ux_editor.pages_error_unique": "Navnet må være unikt.", "ux_editor.preview": "Forhåndsvisning", + "ux_editor.properties_panel.options.add_options": "Legg til alternativer", + "ux_editor.properties_panel.options.codelist_switch_to_custom": "Bytt til egendefinert kodeliste", + "ux_editor.properties_panel.options.codelist_switch_to_static": "Bytt til statisk kodeliste", + "ux_editor.properties_panel.options.remove_option": "Slett alternativ", + "ux_editor.properties_panel.options.use_code_list_helptext": "Skru på denne innstillingen for å bruke en kodeliste for å styre alternativene til denne komponenten. Skru av innstillingen for å legge til alternativene manuelt.", + "ux_editor.properties_panel.options.use_code_list_label": "Bruk kodeliste", + "ux_editor.properties_panel.texts.no_properties": "Det er ingen tekster å konfigurere for denne komponenten.", + "ux_editor.properties_panel.texts.options_title": "Kodelister og alternativer", "ux_editor.radios_description_add": "Legg til beskrivelse", "ux_editor.radios_description_placeholder": "Ingen beskrivelse", "ux_editor.radios_error_DuplicateValues": "Alle verdier må være unike.", diff --git a/frontend/packages/ux-editor-v3/src/components/config/componentConfig.tsx b/frontend/packages/ux-editor-v3/src/components/config/componentConfig.tsx index d719bc4a3c8..bcd4c9887f2 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/componentConfig.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/componentConfig.tsx @@ -114,8 +114,8 @@ export const configComponents: IConfigComponents = { component={component} handleComponentChange={handleComponentChange} textKey={EditSettings.TagTitle} - labelKey='ux_editor.modal_properties_textResourceBindings_tag' - placeholderKey='ux_editor.modal_properties_textResourceBindings_tag_add' + labelKey='ux_editor.modal_properties_textResourceBindings_tagTitle' + placeholderKey='ux_editor.modal_properties_textResourceBindings_tagTitle_add' /> ), [EditSettings.Options]: EditOptions, diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx index e7f015c9c2f..f611ca78ec3 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.test.tsx @@ -14,24 +14,9 @@ import { useLayoutSchemaQuery } from '../../hooks/queries/useLayoutSchemaQuery'; const user = userEvent.setup(); -// Test data: -const textResourceEditTestId = 'text-resource-edit'; - -// Mocks: -jest.mock('../TextResourceEdit', () => ({ - TextResourceEdit: () =>
, -})); - describe('ContentTab', () => { afterEach(jest.clearAllMocks); - describe('when editing a text resource', () => { - it('should render the component', async () => { - await render({ props: {}, editId: 'test' }); - expect(screen.getByTestId(textResourceEditTestId)).toBeInTheDocument(); - }); - }); - describe('when editing a container', () => { const props = { formId: container1IdMock, diff --git a/frontend/packages/ux-editor/src/components/Properties/Content.tsx b/frontend/packages/ux-editor/src/components/Properties/Content.tsx index 8a287f5baab..1825b36eb15 100644 --- a/frontend/packages/ux-editor/src/components/Properties/Content.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/Content.tsx @@ -1,20 +1,11 @@ import React from 'react'; -import { TextResourceEdit } from '../TextResourceEdit'; import { EditFormComponent } from '../config/EditFormComponent'; import { EditFormContainer } from '../config/EditFormContainer'; -import { getCurrentEditId } from '../../selectors/textResourceSelectors'; -import { useSelector } from 'react-redux'; import { useFormContext } from '../../containers/FormContext'; -import { useTranslation } from 'react-i18next'; import { isContainer } from '../../utils/formItemUtils'; export const Content = () => { const { formId, form, handleUpdate, debounceSave } = useFormContext(); - const editId = useSelector(getCurrentEditId); - const { t } = useTranslation(); - - if (editId) return@@ -39,9 +45,14 @@ export function EditCodeList({ component, handleComponentChange }: IGenericEditC variant='tertiary' onClick={() => setUseCustomCodeList(!useCustomCodeList)} size='small' + className={classes.customOrStaticButton} > - {optionListIds?.length > 0 && useCustomCodeList && <>Bytt til statisk kodeliste>} - {!useCustomCodeList && <>Bytt til egendefinert kodeliste>} + {optionListIds?.length > 0 && useCustomCodeList && ( + <>{t('ux_editor.properties_panel.options.codelist_switch_to_static')}> + )} + {!useCustomCodeList && ( + <>{t('ux_editor.properties_panel.options.codelist_switch_to_custom')}> + )}
diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/index.ts b/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/index.ts new file mode 100644 index 00000000000..951b645ee4a --- /dev/null +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/index.ts @@ -0,0 +1 @@ +export { EditCodeList } from './EditCodeList'; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.module.css b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.module.css index 4935b9a81bd..f7b28d29607 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.module.css +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.module.css @@ -15,3 +15,10 @@ flex-direction: column; gap: 24px; } + +.codeListSwitchWrapper { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; +} diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.test.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.test.tsx index 172b3ddb0f3..9f27fcf3020 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { screen } from '@testing-library/react'; +import { act, screen } from '@testing-library/react'; import { EditOptions } from './EditOptions'; import { renderWithMockStore } from '../../../testing/mocks'; @@ -27,13 +27,15 @@ describe('EditOptions', () => { it('should render', () => { renderEditOptions(); expect( - screen.getByText(textMock('ux_editor.modal_properties_add_radio_button_options')), + screen.getByText(textMock('ux_editor.properties_panel.options.use_code_list_label')), ).toBeInTheDocument(); }); it('should show code list input by default when neither options nor optionId are set', async () => { renderEditOptions(); - expect(screen.getByText(textMock('ux_editor.modal_add_options_codelist'))).toBeInTheDocument(); + expect( + screen.getByText(textMock('ux_editor.modal_properties_custom_code_list_id')), + ).toBeInTheDocument(); }); it('should show manual input when component has options defined', async () => { @@ -41,9 +43,15 @@ describe('EditOptions', () => { component: { ...mockComponent, options: [{ label: 'option1', value: 'option1' }], + optionsId: undefined, }, }); - expect(screen.getByText(textMock('ux_editor.modal_add_options_manual'))).toBeInTheDocument(); + expect( + screen.getByText(textMock('ux_editor.properties_panel.options.add_options')), + ).toBeInTheDocument(); + expect( + screen.getByText(textMock('ux_editor.modal_radio_button_increment') + ' 1'), + ).toBeInTheDocument(); }); it('should show code list input when component has optionsId defined', async () => { @@ -53,6 +61,69 @@ describe('EditOptions', () => { optionsId: 'optionsId', }, }); - expect(screen.getByText(textMock('ux_editor.modal_add_options_manual'))).toBeInTheDocument(); + expect( + screen.getByText(textMock('ux_editor.modal_properties_custom_code_list_id')), + ).toBeInTheDocument(); + }); + + it('should switch to manual input when toggling codelist switch off', async () => { + const handleComponentChange = jest.fn(); + renderEditOptions({ handleComponentChange }); + const switchElement = screen.getByRole('checkbox'); + await act(() => switchElement.click()); + expect(handleComponentChange).toHaveBeenCalledWith({ ...mockComponent, options: [] }); + }); + + it('should switch to codelist input when toggling codelist switch on', async () => { + const handleComponentChange = jest.fn(); + renderEditOptions({ + handleComponentChange, + component: { + ...mockComponent, + options: [{ label: 'option1', value: 'option1' }], + optionsId: undefined, + }, + }); + const switchElement = screen.getByRole('checkbox'); + await act(() => switchElement.click()); + expect(handleComponentChange).toHaveBeenCalledWith({ ...mockComponent, optionsId: '' }); + }); + + it('should update component options when adding new option', async () => { + const handleComponentChange = jest.fn(); + renderEditOptions({ + handleComponentChange, + component: { + ...mockComponent, + options: [{ label: 'option1', value: 'option1' }], + }, + }); + const addOptionButton = screen.getByRole('button', { + name: textMock('ux_editor.modal_new_option'), + }); + await act(() => addOptionButton.click()); + expect(handleComponentChange).toHaveBeenCalledWith({ + ...mockComponent, + options: expect.arrayContaining([ + { label: 'option1', value: 'option1' }, + expect.objectContaining({ label: '' }), + ]), + }); + }); + + it('should update component options when removing option', async () => { + const handleComponentChange = jest.fn(); + renderEditOptions({ + handleComponentChange, + component: { + ...mockComponent, + options: [{ label: 'option1', value: 'option1' }], + }, + }); + const removeOptionButton = screen.getByRole('button', { + name: textMock('ux_editor.properties_panel.options.remove_option'), + }); + await act(() => removeOptionButton.click()); + expect(handleComponentChange).toHaveBeenCalledWith({ ...mockComponent, options: [] }); }); }); diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.tsx index f95120d0fd0..0f1be15fe13 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions.tsx @@ -1,10 +1,17 @@ import React, { useEffect, useRef, useState } from 'react'; import type { IOption } from '../../../types/global'; -import { Fieldset, Radio, Textfield } from '@digdir/design-system-react'; +import { + Fieldset, + Heading, + HelpText, + Paragraph, + Switch, + Textfield, +} from '@digdir/design-system-react'; import classes from './EditOptions.module.css'; import type { IGenericEditComponent } from '../componentConfig'; import { EditCodeList } from './EditCodeList'; -import { PlusIcon, XMarkIcon } from '@navikt/aksel-icons'; +import { PlusIcon, TrashIcon } from '@navikt/aksel-icons'; import { TextResource } from '../../TextResource'; import { useText, useComponentErrorMessage } from '../../../hooks'; import { addOptionToComponent, generateRandomOption } from '../../../utils/component'; @@ -28,6 +35,17 @@ export enum SelectedOptionsType { Unknown = '', } +const optionsTypeMap = { + [SelectedOptionsType.CodeList]: { + propertyName: 'optionsId', + defaultValue: '', + }, + [SelectedOptionsType.Manual]: { + propertyName: 'options', + defaultValue: [], + }, +}; + const getSelectedOptionsType = (codeListId: string, options: IOption[]): SelectedOptionsType => { if (options?.length) { return SelectedOptionsType.Manual; @@ -39,6 +57,7 @@ export function EditOptions