Simplify Widgets tab: state button instead of checkbox, add drag-free up/down reordering
Drops the checkbox/tooltip/hint-paragraph combo for a single click-to-toggle Active/Disabled badge (same pattern as EventsTab's Active/Paused). Widget order is now admin-sortable via up/down arrows and persisted as widgetOrder, with Sidebar.svelte rendering widgets in that exact sequence instead of a fixed hardcoded order.
This commit is contained in:
@@ -62,10 +62,13 @@ export async function registerPublicRoutes(app: FastifyInstance) {
|
||||
return categories.filter((c) => !c.isPrivate);
|
||||
});
|
||||
|
||||
// Per-widget sidebar visibility — see the admin panel's consolidated "Widgets" tab.
|
||||
// Each widget keeps polling/config regardless of this; it only gates whether the
|
||||
// sidebar renders it at all.
|
||||
app.get('/api/widgets', async () => settingsDb.getSettings().widgets);
|
||||
// Per-widget enable flags + display order — see the admin panel's consolidated
|
||||
// "Widgets" tab. Weather/Stocks/PoE2's backend pollers are also gated on these
|
||||
// flags (see scheduler.ts); Sidebar.svelte renders in exactly this order.
|
||||
app.get('/api/widgets', async () => {
|
||||
const { widgets, widgetOrder } = settingsDb.getSettings();
|
||||
return { ...widgets, order: widgetOrder };
|
||||
});
|
||||
|
||||
// Sidebar widgets — see WeatherTab/StocksTab/BookmarksTab in the admin panel.
|
||||
app.get('/api/weather', async () => settingsDb.getSettings().weather);
|
||||
|
||||
@@ -188,6 +188,7 @@ export function migrate() {
|
||||
widget_stocks_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
widget_bookmarks_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
widget_poe2_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
widget_order TEXT NOT NULL DEFAULT '["weather","stocks","poe2","bookmarks"]', -- JSON array, admin-sortable via the Widgets tab
|
||||
weather_location_name TEXT,
|
||||
weather_latitude REAL,
|
||||
weather_longitude REAL,
|
||||
@@ -363,6 +364,11 @@ export function migrate() {
|
||||
db.exec('ALTER TABLE global_settings ADD COLUMN widget_bookmarks_enabled INTEGER NOT NULL DEFAULT 1');
|
||||
db.exec('ALTER TABLE global_settings ADD COLUMN widget_poe2_enabled INTEGER NOT NULL DEFAULT 1');
|
||||
}
|
||||
if (!hasColumn('global_settings', 'widget_order')) {
|
||||
db.exec(
|
||||
`ALTER TABLE global_settings ADD COLUMN widget_order TEXT NOT NULL DEFAULT '["weather","stocks","poe2","bookmarks"]'`
|
||||
);
|
||||
}
|
||||
|
||||
// Seed a handful of sensible default tickers so the Stocks widget isn't empty on a
|
||||
// fresh install — the admin can remove/replace any of them via the Stocks tab.
|
||||
|
||||
@@ -21,6 +21,7 @@ function rowToSettings(row: any): GlobalSettings {
|
||||
bookmarks: !!row.widget_bookmarks_enabled,
|
||||
poe2: !!row.widget_poe2_enabled
|
||||
},
|
||||
widgetOrder: JSON.parse(row.widget_order),
|
||||
retention: {
|
||||
publishedArticleMaxAgeDays: row.published_article_max_age_days,
|
||||
rawItemMaxAgeDays: row.raw_item_max_age_days,
|
||||
@@ -79,6 +80,7 @@ export function updateSettings(patch: Partial<GlobalSettings>): GlobalSettings {
|
||||
nitter_media_mode=$nitter_media_mode, fxtwitter_base_url=$fxtwitter_base_url, telegram_media_mode=$telegram_media_mode,
|
||||
widget_weather_enabled=$widget_weather_enabled, widget_stocks_enabled=$widget_stocks_enabled,
|
||||
widget_bookmarks_enabled=$widget_bookmarks_enabled, widget_poe2_enabled=$widget_poe2_enabled,
|
||||
widget_order=$widget_order,
|
||||
published_article_max_age_days=$published_article_max_age_days, raw_item_max_age_days=$raw_item_max_age_days,
|
||||
storage_cap_enabled=$storage_cap_enabled, storage_cap_value=$storage_cap_value, storage_cap_unit=$storage_cap_unit,
|
||||
weather_location_name=$weather_location_name, weather_latitude=$weather_latitude, weather_longitude=$weather_longitude,
|
||||
@@ -104,6 +106,7 @@ export function updateSettings(patch: Partial<GlobalSettings>): GlobalSettings {
|
||||
$widget_stocks_enabled: merged.widgets.stocks ? 1 : 0,
|
||||
$widget_bookmarks_enabled: merged.widgets.bookmarks ? 1 : 0,
|
||||
$widget_poe2_enabled: merged.widgets.poe2 ? 1 : 0,
|
||||
$widget_order: JSON.stringify(merged.widgetOrder),
|
||||
$published_article_max_age_days: merged.retention.publishedArticleMaxAgeDays,
|
||||
$raw_item_max_age_days: merged.retention.rawItemMaxAgeDays,
|
||||
$storage_cap_enabled: merged.retention.storageCapEnabled ? 1 : 0,
|
||||
|
||||
@@ -281,13 +281,15 @@ export interface GlobalSettings {
|
||||
fxtwitterBaseUrl: string;
|
||||
/** How Telegram message media (attached photos/videos, channel avatars) is served — see pipeline/publish.ts's resolveTelegramMedia. No "direct" option: Telegram has no public hotlinkable media URL, bytes only come from the authenticated MTProto session. */
|
||||
telegramMediaMode: 'self-host' | 'proxy';
|
||||
/** Per-widget sidebar visibility — see admin/settings' consolidated "Widgets" tab. Each widget keeps polling/config regardless (disabling doesn't pause its poller), this only gates whether GET /api/widgets tells the sidebar to render it. */
|
||||
/** Per-widget enable flags — see admin/settings' consolidated "Widgets" tab. Weather/Stocks/PoE2's backend pollers (scheduler.ts) are gated on these too, not just sidebar visibility; Bookmarks has no poller so its flag only affects the sidebar. */
|
||||
widgets: {
|
||||
weather: boolean;
|
||||
stocks: boolean;
|
||||
bookmarks: boolean;
|
||||
poe2: boolean;
|
||||
};
|
||||
/** Sidebar widget display order, admin-sortable via the Widgets tab's up/down arrows — mirrored exactly by Sidebar.svelte. */
|
||||
widgetOrder: ('weather' | 'stocks' | 'bookmarks' | 'poe2')[];
|
||||
retention: {
|
||||
publishedArticleMaxAgeDays: number | null;
|
||||
rawItemMaxAgeDays: number | null;
|
||||
|
||||
Reference in New Issue
Block a user