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: 14164 implement the legg til ny component for the last four standard choices #14392

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1a87bcc
render komponentbredde through a button --WIP
JamalAlabdullah Jan 3, 2025
7f1f2ea
Merge remote-tracking branch 'origin/main' into 14164-implement-the-l…
JamalAlabdullah Jan 7, 2025
17897d2
render sortOrder inside a button
JamalAlabdullah Jan 7, 2025
2aa8afe
render validation and preselected props through buttons
JamalAlabdullah Jan 8, 2025
b510fde
move CollapsiblePropertyEditor files to an own folder
JamalAlabdullah Jan 8, 2025
90b6cf6
added test fro CollapsiblePropertyEditor
JamalAlabdullah Jan 8, 2025
ec78568
added test
JamalAlabdullah Jan 9, 2025
61f9d12
fixed plass for grid button
JamalAlabdullah Jan 9, 2025
8f8be43
Merge remote-tracking branch 'origin/main' into 14164-implement-the-l…
JamalAlabdullah Jan 16, 2025
90aefab
reorder
JamalAlabdullah Jan 17, 2025
4aaeba1
unused textResouce for grid
JamalAlabdullah Jan 17, 2025
7eec7f6
render all strig properites through CollapsiblePropertyEditor
JamalAlabdullah Jan 19, 2025
660230b
render grid inside card
JamalAlabdullah Jan 20, 2025
d9cf36b
update test
JamalAlabdullah Jan 20, 2025
4e745a0
test
JamalAlabdullah Jan 20, 2025
06a64ba
Merge branch 'main' into 14164-implement-the-legg-til-ny-component-fo…
JamalAlabdullah Jan 20, 2025
14749f7
Merge remote-tracking branch 'origin/main' into 14164-implement-the-l…
JamalAlabdullah Jan 20, 2025
bb758a5
update
JamalAlabdullah Jan 20, 2025
b9258b8
add test
JamalAlabdullah Jan 20, 2025
442fc6a
refacture
JamalAlabdullah Jan 20, 2025
fe43f1c
Merge branch 'main' into 14164-implement-the-legg-til-ny-component-fo…
JamalAlabdullah Jan 21, 2025
b7caecd
fixed css of grid
JamalAlabdullah Jan 21, 2025
18c1102
Merge branch '14164-implement-the-legg-til-ny-component-for-the-last-…
JamalAlabdullah Jan 21, 2025
51e4a2b
fixed comments
JamalAlabdullah Jan 23, 2025
86637a4
Fix Form component config
mlqn Jan 28, 2025
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
3 changes: 2 additions & 1 deletion frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,7 @@
"ux_editor.component_properties.pagination": "Sidenummerering",
"ux_editor.component_properties.position": "Plassering av valuta",
"ux_editor.component_properties.preselectedOptionIndex": "Angi det valget som skal være forhåndsvalgt.",
"ux_editor.component_properties.preselectedOptionIndex_button": "Plassering av forhåndsvalgt verdi (indeks)",
"ux_editor.component_properties.preselected_help_text": "Eksempel: Hvis du har 5 valg, kan du bruke tall fra 0-4.",
"ux_editor.component_properties.queryParameters": "Parametere i spørringen",
"ux_editor.component_properties.readOnly": "Feltet kan kun leses",
Expand Down Expand Up @@ -1419,7 +1420,7 @@
"ux_editor.component_properties.showIcon": "Vis ikon",
"ux_editor.component_properties.showLabelsInTable": "Alternativene skal alltid vises i tabeller",
"ux_editor.component_properties.showPageInAccordion": "Vis side i trekkspilliste",
"ux_editor.component_properties.showValidations": "Vis valideringer",
"ux_editor.component_properties.showValidations": "Vis valideringstyper",
"ux_editor.component_properties.simplified": "Forenklet visning",
"ux_editor.component_properties.size": "Størrelse",
"ux_editor.component_properties.sortOrder": "Sorteringsrekkefølge",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,50 @@ describe('TextResource', () => {
expect(textbox.style.height).toBe('100px'); // the min height passed to the useAutoSizeTextArea hook from TextResourceValueEditor
expect(textbox.style.overflow).toBe('hidden');
});

it('Does not render the TextResourceEditor when disableEditor is true', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: true });
await user.click(screen.getByRole('button', { name: label }));
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
});

