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({