DataTable: neue Spalten ruecken in die gespeicherte Reihenfolge nach

Die Gruppen-Spalte fehlte im Spalten-Menue - aus zwei Gruenden, und der zweite
ist der ernstere.

1) order wurde EINMAL beim Mounten berechnet: gespeicherte Reihenfolge plus
alles, was zu dem Zeitpunkt in columns stand. Aendert eine Seite ihre Spalten
danach - die Artikelliste zeigt "Verwaltung" nur bei Gegenstaenden -, fehlt die
neue Spalte in order und faellt damit aus allOrdered heraus. Sie ist dann nicht
bloss aus dem Menue verschwunden, sondern aus der TABELLE. Ein useEffect zieht
fehlende Schluessel jetzt nach; angehaengt, nicht einsortiert, damit eine selbst
gewaehlte Reihenfolge nicht umspringt.

2) Die Liste im Menue war fest auf 240px begrenzt. Bei zehn Spalten stand der
letzte Eintrag ausserhalb, und weil macOS die Bildlaufleiste ausblendet, sah es
aus, als gaebe es ihn nicht. Die Hoehe richtet sich jetzt nach dem freien Platz
bis zum unteren Bildrand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-16 22:31:40 +02:00
parent 68feb43b3e
commit 4e2dd3e3eb
2 changed files with 28 additions and 3 deletions

View File

@@ -40,6 +40,22 @@ export default function DataTable({
const rest = columns.map((c) => c.key).filter((k) => !saved.includes(k));
return [...saved, ...rest];
});
// `order` ist eine Momentaufnahme vom Mounten. Seiten duerfen ihre Spalten
// aber danach aendern (die Artikelliste zeigt „Verwaltung" nur bei
// Gegenstaenden), und eine neu hinzugefuegte Spalte steht ohnehin nie in der
// gespeicherten Reihenfolge. Fehlt sie dort, faellt sie aus allOrdered heraus
// und ist WEG nicht nur aus dem Spalten-Menue, sondern aus der Tabelle.
// Deshalb hier nachziehen. Angehaengt, nicht einsortiert: eine selbst
// gewaehlte Reihenfolge soll nicht umspringen.
const schluessel = columns.map((c) => c.key).join("|");
useEffect(() => {
setOrder((alt) => {
const fehlend = columns.map((c) => c.key).filter((k) => !alt.includes(k));
return fehlend.length ? [...alt, ...fehlend] : alt;
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [schluessel]);
const [widths, setWidths] = useState(() => loadPersisted(id).widths || {});
// Filter + Sortierung bleiben erhalten (localStorage je Tabelle), bis man
// „Filter löschen" drückt oder anders sortiert auch nach Navigieren/Neuladen.
@@ -98,7 +114,14 @@ export default function DataTable({
useLayoutEffect(() => {
if (chooserOpen && chooserBtn.current) {
const r = chooserBtn.current.getBoundingClientRect();
setChooserPos({ left: Math.min(r.left, window.innerWidth - 240), top: r.bottom + 4 });
// Hoehe an den freien Platz koppeln. Eine feste Obergrenze schnitt die
// letzten Eintraege ab, ohne dass man es sah auf macOS blendet das
// System die Bildlaufleiste aus, und dann fehlt die Spalte scheinbar.
setChooserPos({
left: Math.min(r.left, window.innerWidth - 240),
top: r.bottom + 4,
maxHeight: Math.max(180, window.innerHeight - r.bottom - 24),
});
}
}, [chooserOpen]);
useEffect(() => {
@@ -316,7 +339,7 @@ export default function DataTable({
</div>
{chooserOpen && chooserPos && createPortal(
<div ref={chooserPop} className="dt-pop" style={{ left: chooserPos.left, top: chooserPos.top }}>
<div className="dt-pop-list">
<div className="dt-pop-list" style={{ maxHeight: chooserPos.maxHeight }}>
{allOrdered.map((c) => (
<label key={c.key} className="dt-pop-opt">
<input type="checkbox" checked={!hidden.has(c.key)} onChange={() => toggleHidden(c.key)} />

View File

@@ -646,7 +646,9 @@ td select { width: auto; min-width: 0; max-width: 100%; }
}
.dt-pop-search { width: 100%; margin: 0 0 var(--sp-2); padding: 5px 8px; font-size: 0.85rem; }
.dt-pop-actions { display: flex; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.dt-pop-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; }
/* Die Hoehe setzt DataTable je nach freiem Platz (siehe chooserPos); hier
nur der Notnagel, falls sie einmal fehlt. */
.dt-pop-list { max-height: 60vh; overflow-y: auto; display: flex; flex-direction: column; }
.dt-pop-opt { display: flex; align-items: center; gap: 8px; padding: 3px 4px; font-size: 0.85rem; cursor: pointer; margin: 0; }
.dt-pop-opt:hover { background: var(--surface-2); }
/* Ohne diese Ausnahme erben die Checkboxen die globale input-Regel (width:100%,