Browse Source

editable table column size (#1852)

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide 7 months ago
parent
commit
2072dd7a10

+ 6 - 6
frontend/taipy-gui/src/components/Taipy/AutoLoadingTable.tsx

@@ -51,7 +51,7 @@ import {
     RowValue,
     EDIT_COL,
     OnRowDeletion,
-    addDeleteColumn,
+    addActionColumn,
     headBoxSx,
     getClassName,
     LINE_STYLE,
@@ -129,7 +129,7 @@ const Row = ({
         <TableRow
             hover
             tabIndex={-1}
-            key={"row" + index}
+            key={`row${index}`}
             component="div"
             sx={style}
             className={(classes && classes.row) + " " + getClassName(rows[index], lineStyle)}
@@ -139,7 +139,7 @@ const Row = ({
         >
             {colsOrder.map((col, cIdx) => (
                 <EditableCell
-                    key={"val" + index + "-" + cIdx}
+                    key={`cell${index}${columns[col].dfid}`}
                     className={getClassName(rows[index], columns[col].style, col)}
                     tableClassName={tableClassName}
                     colDesc={columns[col]}
@@ -305,7 +305,7 @@ const AutoLoadingTable = (props: TaipyTableProps) => {
                         nDesc.tooltip = props.tooltip;
                     }
                 });
-                addDeleteColumn(
+                addActionColumn(
                     (active && partialEditable && (onAdd || onDelete) ? 1 : 0) +
                         (active && filter ? 1 : 0) +
                         (active && downloadable ? 1 : 0),
@@ -607,9 +607,9 @@ const AutoLoadingTable = (props: TaipyTableProps) => {
                         <MuiTable sx={tableSx} aria-labelledby="tableTitle" size={size} stickyHeader={true}>
                             <TableHead>
                                 <TableRow ref={headerRow}>
-                                    {colsOrder.map((col, idx) => (
+                                    {colsOrder.map((col) => (
                                         <TableCell
-                                            key={col + idx}
+                                            key={`head${columns[col].dfid}`}
                                             sortDirection={orderBy === columns[col].dfid && order}
                                             sx={columns[col].width ? { width: columns[col].width } : {}}
                                         >

+ 5 - 5
frontend/taipy-gui/src/components/Taipy/FileSelector.tsx

@@ -71,7 +71,7 @@ const FileSelector = (props: FileSelectorProps) => {
         withBorder = true,
     } = props;
     const [dropLabel, setDropLabel] = useState("");
-    const [dropSx, setDropSx] = useState<SxProps>(defaultSx);
+    const [dropSx, setDropSx] = useState<SxProps | undefined>(defaultSx);
     const [upload, setUpload] = useState(false);
     const [progress, setProgress] = useState(0);
     const { state, dispatch } = useContext(TaipyContext);
@@ -85,7 +85,7 @@ const FileSelector = (props: FileSelectorProps) => {
 
     useEffect(
         () =>
-            setDropSx((sx: SxProps) =>
+            setDropSx((sx: SxProps | undefined) =>
                 expandSx(
                     sx,
                     props.width ? { width: getCssSize(props.width) } : undefined,
@@ -139,7 +139,7 @@ const FileSelector = (props: FileSelectorProps) => {
     const handleDrop = useCallback(
         (e: DragEvent) => {
             setDropLabel("");
-            setDropSx((sx: SxProps) => ({ ...sx, ...defaultSx }));
+            setDropSx((sx: SxProps | undefined) => expandSx(sx, defaultSx));
             handleFiles(e.dataTransfer?.files, e);
         },
         [handleFiles]
@@ -147,13 +147,13 @@ const FileSelector = (props: FileSelectorProps) => {
 
     const handleDragLeave = useCallback(() => {
         setDropLabel("");
-        setDropSx((sx: SxProps) => ({ ...sx, ...defaultSx }));
+        setDropSx((sx: SxProps | undefined) => expandSx(sx, defaultSx));
     }, []);
 
     const handleDragOverWithLabel = useCallback(
         (evt: DragEvent) => {
             const target = evt.currentTarget as HTMLElement;
-            setDropSx((sx: SxProps) =>
+            setDropSx((sx: SxProps | undefined) =>
                 expandSx(
                     sx,
                     (sx as CSSProperties).minWidth === defaultSx.minWidth && target

+ 103 - 80
frontend/taipy-gui/src/components/Taipy/PaginatedTable.tsx

@@ -43,7 +43,7 @@ import Download from "@mui/icons-material/Download";
 
 import { createRequestTableUpdateAction, createSendActionNameAction } from "../../context/taipyReducers";
 import {
-    addDeleteColumn,
+    addActionColumn,
     baseBoxSx,
     defaultColumns,
     EditableCell,
@@ -133,82 +133,99 @@ const PaginatedTable = (props: TaipyPaginatedTableProps) => {
     const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
     const baseColumns = useDynamicJsonProperty(props.columns, props.defaultColumns, defaultColumns);
 
-    const [colsOrder, columns, styles, tooltips, formats, handleNan, filter, partialEditable] = useMemo(() => {
-        let hNan = !!props.nanValue;
-        if (baseColumns) {
-            try {
-                let filter = false;
-                let partialEditable = editable;
-                const newCols: Record<string, ColumnDesc> = {};
-                Object.entries(baseColumns).forEach(([cId, cDesc]) => {
-                    const nDesc = (newCols[cId] = { ...cDesc });
-                    if (typeof nDesc.filter != "boolean") {
-                        nDesc.filter = !!props.filter;
-                    }
-                    filter = filter || nDesc.filter;
-                    if (typeof nDesc.notEditable == "boolean") {
-                        partialEditable = partialEditable || !nDesc.notEditable;
-                    } else {
-                        nDesc.notEditable = !editable;
-                    }
-                    if (nDesc.tooltip === undefined) {
-                        nDesc.tooltip = props.tooltip;
-                    }
-                });
-                addDeleteColumn(
-                    (active && partialEditable && (onAdd || onDelete) ? 1 : 0) +
-                        (active && filter ? 1 : 0) +
-                        (active && downloadable ? 1 : 0),
-                    newCols
-                );
-                const colsOrder = Object.keys(newCols).sort(getSortByIndex(newCols));
-                const styTt = colsOrder.reduce<Record<string, Record<string, string>>>((pv, col) => {
-                    if (newCols[col].style) {
-                        pv.styles = pv.styles || {};
-                        pv.styles[newCols[col].dfid] = newCols[col].style;
-                    }
-                    hNan = hNan || !!newCols[col].nanValue;
-                    if (newCols[col].tooltip) {
-                        pv.tooltips = pv.tooltips || {};
-                        pv.tooltips[newCols[col].dfid] = newCols[col].tooltip;
-                    }
-                    if (newCols[col].formatFn) {
-                        pv.formats = pv.formats || {};
-                        pv.formats[newCols[col].dfid] = newCols[col].formatFn;
+    const [colsOrder, columns, styles, tooltips, formats, handleNan, filter, partialEditable, nbWidth] =
+        useMemo(() => {
+            let hNan = !!props.nanValue;
+            if (baseColumns) {
+                try {
+                    let filter = false;
+                    let partialEditable = editable;
+                    const newCols: Record<string, ColumnDesc> = {};
+                    Object.entries(baseColumns).forEach(([cId, cDesc]) => {
+                        const nDesc = (newCols[cId] = { ...cDesc });
+                        if (typeof nDesc.filter != "boolean") {
+                            nDesc.filter = !!props.filter;
+                        }
+                        filter = filter || nDesc.filter;
+                        if (typeof nDesc.notEditable == "boolean") {
+                            partialEditable = partialEditable || !nDesc.notEditable;
+                        } else {
+                            nDesc.notEditable = !editable;
+                        }
+                        if (nDesc.tooltip === undefined) {
+                            nDesc.tooltip = props.tooltip;
+                        }
+                    });
+                    addActionColumn(
+                        (active && partialEditable && (onAdd || onDelete) ? 1 : 0) +
+                            (active && filter ? 1 : 0) +
+                            (active && downloadable ? 1 : 0),
+                        newCols
+                    );
+                    const colsOrder = Object.keys(newCols).sort(getSortByIndex(newCols));
+                    let nbWidth = 0;
+                    const styTt = colsOrder.reduce<Record<string, Record<string, string>>>((pv, col) => {
+                        if (newCols[col].style) {
+                            pv.styles = pv.styles || {};
+                            pv.styles[newCols[col].dfid] = newCols[col].style;
+                        }
+                        hNan = hNan || !!newCols[col].nanValue;
+                        if (newCols[col].tooltip) {
+                            pv.tooltips = pv.tooltips || {};
+                            pv.tooltips[newCols[col].dfid] = newCols[col].tooltip;
+                        }
+                        if (newCols[col].formatFn) {
+                            pv.formats = pv.formats || {};
+                            pv.formats[newCols[col].dfid] = newCols[col].formatFn;
+                        }
+                        if (newCols[col].width !== undefined) {
+                            nbWidth ++;
+                        }
+                        return pv;
+                    }, {});
+                    nbWidth = colsOrder.length - nbWidth;
+                    if (props.lineStyle) {
+                        styTt.styles = styTt.styles || {};
+                        styTt.styles[LINE_STYLE] = props.lineStyle;
                     }
-                    return pv;
-                }, {});
-                if (props.lineStyle) {
-                    styTt.styles = styTt.styles || {};
-                    styTt.styles[LINE_STYLE] = props.lineStyle;
+                    return [
+                        colsOrder,
+                        newCols,
+                        styTt.styles,
+                        styTt.tooltips,
+                        styTt.formats,
+                        hNan,
+                        filter,
+                        partialEditable,
+                        nbWidth,
+                    ];
+                } catch (e) {
+                    console.info("PaginatedTable.columns: ", (e as Error).message || e);
                 }
-                return [colsOrder, newCols, styTt.styles, styTt.tooltips, styTt.formats, hNan, filter, partialEditable];
-            } catch (e) {
-                console.info("PaginatedTable.columns: ", (e as Error).message || e);
             }
-        }
-        return [
-            [] as string[],
-            {} as Record<string, ColumnDesc>,
-            {} as Record<string, string>,
-            {} as Record<string, string>,
-            {} as Record<string, string>,
-            hNan,
-            false,
-            false,
-        ];
-    }, [
-        active,
-        editable,
-        onAdd,
-        onDelete,
-        baseColumns,
-        props.lineStyle,
-        props.tooltip,
-        props.nanValue,
-        props.filter,
-        downloadable,
-    ]);
+            return [
+                [] as string[],
+                {} as Record<string, ColumnDesc>,
+                {} as Record<string, string>,
+                {} as Record<string, string>,
+                {} as Record<string, string>,
+                hNan,
+                false,
+                false,
+                0,
+            ];
+        }, [
+            active,
+            editable,
+            onAdd,
+            onDelete,
+            baseColumns,
+            props.lineStyle,
+            props.tooltip,
+            props.nanValue,
+            props.filter,
+            downloadable,
+        ]);
 
     useDispatchRequestUpdateOnFirstRender(dispatch, id, module, updateVars);
 
@@ -489,11 +506,17 @@ const PaginatedTable = (props: TaipyPaginatedTableProps) => {
                         <Table sx={tableSx} aria-labelledby="tableTitle" size={size} stickyHeader={true}>
                             <TableHead>
                                 <TableRow>
-                                    {colsOrder.map((col, idx) => (
+                                    {colsOrder.map((col) => (
                                         <TableCell
-                                            key={col + idx}
+                                            key={`head${columns[col].dfid}`}
                                             sortDirection={orderBy === columns[col].dfid && order}
-                                            sx={columns[col].width ? { width: columns[col].width } : {}}
+                                            sx={
+                                                columns[col].width
+                                                    ? { width: columns[col].width }
+                                                    : nbWidth
+                                                    ? { width: `${100/nbWidth}%`, maxWidth: 0 }
+                                                    : undefined
+                                            }
                                         >
                                             {columns[col].dfid === EDIT_COL ? (
                                                 [
@@ -588,16 +611,16 @@ const PaginatedTable = (props: TaipyPaginatedTableProps) => {
                                         <TableRow
                                             hover
                                             tabIndex={-1}
-                                            key={"row" + index}
+                                            key={`row${index}`}
                                             selected={sel > -1}
                                             ref={sel == 0 ? selectedRowRef : undefined}
                                             className={getClassName(row, props.lineStyle)}
                                             data-index={index}
                                             onClick={active && onAction ? onRowClick : undefined}
                                         >
-                                            {colsOrder.map((col, cIdx) => (
+                                            {colsOrder.map((col) => (
                                                 <EditableCell
-                                                    key={"val" + index + "-" + cIdx}
+                                                    key={`cell${index}${columns[col].dfid}`}
                                                     className={getClassName(row, columns[col].style, col)}
                                                     tableClassName={className}
                                                     colDesc={columns[col]}

+ 1 - 1
frontend/taipy-gui/src/components/Taipy/Part.tsx

@@ -56,7 +56,7 @@ const Part = (props: PartProps) => {
         return false;
     }, [state.locations, page, defaultPartial]);
 
-    const boxSx = useMemo(() => expandSx({}, height ? { height: height } : undefined, props.width ? {width: getCssSize(props.width)}: undefined), [height, props.width]);
+    const boxSx = useMemo(() => expandSx(height ? { height: height } : undefined, props.width ? {width: getCssSize(props.width)}: undefined), [height, props.width]);
     return render ? (
         <Box id={id} className={className} sx={boxSx}>
             {iFrame ? (

+ 1 - 1
frontend/taipy-gui/src/components/Taipy/tableUtils.tsx

@@ -250,7 +250,7 @@ const getCellProps = (col: ColumnDesc, base: Partial<TableCellProps> = {}): Part
 export const getRowIndex = (row: Record<string, RowValue>, rowIndex: number, startIndex = 0) =>
     typeof row["_tp_index"] === "number" ? row["_tp_index"] : rowIndex + startIndex;
 
-export const addDeleteColumn = (nbToRender: number, columns: Record<string, ColumnDesc>) => {
+export const addActionColumn = (nbToRender: number, columns: Record<string, ColumnDesc>) => {
     if (nbToRender) {
         Object.keys(columns).forEach((key) => columns[key].index++);
         columns[EDIT_COL] = {

+ 5 - 3
frontend/taipy-gui/src/components/Taipy/utils.ts

@@ -148,11 +148,13 @@ export const getProps = (p: DateProps, start: boolean, val: Date | null, withTim
     return { ...p, [propName]: val };
 };
 
-export const expandSx = (sx: SxProps, ...partials: (SxProps | undefined)[]) => {
-    return partials.reduce((prevSx: SxProps, partialSx) => {
+export const expandSx = (sx: SxProps | undefined, ...partials: (SxProps | undefined)[]) => {
+    const start = sx || {};
+    const end = partials.reduce((prevSx: SxProps, partialSx) => {
         if (partialSx) {
             return { ...prevSx, ...partialSx } as SxProps;
         }
         return prevSx;
-    }, sx);
+    }, start);
+    return start === end ? sx : end;
 };