Skip to content

Commit

Permalink
Merge pull request #45 from AntaresSimulatorTeam/feature/ANT-2534_dis…
Browse files Browse the repository at this point in the history
…play_table_in_area_and_link_sectionn

Feature/ant 2534 display table in area and link section
  • Loading branch information
vargastat authored Feb 3, 2025
2 parents 880d20a + f7eccf9 commit 2e93557
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 238 deletions.
4 changes: 4 additions & 0 deletions src/components/common/data/stdSimpleTable/StdSimpleTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
useReactTable,
} from '@tanstack/react-table';
import TableCore, { TableCoreProps } from '../stdTable/TableCore';
import { ReadOnlyFeature } from '@common/data/stdTable/features/readOnly.ts';

export type StdSimpleTableProps<TData> = {
getCoreRowModel?: (table: Table<TData>) => () => RowModel<TData>;
Expand All @@ -33,15 +34,18 @@ const StdSimpleTable = <TData,>({
columnResizeMode = undefined,
enableRowSelection = false,
enableMultiRowSelection = false,
enableReadOnly = false,
...tableOptions
}: StdSimpleTableProps<TData>) => {
const table = useReactTable<TData>({
_features: [ReadOnlyFeature],
columns,
data,
getCoreRowModel: getCustomCoreRowModel ?? getTstCoreRowModel<TData>(),
columnResizeMode,
enableRowSelection,
enableMultiRowSelection,
enableReadOnly,
...tableOptions,
});

Expand Down
26 changes: 14 additions & 12 deletions src/components/common/data/stdTable/TableCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,20 @@ const TableCore = <TData,>({ table, id: propId, striped, trClassName, columnSize
</tr>
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr
key={row.id}
className={tableCoreRowClassBuilder(striped, row.getIsSelected(), row.getReadOnly?.(), trClassName)}
onClick={handleToggleRow(row)}
aria-readonly={row.getReadOnly?.()}
>
{row.getVisibleCells().map((cell) => (
<TableDataCell key={cell.id} cell={cell} />
))}
</tr>
))}
{table.getRowModel().rows.map((row) => {
return (
<tr
key={row.id}
className={tableCoreRowClassBuilder(striped, row.getIsSelected(), row.getReadOnly?.(), trClassName)}
onClick={handleToggleRow(row)}
aria-readonly={row.getReadOnly?.()}
>
{row.getVisibleCells().map((cell) => (
<TableDataCell key={cell.id} cell={cell} />
))}
</tr>
);
})}
</tbody>
</table>
);
Expand Down
25 changes: 21 additions & 4 deletions src/components/common/data/stdTable/features/readOnly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,35 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { Row, RowData, Table, TableFeature } from '@tanstack/react-table';
import { ReadOnlyOptions, ReadOnlyTableState } from '../types/readOnly.type';
import { functionalUpdate, makeStateUpdater, Row, RowData, Table, TableFeature, Updater } from '@tanstack/react-table';
import { ReadOnlyObject, ReadOnlyOptions, ReadOnlyTableState } from '../types/readOnly.type';

export const ReadOnlyFeature: TableFeature = {
getInitialState: (state): ReadOnlyTableState => ({
readOnly: {},
...state,
}),

getDefaultOptions: <TData extends RowData>(_table: Table<TData>): ReadOnlyOptions => ({}) as ReadOnlyOptions,
getDefaultOptions: <TData extends RowData>(table: Table<TData>): ReadOnlyOptions => {
return {
enableReadOnly: false,
onReadOnlyChange: makeStateUpdater('readOnly', table),
} as ReadOnlyOptions;
},

createTable: <TData extends RowData>(table: Table<TData>): void => {
table.setReadOnly = (updater) => {
const safeUpdater: Updater<ReadOnlyObject> = (old) => {
return functionalUpdate(updater, old);
};
return table.options.onReadOnlyChange?.(safeUpdater);
};
// table.toggleReadOnly = value => {
// table.setReadOnly(old => !old);
// };
},

createRow: <TData extends RowData>(row: Row<TData>, table: Table<TData>): void => {
row.getReadOnly = () => !!table.getState().readOnly[row.id];
row.getReadOnly = () => table.getState().readOnly[row.id];
},
};
15 changes: 8 additions & 7 deletions src/components/common/data/stdTable/tableCoreRowClassBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

