feat: refine ISAC design and prepare production deployment
Validate and deploy production / validate (push) Successful in 18s
Validate and deploy staging / validate (push) Successful in 18s
Validate and deploy production / deploy (push) Successful in 1m1s
Validate and deploy staging / deploy (push) Successful in 28s

This commit is contained in:
JB
2026-07-26 12:25:47 -04:00
parent 75faef50b8
commit 2e868d86ff
153 changed files with 64660 additions and 264 deletions
+7
View File
@@ -1,4 +1,11 @@
<script lang="ts">
import '@fontsource/barlow/400.css';
import '@fontsource/barlow/600.css';
import '@fontsource/barlow/700.css';
import '@fontsource/barlow/800.css';
import '@fontsource/barlow/900.css';
import '@fontsource/source-serif-4/400.css';
import '@fontsource/source-serif-4/600.css';
import '../app.css';
import AppShell from '$lib/components/AppShell.svelte';
import ToastViewport from '$lib/components/ToastViewport.svelte';
+71 -37
View File
@@ -1,5 +1,7 @@
<script lang="ts">
import { page } from '$app/state';
import { onMount } from 'svelte';
import MutationConsequence from '$lib/components/MutationConsequence.svelte';
let { data, children } = $props();
const can = (permission: string) => data.permissions.includes('*') || data.permissions.includes(permission);
const canSeeData = $derived(['data.view', 'data.manage', 'data.propose', 'data.approve'].some(can));
@@ -10,33 +12,60 @@
const dataModeClass = $derived(dataMode.toLowerCase().replace(' ', '-'));
let readOnlyBlocked = $state(false);
const dataSections = [
{ href: '/isac/configuration', label: 'Global configuration', code: 'CONF', module: 'configuration' },
{ href: '/isac/attributes', label: 'Attributes', code: 'ATTR', module: 'attributes' },
{ href: '/isac/talents', label: 'Talents', code: 'TLNT', module: 'talents' },
{ href: '/isac/brands', label: 'Brand sets', code: 'BRND', module: 'brands' },
{ href: '/isac/gear', label: 'Gear', code: 'GEAR', module: 'gear' },
{ href: '/isac/weapons', label: 'Weapons', code: 'WPN', module: 'weapons' },
{ href: '/isac/weaponmods', label: 'Weapon Mods', code: 'WMOD', module: 'weaponmods' },
{ href: '/isac/gearmods', label: 'Gear Mods', code: 'GMOD', module: 'gearmods' },
{ href: '/isac/protocols', label: 'OS Protocols', code: 'OSPR', module: 'protocols' },
{ href: '/isac/skillchips', label: 'Skill Chips', code: 'CHIP', module: 'skillchips' }
{ href: '/isac/configuration', label: 'Global configuration', module: 'configuration' },
{ href: '/isac/attributes', label: 'Attributes', module: 'attributes' },
{ href: '/isac/talents', label: 'Talents', module: 'talents' },
{ href: '/isac/brands', label: 'Brand sets', module: 'brands' },
{ href: '/isac/gear', label: 'Gear', module: 'gear' },
{ href: '/isac/weapons', label: 'Weapons', module: 'weapons' },
{ href: '/isac/weaponmods', label: 'Weapon Mods', module: 'weaponmods' },
{ href: '/isac/gearmods', label: 'Gear Mods', module: 'gearmods' },
{ href: '/isac/protocols', label: 'OS Protocols', module: 'protocols' },
{ href: '/isac/skillchips', label: 'Skill Chips', module: 'skillchips' }
];
const dataModulePage = $derived(dataSections.some((section) => page.url.pathname === section.href));
const userSections = [
{ href: '/isac/users', label: 'User operations', code: 'USER', permission: 'users.view' },
{ href: '/isac/roles', label: 'Roles', code: 'ROLE', permission: 'users.roles' }
{ href: '/isac/users', label: 'User operations', permission: 'users.view' },
{ href: '/isac/roles', label: 'Roles', permission: 'users.roles' }
];
const visibleUserSections = $derived(userSections.filter((section) => can(section.permission)));
const oversightSections: Array<{ href: string; label: string; code: string; permission: string; reviewKey?: 'data' | 'avatars' }> = [
{ href: '/isac/data-moderation', label: 'Data Oversight', code: 'OVST', permission: 'data.approve', reviewKey: 'data' },
{ href: '/isac/avatar-oversight', label: 'Avatar Oversight', code: 'AVTR', permission: 'avatars.review', reviewKey: 'avatars' },
{ href: '/isac/audit', label: 'Audit history', code: 'AUDT', permission: 'audit.view' }
const oversightSections: Array<{ href: string; label: string; permission: string; reviewKey?: 'data' | 'avatars' }> = [
{ href: '/isac/data-moderation', label: 'Data Oversight', permission: 'data.approve', reviewKey: 'data' },
{ href: '/isac/avatar-oversight', label: 'Avatar Oversight', permission: 'avatars.review', reviewKey: 'avatars' },
{ href: '/isac/audit', label: 'Audit history', permission: 'audit.view' }
];
const visibleOversightSections = $derived(oversightSections.filter((section) => can(section.permission)));
const systemSections = [
{ href: '/isac/system-messages', label: 'Automated messages', code: 'MSG', permission: 'system.notifications.manage' },
{ href: '/isac/metrics', label: 'System metrics', code: 'MTRX', permission: 'metrics.view' }
{ href: '/isac/system-messages', label: 'Automated messages', permission: 'system.notifications.manage' },
{ href: '/isac/metrics', label: 'System metrics', permission: 'metrics.view' }
];
const visibleSystemSections = $derived(systemSections.filter((section) => can(section.permission)));
type SidebarGroup = 'users' | 'data' | 'oversight' | 'system';
let moduleQuery = $state('');
let groupOpen = $state<Record<SidebarGroup, boolean>>({ users: false, data: false, oversight: false, system: false });
const matchesModuleQuery = (label: string) => label.toLocaleLowerCase().includes(moduleQuery.trim().toLocaleLowerCase());
const filteredUserSections = $derived(visibleUserSections.filter((section) => matchesModuleQuery(section.label)));
const filteredDataSections = $derived(dataSections.filter((section) => matchesModuleQuery(section.label)));
const filteredOversightSections = $derived(visibleOversightSections.filter((section) => matchesModuleQuery(section.label)));
const filteredSystemSections = $derived(visibleSystemSections.filter((section) => matchesModuleQuery(section.label)));
const activeGroup = (pathname: string): SidebarGroup =>
pathname === '/isac' ? (visibleUserSections.length ? 'users' : canSeeData ? 'data' : visibleOversightSections.length ? 'oversight' : 'system')
: userSections.some((section) => pathname.startsWith(section.href)) ? 'users'
: dataSections.some((section) => pathname === section.href) || pathname === '/isac/contributor-guidelines' ? 'data'
: oversightSections.some((section) => pathname.startsWith(section.href)) ? 'oversight'
: 'system';
const setGroupOpen = (group: SidebarGroup, open: boolean) => {
groupOpen = { ...groupOpen, [group]: open };
localStorage.setItem('shd.isac.sidebar-groups', JSON.stringify(groupOpen));
};
onMount(() => {
try {
const remembered = JSON.parse(localStorage.getItem('shd.isac.sidebar-groups') ?? '{}');
groupOpen = { ...groupOpen, ...remembered, [activeGroup(page.url.pathname)]: true };
} catch {
groupOpen = { ...groupOpen, [activeGroup(page.url.pathname)]: true };
}
});
const selectNumericValue = (event: FocusEvent) => {
const input = event.target;
if (input instanceof HTMLInputElement && input.type === 'number' && !input.disabled) input.select();
@@ -46,32 +75,36 @@
<main class="admin-page">
<header class="admin-command">
<div class="command-title"><p class="eyebrow"><span></span> INTELLIGENT SYSTEM ANALYTIC COMPUTER</p><h1>ISAC</h1><p>SHD.build operations and intelligence control surface</p></div>
<div class="command-status"><div><i></i><span>SYSTEM</span><strong>ONLINE</strong></div><div><span>ACCESS</span><strong>AUTHORIZED</strong></div><div><span>ENVIRONMENT</span><strong>LOCAL</strong></div><div class="data-mode-status" class:admin={dataModeClass === 'admin'} class:data-manager={dataModeClass === 'data-manager'} class:oversight={dataModeClass === 'oversight'} class:contributor={dataModeClass === 'contributor'} class:read-only={dataModeClass === 'read-only'}><span>DATA MODE</span><strong>{dataMode}</strong></div></div>
<div class="command-status compact-status" aria-label="ISAC system status"><span><i></i>SYSTEM <strong>ONLINE</strong></span><span>ACCESS <strong>AUTHORIZED</strong></span><span>ENV <strong>LOCAL</strong></span><span class="data-mode-status" class:admin={dataModeClass === 'admin'} class:data-manager={dataModeClass === 'data-manager'} class:oversight={dataModeClass === 'oversight'} class:contributor={dataModeClass === 'contributor'} class:read-only={dataModeClass === 'read-only'}>MODE <strong>{dataMode}</strong></span></div>
</header>
<div class="admin-dashboard">
<aside class="admin-sidebar">
{#if visibleUserSections.length}
<div class="sidebar-label"><span>USER OPERATIONS</span><b>{String(visibleUserSections.length).padStart(2, '0')} MODULE{visibleUserSections.length === 1 ? '' : 'S'}</b></div>
<nav aria-label="User operations">{#each visibleUserSections as section}<a class:active={page.url.pathname.startsWith(section.href)} href={section.href}><small>{section.code}</small><span>{section.label}</span><b>›</b></a>{/each}</nav>
<label class="sidebar-module-search">
<span>FIND MODULE</span>
<input type="search" bind:value={moduleQuery} placeholder="Search ISAC…" aria-label="Search authorized ISAC modules"/>
</label>
{#if visibleUserSections.length && (!moduleQuery || filteredUserSections.length)}
<button class="sidebar-label" type="button" aria-expanded={groupOpen.users || Boolean(moduleQuery)} aria-controls="isac-nav-users" onclick={() => setGroupOpen('users', !groupOpen.users)}><span>USER OPERATIONS</span><b>{String(visibleUserSections.length).padStart(2, '0')} <i>{groupOpen.users || moduleQuery ? '−' : '+'}</i></b></button>
{#if groupOpen.users || moduleQuery}<nav id="isac-nav-users" aria-label="User operations">{#each filteredUserSections as section}<a class:active={page.url.pathname.startsWith(section.href)} href={section.href}><span>{section.label}</span><b>›</b></a>{/each}</nav>{/if}
{/if}
{#if canSeeData}
<div class="sidebar-label" class:section-label={visibleUserSections.length > 0}><span>DATA MANAGEMENT</span><b>{String(dataSections.length).padStart(2, '0')} MODULES</b></div>
<nav aria-label="Data management">
{#each dataSections as section}<a class:active={page.url.pathname === section.href} class:has-pending={Boolean(data.pendingProposals[section.module])} href={section.href}><small>{section.code}</small><span>{section.label}</span>{#if data.pendingProposals[section.module]}<em aria-label={`${data.pendingProposals[section.module]} pending change proposal${data.pendingProposals[section.module] === 1 ? '' : 's'}`} title="Pending change proposals">{data.pendingProposals[section.module]}</em>{/if}<b>›</b></a>{/each}
</nav>
{#if canSeeData && (!moduleQuery || filteredDataSections.length)}
<button class="sidebar-label" class:section-label={visibleUserSections.length > 0} type="button" aria-expanded={groupOpen.data || Boolean(moduleQuery)} aria-controls="isac-nav-data" onclick={() => setGroupOpen('data', !groupOpen.data)}><span>DATA MANAGEMENT</span><b>{String(dataSections.length).padStart(2, '0')} <i>{groupOpen.data || moduleQuery ? '−' : '+'}</i></b></button>
{#if groupOpen.data || moduleQuery}<nav id="isac-nav-data" aria-label="Data management">
{#each filteredDataSections as section}<a class:active={page.url.pathname === section.href} class:has-pending={Boolean(data.pendingProposals[section.module])} href={section.href}><span>{section.label}</span>{#if data.pendingProposals[section.module]}<em aria-label={`${data.pendingProposals[section.module]} pending change proposal${data.pendingProposals[section.module] === 1 ? '' : 's'}`} title="Pending change proposals">{data.pendingProposals[section.module]}</em>{/if}<b>›</b></a>{/each}
</nav>{/if}
{/if}
{#if visibleOversightSections.length}
<div class="sidebar-label section-label"><span>SYSTEM OVERSIGHT</span><b>{String(visibleOversightSections.length).padStart(2, '0')} MODULE{visibleOversightSections.length === 1 ? '' : 'S'}</b></div>
<nav aria-label="System oversight">{#each visibleOversightSections as section}
{#if visibleOversightSections.length && (!moduleQuery || filteredOversightSections.length)}
<button class="sidebar-label section-label" type="button" aria-expanded={groupOpen.oversight || Boolean(moduleQuery)} aria-controls="isac-nav-oversight" onclick={() => setGroupOpen('oversight', !groupOpen.oversight)}><span>SYSTEM OVERSIGHT</span><b>{String(visibleOversightSections.length).padStart(2, '0')} <i>{groupOpen.oversight || moduleQuery ? '−' : '+'}</i></b></button>
{#if groupOpen.oversight || moduleQuery}<nav id="isac-nav-oversight" aria-label="System oversight">{#each filteredOversightSections as section}
{@const reviewCount = section.reviewKey ? Number(data.oversightReviewCounts[section.reviewKey] ?? 0) : 0}
<a class:active={page.url.pathname.startsWith(section.href)} class:has-pending={reviewCount > 0} href={section.href}><small>{section.code}</small><span>{section.label}</span>{#if reviewCount}<em aria-label={`${reviewCount} item${reviewCount === 1 ? '' : 's'} awaiting review`} title="Awaiting review">{reviewCount}</em>{/if}<b>›</b></a>
{/each}</nav>
<a class:active={page.url.pathname.startsWith(section.href)} class:has-pending={reviewCount > 0} href={section.href}><span>{section.label}</span>{#if reviewCount}<em aria-label={`${reviewCount} item${reviewCount === 1 ? '' : 's'} awaiting review`} title="Awaiting review">{reviewCount}</em>{/if}<b>›</b></a>
{/each}</nav>{/if}
{/if}
{#if visibleSystemSections.length}
<div class="sidebar-label section-label"><span>SYSTEM CONFIGURATION</span><b>{String(visibleSystemSections.length).padStart(2, '0')} MODULE{visibleSystemSections.length === 1 ? '' : 'S'}</b></div>
<nav aria-label="System configuration">{#each visibleSystemSections as section}
<a class:active={page.url.pathname.startsWith(section.href)} href={section.href}><small>{section.code}</small><span>{section.label}</span><b>›</b></a>
{/each}</nav>
{#if visibleSystemSections.length && (!moduleQuery || filteredSystemSections.length)}
<button class="sidebar-label section-label" type="button" aria-expanded={groupOpen.system || Boolean(moduleQuery)} aria-controls="isac-nav-system" onclick={() => setGroupOpen('system', !groupOpen.system)}><span>SYSTEM CONFIGURATION</span><b>{String(visibleSystemSections.length).padStart(2, '0')} <i>{groupOpen.system || moduleQuery ? '−' : '+'}</i></b></button>
{#if groupOpen.system || moduleQuery}<nav id="isac-nav-system" aria-label="System configuration">{#each filteredSystemSections as section}
<a class:active={page.url.pathname.startsWith(section.href)} href={section.href}><span>{section.label}</span><b>›</b></a>
{/each}</nav>{/if}
{/if}
<div class="sidebar-foot"><span>ISAC NODE</span><strong>NYC-01</strong><small>Access policy synchronized</small></div>
</aside>
@@ -85,6 +118,7 @@
{#if dataReadOnly}<div class="data-access-banner"><div><b>READ-ONLY DATA ACCESS</b><span>You can inspect registries without submitting changes.</span></div>{#if can('data.propose')}<a class="mode-toggle" href={`/isac/contributor-guidelines?returnTo=${encodeURIComponent(page.url.pathname + page.url.search)}`}>ENABLE CONTRIBUTOR MODE →</a>{/if}</div>
{:else if contributorEnabled && !guidelinesPage && can('data.propose') && !can('data.manage')}<div class="data-access-banner contributor"><div><b>CONTRIBUTOR MODE</b><span>Suggestions enter moderation and do not immediately change live data.</span></div><form method="POST" action="/isac/contributor-guidelines?/disable"><input type="hidden" name="returnTo" value={page.url.pathname + page.url.search}/><button class="mode-toggle" type="submit">RETURN TO READ-ONLY</button></form></div>{/if}
{#if readOnlyBlocked}<p class="error data-access-error" role="alert">This account has read-only game-data access.</p>{/if}
{#if dataModulePage && !dataReadOnly}<div class="mutation-policy-strip"><MutationConsequence/></div>{/if}
{@render children()}
</section>
</div>