refactor(webui): use central widget selection

This commit is contained in:
2026-07-21 12:34:39 +02:00
parent 4a2d68b491
commit cfacc47ebb
2 changed files with 8 additions and 58 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { RefreshCw, RotateCcw, SlidersHorizontal } from "lucide-react"; import { RefreshCw, RotateCcw, SlidersHorizontal } from "lucide-react";
import { import {
AdminSelectionList,
Button, Button,
Card, Card,
MetricCard, MetricCard,
@@ -50,14 +51,9 @@ export default function DashboardPage({ settings, auth }: { settings: ApiSetting
writeLayout(storageKey, next); writeLayout(storageKey, next);
} }
function setWidgetVisible(widgetId: string, visible: boolean) { function setVisibleWidgets(selected: string[]) {
const allIds = widgets.map((widget) => widget.id); const allIds = widgets.map((widget) => widget.id);
const nextVisible = new Set(visibleWidgetIds); const nextVisible = new Set(selected);
if (visible) {
nextVisible.add(widgetId);
} else {
nextVisible.delete(widgetId);
}
saveLayout({ saveLayout({
known: allIds, known: allIds,
visible: allIds.filter((id) => nextVisible.has(id)) visible: allIds.filter((id) => nextVisible.has(id))
@@ -93,21 +89,11 @@ export default function DashboardPage({ settings, auth }: { settings: ApiSetting
title="Dashboard widgets" title="Dashboard widgets"
actions={<Button onClick={resetLayout}><RotateCcw size={16} /> Reset</Button>}> actions={<Button onClick={resetLayout}><RotateCcw size={16} /> Reset</Button>}>
{widgets.length === 0 ? <p className="muted">No installed module exposes dashboard widgets yet.</p> : {widgets.length === 0 ? <p className="muted">No installed module exposes dashboard widgets yet.</p> :
<div className="dashboard-widget-picker"> <AdminSelectionList
{widgets.map((widget) => options={widgets.map((widget) => ({ id: widget.id, label: widget.title, description: widget.description ?? widget.id }))}
<label key={widget.id} className="dashboard-widget-toggle"> selected={visibleWidgetIds}
<input onChange={setVisibleWidgets}
type="checkbox" />
checked={visibleWidgetIds.includes(widget.id)}
onChange={(event) => setWidgetVisible(widget.id, event.currentTarget.checked)}
/>
<span>
<strong>{widget.title}</strong>
<small>{widget.description ?? widget.id}</small>
</span>
</label>
)}
</div>
} }
</Card> </Card>
} }
@@ -183,4 +169,3 @@ function moduleLabels(modules: Array<{ id: string }>): string {
if (!modules.length) return "Core shell only"; if (!modules.length) return "Core shell only";
return modules.slice(0, 4).map((module) => module.id).join(", "); return modules.slice(0, 4).map((module) => module.id).join(", ");
} }

View File

@@ -32,39 +32,6 @@
grid-column: 1 / -1; grid-column: 1 / -1;
} }
.dashboard-widget-picker {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 12px;
}
.dashboard-widget-toggle {
min-width: 0;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 10px;
align-items: start;
border: var(--border-line);
border-radius: var(--radius-sm);
background: var(--panel-soft);
padding: 12px;
}
.dashboard-widget-toggle input {
margin-top: 3px;
}
.dashboard-widget-toggle strong,
.dashboard-widget-toggle small {
display: block;
}
.dashboard-widget-toggle small {
color: var(--muted);
margin-top: 4px;
line-height: 1.35;
}
.dashboard-compact-list.detail-list div { .dashboard-compact-list.detail-list div {
grid-template-columns: minmax(92px, auto) minmax(0, 1fr); grid-template-columns: minmax(92px, auto) minmax(0, 1fr);
} }
@@ -82,7 +49,6 @@
@media (max-width: 900px) { @media (max-width: 900px) {
.dashboard-widget-grid, .dashboard-widget-grid,
.dashboard-widget-picker,
.dashboard-widget-metrics.metric-grid { .dashboard-widget-metrics.metric-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@@ -94,4 +60,3 @@
grid-column: 1; grid-column: 1;
} }
} }