it('Renders the TextResourceEditor when disableEditor is false', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: false });
await user.click(screen.getByRole('button', { name: label }));
expect(screen.getByRole('textbox')).toBeInTheDocument();
});

it('Renders the TextResourceEditor when disableEditor is false', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: false });
await user.click(screen.getByRole('button', { name: label }));
expect(screen.getByRole('textbox')).toBeInTheDocument();
});
JamalAlabdullah marked this conversation as resolved.
Show resolved Hide resolved

it('Does not render the TextResourceEditor when disableEditor is true', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: true });
await user.click(screen.getByRole('button', { name: label }));
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
});

it('Renders the delete button when disableEditor is false', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: false });
await user.click(screen.getByRole('button', { name: label }));
expect(screen.getByRole('button', { name: textMock('general.delete') })).toBeInTheDocument();
});

it('Does not render the delete button when disableEditor is true', async () => {
const label = 'Test';
renderTextResource({ label, disableEditor: true });
await user.click(screen.getByRole('button', { name: label }));
expect(
screen.queryByRole('button', { name: textMock('general.delete') }),
).not.toBeInTheDocument();
});
});

const renderAndOpenSearchSection = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export interface TextResourceProps {
textResourceId?: string;
generateIdOptions?: GenerateTextResourceIdOptions;
compact?: boolean;
disableEditor?: boolean;
children?: React.ReactNode;
className?: string;
}

