refactor(ui): semantic token theming + cleaner SaaS palette
Replace the brittle 266-rule `:root.light` `!important` override block with a Tailwind v4 `@theme inline` semantic token system (surface/header/card/inner/ field/line/fg/fg-muted/fg-faint + success/info/primary/warning/danger/rose/ violet/sky/orange/blue, each with vivid/soft/line). Migrate all 14 components and App.tsx off hardcoded slate/hex utilities onto the tokens, so dark/light is now a pure CSS-variable swap with no per-utility overrides. - index.css ~984 -> ~150 lines; CSS bundle 145 -> 98 kB - calmer, desaturated accents; removed gratuitous glows and constant pulsing - branding, playful copy and intentionally-dark code blocks preserved Also wires `requireAdmin` onto settings, bookings-delete, database, checkmk, semaphore and caddy routes.
This commit is contained in:
26
server.ts
26
server.ts
@ -399,7 +399,7 @@ async function startServer() {
|
||||
// -------------------------------------------------------------
|
||||
// RESTFUL API: Settings (admin only)
|
||||
// -------------------------------------------------------------
|
||||
app.get('/api/settings', requireAuth, (_req, res) => {
|
||||
app.get('/api/settings', requireAuth, requireAdmin, (_req, res) => {
|
||||
try {
|
||||
res.json(maskSettings(getAllSettings()));
|
||||
} catch (err: any) {
|
||||
@ -407,7 +407,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/settings', requireAuth, (req, res) => {
|
||||
app.put('/api/settings', requireAuth, requireAdmin, (req, res) => {
|
||||
try {
|
||||
const allowed = ['azure_enabled', 'azure_client_id', 'azure_tenant_id', 'azure_client_secret',
|
||||
'azure_redirect_uri', 'azure_allowed_group', 'checkmk_enabled', 'checkmk_api_url', 'checkmk_api_user',
|
||||
@ -844,7 +844,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/bookings/:id', requireAuth, (req, res) => {
|
||||
app.delete('/api/bookings/:id', requireAuth, requireAdmin, (req, res) => {
|
||||
try {
|
||||
const id = req.params.id;
|
||||
const booking = db.prepare('SELECT * FROM bookings WHERE id = ?').get(id) as any;
|
||||
@ -961,7 +961,7 @@ async function startServer() {
|
||||
// -------------------------------------------------------------
|
||||
// DATABASE API
|
||||
// -------------------------------------------------------------
|
||||
app.get('/api/database/info', requireAuth, (_req, res) => {
|
||||
app.get('/api/database/info', requireAuth, requireAdmin, (_req, res) => {
|
||||
try {
|
||||
const stats = fs.statSync(DB_FILE);
|
||||
const tables = ['users', 'devices', 'labs', 'bookings', 'logs', 'links', 'settings', 'caddy'];
|
||||
@ -980,7 +980,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/database/backup', requireAuth, async (_req, res) => {
|
||||
app.get('/api/database/backup', requireAuth, requireAdmin, async (_req, res) => {
|
||||
const tempPath = `${DB_FILE}.backup-${Date.now()}`;
|
||||
try {
|
||||
await db.backup(tempPath);
|
||||
@ -994,7 +994,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/database/import', requireAuth,
|
||||
app.post('/api/database/import', requireAuth, requireAdmin,
|
||||
express.raw({ type: 'application/octet-stream', limit: '50mb' }),
|
||||
(req, res) => {
|
||||
const tempPath = `${DB_FILE}.import-${Date.now()}`;
|
||||
@ -1154,7 +1154,7 @@ async function startServer() {
|
||||
}
|
||||
scheduleSync();
|
||||
|
||||
app.post('/api/checkmk/sync', requireAuth, async (_req, res) => {
|
||||
app.post('/api/checkmk/sync', requireAuth, requireAdmin, async (_req, res) => {
|
||||
try {
|
||||
await syncCheckMkStatuses();
|
||||
res.json({ ok: true });
|
||||
@ -1266,7 +1266,7 @@ async function startServer() {
|
||||
scheduleSemaphoreCheck();
|
||||
|
||||
// Proxy Semaphore template list so the UI can populate dropdowns
|
||||
app.get('/api/semaphore/templates', requireAuth, async (_req, res) => {
|
||||
app.get('/api/semaphore/templates', requireAuth, requireAdmin, async (_req, res) => {
|
||||
const apiUrl = getSetting('semaphore_api_url');
|
||||
const token = getSetting('semaphore_api_token');
|
||||
const projectId = getSetting('semaphore_project_id');
|
||||
@ -1320,7 +1320,7 @@ async function startServer() {
|
||||
// -------------------------------------------------------------
|
||||
// CADDY API
|
||||
// -------------------------------------------------------------
|
||||
app.get('/api/caddy/status', requireAuth, async (_req, res) => {
|
||||
app.get('/api/caddy/status', requireAuth, requireAdmin, async (_req, res) => {
|
||||
try {
|
||||
const adminUrl = getSetting('caddy_admin_url') || 'http://127.0.0.1:2019';
|
||||
const r = await fetch(`${adminUrl}/config/`, { signal: AbortSignal.timeout(2000) });
|
||||
@ -1330,7 +1330,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/caddy/routes', requireAuth, (_req, res) => {
|
||||
app.get('/api/caddy/routes', requireAuth, requireAdmin, (_req, res) => {
|
||||
try {
|
||||
res.json(getCaddyRoutes());
|
||||
} catch (err: any) {
|
||||
@ -1338,7 +1338,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/caddy/routes', requireAuth, async (req, res) => {
|
||||
app.post('/api/caddy/routes', requireAuth, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
if (!IS_PRODUCTION) return res.status(403).json({ error: 'Caddy is managed by another instance.' });
|
||||
const { hostname, upstream, tls, compress, redirect } = req.body as {
|
||||
@ -1356,7 +1356,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/caddy/routes/:id', requireAuth, async (req, res) => {
|
||||
app.put('/api/caddy/routes/:id', requireAuth, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
if (!IS_PRODUCTION) return res.status(403).json({ error: 'Caddy is managed by another instance.' });
|
||||
const id = Number(req.params.id);
|
||||
@ -1374,7 +1374,7 @@ async function startServer() {
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/caddy/routes/:id', requireAuth, (req, res) => {
|
||||
app.delete('/api/caddy/routes/:id', requireAuth, requireAdmin, (req, res) => {
|
||||
try {
|
||||
if (!IS_PRODUCTION) return res.status(403).json({ error: 'Caddy is managed by another instance.' });
|
||||
const id = Number(req.params.id);
|
||||
|
||||
Reference in New Issue
Block a user