Skip to content

Commit

Permalink
JNG-5899 inline table editing
Browse files Browse the repository at this point in the history
  • Loading branch information
noherczeg committed Aug 29, 2024
1 parent f586ba1 commit 6fc9c68
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5576,7 +5576,7 @@
</pageContainers>
<pageContainers xmi:id="God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTablePageContainer" name="View::Galaxy::Table" label="Galaxies" dataElement="God/(esm/_YTkpoE7rEeycO-gUAWxcVg)/ClassType" onInit="God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTableRefreshActionDefinition">
<children xsi:type="ui:Flex" xmi:id="God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableVisualElement" name="Table" col="12.0" direction="VERTICAL" mainAxisAlignment="START" crossAxisAlignment="STRETCH">
<children xsi:type="ui:Table" xmi:id="God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTable" name="Table" sourceId="_YT0hQE7rEeycO-gUAWxcVg" label="Galaxies" col="12.0" row="12.0" dataElement="God/(esm/_YTkpoE7rEeycO-gUAWxcVg)/ClassType" crudOperationsDisplayed="1" rowsPerPage="25" selectorRowsPerPage="25">
<children xsi:type="ui:Table" xmi:id="God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTable" name="Table" isInlineEditable="true" sourceId="_YT0hQE7rEeycO-gUAWxcVg" label="Galaxies" col="12.0" row="12.0" dataElement="God/(esm/_YTkpoE7rEeycO-gUAWxcVg)/ClassType" crudOperationsDisplayed="1" rowsPerPage="25" selectorRowsPerPage="25">
<columns xmi:id="God/(esm/_8AiKcE7tEeycO-gUAWxcVg)/TableColumn/(discriminator/God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTable)" name="name" label="Name" col="2.0" format="%s" attributeType="God/(esm/_YT6n4E7rEeycO-gUAWxcVg)/AttributeType" sort="ASC"/>
<columns xmi:id="God/(esm/_EIBPIFjXEeyV2_3ibolaNQ)/TableColumn/(discriminator/God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTable)" name="real" label="Real" col="2.0" format="%s" attributeType="God/(esm/_Q3EmkFjVEeyV2_3ibolaNQ)/AttributeType"/>
<columns xmi:id="God/(esm/_Vne4AFjJEeyV2_3ibolaNQ)/TableColumn/(discriminator/God/(esm/_YT0hQE7rEeycO-gUAWxcVg)/TransferObjectTableTable)" name="constellation" label="Constellation" col="2.0" format="%s" attributeType="God/(esm/_ABgK4FjFEeyV2_3ibolaNQ)/AttributeType"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ public static boolean isColumnEnumeration(Column column) {
return dataType instanceof EnumerationType;
}

public static boolean isColumnEditable(Column column) {
return !column.getAttributeType().getIsMemberTypeDerived();
}

public static boolean isColumnTimestamp(Column column) {
DataType dataType = column.getAttributeType().getDataType();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
useGridApiRef,
GridToolbarContainer,
GridEventListener,
GridRowModesModel,
GridRowModes,
GridRowEditStopReasons,
} from '@mui/x-data-grid{{ getMUIDataGridPlanSuffix }}';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { MouseEvent, useCallback, useMemo, useRef, useState, useEffect, ElementType } from 'react';
Expand Down Expand Up @@ -88,6 +91,10 @@ interface EagerTableProps<T extends GridValidRowModel, TStored extends GridValid
relationName: string;
filtersSerializer: FiltersSerializer;
navigable?: boolean;
rowModesModel?: GridRowModesModel;
handleRowModesModelChange?: (newRowModesModel: GridRowModesModel) => void;
handleRowEditStop?: GridEventListener<'rowEditStop'>;
processRowUpdate?: (newRow: GridRowModel) => void;
}

export function EagerTable<T extends GridValidRowModel, TStored extends T, S extends QueryCustomizer<T>>(props: EagerTableProps<T, TStored>) {
Expand Down Expand Up @@ -125,6 +132,10 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
checkboxSelection,
filtersSerializer,
navigable = true,
rowModesModel = {},
handleRowModesModelChange,
handleRowEditStop,
processRowUpdate,
} = props;

const apiRef = useGridApiRef();
Expand Down Expand Up @@ -190,8 +201,6 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext

const columns = useMemo<GridColDef<TStored>[]>(() => tableColumns, [l10nLocale]);

const rowActions: TableRowAction<T, TStored>[] = useMemo(() => tableRowActions, [actions, isLoading]);

