Skip to content

Commit

Permalink
fix: tablecolumns saving/deleting a column affects other columns
Browse files Browse the repository at this point in the history
Removes unecessary state, and dependence on custom text-key for custom
labels

commit-id:2ef223ec
  • Loading branch information
Jondyr committed Feb 3, 2025
1 parent 80f442d commit 9825a74
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ const defaultProps: ColumnElementProps = {
columnNumber: columnNumberMock,
isInitialOpenForEdit: false,
onDeleteColumn: jest.fn(),
onEdit: jest.fn(),
onChange: jest.fn(),
subformLayout: layoutSet3SubformNameMock,
};

describe('ColumnElement', () => {
afterEach(() => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should call onEdit with updated header content when click on save button', async () => {
const onEditMock = jest.fn();
it('should call onEdit with component values when selecting component', async () => {
const onChangeMock = jest.fn();

const user = userEvent.setup();
renderColumnElement({
onEdit: onEditMock,
onChange: onChangeMock,
});

const editButton = screen.getByRole('button', {
Expand All @@ -66,21 +66,56 @@ describe('ColumnElement', () => {
textMock('ux_editor.properties_panel.subform_table_columns.column_title_unedit'),
),
);
await user.type(
screen.getByText(
textMock('ux_editor.properties_panel.subform_table_columns.column_title_edit'),

const saveButton = await screen.findByRole('button', { name: textMock('general.save') });
await user.click(saveButton);

expect(onChangeMock).toHaveBeenCalledWith({
...mockTableColumn,
cellContent: {
query: subformLayoutMock.component1.dataModelBindings.simpleBinding,
},
headerContent: subformLayoutMock.component1.textResourceBindings.title,
});
});

it('should call onEdit with updated header content on manual change', async () => {
const onChangeMock = jest.fn();

const user = userEvent.setup();
renderColumnElement({
onChange: onChangeMock,
});

const editButton = screen.getByRole('button', {
name: /ux_editor.properties_panel.subform_table_columns.column_header/,
});
await user.click(editButton);

await user.click(
await screen.findByText(
textMock('ux_editor.properties_panel.subform_table_columns.column_title_unedit'),
),
'New Title',
);
const customTitleString = 'Custom title';
await user.clear(
screen.getByRole('textbox', {
name: textMock('ux_editor.properties_panel.subform_table_columns.column_title_edit'),
}),
);
await user.type(
screen.getByRole('textbox', {
name: textMock('ux_editor.properties_panel.subform_table_columns.column_title_edit'),
}),
customTitleString,
);

const saveButton = await screen.findByRole('button', { name: textMock('general.save') });
await user.click(saveButton);

expect(onEditMock).toHaveBeenCalledTimes(1);
expect(onEditMock).toHaveBeenCalledWith({
expect(onChangeMock).toHaveBeenCalledWith({
...mockTableColumn,
headerContent: expect.stringContaining('subform_table_column_title_'),
cellContent: { query: subformLayoutMock.component1.dataModelBindings.simpleBinding },
headerContent: customTitleString,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,36 @@ export type ColumnElementProps = {
columnNumber: number;
isInitialOpenForEdit: boolean;
onDeleteColumn: () => void;
onEdit: (tableColumn: TableColumn) => void;
onChange: (tableColumn: TableColumn) => void;
};

export const ColumnElement = ({
tableColumn,
columnNumber,
isInitialOpenForEdit,
onDeleteColumn,
onEdit,
onChange,
subformLayout,
}: ColumnElementProps): ReactElement => {
const { t } = useTranslation();
const [editing, setEditing] = useState(isInitialOpenForEdit);
const { org, app } = useStudioEnvironmentParams();
const { data: textResources } = useTextResourcesQuery(org, app);

const textKeyValue = textResourceByLanguageAndIdSelector(
'nb',
tableColumn.headerContent,
)(textResources)?.value;
const textKeyValue =
textResourceByLanguageAndIdSelector('nb', tableColumn.headerContent)(textResources)?.value ||
tableColumn.headerContent;

if (editing) {
return (
<EditColumnElement
subformLayout={subformLayout}
sourceColumn={tableColumn}
tableColumn={tableColumn}
columnNumber={columnNumber}
onDeleteColumn={onDeleteColumn}
onEdit={(col) => {
onChange={onChange}
onClose={() => {
setEditing(false);
onEdit(col);
}}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, type ReactElement } from 'react';
import React, { type ReactElement } from 'react';
import classes from './EditColumnElement.module.css';
import { type TableColumn } from '../../types/TableColumn';
import { useTranslation } from 'react-i18next';
Expand All @@ -15,79 +15,55 @@ import { useFormLayoutsQuery } from '../../../../../hooks/queries/useFormLayouts
import type { FormItem } from '../../../../../types/FormItem';
import { EditColumnElementContent } from './EditColumnElementContent';
import { useTextResourcesQuery } from 'app-shared/hooks/queries';
import { useUpsertTextResourceMutation } from 'app-shared/hooks/mutations';
import { useTextIdMutation } from 'app-development/hooks/mutations';
import {
getComponentsForSubformTable,
getDefaultDataModel,
getTitleIdForColumn,
getValueOfTitleId,
} from '../../utils/editSubformTableColumnsUtils';
import { convertDataBindingToInternalFormat } from '../../../../../utils/dataModelUtils';
import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery';

export type ColumnElementProps = {
sourceColumn: TableColumn;
tableColumn: TableColumn;
columnNumber: number;
onDeleteColumn: () => void;
onEdit: (tableColumn: TableColumn) => void;
onChange: (tableColumn: TableColumn) => void;
onClose: () => void;
subformLayout: string;
};

export const EditColumnElement = ({
sourceColumn,
tableColumn,
columnNumber,
onDeleteColumn,
onEdit,
onChange,
onClose,
subformLayout,
}: ColumnElementProps): ReactElement => {
const { t } = useTranslation();
const { org, app } = useStudioEnvironmentParams();
const { data: textResources } = useTextResourcesQuery(org, app);
const [tableColumn, setTableColumn] = useState(sourceColumn);
const [title, setTitle] = useState<string>(
getValueOfTitleId(sourceColumn.headerContent, textResources),
);
const [uniqueTitleId, _] = useState(
getTitleIdForColumn({
titleId: tableColumn.headerContent,
subformId: subformLayout,
textResources,
}),
);
const { mutate: upsertTextResource } = useUpsertTextResourceMutation(org, app);
const { mutate: textIdMutation } = useTextIdMutation(org, app);
const { data: formLayouts } = useFormLayoutsQuery(org, app, subformLayout);
const { data: layoutSets } = useLayoutSetsQuery(org, app);

const handleSave = () => {
upsertTextResource({ language: 'nb', textId: uniqueTitleId, translation: title });
onEdit({ ...tableColumn, headerContent: uniqueTitleId });
};

const handleDelete = () => {
textIdMutation([{ oldId: uniqueTitleId }]);
onDeleteColumn();
};

const selectComponent = (values: string[]) => {
const selectedComponentId = values[0];
const selectedComponent = availableComponents.find((comp) => comp.id === selectedComponentId);

const binding = convertDataBindingToInternalFormat(selectedComponent, 'simpleBinding');
const updatedTableColumn = {
...sourceColumn,
...tableColumn,
headerContent: selectedComponent.textResourceBindings?.title,
cellContent: { query: binding.field },
};

setTitle(getValueOfTitleId(selectedComponent.textResourceBindings.title, textResources));
setTableColumn(updatedTableColumn);
onChange(updatedTableColumn);
};

const textResourceValue =
getValueOfTitleId(tableColumn.headerContent, textResources) || tableColumn.headerContent;
const subformDefaultDataModel = getDefaultDataModel(layoutSets, subformLayout);
const availableComponents = getComponentsForSubformTable(formLayouts, subformDefaultDataModel);
const isSaveButtonDisabled = !tableColumn.headerContent || !title?.trim();
const isSaveButtonDisabled = !tableColumn.headerContent;

return (
<StudioCard className={classes.wrapper}>
Expand All @@ -100,18 +76,18 @@ export const EditColumnElement = ({
{tableColumn.headerContent && (
<EditColumnElementContent
cellContent={tableColumn.cellContent.query}
title={title}
setTitle={setTitle}
title={textResourceValue}
setTitle={(title) => onChange({ ...tableColumn, headerContent: title })}
/>
)}
<div className={classes.buttons}>
<StudioActionCloseButton
variant='secondary'
onClick={handleSave}
onClick={onClose}
title={t('general.save')}
disabled={isSaveButtonDisabled}
/>
<StudioDeleteButton title={t('general.delete')} onDelete={handleDelete} />
<StudioDeleteButton title={t('general.delete')} onDelete={onDeleteColumn} />
</div>
</StudioCard.Content>
</StudioCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ describe('EditSubformTableColumns', () => {
expect(handleComponentChangeMock).toHaveBeenCalledTimes(1);

const columnTitleKey = getUpdatedTableColumns(handleComponentChangeMock)[0].headerContent;
expect(columnTitleKey).toEqual(expect.stringContaining('subform_table_column_title_'));
expect(columnTitleKey).toEqual(
expect.stringContaining(subformLayoutMock.component1.textResourceBindings.title),
);
});

it('should call handleComponentChange when a column is deleted', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const EditSubformTableColumns = ({
columnNumber={index + 1}
isInitialOpenForEdit={newColumnNumber === index + 1}
onDeleteColumn={() => deleteColumn(tableColumn, index)}
onEdit={(updatedTableColumn: TableColumn) => editColumn(updatedTableColumn, index)}
onChange={(updatedTableColumn: TableColumn) => editColumn(updatedTableColumn, index)}
/>
))}
<StudioButton
Expand Down

0 comments on commit 9825a74

Please sign in to comment.