Rename Tracked Events to Tracked Items, add More>> spillover, lock recap cadence
- Tracked items get the same isSpillover flag as categories: a per-item "More" checkbox collapses it into the "More »" nav tab instead of its own top-level tab, mirroring Category.isSpillover end to end (schema, CRUD, public API, nav partitioning, /more page). - Renamed user-facing "Tracked events" text to "Tracked items" (admin tab, toolbar, buttons, placeholders, /event/:id subtitle) — the underlying TrackedEvent/events data model and routes are unchanged. - Locked the per-item recap cadence dropdown (previously a live Continuous/Daily/Hourly picker) and moved it to its own labeled section with an explanatory hint: reading eventsRecap.ts confirmed Continuous and Hourly currently behave identically, so the live choice was more confusing than useful. New items are fixed to Continuous; existing items show their real cadence read-only.
This commit is contained in:
@@ -47,7 +47,9 @@ export async function registerPublicRoutes(app: FastifyInstance) {
|
||||
|
||||
app.get('/api/events', async () => {
|
||||
// Public fields only — sourceIds, cadenceTime etc. stay admin-only.
|
||||
return eventsDb.listEvents().map((e) => ({ id: e.id, name: e.name, active: e.active, cadence: e.cadence }));
|
||||
return eventsDb
|
||||
.listEvents()
|
||||
.map((e) => ({ id: e.id, name: e.name, active: e.active, cadence: e.cadence, isSpillover: e.isSpillover }));
|
||||
});
|
||||
|
||||
// Drives the site nav — admin-editable (add/remove/reorder) via /api/admin/categories,
|
||||
|
||||
@@ -12,6 +12,7 @@ function rowToEvent(row: any): TrackedEvent {
|
||||
cadence: row.cadence,
|
||||
cadenceTime: row.cadence_time,
|
||||
active: !!row.active,
|
||||
isSpillover: !!row.is_spillover,
|
||||
retentionOverrideDays: row.retention_override_days,
|
||||
lastRecapAt: row.last_recap_at,
|
||||
createdAt: row.created_at
|
||||
@@ -52,8 +53,8 @@ export function createEvent(input: Partial<TrackedEvent>): TrackedEvent {
|
||||
const id = `evt-${randomUUID()}`;
|
||||
const now = new Date().toISOString();
|
||||
db.prepare(
|
||||
`INSERT INTO tracked_events (id, name, description, source_ids, keywords, cadence, cadence_time, active, retention_override_days, last_recap_at, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`
|
||||
`INSERT INTO tracked_events (id, name, description, source_ids, keywords, cadence, cadence_time, active, is_spillover, retention_override_days, last_recap_at, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`
|
||||
).run(
|
||||
id,
|
||||
input.name ?? 'Untitled event',
|
||||
@@ -63,6 +64,7 @@ export function createEvent(input: Partial<TrackedEvent>): TrackedEvent {
|
||||
input.cadence ?? 'continuous',
|
||||
input.cadenceTime ?? null,
|
||||
input.active === false ? 0 : 1,
|
||||
input.isSpillover ? 1 : 0,
|
||||
input.retentionOverrideDays ?? null,
|
||||
now
|
||||
);
|
||||
@@ -74,7 +76,7 @@ export function updateEvent(id: string, patch: Partial<TrackedEvent>): TrackedEv
|
||||
if (!existing) return null;
|
||||
const merged = { ...existing, ...patch };
|
||||
db.prepare(
|
||||
`UPDATE tracked_events SET name=?, description=?, source_ids=?, keywords=?, cadence=?, cadence_time=?, active=?, retention_override_days=?, last_recap_at=? WHERE id=?`
|
||||
`UPDATE tracked_events SET name=?, description=?, source_ids=?, keywords=?, cadence=?, cadence_time=?, active=?, is_spillover=?, retention_override_days=?, last_recap_at=? WHERE id=?`
|
||||
).run(
|
||||
merged.name,
|
||||
merged.description,
|
||||
@@ -83,6 +85,7 @@ export function updateEvent(id: string, patch: Partial<TrackedEvent>): TrackedEv
|
||||
merged.cadence,
|
||||
merged.cadenceTime,
|
||||
merged.active ? 1 : 0,
|
||||
merged.isSpillover ? 1 : 0,
|
||||
merged.retentionOverrideDays,
|
||||
merged.lastRecapAt,
|
||||
id
|
||||
|
||||
@@ -133,6 +133,7 @@ export function migrate() {
|
||||
cadence TEXT NOT NULL DEFAULT 'continuous',
|
||||
cadence_time TEXT,
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
is_spillover INTEGER NOT NULL DEFAULT 0,
|
||||
retention_override_days INTEGER,
|
||||
last_recap_at TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
@@ -328,6 +329,9 @@ export function migrate() {
|
||||
if (!hasColumn('tracked_events', 'keywords')) {
|
||||
db.exec("ALTER TABLE tracked_events ADD COLUMN keywords TEXT NOT NULL DEFAULT '[]'");
|
||||
}
|
||||
if (!hasColumn('tracked_events', 'is_spillover')) {
|
||||
db.exec('ALTER TABLE tracked_events ADD COLUMN is_spillover INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
if (!hasColumn('merged_articles', 'is_recap')) {
|
||||
db.exec('ALTER TABLE merged_articles ADD COLUMN is_recap INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
|
||||
@@ -181,6 +181,8 @@ export interface TrackedEvent {
|
||||
cadence: 'continuous' | 'daily' | 'hourly' | 'custom';
|
||||
cadenceTime: string | null;
|
||||
active: boolean;
|
||||
/** Collapses into the "More »" nav tab instead of getting its own top-level tab — same idea as Category.isSpillover. */
|
||||
isSpillover: boolean;
|
||||
retentionOverrideDays: number | null;
|
||||
lastRecapAt: string | null;
|
||||
createdAt: string;
|
||||
|
||||
Reference in New Issue
Block a user