diff --git a/web/src/components/DataTable.jsx b/web/src/components/DataTable.jsx
index 0cca1c2..c154c28 100644
--- a/web/src/components/DataTable.jsx
+++ b/web/src/components/DataTable.jsx
@@ -11,7 +11,8 @@ import { Skeleton } from "./Skeleton";
*
* Spalten-Def: { key, header, render(row)→JSX, filterText(row)? (aktiviert Filter),
* sortValue(row)? (Sortierung), align:"num", grow:true (füllt Restbreite),
- * fixed:true (kein Reorder/Resize), width, min }.
+ * fixed:true (kein Reorder/Resize), pin:"right" (klebt am rechten Rand
+ * und steht immer ganz hinten), width, min }.
*/
const DEFAULT_WIDTH = 150;
@@ -96,7 +97,12 @@ export default function DataTable({
return () => ro.disconnect();
}, []);
- const allOrdered = order.map((k) => colByKey[k]).filter(Boolean);
+ const gespeichert = order.map((k) => colByKey[k]).filter(Boolean);
+ // Angeheftete Spalten gehoeren ans Ende, egal was gespeichert ist. Sonst
+ // klebte etwa die Knopfspalte mitten im Scrollbereich und deckte ihre
+ // Nachbarn zu – und neu hinzugekommene Spalten landen ohnehin dahinter.
+ const allOrdered = [...gespeichert.filter((c) => !c.pin),
+ ...gespeichert.filter((c) => c.pin)];
const orderedCols = allOrdered.filter((c) => !hidden.has(c.key));
const chooserBtn = useRef(null);
@@ -285,7 +291,7 @@ export default function DataTable({
{orderedCols.map((c) => (
| onDragStart(e, c)}
onDragOver={(e) => onDragOver(e, c)}
@@ -301,7 +307,7 @@ export default function DataTable({
{filterShown && (
|
{orderedCols.map((c) => (
- |
+ |
{(c.filterText || c.filterValues) ? (
onRowClick(row, e) : undefined}
style={onRowClick ? { cursor: "pointer" } : undefined}>
{orderedCols.map((c) => (
- | {c.render(row)} |
+ {c.render(row)} |
))}
|
))}
diff --git a/web/src/finance.css b/web/src/finance.css
index eae5f87..b59f3de 100644
--- a/web/src/finance.css
+++ b/web/src/finance.css
@@ -774,6 +774,26 @@ tr.row-dup {
cursor: pointer;
}
+/* Angeheftete Spalte: klebt am rechten Rand, wenn die Tabelle breiter ist als
+ das Fenster. Der Hintergrund muss deckend sein, sonst scrollen die anderen
+ Zellen sichtbar darunter durch. */
+.datatable th.dt-pin,
+.datatable td.dt-pin {
+ position: sticky;
+ right: 0;
+ z-index: 2;
+ background: var(--surface);
+}
+.datatable tbody tr:hover td.dt-pin { background: var(--surface-2); }
+/* Eine Kante nach links, damit man sieht, dass dahinter weitergeht. */
+.datatable th.dt-pin::before,
+.datatable td.dt-pin::before {
+ content: "";
+ position: absolute;
+ left: 0; top: 0; bottom: 0;
+ border-left: 1px solid var(--border);
+}
+
/* DataTable-Zellen einzeilig halten, damit „…" greift (Excel-artig). */
.datatable td { white-space: nowrap; vertical-align: middle; }
.datatable td .named-text { min-width: 0; }
diff --git a/web/src/pages/Transactions.jsx b/web/src/pages/Transactions.jsx
index 94cedb0..0e0eb95 100644
--- a/web/src/pages/Transactions.jsx
+++ b/web/src/pages/Transactions.jsx
@@ -624,7 +624,10 @@ export default function Transactions() {
},
},
{
- key: "actions", header: "", width: 118, fixed: true,
+ // Angeheftet: Seit Notiz und Tags dazugekommen sind, ist die Tabelle
+ // breiter als der Bildschirm – ohne das scrollten Bearbeiten und
+ // Loeschen einfach aus dem Bild.
+ key: "actions", header: "", width: 118, fixed: true, pin: "right",
render: (tx) => (