Skip to content

Commit

Permalink
Merge branch 'main' into feat/13686-support-access-packages-in-policy…
Browse files Browse the repository at this point in the history
…-editor-v1
  • Loading branch information
mgunnerud authored Dec 13, 2024
2 parents 782440f + c6690b7 commit c312f89
Show file tree
Hide file tree
Showing 28 changed files with 405 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('WebSocketSyncWrapper', () => {
const queryClientMock = createQueryClientMock();
const invalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);

invalidator.invalidateQueryByFileLocation = jest.fn();
invalidator.invalidateQueriesByFileLocation = jest.fn();
const mockOnWSMessageReceived = jest
.fn()
.mockImplementation((callback: Function) => callback(syncSuccessMock));
Expand All @@ -80,7 +80,7 @@ describe('WebSocketSyncWrapper', () => {

renderWebSocketSyncWrapper();
await waitFor(() => {
expect(invalidator.invalidateQueryByFileLocation).toHaveBeenCalledWith(
expect(invalidator.invalidateQueriesByFileLocation).toHaveBeenCalledWith(
syncSuccessMock.source.name,
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export const WebSocketSyncWrapper = ({

const isSuccessMessage = 'source' in message;
if (isSuccessMessage) {
// Please extend the "fileNameCacheKeyMap" inside the "SyncSuccessQueriesInvalidator" class. Do not add query-client invalidation directly here.
invalidator.invalidateQueryByFileLocation(message.source.name);
// Please extend the "fileNameCacheKeysMap" inside the "SyncSuccessQueriesInvalidator" class. Do not add query-client invalidation directly here.
invalidator.invalidateQueriesByFileLocation(message.source.name);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const useAddLayoutSetMutation = (org: string, app: string) => {
// when process-editor renders the tasks and 'adds' them on first mount, when they already exists.
if (isLayoutSets(layoutSets)) {
queryClient.setQueryData([QueryKey.LayoutSets, org, app], layoutSets);
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useDeleteLayoutSetMutation = (org: string, app: string) => {
deleteLayoutSet(org, app, layoutSetIdToUpdate),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.AppMetadataModelIds, org, app] });
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const useUpdateLayoutSetIdMutation = (org: string, app: string) => {
}) => updateLayoutSetId(org, app, layoutSetIdToUpdate, newLayoutSetId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('useUpdateProcessDataTypeMutation', () => {

await renderHook({ queryClient });

expect(invalidateQueriesSpy).toHaveBeenCalledTimes(2);
expect(invalidateQueriesSpy).toHaveBeenCalledTimes(3);
expect(invalidateQueriesSpy).toHaveBeenCalledWith({
queryKey: [QueryKey.AppMetadataModelIds, org, app],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useUpdateProcessDataTypesMutation = (org: string, app: string) => {
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: [QueryKey.AppMetadataModelIds, org, app] });
await queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
await queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
},
});
};
13 changes: 9 additions & 4 deletions frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,8 @@
"ux_editor.component_help_text.TextArea": "Du bruker Stort tekstfelt når du vil at brukerne skal skrive litt lengre tekst.",
"ux_editor.component_help_text.default": "Ingen informasjon å vise om denne komponenten.",
"ux_editor.component_help_text_general_title": "Åpne hjelpetekst for komponenten",
"ux_editor.component_other_properties_hide_many_settings": "Skjul flere innstillinger",
"ux_editor.component_other_properties_show_many_settings": "Vis flere innstillinger",
"ux_editor.component_other_properties_title": "Andre innstillinger",
"ux_editor.component_properties.action": "Handling",
"ux_editor.component_properties.actions": "Handlinger",
Expand Down Expand Up @@ -1425,11 +1427,14 @@
"ux_editor.component_properties.tableHeadersMobile": "Felter som skal vises i tabellens overskrift (mobil)",
"ux_editor.component_properties.tabs": "Faner",
"ux_editor.component_properties.tagName": "Tag-navn",
"ux_editor.component_properties.target": "Mål",
"ux_editor.component_properties.target_description": "Mål for oppsummeringskomponenten",
"ux_editor.component_properties.target": "Hva vil du vise i oppsummeringen?",
"ux_editor.component_properties.target_description": "Her kan du velge hva som skal vises på oppsummeringssiden. Du kan for eksempel vise hele sidegrupper, utvalgte sider eller utvalgte komponenter",
"ux_editor.component_properties.target_invalid": "Ugyldig mål",
"ux_editor.component_properties.target_taskId": "Oppgave-ID",
"ux_editor.component_properties.target_type": "Type",
"ux_editor.component_properties.target_taskId": "1. Oppsummer fra denne sidegruppen",
"ux_editor.component_properties.target_type": "2. Vis sidegruppe, side eller komponent",
"ux_editor.component_properties.target_unit_component": "3. Komponent",
"ux_editor.component_properties.target_unit_layout_set": "3. Sidegruppe",
"ux_editor.component_properties.target_unit_page": "3. Side",
"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 utløse:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ const codeList: CodeList = [
helpText: 'Test 3 help text',
},
];
const onBlurAny = jest.fn();
const onChange = jest.fn();
const onInvalid = jest.fn();
const defaultProps: StudioCodeListEditorProps = {
codeList,
texts,
onBlurAny,
onChange,
onInvalid,
};
Expand Down Expand Up @@ -119,8 +121,7 @@ describe('StudioCodeListEditor', () => {
const labelInput = screen.getByRole('textbox', { name: texts.itemLabel(1) });
const newValue = 'new text';
await user.type(labelInput, newValue);
await user.tab();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledTimes(newValue.length);
expect(onChange).toHaveBeenLastCalledWith([
{ ...codeList[0], label: newValue },
codeList[1],
Expand All @@ -134,8 +135,7 @@ describe('StudioCodeListEditor', () => {
const valueInput = screen.getByRole('textbox', { name: texts.itemValue(1) });
const newValue = 'new text';
await user.type(valueInput, newValue);
await user.tab();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledTimes(newValue.length);
expect(onChange).toHaveBeenLastCalledWith([
{ ...codeList[0], value: newValue },
codeList[1],
Expand All @@ -149,8 +149,7 @@ describe('StudioCodeListEditor', () => {
const descriptionInput = screen.getByRole('textbox', { name: texts.itemDescription(1) });
const newValue = 'new text';
await user.type(descriptionInput, newValue);
await user.tab();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledTimes(newValue.length);
expect(onChange).toHaveBeenLastCalledWith([
{ ...codeList[0], description: newValue },
codeList[1],
Expand All @@ -164,8 +163,7 @@ describe('StudioCodeListEditor', () => {
const helpTextInput = screen.getByRole('textbox', { name: texts.itemHelpText(1) });
const newValue = 'new text';
await user.type(helpTextInput, newValue);
await user.tab();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledTimes(newValue.length);
expect(onChange).toHaveBeenLastCalledWith([
{ ...codeList[0], helpText: newValue },
codeList[1],
Expand Down Expand Up @@ -196,6 +194,21 @@ describe('StudioCodeListEditor', () => {
]);
});

it('Calls the onBlurAny callback with the current code list when an item in the table is blurred', async () => {
const user = userEvent.setup();
renderCodeListEditor();
const valueInput = screen.getByRole('textbox', { name: texts.itemValue(1) });
const newValue = 'new text';
await user.type(valueInput, newValue);
await user.tab();
expect(onBlurAny).toHaveBeenCalledTimes(1);
expect(onBlurAny).toHaveBeenLastCalledWith([
{ ...codeList[0], value: newValue },
codeList[1],
codeList[2],
]);
});

it('Updates itself when the user changes something', async () => {
const user = userEvent.setup();
renderCodeListEditor();
Expand Down Expand Up @@ -267,8 +280,7 @@ describe('StudioCodeListEditor', () => {
const validValueInput = screen.getByRole('textbox', { name: texts.itemValue(3) });
const newValue = 'new value';
await user.type(validValueInput, newValue);
await user.tab();
expect(onInvalid).toHaveBeenCalledTimes(1);
expect(onInvalid).toHaveBeenCalledTimes(newValue.length);
});

it('Does not trigger onInvalid if an invalid code list is changed to a valid state', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,32 @@ import { areThereCodeListErrors, findCodeListErrors, isCodeListValid } from './v
import type { ValueErrorMap } from './types/ValueErrorMap';
import { StudioFieldset } from '../StudioFieldset';
import { StudioErrorMessage } from '../StudioErrorMessage';
import type { Override } from '../../types/Override';
import type { StudioInputTableProps } from '../StudioInputTable/StudioInputTable';

export type StudioCodeListEditorProps = {
codeList: CodeList;
onChange: (codeList: CodeList) => void;
onBlurAny?: (codeList: CodeList) => void;
onChange?: (codeList: CodeList) => void;
onInvalid?: () => void;
texts: CodeListEditorTexts;
};

export function StudioCodeListEditor({
codeList,
onBlurAny,
onChange,
onInvalid,
texts,
}: StudioCodeListEditorProps): ReactElement {
return (
<StudioCodeListEditorContext.Provider value={{ texts }}>
<StatefulCodeListEditor codeList={codeList} onChange={onChange} onInvalid={onInvalid} />
<StatefulCodeListEditor
codeList={codeList}
onBlurAny={onBlurAny}
onChange={onChange}
onInvalid={onInvalid}
/>
</StudioCodeListEditorContext.Provider>
);
}
Expand All @@ -48,6 +57,7 @@ type StatefulCodeListEditorProps = Omit<StudioCodeListEditorProps, 'texts'>;

function StatefulCodeListEditor({
codeList: defaultCodeList,
onBlurAny,
onChange,
onInvalid,
}: StatefulCodeListEditorProps): ReactElement {
Expand All @@ -60,18 +70,32 @@ function StatefulCodeListEditor({
const handleChange = useCallback(
(newCodeList: CodeList) => {
setCodeList(newCodeList);
isCodeListValid(newCodeList) ? onChange(newCodeList) : onInvalid?.();
isCodeListValid(newCodeList) ? onChange?.(newCodeList) : onInvalid?.();
},
[onChange, onInvalid],
);

return <ControlledCodeListEditor codeList={codeList} onChange={handleChange} />;
const handleBlurAny = useCallback(() => {
onBlurAny?.(codeList);
}, [onBlurAny, codeList]);

return (
<ControlledCodeListEditor
codeList={codeList}
onBlurAny={handleBlurAny}
onChange={handleChange}
/>
);
}

type InternalCodeListEditorProps = Omit<StatefulCodeListEditorProps, 'onInvalid'>;
type InternalCodeListEditorProps = Override<
Pick<StudioInputTableProps, 'onBlurAny'>,
Omit<StatefulCodeListEditorProps, 'onInvalid'>
>;

function ControlledCodeListEditor({
codeList,
onBlurAny,
onChange,
}: InternalCodeListEditorProps): ReactElement {
const { texts } = useStudioCodeListEditorContext();
Expand All @@ -86,12 +110,18 @@ function ControlledCodeListEditor({

return (
<StudioFieldset legend={texts.codeList} className={classes.codeListEditor} ref={fieldsetRef}>
<CodeListTable codeList={codeList} errorMap={errorMap} onChange={onChange} />
<CodeListTable
codeList={codeList}
errorMap={errorMap}
onBlurAny={onBlurAny}
onChange={onChange}
/>
<AddButton onClick={handleAddButtonClick} />
<Errors errorMap={errorMap} />
</StudioFieldset>
);
}

type InternalCodeListEditorWithErrorsProps = InternalCodeListEditorProps & ErrorsProps;

function CodeListTable(props: InternalCodeListEditorWithErrorsProps): ReactElement {
Expand All @@ -107,11 +137,14 @@ function EmptyCodeListTable(): ReactElement {
return <StudioParagraph size='small'>{texts.emptyCodeList}</StudioParagraph>;
}

function CodeListTableWithContent(props: InternalCodeListEditorWithErrorsProps): ReactElement {
function CodeListTableWithContent({
onBlurAny,
...rest
}: InternalCodeListEditorWithErrorsProps): ReactElement {
return (
<StudioInputTable>
<StudioInputTable onBlurAny={onBlurAny}>
<TableHeadings />
<TableBody {...props} />
<TableBody {...rest} />
</StudioInputTable>
);
}
Expand Down Expand Up @@ -145,7 +178,7 @@ function TableBody({
[codeList, onChange],
);

const handleBlur = useCallback(
const handleChange = useCallback(
(index: number, newItem: CodeListItem) => {
const updatedCodeList = changeCodeListItem(codeList, index, newItem);
onChange(updatedCodeList);
Expand All @@ -161,7 +194,7 @@ function TableBody({
item={item}
key={index}
number={index + 1}
onBlur={(newItem) => handleBlur(index, newItem)}
onChange={(newItem) => handleChange(index, newItem)}
onDeleteButtonClick={() => handleDeleteButtonClick(index)}
/>
))}
Expand Down
Loading

0 comments on commit c312f89

Please sign in to comment.