Add activity logs, sidebar badges, and logout with working alert colors.
Record auth audits and surface them in Activity, poll sidebar counts without resetting idle, and add a profile logout path plus theme red/green/blue tokens so failure badges render.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
fetchGroups,
|
||||
fetchHealth,
|
||||
fetchNetwork,
|
||||
fetchAuthLogs,
|
||||
fetchNodeLogs,
|
||||
fetchSecurity,
|
||||
fetchStatus,
|
||||
@@ -396,6 +397,51 @@ describe('fetchNodeLogs', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchAuthLogs', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('returns parsed auth logs payload', async () => {
|
||||
const events = [
|
||||
{
|
||||
id: 'a1',
|
||||
at: '2026-01-01T00:00:00Z',
|
||||
action: 'login',
|
||||
outcome: 'success',
|
||||
category: 'auth',
|
||||
actor: 'Admin',
|
||||
target: 'Admin',
|
||||
},
|
||||
]
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ events }),
|
||||
})
|
||||
|
||||
const payload = await fetchAuthLogs(fetchMock)
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'http://localhost:8080/api/v1/auth-logs',
|
||||
expect.objectContaining({ credentials: 'include' }),
|
||||
)
|
||||
expect(payload.events).toEqual(events)
|
||||
})
|
||||
|
||||
it('sends idle-exempt header when requested', async () => {
|
||||
const { SESSION_IDLE_EXEMPT_HEADER } = await import('./client')
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ events: [] }),
|
||||
})
|
||||
|
||||
await fetchAuthLogs(fetchMock, { idleExempt: true })
|
||||
|
||||
const init = fetchMock.mock.calls[0][1] as { headers: Headers }
|
||||
expect(init.headers.get(SESSION_IDLE_EXEMPT_HEADER)).toBe('1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchSecurity', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
@@ -565,6 +611,39 @@ describe('nodes API', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('sends idle-exempt header when requested', async () => {
|
||||
const { fetchNodes, SESSION_IDLE_EXEMPT_HEADER } = await import('./client')
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ nodes: [] }),
|
||||
})
|
||||
|
||||
await fetchNodes(undefined, fetchMock, { idleExempt: true })
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'http://localhost:8080/api/v1/nodes',
|
||||
expect.objectContaining({
|
||||
credentials: 'include',
|
||||
headers: expect.any(Headers),
|
||||
}),
|
||||
)
|
||||
const init = fetchMock.mock.calls[0][1] as { headers: Headers }
|
||||
expect(init.headers.get(SESSION_IDLE_EXEMPT_HEADER)).toBe('1')
|
||||
})
|
||||
|
||||
it('omits idle-exempt header by default', async () => {
|
||||
const { fetchNodes, SESSION_IDLE_EXEMPT_HEADER } = await import('./client')
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ nodes: [] }),
|
||||
})
|
||||
|
||||
await fetchNodes(undefined, fetchMock)
|
||||
|
||||
const init = fetchMock.mock.calls[0][1] as { headers: Headers }
|
||||
expect(init.headers.get(SESSION_IDLE_EXEMPT_HEADER)).toBeNull()
|
||||
})
|
||||
|
||||
it('creates a node with generate options', async () => {
|
||||
const { createNode } = await import('./client')
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user