export interface GenerateTextResourceIdOptions {
Expand All @@ -39,6 +42,9 @@ export const TextResource = ({
handleRemoveTextResource,
label,
textResourceId,
disableEditor,
children,
className,
}: TextResourceProps) => {
const { formItemId } = useFormItemContext();
const { selectedFormLayoutName: formLayoutName } = useAppContext();
Expand Down Expand Up @@ -85,9 +91,13 @@ export const TextResource = ({
onSetCurrentValue={setCurrentValue}
onReferenceChange={handleIdChange}
textResourceId={textResourceId}
/>
showTextResourceEditor={!disableEditor}
>
{children}
</TextResourceFieldset>
) : (
<TextResourceButton
className={className}
compact={compact}
label={label}
onOpen={handleOpen}
Expand All @@ -104,6 +114,8 @@ type TextResourceFieldsetProps = {
onReferenceChange: (id: string) => void;
onSetCurrentValue: (value: string) => void;
textResourceId: string;
showTextResourceEditor?: boolean;
children?: React.ReactNode;
};

const TextResourceFieldset = ({
Expand All @@ -114,6 +126,8 @@ const TextResourceFieldset = ({
onReferenceChange,
onSetCurrentValue,
textResourceId,
showTextResourceEditor = true,
children,
}: TextResourceFieldsetProps) => {
const { t } = useTranslation();

Expand All @@ -123,27 +137,32 @@ const TextResourceFieldset = ({
legend={legend}
menubar={
<>
<span>{t('language.' + DEFAULT_LANGUAGE)}</span>
{showTextResourceEditor && <span>{t('language.' + DEFAULT_LANGUAGE)}</span>}
<StudioButton
icon={<XMarkIcon />}
onClick={onClose}
title={t('general.close')}
variant='secondary'
/>
<StudioDeleteButton
confirmMessage={t('ux_editor.text_resource_bindings.delete_confirm_question')}
disabled={!onDelete}
onDelete={() => onDelete?.()}
title={t('general.delete')}
/>
{showTextResourceEditor && (
<StudioDeleteButton
confirmMessage={t('ux_editor.text_resource_bindings.delete_confirm_question')}
disabled={!onDelete}
onDelete={() => onDelete?.()}
title={t('general.delete')}
/>
)}
</>
}
>
<TextResourceEditor
textResourceId={textResourceId}
onReferenceChange={onReferenceChange}
onSetCurrentValue={onSetCurrentValue}
/>
{showTextResourceEditor && (
<TextResourceEditor
textResourceId={textResourceId}
onReferenceChange={onReferenceChange}
onSetCurrentValue={onSetCurrentValue}
/>
)}
{children}
</StudioProperty.Fieldset>
);
};
Expand All @@ -153,16 +172,24 @@ type TextResourceButtonProps = {
label: string;
onOpen: () => void;
textResourceId: string;
className?: string;
};

const TextResourceButton = ({
compact,
label,
onOpen,
textResourceId,
className,
}: TextResourceButtonProps) => {
const value = useTextResourceValue(textResourceId);
return (
<StudioProperty.Button compact={compact} onClick={onOpen} property={label} value={value} />
<StudioProperty.Button
compact={compact}
onClick={onOpen}
property={label}
value={value}
className={className}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.collapsibleContainer {
display: flex;
width: 100%;
flex-direction: row;
align-items: flex-end;
gap: var(--fds-spacing-4);
padding-bottom: var(--fds-spacing-3);
padding-top: var(--fds-spacing-3);
}

.collapsibleContainerClosed {
padding: 0;
}

.editorContent {
flex: 1;
}

.button {
display: flex;
gap: var(--fds-spacing-3);
padding-left: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import {
CollapsiblePropertyEditor,
type CollapsiblePropertyEditorProps,
} from './CollapsiblePropertyEditor';
import userEvent from '@testing-library/user-event';
import { screen } from '@testing-library/react';
import { renderWithProviders } from 'app-development/test/mocks';
import { textMock } from '@studio/testing/mocks/i18nMock';

// Test data
const label = 'Test label';
const children = <div>Test children</div>;
const icon = <div>Test icon</div>;

describe('CollapsiblePropertyEditor', () => {
it('should render the label', () => {
renderCollapsiblePropertyEditor({ label: label });
expect(screen.getByText('Test label')).toBeInTheDocument();
});

it('should render the icon', () => {
renderCollapsiblePropertyEditor({ icon: <div>Test icon</div> });
expect(screen.getByText('Test icon')).toBeInTheDocument();
});

it('should render the children', () => {
renderCollapsiblePropertyEditor();
expect(screen.queryByText('Test children')).not.toBeInTheDocument();
});

it('should render the children when the button is clicked', async () => {
const user = userEvent.setup();
renderCollapsiblePropertyEditor();
await user.click(screen.getByText('Test label'));
expect(screen.getByText('Test children')).toBeInTheDocument();
});

it('should hide the children when the close button is clicked', async () => {
const user = userEvent.setup();
renderCollapsiblePropertyEditor();
await user.click(screen.getByText('Test label'));
expect(screen.getByText('Test children')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: textMock('general.close') }));
expect(screen.queryByText('Test children')).not.toBeInTheDocument();
});
});

const defaultProps: CollapsiblePropertyEditorProps = {
label,
children,
icon,
};

const renderCollapsiblePropertyEditor = (props: Partial<CollapsiblePropertyEditorProps> = {}) => {
renderWithProviders()(<CollapsiblePropertyEditor {...defaultProps} {...props} />);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { useState } from 'react';
import { PlusCircleIcon, XMarkIcon } from '@studio/icons';
import { StudioButton, StudioProperty } from '@studio/components';
import classes from './CollapsiblePropertyEditor.module.css';
import { useTranslation } from 'react-i18next';
import cn from 'classnames';

export type CollapsiblePropertyEditorProps = {
label?: string;
children?: React.ReactNode;
icon?: React.ReactNode;
};

export const CollapsiblePropertyEditor = ({
label,
children,
icon = <PlusCircleIcon />,
}: CollapsiblePropertyEditorProps) => {
const { t } = useTranslation();
const [isVisible, setIsVisible] = useState(false);

return (
<div
className={cn(isVisible ? classes.collapsibleContainer : classes.collapsibleContainerClosed)}
>
{!isVisible ? (
<StudioProperty.Button
className={classes.button}
icon={icon}
onClick={() => setIsVisible(true)}
property={label}
/>
JamalAlabdullah marked this conversation as resolved.
Show resolved Hide resolved
) : (
<>
<div className={classes.editorContent}>{children}</div>
<StudioButton
icon={<XMarkIcon />}
onClick={() => setIsVisible(false)}
title={t('general.close')}
variant='secondary'
/>
</>
)}
</div>
JamalAlabdullah marked this conversation as resolved.
Show resolved Hide resolved
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CollapsiblePropertyEditor } from './CollapsiblePropertyEditor';
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
.downIcon {
font-size: var(--fds-sizing-6);
}

.gridButton {
padding: 0;
}
Loading
Loading