diff --git a/src/lib/server/activity.ts b/src/lib/server/activity.ts index dac5581..21de7f8 100644 --- a/src/lib/server/activity.ts +++ b/src/lib/server/activity.ts @@ -101,7 +101,7 @@ items AS ( 'Beta test #' || b.id,NULL,bs.server,bs.server_deleted_at,NULL,NULL,'beta',CAST(b.id AS TEXT) FROM betas b JOIN beta_servers bs ON bs.beta_id=b.id UNION ALL - SELECT 'host:' || o.id,o.created_at,'host','|host|', + SELECT 'host:' || o.id,o.created_at,CASE WHEN o.kind='instance.restart' THEN 'restart' ELSE 'host' END,'|host|', CASE WHEN o.state='completed' AND o.routine=1 AND o.observation_success=0 THEN 'observation-failed' WHEN o.state='completed' AND COALESCE(o.error,'')<>'' THEN 'warning' ELSE o.state END, ${labelCase('o.kind', hostOperationTitles, 'Host operation')}, @@ -153,7 +153,7 @@ export function activityHistory(input: ActivityQuery = {}, now = Date.now()): Ac const conditions: string[] = []; // Keep lifecycle jobs in Provisioning, including jobs triggered by automation. // Apply this before totals and pagination; resource histories can still include them. - if (query.excludeProvisioning) conditions.push("route <> 'provisioning'"); + if (query.excludeProvisioning) conditions.push("route <> 'provisioning' AND type <> 'restart'"); const bindings: Record = {}; for (const key of ['server', 'type', 'state'] as const) if (query[key]) { conditions.push(`${key}=@${key}`); bindings[key] = query[key]; } if (query.host) { conditions.push('(hostId=@host OR secondaryHostId=@host)'); bindings.host = query.host; } diff --git a/src/lib/ui/components/ActivityLog.svelte b/src/lib/ui/components/ActivityLog.svelte index c5a4c74..540d734 100644 --- a/src/lib/ui/components/ActivityLog.svelte +++ b/src/lib/ui/components/ActivityLog.svelte @@ -33,7 +33,7 @@ const filters = $derived(activityQuery($page.url, { server, source, excludeProvisioning })); const apiUrl = $derived(activityApiHref($page.url, { server, source, excludeProvisioning })); let loadedUrl = $state(untrack(() => initial ? apiUrl : '')); - const typeOptions = $derived(Object.entries(activityTypes).filter(([key]) => !excludeProvisioning || !['create', 'start', 'rebuild', 'stop', 'remove'].includes(key))); + const typeOptions = $derived(Object.entries(activityTypes).filter(([key]) => !excludeProvisioning || !['create', 'start', 'restart', 'rebuild', 'stop', 'remove'].includes(key))); const sourceOptions = $derived(Object.entries(activitySources).filter(([key]) => !excludeProvisioning || !['provisioning', 'autoscaling'].includes(key))); const filterCount = $derived([filters.type, filters.state, source === undefined ? filters.source : '', server === undefined ? filters.server : '', filters.host, filters.days, filters.q].filter(Boolean).length); const serverOptions = $derived.by(() => { diff --git a/tests/unit/activity.test.ts b/tests/unit/activity.test.ts index f8bf9cf..ce4add4 100644 --- a/tests/unit/activity.test.ts +++ b/tests/unit/activity.test.ts @@ -66,6 +66,9 @@ describe('unified retained Activity', () => { } } api.remote('check', { kind: 'instance.inspect', routine: 1 }); + api.remote('standalone-restart', { kind: 'instance.restart' }); + api.maintenance(3); + api.handle.prepare("UPDATE maintenance_jobs SET kind='schedule' WHERE id=3").run(); api.incident('finding'); api.maintenance(2); const query = { excludeProvisioning: true, limit: 2 }; @@ -77,8 +80,9 @@ describe('unified retained Activity', () => { expect(last.rows).toHaveLength(1); expect([...first.rows, ...last.rows].map(row => row.id).sort()).toEqual(['host:check', 'maintenance:2', 'recovery:finding']); expect(api.activityHistory({ ...query, type: 'create' }).total).toBe(0); + expect(api.activityHistory({ ...query, type: 'restart' }).total).toBe(0); expect(api.activityHistory({ ...query, source: 'autoscaling' }).total).toBe(0); - expect(api.activityHistory({ server }).total).toBe(39); + expect(api.activityHistory({ server }).total).toBe(41); }); it('paginates the full union with exact totals, stable ties and removed-server history', async () => { diff --git a/tests/unit/ui-activity.test.ts b/tests/unit/ui-activity.test.ts index 06d2827..3d9428f 100644 --- a/tests/unit/ui-activity.test.ts +++ b/tests/unit/ui-activity.test.ts @@ -60,6 +60,7 @@ it('renders one page heading with provisioning management and filters removed', const body = render(ActivityPage, { props: { data: { activity: report(), user: { role: 'admin' }, setupRequired: false } as any } }).body; expect(body.match(/]/g)).toHaveLength(1); expect(body).not.toContain('Manage servers'); expect(body).not.toContain('href="/provisioning"'); expect(body).not.toContain('