dragonflight/services/web-ui/public/auth-gate.jsx

78 lines
3 KiB
React
Raw Normal View History

ui: full audit pass (fixes #146, #147, #148, #149, #151, #152, #153, #154, #155) Sweep of 9 web-ui audit findings from tracker #156. Issue #150 (modal codec stubs) deferred per user request. ## #146 sweep em-dashes (186 to 0) - Replace placeholder '—' with '·' across all jsx - Convert ' — ' to ': ' or '. ' in copy where context permits - Comment-only em-dashes converted to ASCII dash - Sweep css files too (16 comments) ## #147 remove glassmorphism + accent gradients - Strip 8 backdrop-filter declarations from styles-screens.css and styles-asset.css. Only legit modal scrim in styles-modal.css remains. - Replace .job-progress-fill gradient with solid var(--accent) - Replace .monitor-tile.audio gradient with flat var(--bg-1) ## #148 extract Jobs inline styles to CSS - Cut 19 inline style={{...}} blocks in screens-jobs.jsx to 1 (dynamic width on progress bar). Live DOM was 487 inline-styled elements due to per-row repetition; now ~0. - Added job-row-kind, job-row-asset, job-row-node, job-row-time, job-row-actions, job-row-status-* utility classes in styles-screens.css ## #149 sidebar IA reorganized - Replace flat NAV_TREE + ADMIN_TREE with NAV_SECTIONS: Workspace / Ingest / Operations / Admin - Move Capture out of Ingest into Operations (it's a live-signal monitor, not an ingest action) - Drop the 0/N capture badge from nav (belongs in topbar) - Add BETA badge to Editor ## #151 redesign Editor 'Coming Soon' bumper - Replace fullscreen glassmorphism + gradient + glow overlay with a flat beta banner across the top of the editor area - New .editor-beta-banner CSS class (flat, accent-soft tint, no blur) ## #152 hide Tokens parody, restore real API token mgmt - New top-level Tokens admin page wraps existing ApiTokensSection - Old parody renamed to TokensParody, accessible at /tokens-parody route - Add window-level df:nav event for cross-component routing ## #153 make Home actually useful - New activity strip below the launcher grid: 'Recording now' tiles for live recorders, 'Last 24 hours' tiles for newly created assets, plus an attention strip when there are failed jobs or errored recorders - Each item is clickable and routes to the relevant screen ## #154 aria-labels on icon-only buttons - Projects + Library grid/list view toggles now have aria-label + title ## #155 page-header pattern - Dashboard now renders a proper .page-header h1 with subtitle + alert badge + cluster status pip - Library toolbar-title promoted to h1 for screen-reader hierarchy - Document Home/Library/Editor full-bleed exceptions in DESIGN.md - Editor's chrome is the beta banner (covered by #151)
2026-05-28 19:50:07 -04:00
// auth-gate.jsx - owns the "logged in or not" state.
//
// The SPA boots into <AuthGate>, which calls GET /auth/me. On 401 it then
// calls GET /auth/setup-required and renders <SetupScreen> or <LoginScreen>
// (defined in screens-auth.jsx, Task 16). On 200 it renders the real <App>.
//
ui: full audit pass (fixes #146, #147, #148, #149, #151, #152, #153, #154, #155) Sweep of 9 web-ui audit findings from tracker #156. Issue #150 (modal codec stubs) deferred per user request. ## #146 sweep em-dashes (186 to 0) - Replace placeholder '—' with '·' across all jsx - Convert ' — ' to ': ' or '. ' in copy where context permits - Comment-only em-dashes converted to ASCII dash - Sweep css files too (16 comments) ## #147 remove glassmorphism + accent gradients - Strip 8 backdrop-filter declarations from styles-screens.css and styles-asset.css. Only legit modal scrim in styles-modal.css remains. - Replace .job-progress-fill gradient with solid var(--accent) - Replace .monitor-tile.audio gradient with flat var(--bg-1) ## #148 extract Jobs inline styles to CSS - Cut 19 inline style={{...}} blocks in screens-jobs.jsx to 1 (dynamic width on progress bar). Live DOM was 487 inline-styled elements due to per-row repetition; now ~0. - Added job-row-kind, job-row-asset, job-row-node, job-row-time, job-row-actions, job-row-status-* utility classes in styles-screens.css ## #149 sidebar IA reorganized - Replace flat NAV_TREE + ADMIN_TREE with NAV_SECTIONS: Workspace / Ingest / Operations / Admin - Move Capture out of Ingest into Operations (it's a live-signal monitor, not an ingest action) - Drop the 0/N capture badge from nav (belongs in topbar) - Add BETA badge to Editor ## #151 redesign Editor 'Coming Soon' bumper - Replace fullscreen glassmorphism + gradient + glow overlay with a flat beta banner across the top of the editor area - New .editor-beta-banner CSS class (flat, accent-soft tint, no blur) ## #152 hide Tokens parody, restore real API token mgmt - New top-level Tokens admin page wraps existing ApiTokensSection - Old parody renamed to TokensParody, accessible at /tokens-parody route - Add window-level df:nav event for cross-component routing ## #153 make Home actually useful - New activity strip below the launcher grid: 'Recording now' tiles for live recorders, 'Last 24 hours' tiles for newly created assets, plus an attention strip when there are failed jobs or errored recorders - Each item is clickable and routes to the relevant screen ## #154 aria-labels on icon-only buttons - Projects + Library grid/list view toggles now have aria-label + title ## #155 page-header pattern - Dashboard now renders a proper .page-header h1 with subtitle + alert badge + cluster status pip - Library toolbar-title promoted to h1 for screen-reader hierarchy - Document Home/Library/Editor full-bleed exceptions in DESIGN.md - Editor's chrome is the beta banner (covered by #151)
2026-05-28 19:50:07 -04:00
// This component is the SINGLE source of truth for the auth check - no other
// component should redirect to a login page or wipe data on 401. Other code
// surfaces auth failure by calling window.AuthGate.bounce(), which re-mounts
// the gate so the next /auth/me request decides what to do.
(function () {
const API = '/api/v1';
const LAST_PATH_KEY = 'df.auth.last_path';
async function authFetch(path, opts) {
return fetch(API + path, {
credentials: 'include',
...opts,
headers: {
...(opts && opts.headers),
'Content-Type': 'application/json',
...((opts && opts.method && opts.method !== 'GET') ? { 'X-Requested-With': 'dragonflight-ui' } : {}),
},
});
}
function AuthGate({ children }) {
const [state, setState] = React.useState({ kind: 'loading' });
const check = React.useCallback(async () => {
setState({ kind: 'loading' });
try {
const r = await authFetch('/auth/me');
if (r.status === 200) {
const me = await r.json();
window.ZAMPP_DATA = window.ZAMPP_DATA || {};
window.ZAMPP_DATA.ME = me;
setState({ kind: 'authed' });
return;
}
} catch (_) { /* fall through to setup/login decision */ }
const setup = await authFetch('/auth/setup-required').then(r => r.json()).catch(() => ({ required: false }));
setState({ kind: setup.required ? 'setup' : 'login' });
}, []);
React.useEffect(() => { check(); }, [check]);
// Global hook: anything else (e.g. data.jsx 401 handler) can re-trigger
// the gate after auth state changes server-side. Saves current path so
// the user is restored to where they were after login.
React.useEffect(() => {
window.AuthGate = {
bounce(reason) {
try { sessionStorage.setItem(LAST_PATH_KEY, location.pathname + location.search); } catch {}
if (reason) console.warn('[AuthGate] bounce:', reason);
check();
},
signedIn() { check(); },
};
}, [check]);
if (state.kind === 'loading') {
return (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', background: 'var(--bg-0)' }}>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-3)' }}>Loading</div>
</div>
);
}
if (state.kind === 'setup') return React.createElement(window.SetupScreen, { onDone: () => window.AuthGate.signedIn() });
if (state.kind === 'login') return React.createElement(window.LoginScreen, { onDone: () => window.AuthGate.signedIn() });
return children;
}
window.AuthGate = window.AuthGate || {};
window.AuthGateComponent = AuthGate;
})();