feat(ui): implement public status endpoint and update UI components
CI / build-and-test (push) Failing after -30m49s
CI / build-and-test (push) Failing after -30m49s
* add public status handler and response types * modify status API to restrict access and update client tracking * adjust UI components to display public status information * update routing to include public status endpoint
This commit is contained in:
+48
-10
@@ -2,7 +2,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import LoginPage from './components/auth/LoginPage.svelte';
|
||||
import AdminShell from './components/shell/AdminShell.svelte';
|
||||
import type { ShellPage, StatusResponse } from './types';
|
||||
import type { PublicStatusResponse, ShellPage, StatusResponse } from './types';
|
||||
import { fromStore } from 'svelte/store';
|
||||
import {
|
||||
ensureApiURL,
|
||||
@@ -20,6 +20,9 @@
|
||||
let data = $state<StatusResponse | null>(null);
|
||||
let loading = $state(false);
|
||||
let error = $state('');
|
||||
let publicStatus = $state<PublicStatusResponse | null>(null);
|
||||
let publicStatusLoading = $state(false);
|
||||
let publicStatusError = $state('');
|
||||
let currentPage = $state<ShellPage>('dashboard');
|
||||
|
||||
ensureApiURL(import.meta.env.VITE_API_URL);
|
||||
@@ -57,7 +60,7 @@
|
||||
const token = await loginWithCredentials(username, password);
|
||||
await GlobalStateStore.getState().login(token, { username });
|
||||
authMessage = 'Login successful.';
|
||||
await loadStatus();
|
||||
await loadDashboardStatus();
|
||||
} catch (err) {
|
||||
authError = err instanceof Error ? err.message : 'Login failed.';
|
||||
} finally {
|
||||
@@ -88,7 +91,7 @@
|
||||
|
||||
authMessage = 'OAuth login complete. Welcome back.';
|
||||
window.history.replaceState({}, '', '/');
|
||||
await loadStatus();
|
||||
await loadDashboardStatus();
|
||||
} catch (err) {
|
||||
authError = err instanceof Error ? err.message : 'OAuth callback failed.';
|
||||
} finally {
|
||||
@@ -100,14 +103,23 @@
|
||||
await GlobalStateStore.getState().logout();
|
||||
authMessage = 'Logged out.';
|
||||
authError = '';
|
||||
await loadPublicStatus();
|
||||
}
|
||||
|
||||
async function loadStatus(): Promise<void> {
|
||||
async function loadDashboardStatus(): Promise<void> {
|
||||
loading = true;
|
||||
error = '';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/status');
|
||||
const token = GlobalStateStore.getState().session?.authToken;
|
||||
if (!token) {
|
||||
throw new Error('Missing auth token for dashboard status.');
|
||||
}
|
||||
const response = await fetch('/api/status', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Status request failed with ${response.status}`);
|
||||
}
|
||||
@@ -141,6 +153,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPublicStatus(): Promise<void> {
|
||||
publicStatusLoading = true;
|
||||
publicStatusError = '';
|
||||
|
||||
try {
|
||||
const response = await fetch('/status');
|
||||
if (!response.ok) {
|
||||
throw new Error(`Public status request failed with ${response.status}`);
|
||||
}
|
||||
const raw = (await response.json()) as Partial<PublicStatusResponse> | null;
|
||||
publicStatus = {
|
||||
connected_count: raw?.connected_count ?? 0,
|
||||
connected_window: raw?.connected_window ?? 'last 10 minutes',
|
||||
entries: Array.isArray(raw?.entries) ? raw.entries : []
|
||||
};
|
||||
} catch (err) {
|
||||
publicStatusError = err instanceof Error ? err.message : 'Failed to load public status';
|
||||
} finally {
|
||||
publicStatusLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
setCurrentPath(window.location.pathname);
|
||||
@@ -153,7 +187,11 @@
|
||||
|
||||
await GlobalStateStore.getState().fetchData();
|
||||
|
||||
await loadStatus();
|
||||
if (GlobalStateStore.getState().isLoggedIn()) {
|
||||
await loadDashboardStatus();
|
||||
return;
|
||||
}
|
||||
await loadPublicStatus();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -169,9 +207,9 @@
|
||||
{authBusy}
|
||||
{authError}
|
||||
{authMessage}
|
||||
statusData={data}
|
||||
statusLoading={loading}
|
||||
statusError={error}
|
||||
statusData={publicStatus}
|
||||
statusLoading={publicStatusLoading}
|
||||
statusError={publicStatusError}
|
||||
onlogin={handleCredentialLogin}
|
||||
/>
|
||||
{:else}
|
||||
@@ -182,7 +220,7 @@
|
||||
{error}
|
||||
onlogout={logout}
|
||||
onnavigate={(page) => { currentPage = page; }}
|
||||
onrefresh={loadStatus}
|
||||
onrefresh={loadDashboardStatus}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user