diff --git a/web/src/components/DataTable.jsx b/web/src/components/DataTable.jsx index cb61d9e..298e492 100644 --- a/web/src/components/DataTable.jsx +++ b/web/src/components/DataTable.jsx @@ -44,8 +44,14 @@ export default function DataTable({ const [filterShown, setFilterShown] = useState(true); const [openFilter, setOpenFilter] = useState(null); const [collapsed, setCollapsed] = useState(() => new Set()); + const [hidden, setHidden] = useState( + () => new Set((loadPersisted(id).hidden || []).filter((k) => colByKey[k])), + ); + const [chooserOpen, setChooserOpen] = useState(false); - useEffect(() => { savePersisted(id, { order, widths }); }, [id, order, widths]); + useEffect(() => { + savePersisted(id, { order, widths, hidden: [...hidden] }); + }, [id, order, widths, hidden]); // Containerbreite messen, damit die grow-Spalte den Rest füllt. const wrapRef = useRef(null); @@ -59,7 +65,39 @@ export default function DataTable({ return () => ro.disconnect(); }, []); - const orderedCols = order.map((k) => colByKey[k]).filter(Boolean); + const allOrdered = order.map((k) => colByKey[k]).filter(Boolean); + const orderedCols = allOrdered.filter((c) => !hidden.has(c.key)); + + // Spalten-Wähler-Popover. + const chooserBtn = useRef(null); + const chooserPop = useRef(null); + const [chooserPos, setChooserPos] = useState(null); + useLayoutEffect(() => { + if (chooserOpen && chooserBtn.current) { + const r = chooserBtn.current.getBoundingClientRect(); + setChooserPos({ left: Math.min(r.left, window.innerWidth - 240), top: r.bottom + 4 }); + } + }, [chooserOpen]); + useEffect(() => { + if (!chooserOpen) return undefined; + function onDoc(e) { + if (chooserBtn.current?.contains(e.target) || chooserPop.current?.contains(e.target)) return; + setChooserOpen(false); + } + document.addEventListener("mousedown", onDoc); + return () => document.removeEventListener("mousedown", onDoc); + }, [chooserOpen]); + + function toggleHidden(key) { + setHidden((s) => { + const n = new Set(s); + if (n.has(key)) { n.delete(key); return n; } + // Mindestens eine Spalte sichtbar lassen. + if (allOrdered.filter((c) => !n.has(c.key) && c.key !== key).length === 0) return s; + n.add(key); + return n; + }); + } const isGrow = (c) => c.grow && widths[c.key] == null; const fixedWidth = (c) => widths[c.key] ?? c.width ?? DEFAULT_WIDTH; @@ -224,6 +262,7 @@ export default function DataTable({ function resetColumns() { setOrder(columns.map((c) => c.key)); setWidths({}); + setHidden(new Set()); savePersisted(id, {}); } @@ -235,9 +274,26 @@ export default function DataTable({ Filter + {toolbarExtra} + {chooserOpen && chooserPos && createPortal( +
+
+ {allOrdered.map((c) => ( + + ))} +
+
, + document.body, + )}