import clsx from 'clsx';

export const STRIPED_CLASSSES = 'even:bg-primary-200';
export const SELECTED_ROW_CLASSSES = 'bg-primary-100';
export const READONLY_ROW_CLASSSES = 'bg-gray-100';
export const STRIPED_CLASSES = 'even:bg-primary-200';
export const SELECTED_ROW_CLASSES = 'bg-primary-100';
export const READONLY_ROW_CLASSES = 'pointer-events-none bg-gray-100 [&_button]:bg-gray-400 [&_button]:border-gray-400';
export const READONLY_SELECTED_ROW_CLASSES = 'hover:bg-gray-100';

export const tableCoreRowClassBuilder = (
isStriped?: boolean,
Expand All @@ -19,10 +20,10 @@ export const tableCoreRowClassBuilder = (
clsx(
{
group: true,
[STRIPED_CLASSSES]: isStriped,
[SELECTED_ROW_CLASSSES]: isSelected,
[READONLY_ROW_CLASSSES]: isReadOnly,
'hover:bg-gray-100': !isReadOnly && !isSelected,
[STRIPED_CLASSES]: isStriped,
[SELECTED_ROW_CLASSES]: isSelected,
[READONLY_ROW_CLASSES]: isReadOnly,
[READONLY_SELECTED_ROW_CLASSES]: !isReadOnly && !isSelected,
},
trClassNames,
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,33 @@
*/

import {
READONLY_ROW_CLASSSES,
SELECTED_ROW_CLASSSES,
STRIPED_CLASSSES,
READONLY_ROW_CLASSES,
READONLY_SELECTED_ROW_CLASSES,
SELECTED_ROW_CLASSES,
STRIPED_CLASSES,
tableCoreRowClassBuilder,
} from '../tableCoreRowClassBuilder';

const TEST_TR_CLASSES = 'bg-acc1-500 text-caption';

describe('tableCoreRowClassBuilder function', () => {
it('should have the expected striped classes', () => {
expect(tableCoreRowClassBuilder(true).includes(STRIPED_CLASSSES)).toBe(true);
expect(tableCoreRowClassBuilder(true).includes(STRIPED_CLASSES)).toBe(true);
});

it('should have the expected selected classes', () => {
expect(tableCoreRowClassBuilder(false, true).includes(SELECTED_ROW_CLASSSES)).toBe(true);
expect(tableCoreRowClassBuilder(false, true).includes(SELECTED_ROW_CLASSES)).toBe(true);
});

it('should have the expected readonly classes', () => {
expect(tableCoreRowClassBuilder(false, false, true).includes(READONLY_ROW_CLASSSES)).toBe(true);
expect(tableCoreRowClassBuilder(false, false, true).includes(READONLY_ROW_CLASSES)).toBe(true);
});

it('should have the expected additional "tr" classes', () => {
expect(tableCoreRowClassBuilder(false, false, false, TEST_TR_CLASSES).includes(TEST_TR_CLASSES)).toBe(true);
expect(
tableCoreRowClassBuilder(false, false, false, READONLY_SELECTED_ROW_CLASSES).includes(
READONLY_SELECTED_ROW_CLASSES,
),
).toBe(true);
});
});
12 changes: 11 additions & 1 deletion src/components/common/data/stdTable/types/readOnly.type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@

/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-object-type */
import { OnChangeFn, Updater } from '@tanstack/react-table';

export type ReadOnlyObject = Record<string, boolean>;

export interface ReadOnlyTableState {
readOnly: ReadOnlyObject;
}

export interface ReadOnlyOptions {}
export interface ReadOnlyOptions {
enableReadOnly?: boolean;
onReadOnlyChange?: OnChangeFn<ReadOnlyObject>;
}

// Define types for our new feature's table APIs
export interface ReadOnlyTableInstance {
setReadOnly: (updater: Updater<ReadOnlyObject>) => void;
toggleReadOnly: (value?: ReadOnlyObject) => void;
}

export interface ReadOnlyRow {
Expand All @@ -25,7 +32,10 @@ export interface ReadOnlyRow {

declare module '@tanstack/react-table' {
interface TableState extends ReadOnlyTableState {}

interface TableOptionsResolved<TData extends RowData> extends ReadOnlyOptions {}

interface Table<TData extends RowData> extends ReadOnlyTableInstance {}

interface Row<TData extends RowData> extends ReadOnlyRow {}
}
123 changes: 64 additions & 59 deletions src/pages/pegase/studies/studyDetails/AreaLinkTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,81 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import {useState} from 'react';
import {ColumnDef} from '@tanstack/react-table';
import { useState } from 'react';
import { ColumnDef } from '@tanstack/react-table';
import StdSimpleTable from '@common/data/stdSimpleTable/StdSimpleTable';
import {RdsButton, RdsInputText} from "rte-design-system-react";

import { RdsButton, RdsInputText } from 'rte-design-system-react';
import { ReadOnlyObject } from '@common/data/stdTable/types/readOnly.type';

type RowStatus = 'Missing' | 'OK' | 'Error';

type RowData = {
hypothesis: string;
trajectory: string | null; // Null si aucune trajectoire n'est sélectionnée
status: RowStatus;
hypothesis: string;
trajectory: string | null; // Null si aucune trajectoire n'est sélectionnée
status: RowStatus;
};

const AreaLinkTab = () => {
const [data, setData] = useState<RowData[]>([
{hypothesis: 'Areas', trajectory: null, status: 'Missing'},
{hypothesis: 'Links', trajectory: null, status: 'Missing'},
]);
const [data, setData] = useState<RowData[]>([
{ hypothesis: 'Areas', trajectory: null, status: 'Missing' },
{ hypothesis: 'Links', trajectory: null, status: 'Missing' },
]);
const [readOnly, _] = useState<ReadOnlyObject>({ '0': false, '1': !data[0].trajectory });

const handleImport = (index: number) => {
const updatedData = [...data];
updatedData[index].trajectory = 'BP_23_ref';
updatedData[index].status = 'OK';
setData(updatedData);
};
const handleImport = (index: number) => {
const updatedData = [...data];
updatedData[index].trajectory = 'BP_23_ref';
updatedData[index].status = 'OK';
setData(updatedData);
};

const columns: ColumnDef<RowData>[] = [
{
header: 'Hypothesis',
accessorKey: 'hypothesis',
},
{
header: 'Trajectory to use',
cell: ({row}) => {
const index = row.index;
const {trajectory} = row.original;
return trajectory ? (
<div className="flex items-center space-x-2">
<span>{trajectory}</span>
</div>
) : (
<div className="flex items-center space-x-2">
<RdsInputText label=""
value=""
placeHolder="choose a Trajectory"
variant="outlined"/>
<span>or</span>
<RdsButton label="Import" onClick={() => handleImport(index)}/>
</div>
);
},
},
{
header: 'Status',
cell: ({row}) => {
const {status} = row.original;
if (status === 'Missing') return <span>❓ Missing</span>;
if (status === 'OK') return <span>✔ OK</span>;
if (status === 'Error') return <span>❌ Error</span>;
return null;
},
},
];
const columns: ColumnDef<RowData>[] = [
{
header: 'Hypothesis',
accessorKey: 'hypothesis',
},
{
header: 'Trajectory to use',
cell: ({ row }) => {
const index = row.index;
const { trajectory } = row.original;
return trajectory ? (
<div className="flex items-center space-x-2">
<span>{trajectory}</span>
</div>
) : (
<div className="flex items-center space-x-2">
<RdsInputText label="" value="" placeHolder="Choose a trajectory" variant="outlined" />
<span>or</span>
<RdsButton label="Import" onClick={() => handleImport(index)} />
</div>
);
},
},
{
header: 'Status',
cell: ({ row }) => {
const { status } = row.original;
if (status === 'Missing') return <span>❓ Missing</span>;
if (status === 'OK') return <span>✔ OK</span>;
if (status === 'Error') return <span>❌ Error</span>;
return null;
},
},
];

return (
<div className="flex-1">
<StdSimpleTable id="example-table" data={data} columns={columns} columnSize="meta"/>
</div>
);
return (
<div className="flex-1">
<StdSimpleTable
id="example-table"
data={data}
columns={columns}
columnSize="meta"
enableReadOnly={true}
state={{ readOnly }}
/>
</div>
);
};

export default AreaLinkTab;
Loading

0 comments on commit 2e93557

Please sign in to comment.