const getSelectedRows: () => T[] = useCallback(() => {
if (tableHasSelectorColumn) {
return selectedRows.current;
Expand All @@ -203,7 +212,7 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
const effectiveTableColumns = useMemo(() => {
const cols = [
...columns,
...columnsActionCalculator(dataElementId, rowActions, t, isLoading, getSelectedRows, ownerData, { crudOperationsDisplayed: crudOperationsDisplayed, transferOperationsDisplayed: transferOperationsDisplayed })
...columnsActionCalculator(dataElementId, tableRowActions, t, isLoading, getSelectedRows, ownerData, { crudOperationsDisplayed: crudOperationsDisplayed, transferOperationsDisplayed: transferOperationsDisplayed })
];
{{# if isMUILicensePlanPro }}
if (columnState.length) {
Expand All @@ -222,7 +231,7 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
}
{{/ if }}
return cols;
}, [columns, rowActions, getSelectedRows, ownerData, isLoading{{# if isMUILicensePlanPro }}, columnState{{/ if }}]);
}, [columns, tableRowActions, getSelectedRows, ownerData, isLoading{{# if isMUILicensePlanPro }}, columnState{{/ if }}]);

{{# if isMUILicensePlanPro }}
const onColumnsChanged = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ import {
GridRowParams,
GridToolbarContainer,
GridEventListener,
GridRowModesModel,
GridRowModes,
GridRowEditStopReasons,
} from '@mui/x-data-grid{{ getMUIDataGridPlanSuffix }}';
import { ComponentProxy, useTrackService } from '@pandino/react-hooks';
import { MouseEvent, useCallback, useMemo, useRef, useState, useEffect, ElementType, Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { X_JUDO_COUNT } from '~/services/data-api/rest/headers';
import { Filter, FilterOption } from '~/components-api';
import {
ContextMenu,
ContextMenuApi,
StripedDataGrid,
columnsActionCalculator,
RowHighlightLegend,
ContextMenu,
ContextMenuApi,
StripedDataGrid,
columnsActionCalculator,
RowHighlightLegend,
} from '~/components/table';
import { useConfirmDialog } from '~/components/dialog';
import { basePageSizeOptions, baseTableConfig, filterDebounceMs } from '~/config';
Expand All @@ -39,6 +42,7 @@ import {
useErrorHandler,
isRowSelectable,
fileHandling,
simpleCloneDeep,
ToolBarActionProps,
calculateActionName,
{{# if isUseInlineColumnFilters }}
Expand Down Expand Up @@ -99,6 +103,7 @@ interface LazyTableProps<T extends GridValidRowModel, TStored extends GridValidR
relationName: string;
filtersSerializer: FiltersSerializer;
navigable?: boolean;
editable?: boolean;
}

export function LazyTable<T extends GridValidRowModel, TStored extends T, S extends QueryCustomizer<T>>(props: LazyTableProps<T, TStored>) {
Expand Down Expand Up @@ -144,6 +149,7 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
checkboxSelection,
filtersSerializer,
navigable = true,
editable = false,
} = props;

const apiRef = useGridApiRef();
Expand Down Expand Up @@ -203,6 +209,8 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
const [lastItem, setLastItem] = useState<TStored>();
const [firstItem, setFirstItem] = useState<TStored>();
const [isNextButtonEnabled, setIsNextButtonEnabled] = useState<boolean>(true);
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
const [rowEditingData, setRowEditingData] = useState<Record<string, TStored>>({});

const isLoading = useMemo(() => isInternalLoading || !!isOwnerLoading, [isInternalLoading, isOwnerLoading]);

Expand All @@ -217,8 +225,6 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte

const columns = useMemo<GridColDef<TStored>[]>(() => tableColumns, [l10nLocale]);

const rowActions: TableRowAction<T, TStored>[] = useMemo(() => tableRowActions, [actions, isLoading]);

const getSelectedRows: () => T[] = useCallback(() => {
if (tableHasSelectorColumn) {
if (containerIsSelector) {
Expand All @@ -231,10 +237,65 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
}
}, [selectionDiff, selectedRows.current]);

const editActions = useMemo(() => [
{
id: `${uniqueId}-row-edit`,
icon: <MdiIcon path="pencil" />,
isCRUD: true,
forceKeep: true,
hidden: (row: any) => rowModesModel[row.__identifier]?.mode === GridRowModes.Edit,
disabled: () => false,
action: async (rowData: any) => {
setRowEditingData({
...rowEditingData,
[rowData.__identifier]: simpleCloneDeep(rowData),
});
setRowModesModel({ ...rowModesModel, [rowData.__identifier!]: { mode: GridRowModes.Edit } });
},
},
{
id: `${uniqueId}-row-save`,
icon: <MdiIcon path="content-save" />,
isCRUD: true,
forceKeep: true,
hidden: (row: any) => !(rowModesModel[row.__identifier]?.mode === GridRowModes.Edit),
disabled: () => false,
action: async (rowData: any) => {

},
},
{
id: `${uniqueId}-row-cancel`,
icon: <MdiIcon path="close" />,
isCRUD: true,
forceKeep: true,
hidden: (row: any) => !(rowModesModel[row.__identifier]?.mode === GridRowModes.Edit),
disabled: () => false,
action: async (rowData: any) => {
setRowModesModel({
...rowModesModel,
[rowData.__identifier!]: { mode: GridRowModes.View, ignoreModifications: true }
});
const tmp = {
...rowEditingData,
};
const original = tmp[rowData.__identifier];
delete rowEditingData[rowData.__identifier];
setData((prevData) => {
const ttt = [...prevData];
const idx = ttt.findIndex(d => d.__identifier === rowData.__identifier);
ttt[idx] = original;
// debugger;
return [...ttt];
});
},
},
], [rowEditingData, tableRowActions, rowModesModel]);

const effectiveTableColumns = useMemo(() => {
const cols = [
...columns,
...columnsActionCalculator(dataElementId, rowActions, t, isLoading, getSelectedRows, ownerData, { crudOperationsDisplayed: crudOperationsDisplayed, transferOperationsDisplayed: transferOperationsDisplayed })
...columnsActionCalculator(dataElementId, [...(editable ? editActions: []), ...tableRowActions], t, isLoading, getSelectedRows, ownerData, { crudOperationsDisplayed: crudOperationsDisplayed, transferOperationsDisplayed: transferOperationsDisplayed })
];
{{# if isMUILicensePlanPro }}
if (columnState.length) {
Expand All @@ -252,7 +313,7 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
}
{{/ if }}
return cols;
}, [columns, rowActions, getSelectedRows, ownerData, isLoading{{# if isMUILicensePlanPro }}, columnState{{/ if }}]);
}, [columns, editActions, tableRowActions, getSelectedRows, ownerData, isLoading, editable{{# if isMUILicensePlanPro }}, columnState{{/ if }}]);

{{# if isMUILicensePlanPro }}
const onColumnsChanged = () => {
Expand Down Expand Up @@ -539,6 +600,27 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
{{/ if }}
}

const processRowUpdate = (newRow: GridRowModel) => {
console.warn(newRow);
//const updatedRow = { ...newRow, isNew: false };
//setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row)));
//return updatedRow;
};

const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => {
// setRowModesModel(newRowModesModel);
};

const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => {
if (params.reason === GridRowEditStopReasons.rowFocusOut) {
event.defaultMuiPrevented = true;
}
};

const handleProcessRowUpdateError = useCallback((error: Error) => {
console.error(error);
}, []);

return (
<>
<ComponentProxy
Expand Down Expand Up @@ -568,6 +650,12 @@ export function LazyTable<T extends GridValidRowModel, TStored extends T, S exte
...transformRowStylings(rowStylings),
{{/ if }}
} }
editMode="row"
rowModesModel={rowModesModel}
onRowModesModelChange={handleRowModesModelChange}
onRowEditStop={handleRowEditStop}
processRowUpdate={processRowUpdate}
onProcessRowUpdateError={handleProcessRowUpdateError}
slotProps={ {
{{# if (stringValueIsTrue useTableContextMenus) }}
cell: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import { MdiIcon } from '../MdiIcon';

export const calculateMinWidth = (entry: TableRowAction<any, any>[]) => entry.length ? ((entry.map(a => (a.label ?? '').length).reduce((p, c) => p + c, 0) * characterMultiplier) + iconAndDropdownIconExtra) : onlyDropdownWidth;

const findLastIndex = <T,>(array: T[], predicate: (e: T) => boolean): number => {
for (let i = array.length - 1; i >= 0; i--) {
if (predicate(array[i])) {
return i;
}
}
return -1;
};

export const columnsActionCalculator: ColumnActionsProvider<any, any> = (
id: string,
actions: TableRowAction<any, any>[],
Expand All @@ -26,7 +35,7 @@ export const columnsActionCalculator: ColumnActionsProvider<any, any> = (
};
const originalCrudActions = actions.filter((a) => !!a.action && a.isCRUD);
const originalOperationActions = actions.filter((a) => !!a.action && !a.isCRUD);
const keptCrudActions = originalCrudActions.splice(0, safeOptions.crudOperationsDisplayed);
const keptCrudActions = originalCrudActions.splice(0, (findLastIndex<TableRowAction<any, any>>(actions, a => !!a.forceKeep) + 1) + (safeOptions.crudOperationsDisplayed || 0));
const keptOperationActions = originalOperationActions.splice(0, safeOptions.transferOperationsDisplayed);
const splitActions = [...keptCrudActions, ...keptOperationActions];
const dropdownActions = [...originalCrudActions, ...originalOperationActions];
Expand All @@ -46,7 +55,7 @@ export const columnsActionCalculator: ColumnActionsProvider<any, any> = (
type: 'actions',
getActions: (params: GridRowParams) => [
<ButtonGroup>
{splitActions.map((a) => (
{splitActions.filter(a => !a.hidden(params.row)).map((a) => (
<Button
id={a.id}
key={a.id}
Expand All @@ -62,7 +71,7 @@ export const columnsActionCalculator: ColumnActionsProvider<any, any> = (
id={id}
variant="text"
showDropdownIcon={false}
menuItems={dropdownActions.map((action) => ({
menuItems={dropdownActions.filter(a => !a.hidden(params.row)).map((action) => ({
id: action.id,
label: action.label,
startIcon: action.icon,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export function {{ componentName table }}(props: {{ componentName table }}Props)
{{# if (isRowActionCRUD button.actionDefinition) }}
isCRUD: true,
{{/ if }}
hidden: (row: any) => false,
disabled: (row: {{ classDataName (getReferenceClassType table) 'Stored' }}, isLoading: boolean, getSelectedRows: () => {{# with (getReferenceClassType table) as |classType| }}{{# if classType.isMapped }}{{ classDataName (getReferenceClassType table) 'Stored' }}[]{{ else }}{{ classDataName (getReferenceClassType table) '' }}[]{{/ if }}{{/ with }}, ownerdata?: any): boolean => {{{ tableRowButtonDisabledConditions button table container }}},
action: actions.{{ simpleActionDefinitionName button.actionDefinition }} ? async (rowData) => {
{{# unless (isParameterOpenerButton button) }}
Expand Down Expand Up @@ -294,6 +295,9 @@ export function {{ componentName table }}(props: {{ componentName table }}Props)
{{ else }}
<LazyTable<{{# with (getReferenceClassType table) as |classType| }}{{# if classType.isMapped }}{{ classDataName (getReferenceClassType table) 'Stored' }}{{ else }}{{ classDataName (getReferenceClassType table) '' }}{{/ if }}{{/ with }}, {{ classDataName (getReferenceClassType table) 'Stored' }}, {{ classDataName (getReferenceClassType table) 'QueryCustomizer' }}>
uniqueId={`{{ createId table }}-${uniqueId}`}
{{# if table.isInlineEditable }}
editable={true}
{{/ if }}
{{# if (stringValueIsTrue useTableRowHighlighting) }}
rowHighlightingHookInterfaceKey={`(&(${OBJECTCLASS}=${TABLE_ROW_HIGHLIGHTING_HOOK_INTERFACE_KEY})(component={{~ componentName table ~}}))`}
{{/ if }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { ElementType, Dispatch, SetStateAction } from 'react';
import type {
GridFilterModel,
GridEventListener,
GridRowModesModel,
GridRowModel,
} from '@mui/x-data-grid{{ getMUIDataGridPlanSuffix }}';
{{# each (getTableAPIImports table container) as |imp| }}
import type {
Expand Down Expand Up @@ -79,4 +82,8 @@ export interface {{ componentName table }}Props {
editMode: boolean;
isFormUpdateable: () => boolean;
{{/ unless }}
rowModesModel?: GridRowModesModel;
handleRowModesModelChange?: (newRowModesModel: GridRowModesModel) => void;
handleRowEditStop?: GridEventListener<'rowEditStop'>;
processRowUpdate?: (newRow: GridRowModel) => void;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
width: {{ columnWidth column }},
type: '{{ columnType column }}',
{{# if (isColumnEditable column) }}
editable: true,
{{/ if }}
filterable: {{ isUseInlineColumnFilters }} && {{# if (isColumnFilterable column) }}true{{ else }}false{{/ if }},
{{# unless (isColumnSortable column) }}
sortable: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface TableRowAction<R, RStored> {
label?: string;
action?: (row: RStored) => Promise<void>;
icon?: ReactNode;
hidden: (row: RStored) => boolean;
disabled: (
row: RStored,
isLoading: boolean,
Expand All @@ -15,6 +16,7 @@ export interface TableRowAction<R, RStored> {
) => boolean,
disabledExpression?: string;
isCRUD?: boolean;
forceKeep?: boolean;
}

export interface ColumnsActionsOptions {
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<node-version>18.14.2</node-version>
<pnpm-version>8.9.2</pnpm-version>

<judo-meta-ui-version>1.1.0.20240725_123755_3c5f2837_develop</judo-meta-ui-version>
<judo-meta-ui-version>1.1.0-SNAPSHOT</judo-meta-ui-version>
<judo-generator-commons-version>1.0.0.20240712_085217_8319ce27_develop</judo-generator-commons-version>
<judo-ui-typescript-rest-version>1.0.0.20240823_165725_58575058_feature_JNG_5888_filter_context</judo-ui-typescript-rest-version>

Expand Down

0 comments on commit 6fc9c68

Please sign in to comment.