@wenathlan/saddle 2.0.151 → 2.0.153
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/biome.jsonc +12 -5
- package/dist/App.d.ts +5 -0
- package/dist/App.js +52 -0
- package/dist/Sol/Sol.d.ts +3 -0
- package/dist/Sol/Sol.js +46 -0
- package/dist/Sol/agentbrowser/agentbrowser.d.ts +9 -0
- package/dist/Sol/agentbrowser/agentbrowser.js +121 -0
- package/dist/Sol/architecture/architecture.d.ts +9 -0
- package/dist/Sol/architecture/architecture.js +93 -0
- package/dist/Sol/compute/compute.d.ts +9 -0
- package/dist/Sol/compute/compute.js +22 -0
- package/dist/Sol/console/console.d.ts +15 -0
- package/dist/Sol/console/console.js +292 -0
- package/dist/Sol/dashboard/dashboard.d.ts +10 -0
- package/dist/Sol/dashboard/dashboard.js +181 -0
- package/dist/Sol/docs/docs.d.ts +9 -0
- package/dist/Sol/docs/docs.js +28 -0
- package/dist/Sol/home/home.d.ts +35 -0
- package/dist/Sol/home/home.js +239 -0
- package/dist/Sol/integrations/integrations.d.ts +9 -0
- package/dist/Sol/integrations/integrations.js +83 -0
- package/dist/Sol/intro/intro.d.ts +7 -0
- package/dist/Sol/intro/intro.js +102 -0
- package/dist/Sol/login/login.d.ts +16 -0
- package/dist/Sol/login/login.js +49 -0
- package/dist/Sol/notfound/notfound.d.ts +9 -0
- package/dist/Sol/notfound/notfound.js +15 -0
- package/dist/Sol/onboarding/onboarding.d.ts +25 -0
- package/dist/Sol/onboarding/onboarding.js +60 -0
- package/dist/Sol/playground/playground.d.ts +9 -0
- package/dist/Sol/playground/playground.js +127 -0
- package/dist/Sol/register/register.d.ts +16 -0
- package/dist/Sol/register/register.js +193 -0
- package/dist/Sol/shell/Shell.d.ts +124 -0
- package/dist/Sol/shell/Shell.js +335 -0
- package/dist/Sol/wingets/ComputeBootladder.d.ts +6 -0
- package/dist/Sol/wingets/ComputeBootladder.js +71 -0
- package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +7 -0
- package/dist/Sol/wingets/ComputeModalitycatalog.js +71 -0
- package/dist/Sol/wingets/ConsoleApibadge.d.ts +7 -0
- package/dist/Sol/wingets/ConsoleApibadge.js +5 -0
- package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +6 -0
- package/dist/Sol/wingets/ConsoleEdgelaw.js +36 -0
- package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +19 -0
- package/dist/Sol/wingets/ConsoleEventstimeline.js +12 -0
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +8 -0
- package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +8 -0
- package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +21 -0
- package/dist/Sol/wingets/ConsoleSpecpanel.js +75 -0
- package/dist/Sol/wingets/ConsoleTerminal.d.ts +22 -0
- package/dist/Sol/wingets/ConsoleTerminal.js +77 -0
- package/dist/Sol/wingets/DashboardAccountpanel.d.ts +18 -0
- package/dist/Sol/wingets/DashboardAccountpanel.js +65 -0
- package/dist/Sol/wingets/DashboardAdminpanel.d.ts +6 -0
- package/dist/Sol/wingets/DashboardAdminpanel.js +90 -0
- package/dist/Sol/wingets/DashboardAuditlog.d.ts +8 -0
- package/dist/Sol/wingets/DashboardAuditlog.js +50 -0
- package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +10 -0
- package/dist/Sol/wingets/DashboardCreatesandboxform.js +71 -0
- package/dist/Sol/wingets/DashboardEventstimeline.d.ts +8 -0
- package/dist/Sol/wingets/DashboardEventstimeline.js +83 -0
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +8 -0
- package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +57 -0
- package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +8 -0
- package/dist/Sol/wingets/DashboardMeshnodestable.js +103 -0
- package/dist/Sol/wingets/DashboardSandboxlist.d.ts +10 -0
- package/dist/Sol/wingets/DashboardSandboxlist.js +163 -0
- package/dist/Sol/wingets/DashboardUserstable.d.ts +8 -0
- package/dist/Sol/wingets/DashboardUserstable.js +78 -0
- package/dist/Sol/wingets/HomeEntrygate.d.ts +23 -0
- package/dist/Sol/wingets/HomeEntrygate.js +73 -0
- package/dist/Sol/wingets/HomeMetricstrip.d.ts +9 -0
- package/dist/Sol/wingets/HomeMetricstrip.js +4 -0
- package/dist/Sol/wingets/HomeRuntimediagram.d.ts +1 -0
- package/dist/Sol/wingets/HomeRuntimediagram.js +22 -0
- package/dist/Sol/wingets/LoginForm.d.ts +19 -0
- package/dist/Sol/wingets/LoginForm.js +141 -0
- package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +13 -0
- package/dist/Sol/wingets/RegisterPasswordconfirm.js +16 -0
- package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +19 -0
- package/dist/Sol/wingets/RegisterPasswordmeter.js +65 -0
- package/dist/Sol/wingets/RegisterUsernamerules.d.ts +11 -0
- package/dist/Sol/wingets/RegisterUsernamerules.js +16 -0
- package/dist/Sol/wingets/index.d.ts +39 -0
- package/dist/Sol/wingets/index.js +39 -0
- package/dist/alternatives.d.ts +508 -0
- package/dist/alternatives.js +950 -0
- package/dist/api.d.ts +154 -0
- package/dist/api.js +174 -0
- package/dist/auth.d.ts +268 -0
- package/dist/auth.js +476 -0
- package/dist/automation.d.ts +425 -0
- package/dist/automation.js +566 -0
- package/dist/browser.d.ts +561 -0
- package/dist/browser.js +1058 -0
- package/dist/capacitor.config.d.ts +45 -0
- package/dist/capacitor.config.js +48 -0
- package/dist/catalog.d.ts +43 -0
- package/dist/catalog.js +44 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +168 -0
- package/dist/communication.d.ts +181 -0
- package/dist/communication.js +376 -0
- package/dist/compute.d.ts +1160 -0
- package/dist/compute.js +2272 -0
- package/dist/dashboardlib.d.ts +58 -0
- package/dist/dashboardlib.js +161 -0
- package/dist/db.d.ts +569 -0
- package/dist/db.js +1080 -0
- package/dist/distribution.d.ts +528 -0
- package/dist/distribution.js +810 -0
- package/dist/drizzle.config.d.ts +20 -0
- package/dist/drizzle.config.js +18 -0
- package/dist/edgelandes.d.ts +70 -0
- package/dist/edgelandes.host.d.ts +26 -0
- package/dist/edgelandes.host.js +1089 -0
- package/dist/edgelandes.inproc.d.ts +27 -0
- package/dist/edgelandes.inproc.js +952 -0
- package/dist/edgelandes.js +1133 -0
- package/dist/edgelandes.ninety.d.ts +31 -0
- package/dist/edgelandes.ninety.js +174 -0
- package/dist/edgelandes.virtual.d.ts +25 -0
- package/dist/edgelandes.virtual.js +629 -0
- package/dist/edgeplane.d.ts +114 -0
- package/dist/edgeplane.js +305 -0
- package/dist/examplelocaljob.d.ts +1 -0
- package/{docs/example-localjob.ts → dist/examplelocaljob.js} +0 -1
- package/dist/execution.d.ts +529 -0
- package/dist/execution.js +760 -0
- package/dist/family.d.ts +16 -0
- package/dist/family.js +42 -0
- package/dist/familyurl.d.ts +21 -0
- package/dist/familyurl.js +24 -0
- package/dist/format.d.ts +18 -0
- package/dist/format.js +59 -0
- package/dist/foundation.d.ts +172 -0
- package/dist/foundation.js +312 -0
- package/dist/index.d.ts +735 -0
- package/dist/index.js +1020 -0
- package/dist/integration.d.ts +235 -0
- package/dist/integration.js +228 -0
- package/dist/intelligence.d.ts +93 -0
- package/dist/intelligence.js +144 -0
- package/dist/isolation.d.ts +128 -0
- package/dist/isolation.js +95 -0
- package/dist/labels.d.ts +665 -0
- package/dist/labels.js +751 -0
- package/dist/localauth.d.ts +127 -0
- package/dist/localauth.js +413 -0
- package/dist/media.d.ts +343 -0
- package/dist/media.js +985 -0
- package/dist/mesh.d.ts +177 -0
- package/dist/mesh.js +468 -0
- package/dist/modalityregistry.d.ts +109 -0
- package/dist/modalityregistry.js +1386 -0
- package/dist/modes.d.ts +358 -0
- package/dist/modes.js +133 -0
- package/dist/onboardingstate.d.ts +79 -0
- package/dist/onboardingstate.js +282 -0
- package/dist/orchestrator.d.ts +1338 -0
- package/dist/orchestrator.js +4310 -0
- package/dist/packager/targetcli.js +4 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +14 -0
- package/dist/performance.d.ts +415 -0
- package/dist/performance.js +826 -0
- package/dist/quantum.d.ts +809 -0
- package/dist/quantum.js +2072 -0
- package/dist/render.d.ts +380 -0
- package/dist/render.js +1072 -0
- package/dist/runall.d.ts +2 -0
- package/dist/runall.js +39 -0
- package/dist/runtimeprobe.d.ts +4 -0
- package/dist/runtimeprobe.js +8 -0
- package/dist/sandbox.d.ts +355 -0
- package/dist/sandbox.js +1721 -0
- package/dist/sandboxenvprofile.d.ts +29 -0
- package/dist/sandboxenvprofile.js +89 -0
- package/dist/sandboxprofile.d.ts +137 -0
- package/dist/sandboxprofile.js +241 -0
- package/dist/sandboxqueue.d.ts +108 -0
- package/dist/sandboxqueue.js +201 -0
- package/dist/sandboxquota.d.ts +121 -0
- package/dist/sandboxquota.js +236 -0
- package/dist/scheduler.d.ts +595 -0
- package/dist/scheduler.js +1258 -0
- package/dist/scriptlanes.d.ts +182 -0
- package/dist/scriptlanes.js +660 -0
- package/dist/scripts.buildengine.d.ts +1 -0
- package/dist/scripts.buildengine.js +39 -0
- package/dist/scripts.securitygate.d.ts +1 -0
- package/dist/scripts.securitygate.js +68 -0
- package/dist/scripts.validateflatnative.d.ts +1 -0
- package/dist/scripts.validateflatnative.js +72 -0
- package/dist/security.d.ts +500 -0
- package/dist/security.js +1169 -0
- package/dist/seedcatalog.d.ts +13 -0
- package/dist/seedcatalog.js +46 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +53 -0
- package/dist/speccatalog.d.ts +31 -0
- package/dist/speccatalog.js +163 -0
- package/dist/tiers.d.ts +1001 -0
- package/dist/tiers.js +2169 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +5 -0
- package/dist/vaulthandoff.d.ts +141 -0
- package/dist/vaulthandoff.js +444 -0
- package/dist/virtual.d.ts +640 -0
- package/dist/virtual.js +1284 -0
- package/dist/virtualcpu.d.ts +315 -0
- package/dist/virtualcpu.js +1180 -0
- package/dist/virtualgpu.d.ts +344 -0
- package/dist/virtualgpu.js +1000 -0
- package/dist/virtualization.d.ts +606 -0
- package/dist/virtualization.js +1186 -0
- package/dist/virtualmemory.d.ts +817 -0
- package/dist/virtualmemory.js +1795 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.js +43 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +25 -0
- package/dist/webserver.d.ts +166 -0
- package/dist/webserver.js +2226 -0
- package/dist/workloadlaw.d.ts +133 -0
- package/dist/workloadlaw.js +193 -0
- package/docs/artifactavailability.md +2 -2
- package/docs/{containerplatforms-2.1.0.md → containerplatforms.2.1.0.md} +1 -1
- package/docs/{documentmap-1.8.12.md → documentmap.1.8.12.md} +1 -1
- package/docs/ninety.modalities.md +108 -0
- package/docs/planning.ninety.md +391 -0
- package/docs/{releasenotes-1.8.13.md → releasenotes.1.8.13.md} +2 -2
- package/docs/{releasenotes-1.8.14.md → releasenotes.1.8.14.md} +1 -1
- package/docs/{repo-synthesis-1.8.16.md → repo.synthesis.1.8.16.md} +1 -1
- package/docs/{todo-1.8.15.md → todo.1.8.15.md} +1 -1
- package/docs/{todo-1.8.16.md → todo.1.8.16.md} +5 -5
- package/docs/todo.md +2 -2
- package/docs/workloadlaw.md +104 -0
- package/index.ts +1 -1
- package/manifest.json +1 -1
- package/modalityregistry.ts +1371 -34
- package/orchestrator.ts +1 -1
- package/package.json +78 -33
- package/docs/CONVERSA.txt +0 -1523
- package/docs/architecture-1.8.19.png +0 -0
- package/docs/assets/architecture.svg +0 -45
- package/docs/assets/saddle-browser-trace.webp +0 -0
- package/docs/assets/saddle-hero-bridge.webp +0 -0
- package/docs/assets/saddle-mark.webp +0 -0
- package/docs/assets/saddle-runtime-map.webp +0 -0
- package/docs/assets/saddlemark.svg +0 -13
- package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
- /package/docs/{architecture-1.8.19.md → architecture.1.8.19.md} +0 -0
- /package/docs/{architecture-1.8.19.mmd → architecture.1.8.19.mmd} +0 -0
- /package/docs/{artifactresearch-1.8.9.md → artifactresearch.1.8.9.md} +0 -0
- /package/docs/{batches-1816-1820.md → batches.1816.to.1820.md} +0 -0
- /package/docs/{brancharchive-2026-08-18.md → brancharchive.2026.08.18.md} +0 -0
- /package/docs/{containerplatforms-1.8.17.md → containerplatforms.1.8.17.md} +0 -0
- /package/docs/{e2ugh-engine.md → e2ugh.engine.md} +0 -0
- /package/docs/{flatbuildresearch-1.8.11.md → flatbuildresearch.1.8.11.md} +0 -0
- /package/docs/{licenseaudit-1.8.12.md → licenseaudit.1.8.12.md} +0 -0
- /package/docs/{mobileconversionresearch-1.8.10.md → mobileconversionresearch.1.8.10.md} +0 -0
- /package/docs/{native-wrappers.md → native.wrappers.md} +0 -0
- /package/docs/{nativeidentityresearch-1.8.11.md → nativeidentityresearch.1.8.11.md} +0 -0
- /package/docs/{releasenotes-1.8.12.md → releasenotes.1.8.12.md} +0 -0
- /package/docs/{releasenotes-1.8.15.md → releasenotes.1.8.15.md} +0 -0
- /package/docs/{releasenotes-1.8.16.md → releasenotes.1.8.16.md} +0 -0
- /package/docs/{releasenotes-1.8.17.md → releasenotes.1.8.17.md} +0 -0
- /package/docs/{releasenotes-1.8.18.md → releasenotes.1.8.18.md} +0 -0
- /package/docs/{releasenotes-1.8.19.md → releasenotes.1.8.19.md} +0 -0
- /package/docs/{reorganization-1.8.8.md → reorganization.1.8.8.md} +0 -0
- /package/docs/{reorganization-1.8.9.md → reorganization.1.8.9.md} +0 -0
- /package/docs/{repo-analysis-1.8.21.json → repo.analysis.1.8.21.json} +0 -0
- /package/docs/{repo-candidates-1.8.21.jsonl → repo.candidates.1.8.21.jsonl} +0 -0
- /package/docs/{repo-research-1.8.16.md → repo.research.1.8.16.md} +0 -0
- /package/docs/{repo-research-1.8.21.md → repo.research.1.8.21.md} +0 -0
- /package/docs/{repo-selected-1.8.21.json → repo.selected.1.8.21.json} +0 -0
- /package/docs/{repo-synthesis-1.8.21.md → repo.synthesis.1.8.21.md} +0 -0
- /package/docs/{research-1.8.18-isolation.md → research.1.8.18.isolation.md} +0 -0
- /package/docs/{research-1.8.19-virtual-browser.md → research.1.8.19.virtual.browser.md} +0 -0
- /package/docs/{scanningresearch-1.8.11.md → scanningresearch.1.8.11.md} +0 -0
- /package/docs/{securityaudit-1.8.7.md → securityaudit.1.8.7.md} +0 -0
- /package/docs/{securityreferences-1.8.11.md → securityreferences.1.8.11.md} +0 -0
- /package/docs/{securityresearch-1.8.11.md → securityresearch.1.8.11.md} +0 -0
- /package/docs/{signingresearch-1.8.12.md → signingresearch.1.8.12.md} +0 -0
- /package/docs/{tauri-glib-risk-1.8.11.md → tauri.glib.risk.1.8.11.md} +0 -0
- /package/docs/{todo-1.8.18.md → todo.1.8.18.md} +0 -0
- /package/docs/{todo-1.8.19.md → todo.1.8.19.md} +0 -0
- /package/docs/{toolchainresearch-1.8.9.md → toolchainresearch.1.8.9.md} +0 -0
- /package/docs/{web-duplicatecleanup.md → web.duplicatecleanup.md} +0 -0
- /package/docs/{web-ideas.md → web.ideas.md} +0 -0
- /package/docs/{workflowimprovements-2026-08-19.md → workflowimprovements.2026.08.19.md} +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* console page anchor — layer 3 of the anchor architecture.
|
|
4
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
5
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
6
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
7
|
+
* this file. This anchor carries the former main component of the folder,
|
|
8
|
+
* which now lives here as the page mount itself.
|
|
9
|
+
*/
|
|
10
|
+
// Real sandbox console: faithful absorption of console.html + console.js —
|
|
11
|
+
// the spec panel, the animated boot sequence, the interactive terminal, the
|
|
12
|
+
// bus event timeline, snapshot/stop and the api detection badge. when the
|
|
13
|
+
// self-hosted node answers, the sandbox is also created through
|
|
14
|
+
// /api/v1/sandboxes and commands run through the api exec endpoint;
|
|
15
|
+
// otherwise the same dispatcher runs locally in the browser.
|
|
16
|
+
import { useEffect, useRef, useState } from 'react';
|
|
17
|
+
import { Link } from 'wouter';
|
|
18
|
+
import { PageShell } from '../shell/Shell.tsx';
|
|
19
|
+
import { apibase, apifetch, fetchhealth } from '../../api';
|
|
20
|
+
import { label, labelfill } from '../../labels.ts';
|
|
21
|
+
import { bootSequence, cpudata, createSandboxState, dispatch, gpudata } from '../../sandbox.ts';
|
|
22
|
+
import { ApiBadge as ApiBadge } from '../wingets';
|
|
23
|
+
import { ConsoleEdgelaw as ConsoleEdgelaw } from '../wingets';
|
|
24
|
+
import { EventsTimeline as EventsTimeline } from '../wingets';
|
|
25
|
+
import { SnapshotControls as SnapshotControls } from '../wingets';
|
|
26
|
+
import { SpecPanel as SpecPanel } from '../wingets';
|
|
27
|
+
import { Terminal as Terminal } from '../wingets';
|
|
28
|
+
export * from '../wingets';
|
|
29
|
+
/** display cap for very large payloads such as cpuinfo at 192 vcpus. */
|
|
30
|
+
const displaycap = 120000;
|
|
31
|
+
/** the session key the home landing writes and this page reads once (then spent). */
|
|
32
|
+
const declaredkey = 'saddle.declared';
|
|
33
|
+
/** initial spec selection mirroring the static page defaults. */
|
|
34
|
+
const initialspec = {
|
|
35
|
+
model: cpudata[0].model,
|
|
36
|
+
quotamb: 16,
|
|
37
|
+
vcpus: 8,
|
|
38
|
+
ramgb: 32,
|
|
39
|
+
gpu: gpudata[0].id,
|
|
40
|
+
mig: 'off',
|
|
41
|
+
};
|
|
42
|
+
/** the sleep used to animate the boot sequence line by line. */
|
|
43
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
44
|
+
/**
|
|
45
|
+
* the console page: wires the spec panel, terminal, events timeline and
|
|
46
|
+
* lifecycle controls to the browser-pure engine (sandbox.ts) and, when
|
|
47
|
+
* available, the self-hosted /api/v1 contract.
|
|
48
|
+
*/
|
|
49
|
+
export default function Console() {
|
|
50
|
+
const rowseq = useRef(0);
|
|
51
|
+
const eventseq = useRef(0);
|
|
52
|
+
const engineref = useRef(null);
|
|
53
|
+
const apiref = useRef(null);
|
|
54
|
+
const [selection, setSelection] = useState(initialspec);
|
|
55
|
+
const [rows, setRows] = useState([]);
|
|
56
|
+
const [events, setEvents] = useState([]);
|
|
57
|
+
const [running, setRunning] = useState(false);
|
|
58
|
+
const [busy, setBusy] = useState(false);
|
|
59
|
+
const [termstate, setTermstate] = useState('halted');
|
|
60
|
+
const [prompt, setPrompt] = useState(labelfill('console.prompt', { host: 'saddle' }));
|
|
61
|
+
const [apimode, setApimode] = useState(false);
|
|
62
|
+
const [badgelabel, setBadgelabel] = useState(label('console.badge.local'));
|
|
63
|
+
const [declared, setDeclared] = useState(null);
|
|
64
|
+
/** api detection: probe the health endpoint once (1.5s budget). */
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
let cancelled = false;
|
|
67
|
+
const detect = async () => {
|
|
68
|
+
const health = await fetchhealth(apibase(), 1500);
|
|
69
|
+
if (cancelled)
|
|
70
|
+
return;
|
|
71
|
+
if (health !== null) {
|
|
72
|
+
setApimode(true);
|
|
73
|
+
setBadgelabel(labelfill('console.badge.api', {
|
|
74
|
+
version: String(health.version),
|
|
75
|
+
uptime: String(health.uptime),
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
setBadgelabel(label('console.badge.local'));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
detect().catch(() => {
|
|
83
|
+
if (!cancelled)
|
|
84
|
+
setBadgelabel(label('console.badge.local'));
|
|
85
|
+
});
|
|
86
|
+
return () => {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
};
|
|
89
|
+
}, []);
|
|
90
|
+
/** the handed-over declaration of the landing prompt: read once, then spent. */
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
try {
|
|
93
|
+
const raw = sessionStorage.getItem(declaredkey);
|
|
94
|
+
if (raw === null)
|
|
95
|
+
return;
|
|
96
|
+
sessionStorage.removeItem(declaredkey);
|
|
97
|
+
const parsed = JSON.parse(raw);
|
|
98
|
+
setDeclared({
|
|
99
|
+
base: typeof parsed.base === 'string' ? parsed.base : null,
|
|
100
|
+
os: typeof parsed.os === 'string' ? parsed.os : null,
|
|
101
|
+
arch: typeof parsed.arch === 'string' ? parsed.arch : null,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* a broken handoff spends itself silently */
|
|
106
|
+
}
|
|
107
|
+
}, []);
|
|
108
|
+
/** appends one text block as a row; truncates giant payloads for display. */
|
|
109
|
+
const printrow = (text, cls) => {
|
|
110
|
+
rowseq.current += 1;
|
|
111
|
+
const id = rowseq.current;
|
|
112
|
+
if (text.length > displaycap) {
|
|
113
|
+
rowseq.current += 1;
|
|
114
|
+
const truncid = rowseq.current;
|
|
115
|
+
setRows((prev) => [
|
|
116
|
+
...prev,
|
|
117
|
+
{ id, text: text.slice(0, displaycap), cls },
|
|
118
|
+
{
|
|
119
|
+
id: truncid,
|
|
120
|
+
text: labelfill('console.boot.truncated', { bytes: String(text.length) }),
|
|
121
|
+
cls: 'trunc',
|
|
122
|
+
},
|
|
123
|
+
]);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
setRows((prev) => [...prev, { id, text, cls }]);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
/** prepends one bus event; the timeline keeps at most 50 entries. */
|
|
130
|
+
const logevent = (topic, detail, kind) => {
|
|
131
|
+
eventseq.current += 1;
|
|
132
|
+
const now = new Date();
|
|
133
|
+
const item = {
|
|
134
|
+
id: eventseq.current,
|
|
135
|
+
time: now.toTimeString().slice(0, 8),
|
|
136
|
+
topic,
|
|
137
|
+
detail,
|
|
138
|
+
kind,
|
|
139
|
+
};
|
|
140
|
+
setEvents((prev) => [item, ...prev].slice(0, 50));
|
|
141
|
+
};
|
|
142
|
+
const onselectionchange = (patch) => {
|
|
143
|
+
setSelection((prev) => ({ ...prev, ...patch }));
|
|
144
|
+
};
|
|
145
|
+
/** boots the sandbox: spec commit, api-backed creation, animated dmesg. */
|
|
146
|
+
const bootsandbox = async () => {
|
|
147
|
+
setBusy(true);
|
|
148
|
+
setRunning(false);
|
|
149
|
+
setRows([]);
|
|
150
|
+
setTermstate('booting');
|
|
151
|
+
const spec = {
|
|
152
|
+
model: selection.model,
|
|
153
|
+
vcpus: selection.vcpus,
|
|
154
|
+
ramgb: selection.ramgb,
|
|
155
|
+
gpu: selection.gpu,
|
|
156
|
+
mig: selection.mig,
|
|
157
|
+
quotamb: selection.quotamb,
|
|
158
|
+
};
|
|
159
|
+
const state = createSandboxState(spec);
|
|
160
|
+
engineref.current = state;
|
|
161
|
+
setPrompt(labelfill('console.prompt', { host: state.hostname }));
|
|
162
|
+
logevent('vm:creating', labelfill('console.event.creating', {
|
|
163
|
+
model: spec.model,
|
|
164
|
+
vcpus: String(state.vcpus),
|
|
165
|
+
ram: String(spec.ramgb),
|
|
166
|
+
gpu: spec.gpu,
|
|
167
|
+
}), 'lifecycle');
|
|
168
|
+
/* api-backed sandbox when the self-hosted server answers */
|
|
169
|
+
if (apimode) {
|
|
170
|
+
try {
|
|
171
|
+
const response = await apifetch('/api/v1/sandboxes', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
body: JSON.stringify(spec),
|
|
174
|
+
});
|
|
175
|
+
if (response.ok) {
|
|
176
|
+
const created = (await response.json());
|
|
177
|
+
apiref.current = created.id;
|
|
178
|
+
logevent('sandbox:created', labelfill('console.event.created', { id: created.id, state: created.state }), 'lifecycle');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
apiref.current = null;
|
|
183
|
+
logevent('sandbox:create-failed', label('console.event.createFailed'), 'lifecycle');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
printrow(labelfill('console.boot.line', {
|
|
187
|
+
model: spec.model,
|
|
188
|
+
vcpus: String(state.vcpus),
|
|
189
|
+
ram: String(spec.ramgb),
|
|
190
|
+
gpu: spec.gpu,
|
|
191
|
+
}), 'boot');
|
|
192
|
+
const lines = bootSequence(spec.model, state.vcpus, spec.ramgb, spec.gpu);
|
|
193
|
+
for (const bootline of lines) {
|
|
194
|
+
printrow(bootline, 'boot');
|
|
195
|
+
await sleep(28 + Math.random() * 34);
|
|
196
|
+
}
|
|
197
|
+
printrow(label('console.boot.ready'), 'ok');
|
|
198
|
+
logevent('vm:created', labelfill('console.event.specsCommitted', { id: state.id }), 'lifecycle');
|
|
199
|
+
logevent('vm:started', label('console.event.started'), 'lifecycle');
|
|
200
|
+
setRunning(true);
|
|
201
|
+
setTermstate('running');
|
|
202
|
+
setBusy(false);
|
|
203
|
+
};
|
|
204
|
+
const onstart = () => {
|
|
205
|
+
bootsandbox().catch(() => {
|
|
206
|
+
printrow(label('console.boot.failed'), 'err');
|
|
207
|
+
setBusy(false);
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
/** executes one command: api exec first, local dispatcher as fallback. */
|
|
211
|
+
const runcommand = async (rawcommand) => {
|
|
212
|
+
printrow(`${prompt} ${rawcommand}`, 'cmdline');
|
|
213
|
+
if (rawcommand === 'clear') {
|
|
214
|
+
setRows([]);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
let result = null;
|
|
218
|
+
let source = 'local';
|
|
219
|
+
if (apiref.current !== null) {
|
|
220
|
+
try {
|
|
221
|
+
const response = await apifetch(`/api/v1/sandboxes/${apiref.current}/exec`, {
|
|
222
|
+
method: 'POST',
|
|
223
|
+
body: JSON.stringify({ command: rawcommand }),
|
|
224
|
+
});
|
|
225
|
+
if (response.ok) {
|
|
226
|
+
result = (await response.json());
|
|
227
|
+
source = 'api';
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
result = null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (result === null) {
|
|
235
|
+
result =
|
|
236
|
+
engineref.current !== null
|
|
237
|
+
? dispatch(rawcommand, engineref.current)
|
|
238
|
+
: { output: label('console.boot.notrunning'), exitCode: 1 };
|
|
239
|
+
source = 'local';
|
|
240
|
+
}
|
|
241
|
+
if (result.output.length > 0) {
|
|
242
|
+
printrow(result.output, result.exitCode === 0 ? '' : 'err');
|
|
243
|
+
}
|
|
244
|
+
logevent('exec:completed', labelfill('console.event.exec', {
|
|
245
|
+
command: rawcommand,
|
|
246
|
+
code: String(result.exitCode),
|
|
247
|
+
source,
|
|
248
|
+
}), 'exec');
|
|
249
|
+
};
|
|
250
|
+
/** snapshot: precopy stage 1 of 1, memory + disk. */
|
|
251
|
+
const onsnapshot = () => {
|
|
252
|
+
if (!running)
|
|
253
|
+
return;
|
|
254
|
+
const snapid = `snap-${Math.random().toString(16).slice(2, 10)}`;
|
|
255
|
+
printrow(labelfill('console.snapshot.created', { id: snapid }), 'ok');
|
|
256
|
+
logevent('snapshot:created', labelfill('console.event.snapshot', { id: snapid, sandbox: engineref.current?.id ?? 'n/a' }), 'snapshot');
|
|
257
|
+
};
|
|
258
|
+
/** teardown: local halt plus the api sandbox delete when connected. */
|
|
259
|
+
const onstop = async () => {
|
|
260
|
+
if (!running)
|
|
261
|
+
return;
|
|
262
|
+
setRunning(false);
|
|
263
|
+
setTermstate('stopped');
|
|
264
|
+
printrow(label('console.stop.done'), 'boot');
|
|
265
|
+
logevent('vm:stopped', labelfill('console.event.stopped', { id: engineref.current?.id ?? 'n/a' }), 'lifecycle');
|
|
266
|
+
if (apiref.current !== null) {
|
|
267
|
+
const id = apiref.current;
|
|
268
|
+
try {
|
|
269
|
+
await apifetch(`/api/v1/sandboxes/${id}`, { method: 'DELETE' });
|
|
270
|
+
logevent('vm:deleted', labelfill('console.event.deleted', { id }), 'lifecycle');
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
logevent('vm:delete-failed', labelfill('console.event.deleteFailed', { id }), 'lifecycle');
|
|
274
|
+
}
|
|
275
|
+
apiref.current = null;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
return (_jsxs(PageShell, { section: label('console.shell.section'), label: label('console.shell.label'), title: label('console.shell.title'), intro: label('console.shell.intro'), children: [_jsx(ConsoleEdgelaw, {}), _jsxs("section", { className: "content-section console-section", children: [_jsxs("div", { className: "content-section-heading", children: [_jsx("p", { className: "eyebrow", children: label('console.eyebrow') }), _jsxs("div", { className: "console-heading-side", children: [_jsx(Link, { href: "/login", className: "console-signin", children: label('console.signin') }), _jsx(ApiBadge, { apion: apimode, label: badgelabel })] })] }), _jsxs("div", { className: "sandbox-grid", children: [_jsxs("section", { className: "sandbox-panel", "aria-labelledby": "specstitle", children: [_jsx("h2", { className: "sandbox-panel-title", id: "specstitle", children: label('console.specs.title') }), declared !== null &&
|
|
279
|
+
(declared.base !== null || declared.os !== null || declared.arch !== null) && (_jsxs("p", { className: "r3-declared-ribbon", role: "note", children: [label('console.declared.head'), [
|
|
280
|
+
declared.base !== null
|
|
281
|
+
? labelfill('console.declared.base', { value: declared.base })
|
|
282
|
+
: null,
|
|
283
|
+
declared.os !== null
|
|
284
|
+
? labelfill('console.declared.guest', { value: declared.os })
|
|
285
|
+
: null,
|
|
286
|
+
declared.arch !== null
|
|
287
|
+
? labelfill('console.declared.arch', { value: declared.arch })
|
|
288
|
+
: null,
|
|
289
|
+
]
|
|
290
|
+
.filter(Boolean)
|
|
291
|
+
.join(' · '), label('console.declared.tail')] })), _jsx(SpecPanel, { spec: selection, onChange: onselectionchange, disabled: busy || running }), _jsxs("div", { className: "sandbox-actions", children: [_jsx("button", { className: "button button-primary", type: "button", onClick: onstart, disabled: busy || running, "aria-label": label('console.startAria'), children: label('console.start') }), _jsx(SnapshotControls, { running: running, onsnapshot: onsnapshot, onstop: onstop })] })] }), _jsx(Terminal, { rows: rows, prompt: prompt, state: termstate, enabled: running, oncommand: runcommand }), _jsx(EventsTimeline, { events: events })] }), _jsx("p", { className: "console-note", children: label('console.note') })] })] }));
|
|
292
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard page anchor — layer 3 of the anchor architecture.
|
|
3
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
4
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
5
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
6
|
+
* this file. This anchor carries the former main component of the folder,
|
|
7
|
+
* which now lives here as the page mount itself.
|
|
8
|
+
*/
|
|
9
|
+
export * from '../wingets';
|
|
10
|
+
export default function Dashboard(): import("react").JSX.Element;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* dashboard page anchor — layer 3 of the anchor architecture.
|
|
4
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
5
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
6
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
7
|
+
* this file. This anchor carries the former main component of the folder,
|
|
8
|
+
* which now lives here as the page mount itself.
|
|
9
|
+
*/
|
|
10
|
+
// Signal & Ledger: the e2ugh dashboard absorbed into the single interface —
|
|
11
|
+
// session via the saddlesession cookie (api) or the browser-local account
|
|
12
|
+
// (static edge), user view and admin view in the same React shell.
|
|
13
|
+
import { useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { Link, useLocation } from 'wouter';
|
|
15
|
+
import { apibase } from '../../api';
|
|
16
|
+
import { apiresult, noderole, pick } from '../../dashboardlib';
|
|
17
|
+
import { label, labelfill } from '../../labels.ts';
|
|
18
|
+
/* the explicit .ts suffix keeps the resolution unambiguous while the
|
|
19
|
+
* typed ES module that replaced the window-global localauth.js of the static edge (the original
|
|
20
|
+
* beside the typed module - the same convention the Login page uses. */
|
|
21
|
+
import { logout, probe, session as readlocalsession } from '../../localauth.ts';
|
|
22
|
+
import { AccountPanel as AccountPanel } from '../wingets';
|
|
23
|
+
import { AdminPanel as AdminPanel } from '../wingets';
|
|
24
|
+
import { CreateSandboxForm as CreateSandboxForm } from '../wingets';
|
|
25
|
+
import { DashboardEventstimeline as EventsTimeline } from '../wingets';
|
|
26
|
+
import { SandboxList as SandboxList } from '../wingets';
|
|
27
|
+
export * from '../wingets';
|
|
28
|
+
export default function Dashboard() {
|
|
29
|
+
const [, navigate] = useLocation();
|
|
30
|
+
const [phase, setphase] = useState('booting');
|
|
31
|
+
const [fatal, setfatal] = useState(null);
|
|
32
|
+
const [me, setme] = useState(null);
|
|
33
|
+
const [localview, setlocalview] = useState(null);
|
|
34
|
+
const [nodelabel, setnodelabel] = useState(label('dashboard.node.pending'));
|
|
35
|
+
const [tab, settab] = useState('user');
|
|
36
|
+
const [sandboxreload, setsandboxreload] = useState(0);
|
|
37
|
+
const [leaving, setleaving] = useState(false);
|
|
38
|
+
const tabrefs = useRef({});
|
|
39
|
+
/** decorative health read: paints the node role badge. */
|
|
40
|
+
async function loadhealth() {
|
|
41
|
+
try {
|
|
42
|
+
const result = await apiresult('/api/v1/health');
|
|
43
|
+
if (result.ok && result.body !== null && typeof result.body === 'object') {
|
|
44
|
+
setnodelabel(noderole(result.body));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* health is decorative; the badge simply stays neutral */
|
|
50
|
+
}
|
|
51
|
+
setnodelabel(label('dashboard.node.standalone'));
|
|
52
|
+
}
|
|
53
|
+
/** the account bootstrap: /auth/me fills the session or the fatal gate. */
|
|
54
|
+
async function loadme() {
|
|
55
|
+
let result;
|
|
56
|
+
try {
|
|
57
|
+
result = await apiresult('/api/v1/auth/me');
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
setfatal(label('dashboard.fatal.apiUnreachable'));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (result.status === 401 || result.status === 403) {
|
|
64
|
+
setfatal(label('dashboard.fatal.needsSession'));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!result.ok || result.body === null || typeof result.body !== 'object') {
|
|
68
|
+
setfatal(label('dashboard.fatal.payload'));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const envelope = result.body;
|
|
72
|
+
const body = envelope.user !== null && typeof envelope.user === 'object'
|
|
73
|
+
? envelope.user
|
|
74
|
+
: envelope;
|
|
75
|
+
setme({
|
|
76
|
+
username: String(pick(body, ['username', 'name', 'user'], 'unknown')),
|
|
77
|
+
role: String(pick(body, ['role'], 'user')).toLowerCase(),
|
|
78
|
+
createdat: pick(body, ['createdAt', 'created_at', 'createdat', 'registeredAt'], null),
|
|
79
|
+
lastloginat: pick(body, ['lastLoginAt', 'last_login_at', 'lastlogin', 'lastLogin'], null),
|
|
80
|
+
id: pick(body, ['id', 'uuid'], null),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/* boot: probe the api once; no answer -> the static edge takes over with
|
|
84
|
+
* the browser-local session (localauth), exactly like the original page. */
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
let cancelled = false;
|
|
87
|
+
void (async () => {
|
|
88
|
+
const answers = await probe(apibase());
|
|
89
|
+
if (cancelled) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!answers) {
|
|
93
|
+
setphase('local');
|
|
94
|
+
setnodelabel(label('dashboard.node.edge'));
|
|
95
|
+
const raw = (await readlocalsession());
|
|
96
|
+
if (raw === null || raw === undefined) {
|
|
97
|
+
setfatal(label('dashboard.fatal.noLocalSession'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const view = {
|
|
101
|
+
user: String(pick(raw, ['user', 'username'], 'unknown')),
|
|
102
|
+
role: String(pick(raw, ['role'], 'user')),
|
|
103
|
+
issuedat: Number(pick(raw, ['issuedat', 'issuedAt'], Date.now())),
|
|
104
|
+
expiresat: Number(pick(raw, ['expiresat', 'expiresAt'], 0)),
|
|
105
|
+
};
|
|
106
|
+
setlocalview(view);
|
|
107
|
+
setme({
|
|
108
|
+
username: view.user,
|
|
109
|
+
role: view.role === 'admin' ? 'admin' : 'local',
|
|
110
|
+
createdat: null,
|
|
111
|
+
lastloginat: new Date(view.issuedat).toISOString(),
|
|
112
|
+
id: null,
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
setphase('api');
|
|
117
|
+
void loadhealth();
|
|
118
|
+
void loadme();
|
|
119
|
+
})();
|
|
120
|
+
return () => {
|
|
121
|
+
cancelled = true;
|
|
122
|
+
};
|
|
123
|
+
}, []);
|
|
124
|
+
/** ends the session (cookie or local) and returns to the sign in page. */
|
|
125
|
+
async function dolgout() {
|
|
126
|
+
setleaving(true);
|
|
127
|
+
/* clears the local browser session too (no-op on the api mode) */
|
|
128
|
+
void logout();
|
|
129
|
+
try {
|
|
130
|
+
await apiresult('/api/v1/auth/logout', { method: 'POST' });
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* the cookie may already be gone; proceed to the login page */
|
|
134
|
+
}
|
|
135
|
+
navigate('/login');
|
|
136
|
+
}
|
|
137
|
+
/** selects one tab and moves the roving focus onto it. */
|
|
138
|
+
function selecttab(next) {
|
|
139
|
+
settab(next);
|
|
140
|
+
requestAnimationFrame(() => {
|
|
141
|
+
tabrefs.current[next]?.focus();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const mode = phase === 'local' ? 'local' : 'api';
|
|
145
|
+
const adminvisible = me !== null && me.role === 'admin';
|
|
146
|
+
const userbadge = me === null
|
|
147
|
+
? label('dashboard.userbadge.pending')
|
|
148
|
+
: mode === 'local'
|
|
149
|
+
? me.role === 'admin'
|
|
150
|
+
? labelfill('dashboard.userbadge.localAdmin', { name: me.username })
|
|
151
|
+
: labelfill('dashboard.userbadge.local', { name: me.username })
|
|
152
|
+
: me.role === 'admin'
|
|
153
|
+
? labelfill('dashboard.userbadge.admin', { name: me.username })
|
|
154
|
+
: me.username;
|
|
155
|
+
const roleclass = nodelabel === 'main' || nodelabel === 'clone'
|
|
156
|
+
? `dash-rolebadge ${nodelabel}`
|
|
157
|
+
: 'dash-rolebadge';
|
|
158
|
+
return (_jsx("div", { className: "dash", children: _jsxs("div", { className: "dash-wrap", children: [_jsxs("header", { className: "dash-topbar", children: [_jsx("h1", { children: _jsx(Link, { href: "/console", children: label('dashboard.brand') }) }), _jsx("span", { className: "dash-tagline", children: label('dashboard.tagline') }), _jsx("span", { className: roleclass, "aria-live": "polite", children: labelfill('dashboard.nodeBadge', { label: nodelabel }) }), _jsx("span", { className: "dash-spacer" }), _jsx("span", { className: "dash-userbadge", children: userbadge }), _jsx("button", { type: "button", "aria-label": label('dashboard.logoutAria'), disabled: leaving, onClick: () => {
|
|
159
|
+
void dolgout();
|
|
160
|
+
}, children: label('dashboard.logout') })] }), fatal !== null && (_jsxs("div", { className: "dash-panel dash-fatal", "aria-live": "polite", children: [_jsx("h2", { children: label('dashboard.fatal.title') }), _jsx("p", { children: fatal }), _jsxs("div", { className: "dash-actions", children: [_jsx(Link, { className: "dash-btn", href: "/login", children: label('dashboard.fatal.signin') }), _jsx(Link, { className: "dash-btn", href: "/console", children: label('dashboard.fatal.backConsole') })] })] })), fatal === null && (_jsxs("div", { className: "dash-tabs", role: "tablist", "aria-label": label('dashboard.tabsAria'), onKeyDown: (event) => {
|
|
161
|
+
if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (adminvisible) {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
selecttab(tab === 'user' ? 'admin' : 'user');
|
|
167
|
+
}
|
|
168
|
+
}, children: [_jsx("button", { type: "button", role: "tab", id: "tab-user", ref: (node) => {
|
|
169
|
+
tabrefs.current.user = node;
|
|
170
|
+
}, "aria-selected": tab === 'user', "aria-controls": "panel-user", tabIndex: tab === 'user' ? 0 : -1, onClick: () => {
|
|
171
|
+
selecttab('user');
|
|
172
|
+
}, children: label('dashboard.tab.user') }), adminvisible && (_jsx("button", { type: "button", role: "tab", id: "tab-admin", ref: (node) => {
|
|
173
|
+
tabrefs.current.admin = node;
|
|
174
|
+
}, "aria-selected": tab === 'admin', "aria-controls": "panel-admin", tabIndex: tab === 'admin' ? 0 : -1, onClick: () => {
|
|
175
|
+
selecttab('admin');
|
|
176
|
+
}, children: label('dashboard.tab.admin') }))] })), fatal === null && (_jsx("div", { role: "tabpanel", id: "panel-user", "aria-labelledby": "tab-user", hidden: tab !== 'user', children: _jsxs("div", { className: "dash-grid2", children: [_jsx("div", { children: _jsxs("section", { className: "dash-panel", "aria-labelledby": "boxtitle", children: [_jsx("h2", { id: "boxtitle", children: label('dashboard.panel.sandboxes') }), _jsx(CreateSandboxForm, { mode: mode, oncreated: () => {
|
|
177
|
+
setsandboxreload((key) => key + 1);
|
|
178
|
+
}, onrefresh: () => {
|
|
179
|
+
setsandboxreload((key) => key + 1);
|
|
180
|
+
} }), _jsx(SandboxList, { mode: mode, reloadkey: sandboxreload, ready: me !== null })] }) }), _jsxs("div", { children: [_jsxs("section", { className: "dash-panel", "aria-labelledby": "infotitle", children: [_jsx("h2", { id: "infotitle", children: label('dashboard.panel.account') }), _jsx(AccountPanel, { mode: mode, user: me, local: localview })] }), _jsxs("section", { className: "dash-panel", "aria-labelledby": "eventstitle", children: [_jsx("h2", { id: "eventstitle", children: label('dashboard.panel.events') }), _jsx(EventsTimeline, { mode: mode, ready: me !== null })] })] })] }) })), fatal === null && adminvisible && (_jsx("div", { role: "tabpanel", id: "panel-admin", "aria-labelledby": "tab-admin", hidden: tab !== 'admin', children: _jsx(AdminPanel, { mode: mode }) })), _jsxs("footer", { className: "dash-footer", children: [_jsx("span", { children: label('dashboard.footer.cookie') }), _jsx("span", { children: label('dashboard.footer.storage') }), _jsx("span", { style: { marginLeft: 'auto' }, children: label('dashboard.footer.api') })] })] }) }));
|
|
181
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docs page anchor — layer 3 of the anchor architecture.
|
|
3
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
4
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
5
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
6
|
+
* this file. This anchor carries the former main component of the folder,
|
|
7
|
+
* which now lives here as the page mount itself.
|
|
8
|
+
*/
|
|
9
|
+
export default function Docs(): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* docs page anchor — layer 3 of the anchor architecture.
|
|
4
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
5
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
6
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
7
|
+
* this file. This anchor carries the former main component of the folder,
|
|
8
|
+
* which now lives here as the page mount itself.
|
|
9
|
+
*/
|
|
10
|
+
// Signal & Ledger: documentation as an operations index, with short paths and preserved context.
|
|
11
|
+
import { ArrowUpRightRegular as ArrowUpRight, BookOpenRegular as BookOpen, BracesRegular as Braces, CodeRegular as FileCode2, FlagRegular as Flag, RecordRegular as GitCommitHorizontal, PlayCircleRegular as PlayCircle, } from '@fluentui/react-icons';
|
|
12
|
+
import { PageShell } from '../shell/Shell.tsx';
|
|
13
|
+
import { label, labelfill } from '../../labels.ts';
|
|
14
|
+
/** the operations index: the glyph and the two-digit index are presentation
|
|
15
|
+
* code, every word rides the store under the docs.note.* family. */
|
|
16
|
+
const docs = [
|
|
17
|
+
{ icon: BookOpen, index: '00', key: 'thesis' },
|
|
18
|
+
{ icon: Braces, index: '01', key: 'session' },
|
|
19
|
+
{ icon: GitCommitHorizontal, index: '02', key: 'repo' },
|
|
20
|
+
{ icon: FileCode2, index: '03', key: 'chain' },
|
|
21
|
+
{ icon: Flag, index: '04', key: 'gates' },
|
|
22
|
+
];
|
|
23
|
+
export default function Docs() {
|
|
24
|
+
return (_jsxs(PageShell, { section: label('docs.shell.section'), label: label('docs.shell.label'), title: label('docs.shell.title'), intro: label('docs.shell.intro'), children: [_jsxs("section", { className: "content-section split-content", children: [_jsxs("div", { children: [_jsx("p", { className: "eyebrow", children: label('docs.split.eyebrow') }), _jsx("h2", { className: "section-title", children: label('docs.split.title') })] }), _jsxs("div", { className: "prose-copy", children: [_jsx("p", { children: label('docs.split.body1') }), _jsx("p", { children: label('docs.split.body2') })] })] }), _jsxs("section", { className: "content-section docs-list", children: [_jsxs("div", { className: "content-section-heading", children: [_jsx("p", { className: "eyebrow", children: label('docs.index.eyebrow') }), _jsx("span", { className: "mono-label", children: labelfill('docs.index.mono', { n: String(docs.length) }) })] }), docs.map((doc) => {
|
|
25
|
+
const Icon = doc.icon;
|
|
26
|
+
return (_jsxs("button", { type: "button", className: "doc-row", onClick: (event) => event.preventDefault(), children: [_jsx("span", { className: "doc-index", children: doc.index }), _jsx(Icon, { fontSize: 20, strokeWidth: 1.5 }), _jsxs("div", { className: "doc-copy", children: [_jsx("span", { children: label(`docs.note.${doc.key}.meta`) }), _jsx("strong", { children: label(`docs.note.${doc.key}.title`) }), _jsx("p", { children: label(`docs.note.${doc.key}.body`) })] }), _jsx(ArrowUpRight, { fontSize: 17 })] }, doc.key));
|
|
27
|
+
})] }), _jsxs("section", { className: "content-section docs-cta", children: [_jsx(PlayCircle, { fontSize: 22 }), _jsxs("div", { children: [_jsx("p", { className: "eyebrow", children: label('docs.cta.eyebrow') }), _jsx("h3", { children: label('docs.cta.title') }), _jsx("p", { children: label('docs.cta.body') })] }), _jsxs("a", { href: "https://github.com/wenathlan/saddle", target: "_blank", rel: "noreferrer", className: "button button-dark", children: [label('docs.cta.link'), _jsx(ArrowUpRight, { fontSize: 15 })] })] })] }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* home page anchor — layer 3 of the anchor architecture.
|
|
3
|
+
* The file carrying the folder's own name is the path manager of the page:
|
|
4
|
+
* it imports the loose components beside it, mounts the page and re-exports
|
|
5
|
+
* the public component surface. Only the theme anchor (Sol/Sol.tsx) consumes
|
|
6
|
+
* this file. This anchor carries the former main component of the folder,
|
|
7
|
+
* which now lives here as the page mount itself.
|
|
8
|
+
*
|
|
9
|
+
* R3-saddle: home is the LANDING of the platform — one sand light over the
|
|
10
|
+
* window stage, the prompt-giga field where the operator declares a sandbox
|
|
11
|
+
* (a giant mono input with the embedded boot key and the real declared
|
|
12
|
+
* vocabulary of sandboxprofile.ts as chips), the sandbox matrix as a
|
|
13
|
+
* hairline ledger of the three runtime bases (base / guests / arch / vgpu /
|
|
14
|
+
* ceiling — the documented development bootstrap limits of
|
|
15
|
+
* sandboxenvprofile.ts), the thesis, the runtime chain, the surfaces
|
|
16
|
+
* ledger, the 01–03 steps and the footer meta-quad. The boot key parses the
|
|
17
|
+
* draft against the declared vocabulary and hands the parsed declaration to
|
|
18
|
+
* the console over the `saddle.declared` session key — the console reads
|
|
19
|
+
* and spends it once on mount (a real handoff: the hardware identities stay
|
|
20
|
+
* caller choices there).
|
|
21
|
+
*
|
|
22
|
+
* The flow law rides this anchor: the default export is the ENTRY GATE
|
|
23
|
+
* (entrygate.tsx, beside this anchor) — the seen flags are consulted before
|
|
24
|
+
* the landing shows, an unfinished flow is replaced at /intro or
|
|
25
|
+
* /onboarding, and only a visitor that finished both stages ever sees the
|
|
26
|
+
* surface below.
|
|
27
|
+
*/
|
|
28
|
+
export * from '../wingets';
|
|
29
|
+
/**
|
|
30
|
+
* The home page anchor: the entry gate rides the surface — the flow law
|
|
31
|
+
* (intro → onboarding → the platform) is consulted before the home shows.
|
|
32
|
+
*
|
|
33
|
+
* @returns the gated home element.
|
|
34
|
+
*/
|
|
35
|
+
export default function Home(): import("react").JSX.Element;
|