open-managed-agents 0.1.0
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/LICENSE +93 -0
- package/README.md +248 -0
- package/bin/oma.mjs +499 -0
- package/dist/scripts/alpha-openai-compatible-fixture.mjs +134 -0
- package/dist/scripts/alpha-smoke-models.mjs +92 -0
- package/dist/scripts/alpha-smoke.mjs +581 -0
- package/dist/scripts/oma-doctor.js +230 -0
- package/dist/scripts/oma-models.js +299 -0
- package/dist/scripts/oma-workspaces.js +133 -0
- package/dist/src/control-plane/admin/auth.js +43 -0
- package/dist/src/control-plane/admin/routes.js +76 -0
- package/dist/src/control-plane/admin/service.js +102 -0
- package/dist/src/control-plane/admission.js +90 -0
- package/dist/src/control-plane/agents/routes.js +63 -0
- package/dist/src/control-plane/agents/service.js +687 -0
- package/dist/src/control-plane/agents/store.js +391 -0
- package/dist/src/control-plane/agents/types.js +1 -0
- package/dist/src/control-plane/api-constants.js +3 -0
- package/dist/src/control-plane/app.js +907 -0
- package/dist/src/control-plane/console/auth.js +68 -0
- package/dist/src/control-plane/console/static.js +112 -0
- package/dist/src/control-plane/deployment-runtime-config.js +328 -0
- package/dist/src/control-plane/deployment-runtime-event-coordinator.js +25 -0
- package/dist/src/control-plane/deployment-runtime-turn-guard.js +14 -0
- package/dist/src/control-plane/deployment-session-coordinator.js +25 -0
- package/dist/src/control-plane/deployment-session-output-coordinator.js +27 -0
- package/dist/src/control-plane/deployment-storage.js +354 -0
- package/dist/src/control-plane/egress/image.js +48 -0
- package/dist/src/control-plane/egress/policy.js +571 -0
- package/dist/src/control-plane/egress/presets.js +77 -0
- package/dist/src/control-plane/egress/proxy.js +72 -0
- package/dist/src/control-plane/egress/ssrf.js +106 -0
- package/dist/src/control-plane/egress/utils/debug.js +14 -0
- package/dist/src/control-plane/egress/vendor/http-proxy.js +335 -0
- package/dist/src/control-plane/egress/vendor/mitm-ca.js +226 -0
- package/dist/src/control-plane/egress/vendor/mitm-leaf.js +124 -0
- package/dist/src/control-plane/egress/vendor/parent-proxy.js +438 -0
- package/dist/src/control-plane/egress/vendor/request-filter.js +105 -0
- package/dist/src/control-plane/egress/vendor/sandbox-config.js +1 -0
- package/dist/src/control-plane/egress/vendor/tls-terminate-proxy.js +269 -0
- package/dist/src/control-plane/environments/routes.js +54 -0
- package/dist/src/control-plane/environments/service.js +112 -0
- package/dist/src/control-plane/environments/store.js +132 -0
- package/dist/src/control-plane/environments/types.js +1 -0
- package/dist/src/control-plane/errors.js +81 -0
- package/dist/src/control-plane/events/broadcaster.js +217 -0
- package/dist/src/control-plane/events/constants.js +2 -0
- package/dist/src/control-plane/events/persist.js +39 -0
- package/dist/src/control-plane/events/request.js +190 -0
- package/dist/src/control-plane/events/routes.js +159 -0
- package/dist/src/control-plane/events/runtime-helpers.js +134 -0
- package/dist/src/control-plane/events/service.js +1985 -0
- package/dist/src/control-plane/events/session-guards.js +29 -0
- package/dist/src/control-plane/events/sse.js +6 -0
- package/dist/src/control-plane/events/store.js +772 -0
- package/dist/src/control-plane/events/tool-persistence.js +102 -0
- package/dist/src/control-plane/events/types.js +21 -0
- package/dist/src/control-plane/files/routes.js +121 -0
- package/dist/src/control-plane/files/service.js +65 -0
- package/dist/src/control-plane/files/store-common.js +87 -0
- package/dist/src/control-plane/files/store-local.js +488 -0
- package/dist/src/control-plane/files/store-memory.js +270 -0
- package/dist/src/control-plane/files/store.js +2 -0
- package/dist/src/control-plane/files/types.js +7 -0
- package/dist/src/control-plane/http.js +25 -0
- package/dist/src/control-plane/ids.js +43 -0
- package/dist/src/control-plane/logging.js +263 -0
- package/dist/src/control-plane/models/auth-storage-backend.js +238 -0
- package/dist/src/control-plane/models/catalog.js +78 -0
- package/dist/src/control-plane/models/config-security.js +376 -0
- package/dist/src/control-plane/models/deployment-config.js +93 -0
- package/dist/src/control-plane/models/routes.js +32 -0
- package/dist/src/control-plane/models/service.js +138 -0
- package/dist/src/control-plane/observability/instruments.js +65 -0
- package/dist/src/control-plane/observability/metrics.js +125 -0
- package/dist/src/control-plane/observability/routes.js +95 -0
- package/dist/src/control-plane/openapi/document.js +282 -0
- package/dist/src/control-plane/openapi/routes.js +78 -0
- package/dist/src/control-plane/request-idempotency.js +85 -0
- package/dist/src/control-plane/secrets/envelope.js +132 -0
- package/dist/src/control-plane/secrets/master-key.js +44 -0
- package/dist/src/control-plane/secrets/routes.js +20 -0
- package/dist/src/control-plane/secrets/service.js +71 -0
- package/dist/src/control-plane/secrets/store.js +212 -0
- package/dist/src/control-plane/secrets/types.js +3 -0
- package/dist/src/control-plane/sessions/pi/custom-tools.js +146 -0
- package/dist/src/control-plane/sessions/pi/mcp/bridge.js +527 -0
- package/dist/src/control-plane/sessions/pi/mcp/client.js +157 -0
- package/dist/src/control-plane/sessions/pi/mcp/credential.js +28 -0
- package/dist/src/control-plane/sessions/pi/mcp/fetch.js +69 -0
- package/dist/src/control-plane/sessions/pi/mcp/probe.js +202 -0
- package/dist/src/control-plane/sessions/pi/mcp/runtime.js +13 -0
- package/dist/src/control-plane/sessions/pi/runner.js +1104 -0
- package/dist/src/control-plane/sessions/pi/sandbox/cma-glob.js +388 -0
- package/dist/src/control-plane/sessions/pi/sandbox/cma-grep.js +124 -0
- package/dist/src/control-plane/sessions/pi/sandbox/docker-egress.js +347 -0
- package/dist/src/control-plane/sessions/pi/sandbox/docker.js +1589 -0
- package/dist/src/control-plane/sessions/pi/sandbox/glob.js +48 -0
- package/dist/src/control-plane/sessions/pi/sandbox/image.js +7 -0
- package/dist/src/control-plane/sessions/pi/sandbox/microsandbox.js +1677 -0
- package/dist/src/control-plane/sessions/pi/sandbox/provider.js +561 -0
- package/dist/src/control-plane/sessions/pi/sandbox/selection.js +168 -0
- package/dist/src/control-plane/sessions/pi/span-normalizer.js +82 -0
- package/dist/src/control-plane/sessions/pi/tool-permissions.js +392 -0
- package/dist/src/control-plane/sessions/pi/translator.js +100 -0
- package/dist/src/control-plane/sessions/request.js +164 -0
- package/dist/src/control-plane/sessions/resources.js +63 -0
- package/dist/src/control-plane/sessions/routes.js +88 -0
- package/dist/src/control-plane/sessions/serialize.js +24 -0
- package/dist/src/control-plane/sessions/service.js +733 -0
- package/dist/src/control-plane/sessions/store.js +538 -0
- package/dist/src/control-plane/sessions/types.js +1 -0
- package/dist/src/control-plane/skills/archive.js +169 -0
- package/dist/src/control-plane/skills/routes.js +41 -0
- package/dist/src/control-plane/skills/service.js +29 -0
- package/dist/src/control-plane/skills/store.js +233 -0
- package/dist/src/control-plane/skills/types.js +5 -0
- package/dist/src/control-plane/sqlite-transaction.js +15 -0
- package/dist/src/control-plane/vaults/mcp-oauth-validate.js +165 -0
- package/dist/src/control-plane/vaults/oauth-refresh-ticker.js +43 -0
- package/dist/src/control-plane/vaults/oauth-refresh.js +448 -0
- package/dist/src/control-plane/vaults/routes.js +66 -0
- package/dist/src/control-plane/vaults/service.js +553 -0
- package/dist/src/control-plane/vaults/store.js +691 -0
- package/dist/src/control-plane/vaults/types.js +1 -0
- package/dist/src/control-plane/wake-loop.js +65 -0
- package/dist/src/control-plane/wiring.js +92 -0
- package/dist/src/control-plane/workspace.js +4 -0
- package/dist/src/control-plane/workspaces/store.js +158 -0
- package/dist/src/egress-proxy-main.js +103 -0
- package/dist/src/main.js +124 -0
- package/dist/src/types/agents.js +1 -0
- package/dist/src/types/common.js +1 -0
- package/dist/src/types/environments.js +1 -0
- package/dist/src/types/events.js +121 -0
- package/dist/src/types/files.js +1 -0
- package/dist/src/types/json.js +19 -0
- package/dist/src/types/sessions.js +1 -0
- package/dist/ui/managed-agents-console/README.md +52 -0
- package/dist/ui/managed-agents-console/docs/agents.md +23 -0
- package/dist/ui/managed-agents-console/docs/console.md +23 -0
- package/dist/ui/managed-agents-console/docs/dreams.md +5 -0
- package/dist/ui/managed-agents-console/docs/environments.md +27 -0
- package/dist/ui/managed-agents-console/docs/events.md +19 -0
- package/dist/ui/managed-agents-console/docs/files.md +17 -0
- package/dist/ui/managed-agents-console/docs/github.md +11 -0
- package/dist/ui/managed-agents-console/docs/integrations.md +19 -0
- package/dist/ui/managed-agents-console/docs/memory.md +11 -0
- package/dist/ui/managed-agents-console/docs/migration.md +17 -0
- package/dist/ui/managed-agents-console/docs/multiagent.md +11 -0
- package/dist/ui/managed-agents-console/docs/outcomes.md +11 -0
- package/dist/ui/managed-agents-console/docs/overview.md +41 -0
- package/dist/ui/managed-agents-console/docs/permissions.md +24 -0
- package/dist/ui/managed-agents-console/docs/quickstart.md +51 -0
- package/dist/ui/managed-agents-console/docs/reference.md +27 -0
- package/dist/ui/managed-agents-console/docs/sandbox-reference.md +19 -0
- package/dist/ui/managed-agents-console/docs/sandbox-security.md +15 -0
- package/dist/ui/managed-agents-console/docs/scheduled-deployments.md +5 -0
- package/dist/ui/managed-agents-console/docs/self-hosted-sandboxes.md +15 -0
- package/dist/ui/managed-agents-console/docs/session-operations.md +21 -0
- package/dist/ui/managed-agents-console/docs/sessions.md +21 -0
- package/dist/ui/managed-agents-console/docs/skills.md +15 -0
- package/dist/ui/managed-agents-console/docs/tools.md +23 -0
- package/dist/ui/managed-agents-console/docs/vaults.md +19 -0
- package/dist/ui/managed-agents-console/docs/webhooks.md +11 -0
- package/dist/ui/managed-agents-console/index.html +47 -0
- package/dist/ui/managed-agents-console/serve.mjs +116 -0
- package/dist/ui/managed-agents-console/src/agents-files.jsx +273 -0
- package/dist/ui/managed-agents-console/src/api.js +1043 -0
- package/dist/ui/managed-agents-console/src/app.jsx +633 -0
- package/dist/ui/managed-agents-console/src/auth.jsx +215 -0
- package/dist/ui/managed-agents-console/src/console.css +733 -0
- package/dist/ui/managed-agents-console/src/data.js +188 -0
- package/dist/ui/managed-agents-console/src/detail.jsx +719 -0
- package/dist/ui/managed-agents-console/src/docs.jsx +200 -0
- package/dist/ui/managed-agents-console/src/environments.jsx +365 -0
- package/dist/ui/managed-agents-console/src/forms.jsx +494 -0
- package/dist/ui/managed-agents-console/src/icons.jsx +48 -0
- package/dist/ui/managed-agents-console/src/skills.jsx +21 -0
- package/dist/ui/managed-agents-console/src/sse.js +185 -0
- package/dist/ui/managed-agents-console/src/states.jsx +90 -0
- package/dist/ui/managed-agents-console/src/tweaks-panel.jsx +541 -0
- package/dist/ui/managed-agents-console/src/ui.jsx +190 -0
- package/dist/ui/managed-agents-console/src/vaults-data.js +89 -0
- package/dist/ui/managed-agents-console/src/vaults.jsx +171 -0
- package/dist/ui/managed-agents-console/vendor/babel.min.js +4 -0
- package/dist/ui/managed-agents-console/vendor/react-dom.production.min.js +267 -0
- package/dist/ui/managed-agents-console/vendor/react.production.min.js +31 -0
- package/dist/ui/openapi-docs/VENDOR.md +27 -0
- package/dist/ui/openapi-docs/index.html +16 -0
- package/dist/ui/openapi-docs/swagger-initializer.js +14 -0
- package/dist/ui/openapi-docs/vendor/LICENSE +202 -0
- package/dist/ui/openapi-docs/vendor/NOTICE +2 -0
- package/dist/ui/openapi-docs/vendor/swagger-ui-bundle.js +2 -0
- package/dist/ui/openapi-docs/vendor/swagger-ui-standalone-preset.js +2 -0
- package/dist/ui/openapi-docs/vendor/swagger-ui.css +3 -0
- package/package.json +53 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;
|
|
2
|
+
const DEFAULT_MAX_RECONNECTS = 5;
|
|
3
|
+
const DEFAULT_RECONNECT_DELAY_MS = 250;
|
|
4
|
+
|
|
5
|
+
export class SseFrameParser {
|
|
6
|
+
constructor({ maxFrameBytes = DEFAULT_MAX_FRAME_BYTES } = {}) {
|
|
7
|
+
this.maxFrameBytes = maxFrameBytes;
|
|
8
|
+
this.buffer = "";
|
|
9
|
+
this.eventType = "message";
|
|
10
|
+
this.eventId = "";
|
|
11
|
+
this.dataLines = [];
|
|
12
|
+
this.frameBytes = 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
push(text) {
|
|
16
|
+
this.buffer += text;
|
|
17
|
+
const events = [];
|
|
18
|
+
while (true) {
|
|
19
|
+
const newline = this.buffer.indexOf("\n");
|
|
20
|
+
if (newline < 0) break;
|
|
21
|
+
let line = this.buffer.slice(0, newline);
|
|
22
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
23
|
+
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
24
|
+
const event = this.consumeLine(line);
|
|
25
|
+
if (event) events.push(event);
|
|
26
|
+
}
|
|
27
|
+
this.ensureBounded(this.buffer);
|
|
28
|
+
return events;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
consumeLine(line) {
|
|
32
|
+
this.addFrameBytes(`${line}\n`);
|
|
33
|
+
if (line === "") return this.dispatch();
|
|
34
|
+
if (line.startsWith(":")) return null;
|
|
35
|
+
const separator = line.indexOf(":");
|
|
36
|
+
const field = separator < 0 ? line : line.slice(0, separator);
|
|
37
|
+
let value = separator < 0 ? "" : line.slice(separator + 1);
|
|
38
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
39
|
+
if (field === "event") this.eventType = value || "message";
|
|
40
|
+
else if (field === "id" && !value.includes("\0")) this.eventId = value;
|
|
41
|
+
else if (field === "data") this.dataLines.push(value);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
dispatch() {
|
|
46
|
+
if (this.dataLines.length === 0) {
|
|
47
|
+
this.resetFrame();
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const event = {
|
|
51
|
+
id: this.eventId,
|
|
52
|
+
type: this.eventType,
|
|
53
|
+
data: this.dataLines.join("\n"),
|
|
54
|
+
};
|
|
55
|
+
this.resetFrame();
|
|
56
|
+
return event;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addFrameBytes(value) {
|
|
60
|
+
this.frameBytes += new TextEncoder().encode(value).byteLength;
|
|
61
|
+
if (this.frameBytes > this.maxFrameBytes) {
|
|
62
|
+
throw new Error("Session event stream frame exceeds the console limit");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ensureBounded(value) {
|
|
67
|
+
const pendingBytes = new TextEncoder().encode(value).byteLength;
|
|
68
|
+
if (this.frameBytes + pendingBytes > this.maxFrameBytes) {
|
|
69
|
+
throw new Error("Session event stream frame exceeds the console limit");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
resetFrame() {
|
|
74
|
+
this.eventType = "message";
|
|
75
|
+
this.eventId = "";
|
|
76
|
+
this.dataLines = [];
|
|
77
|
+
this.frameBytes = 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function followEventStream({
|
|
82
|
+
url,
|
|
83
|
+
headers,
|
|
84
|
+
signal,
|
|
85
|
+
onEvent,
|
|
86
|
+
onState = () => {},
|
|
87
|
+
fetchImpl = fetch,
|
|
88
|
+
lastEventId,
|
|
89
|
+
maxReconnects = DEFAULT_MAX_RECONNECTS,
|
|
90
|
+
reconnectDelayMs = DEFAULT_RECONNECT_DELAY_MS,
|
|
91
|
+
maxFrameBytes = DEFAULT_MAX_FRAME_BYTES,
|
|
92
|
+
}) {
|
|
93
|
+
let cursor = lastEventId || null;
|
|
94
|
+
let reconnects = 0;
|
|
95
|
+
const seen = new Set();
|
|
96
|
+
const seenOrder = [];
|
|
97
|
+
|
|
98
|
+
while (!signal?.aborted) {
|
|
99
|
+
const requestHeaders = { ...headers };
|
|
100
|
+
if (cursor) requestHeaders["last-event-id"] = cursor;
|
|
101
|
+
try {
|
|
102
|
+
const response = await fetchImpl(url, {
|
|
103
|
+
method: "GET",
|
|
104
|
+
headers: requestHeaders,
|
|
105
|
+
signal,
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const error = new Error(`Session event stream failed (${response.status})`);
|
|
109
|
+
error.status = response.status;
|
|
110
|
+
if (response.status < 500) throw terminal(error);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
const contentType = response.headers?.get?.("content-type") ?? "";
|
|
114
|
+
if (!contentType.toLowerCase().includes("text/event-stream")) {
|
|
115
|
+
throw terminal(new Error("Session event stream returned an unexpected content type"));
|
|
116
|
+
}
|
|
117
|
+
if (!response.body) throw new Error("Session event stream returned no body");
|
|
118
|
+
onState({ status: "connected", lastEventId: cursor });
|
|
119
|
+
const reader = response.body.getReader();
|
|
120
|
+
const decoder = new TextDecoder();
|
|
121
|
+
const parser = new SseFrameParser({ maxFrameBytes });
|
|
122
|
+
try {
|
|
123
|
+
while (!signal?.aborted) {
|
|
124
|
+
const next = await reader.read();
|
|
125
|
+
if (next.done) break;
|
|
126
|
+
const frames = parser.push(decoder.decode(next.value, { stream: true }));
|
|
127
|
+
for (const frame of frames) {
|
|
128
|
+
if (frame.id && seen.has(frame.id)) continue;
|
|
129
|
+
let event;
|
|
130
|
+
try {
|
|
131
|
+
event = JSON.parse(frame.data);
|
|
132
|
+
} catch {
|
|
133
|
+
throw terminal(new Error("Session event stream returned invalid JSON"));
|
|
134
|
+
}
|
|
135
|
+
if (frame.id) {
|
|
136
|
+
cursor = frame.id;
|
|
137
|
+
rememberSeen(seen, seenOrder, frame.id);
|
|
138
|
+
}
|
|
139
|
+
await onEvent(event, { id: frame.id, type: frame.type });
|
|
140
|
+
reconnects = 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} finally {
|
|
144
|
+
await reader.cancel().catch(() => {});
|
|
145
|
+
}
|
|
146
|
+
if (signal?.aborted) break;
|
|
147
|
+
throw new Error("Session event stream closed");
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (signal?.aborted || error?.name === "AbortError") break;
|
|
150
|
+
if (error?.terminal || reconnects >= maxReconnects) {
|
|
151
|
+
onState({ status: "failed", error, lastEventId: cursor });
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
reconnects += 1;
|
|
155
|
+
onState({ status: "reconnecting", attempt: reconnects, error, lastEventId: cursor });
|
|
156
|
+
await abortableDelay(reconnectDelayMs * reconnects, signal);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
onState({ status: "closed", lastEventId: cursor });
|
|
160
|
+
return cursor;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function terminal(error) {
|
|
164
|
+
error.terminal = true;
|
|
165
|
+
return error;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function rememberSeen(seen, order, id) {
|
|
169
|
+
seen.add(id);
|
|
170
|
+
order.push(id);
|
|
171
|
+
if (order.length > 2048) seen.delete(order.shift());
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function abortableDelay(ms, signal) {
|
|
175
|
+
if (signal?.aborted) return Promise.resolve();
|
|
176
|
+
return new Promise((resolve) => {
|
|
177
|
+
const timeout = setTimeout(done, ms);
|
|
178
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
179
|
+
function done() {
|
|
180
|
+
clearTimeout(timeout);
|
|
181
|
+
signal?.removeEventListener("abort", done);
|
|
182
|
+
resolve();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// states.jsx — loading skeletons, empty states, error envelope → window
|
|
2
|
+
// Anthropic-shaped error envelope for the error state.
|
|
3
|
+
function errEnvelope(resource) {
|
|
4
|
+
return JSON.stringify({
|
|
5
|
+
type:'error',
|
|
6
|
+
error:{ type:'api_error', message:`Failed to load ${resource}. The upstream OMA server returned an internal error.` },
|
|
7
|
+
request_id:'req_011CRvH9b2Qm4kZ2nXa7TfP',
|
|
8
|
+
}, null, 2);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// skeleton table — cols: array of widths (number=px fixed, 'grow'=flex)
|
|
12
|
+
function SkeletonTable({ rows = 6, cols = ['grow', 90, 160, 70], lead = true }) {
|
|
13
|
+
return (
|
|
14
|
+
<div className="panel" aria-busy="true">
|
|
15
|
+
{Array.from({ length: rows }).map((_, i) => (
|
|
16
|
+
<div className="skel-row" key={i}>
|
|
17
|
+
{lead && <span className="skel skel-dot" />}
|
|
18
|
+
{cols.map((c, j) => {
|
|
19
|
+
if (c === 'grow') return <span key={j} className="skel" style={{ height:11, flex:1, maxWidth: 120 + (i * 37 % 180) }} />;
|
|
20
|
+
if (typeof c === 'string' && c === 'pill') return <span key={j} className="skel skel-pill" style={{ width:84, flex:'0 0 auto' }} />;
|
|
21
|
+
return <span key={j} className="skel" style={{ height:11, width:c, flex:'0 0 auto' }} />;
|
|
22
|
+
})}
|
|
23
|
+
</div>
|
|
24
|
+
))}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function EmptyState({ icon = 'folder', title, message, actionLabel, onAction, secondaryLabel, onSecondary }) {
|
|
30
|
+
return (
|
|
31
|
+
<div className="panel">
|
|
32
|
+
<div className="state">
|
|
33
|
+
<div className="state-ic"><Icon name={icon} size={22} /></div>
|
|
34
|
+
<h3>{title}</h3>
|
|
35
|
+
<p>{message}</p>
|
|
36
|
+
{(actionLabel || secondaryLabel) && (
|
|
37
|
+
<div className="actions">
|
|
38
|
+
{secondaryLabel && <button className="btn" onClick={onSecondary}>{secondaryLabel}</button>}
|
|
39
|
+
{actionLabel && <button className="btn btn-primary" onClick={onAction}><Icon name="plus" size={15} />{actionLabel}</button>}
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ErrorState({ resource = 'data', onRetry }) {
|
|
48
|
+
return (
|
|
49
|
+
<div className="panel">
|
|
50
|
+
<div className="state">
|
|
51
|
+
<div className="state-ic err"><Icon name="alert" size={22} /></div>
|
|
52
|
+
<h3>Couldn’t load {resource}</h3>
|
|
53
|
+
<p>The request to the OMA control plane failed. Check that the local server is running, then retry.</p>
|
|
54
|
+
<div className="err-envelope">
|
|
55
|
+
<div className="code scroll"><pre>{errEnvelope(resource)}</pre></div>
|
|
56
|
+
<div className="req"><Icon name="hash" size={13} />request_id <span className="mono">req_011CRvH9b2Qm4kZ2nXa7TfP</span></div>
|
|
57
|
+
</div>
|
|
58
|
+
<div className="actions">
|
|
59
|
+
<button className="btn btn-primary" onClick={onRetry}><Icon name="refresh" size={15} />Retry</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function PartialNotice({ resource = 'data' }) {
|
|
67
|
+
return (
|
|
68
|
+
<div className="inline-warn">
|
|
69
|
+
<Icon name="alert" size={14} />
|
|
70
|
+
<span>{resource} reached the 100-page safety cap; this view may be incomplete.</span>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// inline stream skeleton (event rows)
|
|
76
|
+
function SkeletonStream({ rows = 5 }) {
|
|
77
|
+
return (
|
|
78
|
+
<div className="panel" aria-busy="true">
|
|
79
|
+
{Array.from({ length: rows }).map((_, i) => (
|
|
80
|
+
<div className="skel-row" key={i}>
|
|
81
|
+
<span className="skel skel-pill" style={{ width:52, flex:'0 0 auto' }} />
|
|
82
|
+
<span className="skel" style={{ height:11, flex:1, maxWidth: 200 + (i * 53 % 220) }} />
|
|
83
|
+
<span className="skel" style={{ height:10, width:46, flex:'0 0 auto', marginLeft:'auto' }} />
|
|
84
|
+
</div>
|
|
85
|
+
))}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
Object.assign(window, { SkeletonTable, SkeletonStream, EmptyState, ErrorState, PartialNotice });
|