@le-space/ui 0.1.54 → 0.1.56
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/package.json +9 -1
- package/react/index.d.ts +17 -0
- package/react/index.js +983 -124
- package/shared/index.d.ts +27 -1
- package/shared/index.js +398 -21
- package/le-space-ui-0.1.54.tgz +0 -0
package/react/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/react/SponsorRelayFab.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
1
4
|
// src/shared/constants.ts
|
|
2
5
|
var DEFAULT_INSTANCE_NAME = "sponsor-relay";
|
|
3
6
|
var DEFAULT_MANIFEST_URL = "./rootfs-manifest.json";
|
|
@@ -17,6 +20,16 @@ var RELAY_PING_IDLE_STATE = {
|
|
|
17
20
|
lastReceivedAt: null,
|
|
18
21
|
error: null
|
|
19
22
|
};
|
|
23
|
+
var IDLE_DEPLOYMENT_PROGRESS = {
|
|
24
|
+
stage: "idle",
|
|
25
|
+
label: "Ready",
|
|
26
|
+
progress: 0,
|
|
27
|
+
status: "info",
|
|
28
|
+
itemHash: null,
|
|
29
|
+
detail: null,
|
|
30
|
+
error: null,
|
|
31
|
+
timestamp: Date.now()
|
|
32
|
+
};
|
|
20
33
|
var REFRESH_INTERVAL_MS = 3e4;
|
|
21
34
|
var RELAY_PING_INTERVAL_MS = 2e4;
|
|
22
35
|
|
|
@@ -696,18 +709,34 @@ function resolveManifestSource(args) {
|
|
|
696
709
|
}
|
|
697
710
|
|
|
698
711
|
// src/shared/wallet-controller.ts
|
|
712
|
+
import { keccak_256 } from "@noble/hashes/sha3";
|
|
699
713
|
function getEthereumProvider() {
|
|
700
714
|
return globalThis.window?.ethereum ?? null;
|
|
701
715
|
}
|
|
716
|
+
function toChecksumAddress(address) {
|
|
717
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
718
|
+
throw new Error("Invalid EVM address.");
|
|
719
|
+
}
|
|
720
|
+
const normalized = address.slice(2).toLowerCase();
|
|
721
|
+
const hash = Array.from(keccak_256(new TextEncoder().encode(normalized))).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
722
|
+
let result = "0x";
|
|
723
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
724
|
+
result += Number.parseInt(hash[index], 16) >= 8 ? normalized[index].toUpperCase() : normalized[index];
|
|
725
|
+
}
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
702
728
|
async function connectWallet(provider = getEthereumProvider()) {
|
|
703
729
|
if (!provider) {
|
|
704
730
|
throw new Error("MetaMask provider not found.");
|
|
705
731
|
}
|
|
706
|
-
const accounts = await provider.request({
|
|
732
|
+
const accounts = await provider.request({
|
|
733
|
+
method: "eth_requestAccounts"
|
|
734
|
+
});
|
|
707
735
|
const chainId = await provider.request({ method: "eth_chainId" });
|
|
736
|
+
const address = accounts[0] ? toChecksumAddress(accounts[0]) : null;
|
|
708
737
|
return {
|
|
709
|
-
connected: Boolean(
|
|
710
|
-
address
|
|
738
|
+
connected: Boolean(address),
|
|
739
|
+
address,
|
|
711
740
|
chainId,
|
|
712
741
|
isMetaMask: Boolean(provider.isMetaMask)
|
|
713
742
|
};
|
|
@@ -963,6 +992,16 @@ async function createUnsignedForgetMessage(args) {
|
|
|
963
992
|
};
|
|
964
993
|
}
|
|
965
994
|
async function forgetAlephMessages(args) {
|
|
995
|
+
args.onProgress?.({
|
|
996
|
+
stage: "building-delete-message",
|
|
997
|
+
label: "Building delete message",
|
|
998
|
+
progress: 18,
|
|
999
|
+
status: "info",
|
|
1000
|
+
itemHash: null,
|
|
1001
|
+
detail: [...new Set((args.hashes ?? []).filter(Boolean))].join(", ") || null,
|
|
1002
|
+
error: null,
|
|
1003
|
+
timestamp: Date.now()
|
|
1004
|
+
});
|
|
966
1005
|
const unsignedMessage = await createUnsignedForgetMessage({
|
|
967
1006
|
sender: args.sender,
|
|
968
1007
|
hashes: args.hashes,
|
|
@@ -972,18 +1011,49 @@ async function forgetAlephMessages(args) {
|
|
|
972
1011
|
channel: args.channel,
|
|
973
1012
|
now: args.now
|
|
974
1013
|
});
|
|
1014
|
+
args.onProgress?.({
|
|
1015
|
+
stage: "signing-delete-message",
|
|
1016
|
+
label: "Waiting for delete signature",
|
|
1017
|
+
progress: 42,
|
|
1018
|
+
status: "info",
|
|
1019
|
+
itemHash: unsignedMessage.item_hash,
|
|
1020
|
+
detail: unsignedMessage.item_hash,
|
|
1021
|
+
error: null,
|
|
1022
|
+
timestamp: Date.now()
|
|
1023
|
+
});
|
|
975
1024
|
const message = await signAlephMessage(unsignedMessage, args.signer);
|
|
1025
|
+
args.onProgress?.({
|
|
1026
|
+
stage: "broadcasting-delete",
|
|
1027
|
+
label: "Broadcasting delete to Aleph",
|
|
1028
|
+
progress: 68,
|
|
1029
|
+
status: "warning",
|
|
1030
|
+
itemHash: message.item_hash,
|
|
1031
|
+
detail: message.item_hash,
|
|
1032
|
+
error: null,
|
|
1033
|
+
timestamp: Date.now()
|
|
1034
|
+
});
|
|
976
1035
|
const { response, httpStatus } = await broadcastAlephMessage2(message, {
|
|
977
1036
|
apiHost: args.apiHost,
|
|
978
1037
|
sync: args.sync,
|
|
979
1038
|
fetch: args.fetch
|
|
980
1039
|
});
|
|
1040
|
+
const status = normalizeBroadcastStatus(httpStatus, response?.message_status);
|
|
1041
|
+
args.onProgress?.({
|
|
1042
|
+
stage: status === "rejected" ? "error" : "delete-completed",
|
|
1043
|
+
label: status === "rejected" ? "Delete rejected by Aleph" : "Delete submitted to Aleph",
|
|
1044
|
+
progress: 100,
|
|
1045
|
+
status: status === "rejected" ? "error" : "success",
|
|
1046
|
+
itemHash: message.item_hash,
|
|
1047
|
+
detail: status === "rejected" ? String(response?.details ?? "Aleph rejected this delete request.") : null,
|
|
1048
|
+
error: status === "rejected" ? String(response?.details ?? "Aleph rejected this delete request.") : null,
|
|
1049
|
+
timestamp: Date.now()
|
|
1050
|
+
});
|
|
981
1051
|
return {
|
|
982
1052
|
sender: args.sender,
|
|
983
1053
|
itemHash: message.item_hash,
|
|
984
1054
|
response,
|
|
985
1055
|
httpStatus,
|
|
986
|
-
status
|
|
1056
|
+
status
|
|
987
1057
|
};
|
|
988
1058
|
}
|
|
989
1059
|
|
|
@@ -1090,6 +1160,16 @@ async function createUnsignedInstanceMessage(args) {
|
|
|
1090
1160
|
};
|
|
1091
1161
|
}
|
|
1092
1162
|
async function deployInstance(args) {
|
|
1163
|
+
args.onProgress?.({
|
|
1164
|
+
stage: "building-message",
|
|
1165
|
+
label: "Building deployment message",
|
|
1166
|
+
progress: 32,
|
|
1167
|
+
status: "info",
|
|
1168
|
+
detail: args.content.metadata?.name ?? null,
|
|
1169
|
+
itemHash: null,
|
|
1170
|
+
error: null,
|
|
1171
|
+
timestamp: Date.now()
|
|
1172
|
+
});
|
|
1093
1173
|
const unsignedMessage = await createUnsignedInstanceMessage({
|
|
1094
1174
|
sender: args.sender,
|
|
1095
1175
|
content: args.content,
|
|
@@ -1097,17 +1177,47 @@ async function deployInstance(args) {
|
|
|
1097
1177
|
channel: args.channel,
|
|
1098
1178
|
now: args.now
|
|
1099
1179
|
});
|
|
1180
|
+
args.onProgress?.({
|
|
1181
|
+
stage: "signing-message",
|
|
1182
|
+
label: "Waiting for MetaMask signature",
|
|
1183
|
+
progress: 48,
|
|
1184
|
+
status: "info",
|
|
1185
|
+
detail: unsignedMessage.item_hash,
|
|
1186
|
+
itemHash: unsignedMessage.item_hash,
|
|
1187
|
+
error: null,
|
|
1188
|
+
timestamp: Date.now()
|
|
1189
|
+
});
|
|
1100
1190
|
const signature = await args.signer(unsignedMessage.sender, [unsignedMessage.chain, unsignedMessage.sender, unsignedMessage.type, unsignedMessage.item_hash].join("\n"));
|
|
1101
1191
|
const message = {
|
|
1102
1192
|
...unsignedMessage,
|
|
1103
1193
|
signature: signature.startsWith("0x") ? signature : `0x${signature}`
|
|
1104
1194
|
};
|
|
1195
|
+
args.onProgress?.({
|
|
1196
|
+
stage: "broadcasting",
|
|
1197
|
+
label: "Broadcasting to Aleph",
|
|
1198
|
+
progress: 64,
|
|
1199
|
+
status: "info",
|
|
1200
|
+
detail: message.item_hash,
|
|
1201
|
+
itemHash: message.item_hash,
|
|
1202
|
+
error: null,
|
|
1203
|
+
timestamp: Date.now()
|
|
1204
|
+
});
|
|
1105
1205
|
const { response, httpStatus } = await broadcastAlephMessage2(message, {
|
|
1106
1206
|
apiHost: args.apiHost,
|
|
1107
1207
|
sync: args.sync,
|
|
1108
1208
|
fetch: args.fetch
|
|
1109
1209
|
});
|
|
1110
1210
|
const status = httpStatus === 202 ? "pending" : typeof response.message_status === "string" ? response.message_status : "unknown";
|
|
1211
|
+
args.onProgress?.({
|
|
1212
|
+
stage: status === "processed" ? "deployment-confirmed" : status === "rejected" ? "deployment-rejected" : "waiting-for-aleph",
|
|
1213
|
+
label: status === "processed" ? "Deployment accepted by Aleph" : status === "rejected" ? "Deployment rejected by Aleph" : "Deployment submitted to Aleph",
|
|
1214
|
+
progress: status === "processed" ? 88 : status === "rejected" ? 100 : 78,
|
|
1215
|
+
status: status === "processed" ? "success" : status === "rejected" ? "error" : "warning",
|
|
1216
|
+
detail: status === "rejected" ? String(response.details ?? "Aleph rejected this deployment.") : null,
|
|
1217
|
+
itemHash: message.item_hash,
|
|
1218
|
+
error: status === "rejected" ? String(response.details ?? "Aleph rejected this deployment.") : null,
|
|
1219
|
+
timestamp: Date.now()
|
|
1220
|
+
});
|
|
1111
1221
|
return {
|
|
1112
1222
|
itemHash: message.item_hash,
|
|
1113
1223
|
httpStatus,
|
|
@@ -1118,6 +1228,107 @@ async function deployInstance(args) {
|
|
|
1118
1228
|
};
|
|
1119
1229
|
}
|
|
1120
1230
|
|
|
1231
|
+
// ../core/src/guest.ts
|
|
1232
|
+
async function notifyCrnAllocation2(args) {
|
|
1233
|
+
const normalizedCrnUrl = typeof args.crnUrl === "string" ? args.crnUrl.trim().replace(/\/+$/, "") : "";
|
|
1234
|
+
if (!normalizedCrnUrl) {
|
|
1235
|
+
return {
|
|
1236
|
+
status: "skipped",
|
|
1237
|
+
reason: "No CRN URL available for allocation notification."
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
try {
|
|
1241
|
+
const response = await args.fetch(
|
|
1242
|
+
`${normalizedCrnUrl}/control/allocation/notify`,
|
|
1243
|
+
{
|
|
1244
|
+
method: "POST",
|
|
1245
|
+
headers: {
|
|
1246
|
+
"content-type": "application/json"
|
|
1247
|
+
},
|
|
1248
|
+
body: JSON.stringify({ instance: args.itemHash })
|
|
1249
|
+
}
|
|
1250
|
+
);
|
|
1251
|
+
const payload = await response.json().catch(() => null);
|
|
1252
|
+
const responseText = payload == null ? "" : typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
1253
|
+
if (!response.ok) {
|
|
1254
|
+
return {
|
|
1255
|
+
status: "unconfirmed",
|
|
1256
|
+
reason: `CRN allocation notify returned ${response.status}${responseText ? ` ${responseText}` : ""}.`,
|
|
1257
|
+
payload
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
return {
|
|
1261
|
+
status: "confirmed",
|
|
1262
|
+
payload
|
|
1263
|
+
};
|
|
1264
|
+
} catch (error) {
|
|
1265
|
+
return {
|
|
1266
|
+
status: "unconfirmed",
|
|
1267
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
function isRetryableAllocationNotifyReason(reason) {
|
|
1272
|
+
const normalized = String(reason ?? "").toLowerCase();
|
|
1273
|
+
return normalized.includes("503") && (normalized.includes("node hash not yet discovered") || normalized.includes("cannot accept targeted allocations"));
|
|
1274
|
+
}
|
|
1275
|
+
async function notifyCrnAllocationWithRetry(args) {
|
|
1276
|
+
const attempts = Math.max(1, Number(args.attempts ?? 6));
|
|
1277
|
+
const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
|
|
1278
|
+
const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
1279
|
+
let lastResult = null;
|
|
1280
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
1281
|
+
args.onProgress?.({
|
|
1282
|
+
stage: "notifying-crn",
|
|
1283
|
+
label: "Notifying selected CRN",
|
|
1284
|
+
progress: 84,
|
|
1285
|
+
status: "info",
|
|
1286
|
+
itemHash: args.itemHash,
|
|
1287
|
+
detail: `${attempt + 1}/${attempts} ${String(args.crnUrl ?? "").trim() || "selected CRN"}`,
|
|
1288
|
+
error: null,
|
|
1289
|
+
timestamp: Date.now()
|
|
1290
|
+
});
|
|
1291
|
+
const result = await notifyCrnAllocation2({
|
|
1292
|
+
crnUrl: args.crnUrl,
|
|
1293
|
+
itemHash: args.itemHash,
|
|
1294
|
+
fetch: args.fetch
|
|
1295
|
+
});
|
|
1296
|
+
if (result.status === "confirmed" || result.status === "skipped") {
|
|
1297
|
+
return result;
|
|
1298
|
+
}
|
|
1299
|
+
lastResult = result;
|
|
1300
|
+
if (!isRetryableAllocationNotifyReason(result.reason)) {
|
|
1301
|
+
return result;
|
|
1302
|
+
}
|
|
1303
|
+
if (attempt < attempts - 1) {
|
|
1304
|
+
await sleep(delayMs);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
return lastResult ?? {
|
|
1308
|
+
status: "unconfirmed",
|
|
1309
|
+
reason: "CRN allocation notify was not confirmed."
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// src/shared/events.ts
|
|
1314
|
+
function createDeploymentProgressEmitter() {
|
|
1315
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1316
|
+
return {
|
|
1317
|
+
emit(event) {
|
|
1318
|
+
listeners.forEach((listener) => listener(event));
|
|
1319
|
+
},
|
|
1320
|
+
subscribe(listener) {
|
|
1321
|
+
listeners.add(listener);
|
|
1322
|
+
return () => {
|
|
1323
|
+
listeners.delete(listener);
|
|
1324
|
+
};
|
|
1325
|
+
},
|
|
1326
|
+
clear() {
|
|
1327
|
+
listeners.clear();
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1121
1332
|
// src/shared/controller.ts
|
|
1122
1333
|
function defaultState(props = {}) {
|
|
1123
1334
|
return {
|
|
@@ -1167,18 +1378,24 @@ function defaultState(props = {}) {
|
|
|
1167
1378
|
selectedCrn: null,
|
|
1168
1379
|
instances: [],
|
|
1169
1380
|
relayPing: RELAY_PING_IDLE_STATE,
|
|
1170
|
-
lastDeploymentHash: null
|
|
1381
|
+
lastDeploymentHash: null,
|
|
1382
|
+
deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
|
|
1171
1383
|
};
|
|
1172
1384
|
}
|
|
1173
1385
|
async function sha256Hex(payload) {
|
|
1174
|
-
const digest = await globalThis.crypto.subtle.digest(
|
|
1386
|
+
const digest = await globalThis.crypto.subtle.digest(
|
|
1387
|
+
"SHA-256",
|
|
1388
|
+
new TextEncoder().encode(payload)
|
|
1389
|
+
);
|
|
1175
1390
|
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1176
1391
|
}
|
|
1177
1392
|
function mappedPorts(execution) {
|
|
1178
|
-
return Object.entries(execution?.networking?.mapped_ports ?? {}).map(
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1393
|
+
return Object.entries(execution?.networking?.mapped_ports ?? {}).map(
|
|
1394
|
+
([port, mapping]) => ({
|
|
1395
|
+
label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
|
|
1396
|
+
hostPort: mapping.host ?? null
|
|
1397
|
+
})
|
|
1398
|
+
);
|
|
1182
1399
|
}
|
|
1183
1400
|
function rootfsHealth(args) {
|
|
1184
1401
|
if (!args.manifestState.valid || !args.manifestState.manifest) {
|
|
@@ -1236,7 +1453,9 @@ async function resolveManifest(args) {
|
|
|
1236
1453
|
}
|
|
1237
1454
|
async function inspectInstanceRuntime(args) {
|
|
1238
1455
|
const details = {
|
|
1239
|
-
messageStatus: String(
|
|
1456
|
+
messageStatus: String(
|
|
1457
|
+
args.instance.status ?? (args.instance.confirmed ? "processed" : "unknown")
|
|
1458
|
+
).toLowerCase(),
|
|
1240
1459
|
allocationSource: null,
|
|
1241
1460
|
crnUrl: null,
|
|
1242
1461
|
hostIpv4: null,
|
|
@@ -1267,11 +1486,15 @@ async function inspectInstanceRuntime(args) {
|
|
|
1267
1486
|
details.allocationSource = allocation?.source ?? null;
|
|
1268
1487
|
details.crnUrl = allocation?.crnUrl ?? null;
|
|
1269
1488
|
details.ipv6 = allocation?.vmIpv6 ?? null;
|
|
1270
|
-
details.webUrl = await args.client.fetch2n6WebAccessUrl(
|
|
1489
|
+
details.webUrl = await args.client.fetch2n6WebAccessUrl(
|
|
1490
|
+
args.instance.item_hash
|
|
1491
|
+
);
|
|
1271
1492
|
if (!allocation?.crnUrl) {
|
|
1272
1493
|
return details;
|
|
1273
1494
|
}
|
|
1274
|
-
const executionLookup = await args.client.fetchCrnExecutionMap(
|
|
1495
|
+
const executionLookup = await args.client.fetchCrnExecutionMap(
|
|
1496
|
+
allocation.crnUrl
|
|
1497
|
+
);
|
|
1275
1498
|
const executionPayload = executionLookup.payload?.[args.instance.item_hash];
|
|
1276
1499
|
if (!executionPayload) {
|
|
1277
1500
|
return details;
|
|
@@ -1299,7 +1522,10 @@ function compatibleCrnsForTier(crns, state) {
|
|
|
1299
1522
|
if (!state.pricingSummary.pricing || !state.pricingSummary.tier) {
|
|
1300
1523
|
return [];
|
|
1301
1524
|
}
|
|
1302
|
-
const spec = tierSpec(
|
|
1525
|
+
const spec = tierSpec(
|
|
1526
|
+
state.pricingSummary.pricing,
|
|
1527
|
+
state.pricingSummary.tier
|
|
1528
|
+
);
|
|
1303
1529
|
return filterDeployableCrns(crns, { spec });
|
|
1304
1530
|
}
|
|
1305
1531
|
async function pingPeer(libp2p) {
|
|
@@ -1361,6 +1587,7 @@ var SponsorRelayController = class {
|
|
|
1361
1587
|
pingTimer = null;
|
|
1362
1588
|
stopWalletWatch = null;
|
|
1363
1589
|
props;
|
|
1590
|
+
progressEmitter = createDeploymentProgressEmitter();
|
|
1364
1591
|
constructor(props = {}) {
|
|
1365
1592
|
this.props = props;
|
|
1366
1593
|
this.state = defaultState(props);
|
|
@@ -1371,6 +1598,9 @@ var SponsorRelayController = class {
|
|
|
1371
1598
|
twoN6ApiHost: props.twoN6ApiHost
|
|
1372
1599
|
});
|
|
1373
1600
|
}
|
|
1601
|
+
subscribeToDeploymentProgress(listener) {
|
|
1602
|
+
return this.progressEmitter.subscribe(listener);
|
|
1603
|
+
}
|
|
1374
1604
|
subscribe(subscriber) {
|
|
1375
1605
|
this.subscribers.add(subscriber);
|
|
1376
1606
|
return () => {
|
|
@@ -1395,6 +1625,18 @@ var SponsorRelayController = class {
|
|
|
1395
1625
|
};
|
|
1396
1626
|
this.emit();
|
|
1397
1627
|
}
|
|
1628
|
+
emitProgress(event) {
|
|
1629
|
+
const nextEvent = {
|
|
1630
|
+
...event,
|
|
1631
|
+
timestamp: Date.now()
|
|
1632
|
+
};
|
|
1633
|
+
this.patch({
|
|
1634
|
+
deploymentProgress: nextEvent,
|
|
1635
|
+
statusText: event.error ?? event.detail ?? event.label,
|
|
1636
|
+
errorText: event.status === "error" ? event.error ?? event.detail ?? event.label : this.state.errorText
|
|
1637
|
+
});
|
|
1638
|
+
this.progressEmitter.emit(nextEvent);
|
|
1639
|
+
}
|
|
1398
1640
|
async init() {
|
|
1399
1641
|
this.stopWalletWatch = watchWallet(() => {
|
|
1400
1642
|
void this.refreshWalletDerivedState();
|
|
@@ -1514,11 +1756,25 @@ var SponsorRelayController = class {
|
|
|
1514
1756
|
statusText: "Refreshing relay sponsor data"
|
|
1515
1757
|
});
|
|
1516
1758
|
try {
|
|
1759
|
+
this.emitProgress({
|
|
1760
|
+
stage: "loading-manifest",
|
|
1761
|
+
label: "Loading manifest",
|
|
1762
|
+
progress: 8,
|
|
1763
|
+
status: "info",
|
|
1764
|
+
detail: this.state.manifestUrl
|
|
1765
|
+
});
|
|
1517
1766
|
const manifestState = await resolveManifest({
|
|
1518
1767
|
manifestUrl: this.state.manifestUrl,
|
|
1519
1768
|
manifestJson: this.state.manifestJson
|
|
1520
1769
|
});
|
|
1521
1770
|
const manifest = manifestState.manifest;
|
|
1771
|
+
this.emitProgress({
|
|
1772
|
+
stage: "loading-pricing",
|
|
1773
|
+
label: "Loading pricing and CRNs",
|
|
1774
|
+
progress: 18,
|
|
1775
|
+
status: "info",
|
|
1776
|
+
detail: "Fetching live Aleph pricing and compatible CRNs."
|
|
1777
|
+
});
|
|
1522
1778
|
const [pricingSummary, crns] = await Promise.all([
|
|
1523
1779
|
fetchInstancePricing(this.client.apiHost),
|
|
1524
1780
|
this.client.fetchCrns()
|
|
@@ -1526,6 +1782,13 @@ var SponsorRelayController = class {
|
|
|
1526
1782
|
let balance = this.state.balance;
|
|
1527
1783
|
let instances = [];
|
|
1528
1784
|
if (this.state.wallet.address) {
|
|
1785
|
+
this.emitProgress({
|
|
1786
|
+
stage: "loading-balance",
|
|
1787
|
+
label: "Loading wallet balance",
|
|
1788
|
+
progress: 28,
|
|
1789
|
+
status: "info",
|
|
1790
|
+
detail: this.state.wallet.address
|
|
1791
|
+
});
|
|
1529
1792
|
const [nextBalance, rawInstances] = await Promise.all([
|
|
1530
1793
|
this.client.fetchBalance(this.state.wallet.address),
|
|
1531
1794
|
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([])
|
|
@@ -1545,8 +1808,21 @@ var SponsorRelayController = class {
|
|
|
1545
1808
|
let rootfsVerified = false;
|
|
1546
1809
|
let rootfsResolution = null;
|
|
1547
1810
|
if (manifestState.valid && manifest) {
|
|
1548
|
-
|
|
1549
|
-
|
|
1811
|
+
this.emitProgress({
|
|
1812
|
+
stage: "verifying-rootfs",
|
|
1813
|
+
label: "Verifying rootfs",
|
|
1814
|
+
progress: 38,
|
|
1815
|
+
status: "info",
|
|
1816
|
+
detail: manifest.rootfsItemHash
|
|
1817
|
+
});
|
|
1818
|
+
rootfsVerified = await verifyRootfsExists(
|
|
1819
|
+
manifest.rootfsItemHash,
|
|
1820
|
+
this.client.apiHost
|
|
1821
|
+
);
|
|
1822
|
+
rootfsResolution = await resolveRootfsReference(
|
|
1823
|
+
manifest.rootfsItemHash,
|
|
1824
|
+
this.client.apiHost
|
|
1825
|
+
);
|
|
1550
1826
|
}
|
|
1551
1827
|
this.patch({
|
|
1552
1828
|
manifestState,
|
|
@@ -1569,12 +1845,26 @@ var SponsorRelayController = class {
|
|
|
1569
1845
|
statusText: "Relay sponsor data ready"
|
|
1570
1846
|
});
|
|
1571
1847
|
this.recomputePricingSummary();
|
|
1848
|
+
this.emitProgress({
|
|
1849
|
+
stage: "completed",
|
|
1850
|
+
label: "Data ready",
|
|
1851
|
+
progress: 100,
|
|
1852
|
+
status: "success",
|
|
1853
|
+
detail: "Manifest, pricing, and wallet state are ready."
|
|
1854
|
+
});
|
|
1572
1855
|
} catch (error) {
|
|
1573
1856
|
this.patch({
|
|
1574
1857
|
busy: { refreshing: false },
|
|
1575
1858
|
errorText: error instanceof Error ? error.message : String(error),
|
|
1576
1859
|
statusText: "Refresh failed"
|
|
1577
1860
|
});
|
|
1861
|
+
this.emitProgress({
|
|
1862
|
+
stage: "error",
|
|
1863
|
+
label: "Refresh failed",
|
|
1864
|
+
progress: 100,
|
|
1865
|
+
status: "error",
|
|
1866
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1867
|
+
});
|
|
1578
1868
|
}
|
|
1579
1869
|
}
|
|
1580
1870
|
async refreshRelayPing() {
|
|
@@ -1587,7 +1877,9 @@ var SponsorRelayController = class {
|
|
|
1587
1877
|
return;
|
|
1588
1878
|
}
|
|
1589
1879
|
if (!this.state.manifest || !this.state.rootfsVerified || !this.state.pricingSummary.pricing || !this.state.pricingSummary.tier) {
|
|
1590
|
-
this.patch({
|
|
1880
|
+
this.patch({
|
|
1881
|
+
errorText: "Manifest, rootfs, and pricing must be ready before deploying."
|
|
1882
|
+
});
|
|
1591
1883
|
return;
|
|
1592
1884
|
}
|
|
1593
1885
|
this.patch({
|
|
@@ -1596,13 +1888,33 @@ var SponsorRelayController = class {
|
|
|
1596
1888
|
statusText: "Broadcasting deployment"
|
|
1597
1889
|
});
|
|
1598
1890
|
try {
|
|
1599
|
-
|
|
1891
|
+
this.emitProgress({
|
|
1892
|
+
stage: "validating",
|
|
1893
|
+
label: "Validating deployment",
|
|
1894
|
+
progress: 5,
|
|
1895
|
+
status: "info",
|
|
1896
|
+
detail: "Checking wallet, manifest, rootfs, pricing, and SSH key."
|
|
1897
|
+
});
|
|
1898
|
+
const spec = tierSpec(
|
|
1899
|
+
this.state.pricingSummary.pricing,
|
|
1900
|
+
this.state.pricingSummary.tier
|
|
1901
|
+
);
|
|
1902
|
+
this.emitProgress({
|
|
1903
|
+
stage: "selecting-crn",
|
|
1904
|
+
label: "Selecting CRN",
|
|
1905
|
+
progress: 18,
|
|
1906
|
+
status: "info",
|
|
1907
|
+
detail: this.state.selectedCrn?.name ?? this.state.selectedCrn?.hash ?? "Auto-selected compatible CRN"
|
|
1908
|
+
});
|
|
1600
1909
|
const content = createInstanceContent({
|
|
1601
1910
|
address: this.state.wallet.address,
|
|
1602
1911
|
name: this.state.instanceName.trim(),
|
|
1603
1912
|
sshPublicKey: this.state.sshPublicKey.trim(),
|
|
1604
1913
|
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
1605
|
-
rootfsSizeMiB: Math.max(
|
|
1914
|
+
rootfsSizeMiB: Math.max(
|
|
1915
|
+
this.state.manifest.rootfsSizeMiB,
|
|
1916
|
+
spec.diskMiB
|
|
1917
|
+
),
|
|
1606
1918
|
vcpus: spec.vcpus,
|
|
1607
1919
|
memoryMiB: spec.memoryMiB,
|
|
1608
1920
|
rootfsVersion: this.state.manifest.version,
|
|
@@ -1615,20 +1927,57 @@ var SponsorRelayController = class {
|
|
|
1615
1927
|
signer: personalSign,
|
|
1616
1928
|
fetch: (url, init) => fetch(url, init),
|
|
1617
1929
|
apiHost: this.client.apiHost,
|
|
1618
|
-
sync: false
|
|
1930
|
+
sync: false,
|
|
1931
|
+
onProgress: (event) => {
|
|
1932
|
+
this.emitProgress(event);
|
|
1933
|
+
}
|
|
1619
1934
|
});
|
|
1620
1935
|
this.patch({
|
|
1621
1936
|
busy: { deploying: false },
|
|
1622
1937
|
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
1623
1938
|
lastDeploymentHash: result.itemHash
|
|
1624
1939
|
});
|
|
1940
|
+
if (result.status === "processed" && this.state.selectedCrn?.address) {
|
|
1941
|
+
await notifyCrnAllocationWithRetry({
|
|
1942
|
+
crnUrl: this.state.selectedCrn.address,
|
|
1943
|
+
itemHash: result.itemHash,
|
|
1944
|
+
fetch: (url, init) => fetch(url, init),
|
|
1945
|
+
onProgress: (event) => {
|
|
1946
|
+
this.emitProgress(event);
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
this.emitProgress({
|
|
1951
|
+
stage: "refreshing-instances",
|
|
1952
|
+
label: "Refreshing instances",
|
|
1953
|
+
progress: 92,
|
|
1954
|
+
status: "info",
|
|
1955
|
+
itemHash: result.itemHash,
|
|
1956
|
+
detail: "Reloading deployments and runtime state."
|
|
1957
|
+
});
|
|
1625
1958
|
await this.refresh();
|
|
1959
|
+
this.emitProgress({
|
|
1960
|
+
stage: "completed",
|
|
1961
|
+
label: "Deployment completed",
|
|
1962
|
+
progress: 100,
|
|
1963
|
+
status: result.status === "rejected" ? "error" : "success",
|
|
1964
|
+
itemHash: result.itemHash,
|
|
1965
|
+
detail: result.status === "rejected" ? result.rejectionReason ?? "Aleph rejected the deployment." : "Deployment submitted and synced back into the panel.",
|
|
1966
|
+
error: result.status === "rejected" ? result.rejectionReason ?? "Aleph rejected the deployment." : null
|
|
1967
|
+
});
|
|
1626
1968
|
} catch (error) {
|
|
1627
1969
|
this.patch({
|
|
1628
1970
|
busy: { deploying: false },
|
|
1629
1971
|
errorText: error instanceof Error ? error.message : String(error),
|
|
1630
1972
|
statusText: "Deployment failed"
|
|
1631
1973
|
});
|
|
1974
|
+
this.emitProgress({
|
|
1975
|
+
stage: "error",
|
|
1976
|
+
label: "Deployment failed",
|
|
1977
|
+
progress: 100,
|
|
1978
|
+
status: "error",
|
|
1979
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1980
|
+
});
|
|
1632
1981
|
}
|
|
1633
1982
|
}
|
|
1634
1983
|
async deleteInstance(instanceHash) {
|
|
@@ -1642,6 +1991,14 @@ var SponsorRelayController = class {
|
|
|
1642
1991
|
statusText: `Deleting ${instanceHash}`
|
|
1643
1992
|
});
|
|
1644
1993
|
try {
|
|
1994
|
+
this.emitProgress({
|
|
1995
|
+
stage: "validating",
|
|
1996
|
+
label: "Validating delete request",
|
|
1997
|
+
progress: 6,
|
|
1998
|
+
status: "warning",
|
|
1999
|
+
itemHash: instanceHash,
|
|
2000
|
+
detail: "Preparing Aleph FORGET message."
|
|
2001
|
+
});
|
|
1645
2002
|
await forgetAlephMessages({
|
|
1646
2003
|
sender: this.state.wallet.address,
|
|
1647
2004
|
hashes: [instanceHash],
|
|
@@ -1653,13 +2010,33 @@ var SponsorRelayController = class {
|
|
|
1653
2010
|
status: response.status,
|
|
1654
2011
|
json: async () => await response.json()
|
|
1655
2012
|
})),
|
|
1656
|
-
apiHost: this.client.apiHost
|
|
2013
|
+
apiHost: this.client.apiHost,
|
|
2014
|
+
onProgress: (event) => {
|
|
2015
|
+
this.emitProgress(event);
|
|
2016
|
+
}
|
|
1657
2017
|
});
|
|
1658
2018
|
this.patch({
|
|
1659
2019
|
busy: { deletingInstanceHash: null },
|
|
1660
2020
|
statusText: `Deletion submitted for ${instanceHash}`
|
|
1661
2021
|
});
|
|
2022
|
+
this.emitProgress({
|
|
2023
|
+
stage: "refreshing-instances",
|
|
2024
|
+
label: "Refreshing instances after delete",
|
|
2025
|
+
progress: 92,
|
|
2026
|
+
status: "info",
|
|
2027
|
+
itemHash: instanceHash,
|
|
2028
|
+
detail: "Reloading current deployments."
|
|
2029
|
+
});
|
|
1662
2030
|
await this.refresh();
|
|
2031
|
+
this.emitProgress({
|
|
2032
|
+
stage: "completed",
|
|
2033
|
+
label: "Delete completed",
|
|
2034
|
+
progress: 100,
|
|
2035
|
+
status: "success",
|
|
2036
|
+
itemHash: instanceHash,
|
|
2037
|
+
detail: "Delete request submitted and deployments refreshed.",
|
|
2038
|
+
error: null
|
|
2039
|
+
});
|
|
1663
2040
|
} catch (error) {
|
|
1664
2041
|
this.patch({
|
|
1665
2042
|
busy: { deletingInstanceHash: null },
|
|
@@ -1708,13 +2085,10 @@ function useSponsorRelayController(props) {
|
|
|
1708
2085
|
|
|
1709
2086
|
// src/react/SponsorRelayFab.tsx
|
|
1710
2087
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1711
|
-
var
|
|
2088
|
+
var basePanelStyle = {
|
|
1712
2089
|
position: "fixed",
|
|
1713
|
-
right: "1.4rem",
|
|
1714
|
-
bottom: "11.5rem",
|
|
1715
2090
|
zIndex: 9999,
|
|
1716
2091
|
width: "min(28rem, calc(100vw - 2rem))",
|
|
1717
|
-
maxHeight: "calc(100vh - 12.5rem)",
|
|
1718
2092
|
overflow: "auto",
|
|
1719
2093
|
border: "1px solid rgba(255,255,255,0.12)",
|
|
1720
2094
|
borderRadius: "1.4rem",
|
|
@@ -1735,33 +2109,282 @@ var fieldStyle = {
|
|
|
1735
2109
|
fontSize: "0.98rem",
|
|
1736
2110
|
lineHeight: 1.45
|
|
1737
2111
|
};
|
|
2112
|
+
function progressToneColor(status) {
|
|
2113
|
+
switch (status) {
|
|
2114
|
+
case "success":
|
|
2115
|
+
return "#37d67a";
|
|
2116
|
+
case "warning":
|
|
2117
|
+
return "#ffc83f";
|
|
2118
|
+
case "error":
|
|
2119
|
+
return "#e91315";
|
|
2120
|
+
default:
|
|
2121
|
+
return "#0176ce";
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
function progressBadgeLabel(stage) {
|
|
2125
|
+
switch (stage) {
|
|
2126
|
+
case "building-delete-message":
|
|
2127
|
+
case "signing-delete-message":
|
|
2128
|
+
case "broadcasting-delete":
|
|
2129
|
+
case "delete-completed":
|
|
2130
|
+
return "DELETE";
|
|
2131
|
+
case "error":
|
|
2132
|
+
return "ERROR";
|
|
2133
|
+
case "completed":
|
|
2134
|
+
return "DONE";
|
|
2135
|
+
default:
|
|
2136
|
+
return "DEPLOY";
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
function launcherIndicator(state) {
|
|
2140
|
+
if (state.deploymentProgress.stage !== "idle" && state.deploymentProgress.stage !== "completed") {
|
|
2141
|
+
return {
|
|
2142
|
+
label: state.deploymentProgress.progress > 0 ? `${Math.round(state.deploymentProgress.progress)}%` : progressBadgeLabel(state.deploymentProgress.stage),
|
|
2143
|
+
detail: state.deploymentProgress.label,
|
|
2144
|
+
tone: state.deploymentProgress.status
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
if (state.deploymentProgress.stage === "completed") {
|
|
2148
|
+
return {
|
|
2149
|
+
label: "DONE",
|
|
2150
|
+
detail: state.deploymentProgress.label,
|
|
2151
|
+
tone: state.deploymentProgress.status === "error" ? "error" : "success"
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
if (state.errorText) {
|
|
2155
|
+
return {
|
|
2156
|
+
label: "ERR",
|
|
2157
|
+
detail: state.errorText,
|
|
2158
|
+
tone: "error"
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
if (!state.wallet.connected) {
|
|
2162
|
+
return {
|
|
2163
|
+
label: "WALLET",
|
|
2164
|
+
detail: "Connect MetaMask",
|
|
2165
|
+
tone: "warning"
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
if (state.rootfsHealth.tone === "error") {
|
|
2169
|
+
return {
|
|
2170
|
+
label: "ROOTFS",
|
|
2171
|
+
detail: state.rootfsHealth.label,
|
|
2172
|
+
tone: "error"
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
if (state.rootfsHealth.tone === "caution") {
|
|
2176
|
+
return {
|
|
2177
|
+
label: "CHECK",
|
|
2178
|
+
detail: state.rootfsHealth.label,
|
|
2179
|
+
tone: "warning"
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
if (state.busy.refreshing) {
|
|
2183
|
+
return {
|
|
2184
|
+
label: "SYNC",
|
|
2185
|
+
detail: "Refreshing relay state",
|
|
2186
|
+
tone: "info"
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
return {
|
|
2190
|
+
label: "READY",
|
|
2191
|
+
detail: state.selectedCrn?.name ?? "Ready to deploy",
|
|
2192
|
+
tone: "success"
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
1738
2195
|
function SponsorRelayFab(props) {
|
|
1739
2196
|
const { controller, state } = useSponsorRelayController(props);
|
|
1740
2197
|
const launcherMode = props.launcherMode ?? "floating";
|
|
2198
|
+
const indicator = launcherIndicator(state);
|
|
2199
|
+
const [successFlash, setSuccessFlash] = React.useState(false);
|
|
2200
|
+
const [hovered, setHovered] = React.useState(false);
|
|
2201
|
+
const launcherRef = React.useRef(null);
|
|
2202
|
+
const [inlinePanelStyle, setInlinePanelStyle] = React.useState(null);
|
|
2203
|
+
const [compactInlineLabel, setCompactInlineLabel] = React.useState(false);
|
|
2204
|
+
React.useEffect(() => {
|
|
2205
|
+
if (state.deploymentProgress.stage !== "completed" || state.deploymentProgress.status !== "success") {
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
setSuccessFlash(true);
|
|
2209
|
+
const timeout = window.setTimeout(() => {
|
|
2210
|
+
setSuccessFlash(false);
|
|
2211
|
+
}, 1400);
|
|
2212
|
+
return () => {
|
|
2213
|
+
window.clearTimeout(timeout);
|
|
2214
|
+
};
|
|
2215
|
+
}, [
|
|
2216
|
+
state.deploymentProgress.stage,
|
|
2217
|
+
state.deploymentProgress.status,
|
|
2218
|
+
state.deploymentProgress.timestamp
|
|
2219
|
+
]);
|
|
2220
|
+
React.useEffect(() => {
|
|
2221
|
+
if (launcherMode !== "inline" || !state.open) {
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
const updateInlinePanelStyle = () => {
|
|
2225
|
+
const launcher = launcherRef.current;
|
|
2226
|
+
if (launcher == null) {
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
const rect = launcher.getBoundingClientRect();
|
|
2230
|
+
const viewportWidth = window.innerWidth;
|
|
2231
|
+
const viewportHeight = window.innerHeight;
|
|
2232
|
+
const anchorRight = Math.max(16, viewportWidth - rect.right);
|
|
2233
|
+
const top = Math.max(72, rect.bottom + 12);
|
|
2234
|
+
setInlinePanelStyle({
|
|
2235
|
+
...basePanelStyle,
|
|
2236
|
+
top,
|
|
2237
|
+
right: anchorRight,
|
|
2238
|
+
maxHeight: `calc(100vh - ${Math.min(viewportHeight - 16, top + 16)}px)`,
|
|
2239
|
+
width: "min(30rem, calc(100vw - 1.5rem))"
|
|
2240
|
+
});
|
|
2241
|
+
};
|
|
2242
|
+
updateInlinePanelStyle();
|
|
2243
|
+
window.addEventListener("resize", updateInlinePanelStyle);
|
|
2244
|
+
window.addEventListener("scroll", updateInlinePanelStyle, true);
|
|
2245
|
+
return () => {
|
|
2246
|
+
window.removeEventListener("resize", updateInlinePanelStyle);
|
|
2247
|
+
window.removeEventListener("scroll", updateInlinePanelStyle, true);
|
|
2248
|
+
};
|
|
2249
|
+
}, [launcherMode, state.open]);
|
|
2250
|
+
React.useEffect(() => {
|
|
2251
|
+
if (launcherMode !== "inline") {
|
|
2252
|
+
setCompactInlineLabel(false);
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
const updateCompactInlineLabel = () => {
|
|
2256
|
+
setCompactInlineLabel(window.innerWidth < 1240);
|
|
2257
|
+
};
|
|
2258
|
+
updateCompactInlineLabel();
|
|
2259
|
+
window.addEventListener("resize", updateCompactInlineLabel);
|
|
2260
|
+
return () => {
|
|
2261
|
+
window.removeEventListener("resize", updateCompactInlineLabel);
|
|
2262
|
+
};
|
|
2263
|
+
}, [launcherMode]);
|
|
2264
|
+
const progressActive = state.deploymentProgress.stage !== "idle" && state.deploymentProgress.stage !== "completed" && state.deploymentProgress.stage !== "error";
|
|
2265
|
+
const pulseScale = progressActive ? 1.03 : hovered ? 1.015 : 1;
|
|
2266
|
+
const pulseShadow = progressActive ? `0 0 0 4px ${progressToneColor(indicator.tone)}22, 0 12px 28px rgba(15, 23, 42, 0.22)` : successFlash ? `0 0 0 5px rgba(55, 214, 122, 0.22), 0 14px 32px rgba(55, 214, 122, 0.22)` : launcherMode === "inline" ? hovered ? "0 14px 30px rgba(79, 70, 229, 0.28)" : "0 10px 24px rgba(99, 102, 241, 0.22)" : void 0;
|
|
2267
|
+
const inlineButtonBackground = indicator.tone === "error" ? "linear-gradient(135deg, #b91c1c 0%, #dc2626 100%)" : indicator.tone === "warning" ? "linear-gradient(135deg, #7c3aed 0%, #8b5cf6 100%)" : indicator.tone === "success" ? "linear-gradient(135deg, #4f46e5 0%, #6366f1 100%)" : "linear-gradient(135deg, #4f46e5 0%, #6366f1 100%)";
|
|
2268
|
+
const inlineButtonBorder = indicator.tone === "error" ? "1px solid rgba(254, 202, 202, 0.45)" : indicator.tone === "warning" ? "1px solid rgba(196, 181, 253, 0.42)" : "1px solid rgba(199, 210, 254, 0.42)";
|
|
2269
|
+
const inlineBadgeBackground = indicator.tone === "error" ? "rgba(127, 29, 29, 0.88)" : indicator.tone === "warning" ? "rgba(88, 28, 135, 0.88)" : indicator.tone === "success" ? "rgba(49, 46, 129, 0.92)" : "rgba(30, 41, 59, 0.92)";
|
|
2270
|
+
const inlineBadgeBorder = indicator.tone === "error" ? "1px solid rgba(254, 202, 202, 0.34)" : indicator.tone === "warning" ? "1px solid rgba(233, 213, 255, 0.28)" : indicator.tone === "success" ? "1px solid rgba(191, 219, 254, 0.24)" : "1px solid rgba(191, 219, 254, 0.2)";
|
|
2271
|
+
const panelStyle = launcherMode === "inline" ? inlinePanelStyle ?? {
|
|
2272
|
+
...basePanelStyle,
|
|
2273
|
+
top: "4.75rem",
|
|
2274
|
+
right: "1rem",
|
|
2275
|
+
maxHeight: "calc(100vh - 6rem)",
|
|
2276
|
+
width: "min(30rem, calc(100vw - 1.5rem))"
|
|
2277
|
+
} : {
|
|
2278
|
+
...basePanelStyle,
|
|
2279
|
+
right: "1.4rem",
|
|
2280
|
+
bottom: "11.5rem",
|
|
2281
|
+
maxHeight: "calc(100vh - 12.5rem)"
|
|
2282
|
+
};
|
|
2283
|
+
const launcherLabel = launcherMode === "inline" && compactInlineLabel ? "Relay" : "Sponsor Relay";
|
|
1741
2284
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1742
|
-
/* @__PURE__ */
|
|
2285
|
+
/* @__PURE__ */ jsxs(
|
|
1743
2286
|
"button",
|
|
1744
2287
|
{
|
|
2288
|
+
ref: launcherRef,
|
|
1745
2289
|
type: "button",
|
|
1746
2290
|
onClick: () => controller.toggleOpen(),
|
|
2291
|
+
onMouseEnter: () => setHovered(true),
|
|
2292
|
+
onMouseLeave: () => setHovered(false),
|
|
2293
|
+
onFocus: () => setHovered(true),
|
|
2294
|
+
onBlur: () => setHovered(false),
|
|
2295
|
+
title: indicator.detail ?? "Sponsor Relay",
|
|
1747
2296
|
style: {
|
|
1748
2297
|
position: launcherMode === "floating" ? "fixed" : "relative",
|
|
1749
2298
|
right: launcherMode === "floating" ? "1.4rem" : void 0,
|
|
1750
2299
|
bottom: launcherMode === "floating" ? "5.8rem" : void 0,
|
|
1751
2300
|
zIndex: launcherMode === "floating" ? 1e4 : "auto",
|
|
1752
2301
|
borderRadius: "999px",
|
|
1753
|
-
border: "2px solid rgba(255,255,255,0.9)",
|
|
1754
|
-
background: "linear-gradient(135deg, #e91315 0%, #ffc83f 100%)",
|
|
2302
|
+
border: launcherMode === "floating" ? "2px solid rgba(255,255,255,0.9)" : inlineButtonBorder,
|
|
2303
|
+
background: launcherMode === "floating" ? "linear-gradient(135deg, #e91315 0%, #ffc83f 100%)" : inlineButtonBackground,
|
|
1755
2304
|
color: "white",
|
|
1756
|
-
|
|
2305
|
+
minHeight: launcherMode === "floating" ? void 0 : "2.25rem",
|
|
2306
|
+
padding: launcherMode === "floating" ? "0.9rem 1.2rem" : "0.42rem 0.56rem 0.42rem 0.76rem",
|
|
1757
2307
|
fontFamily: '"Epilogue", sans-serif',
|
|
1758
2308
|
fontWeight: 700,
|
|
1759
|
-
fontSize: launcherMode === "floating" ? "0.84rem" : "0.
|
|
2309
|
+
fontSize: launcherMode === "floating" ? "0.84rem" : "0.73rem",
|
|
1760
2310
|
textTransform: "uppercase",
|
|
1761
2311
|
letterSpacing: "0.08em",
|
|
1762
|
-
cursor: "pointer"
|
|
2312
|
+
cursor: "pointer",
|
|
2313
|
+
display: "inline-flex",
|
|
2314
|
+
alignItems: "center",
|
|
2315
|
+
justifyContent: "center",
|
|
2316
|
+
gap: launcherMode === "floating" ? "0.45rem" : "0.34rem",
|
|
2317
|
+
boxShadow: pulseShadow,
|
|
2318
|
+
transform: `translateY(${hovered && !progressActive ? "-1px" : "0"}) scale(${pulseScale})`,
|
|
2319
|
+
transition: "transform 180ms ease, box-shadow 220ms ease, background 220ms ease, border-color 220ms ease"
|
|
1763
2320
|
},
|
|
1764
|
-
children:
|
|
2321
|
+
children: [
|
|
2322
|
+
/* @__PURE__ */ jsxs(
|
|
2323
|
+
"span",
|
|
2324
|
+
{
|
|
2325
|
+
style: {
|
|
2326
|
+
display: "inline-flex",
|
|
2327
|
+
alignItems: "center",
|
|
2328
|
+
gap: "0.36rem"
|
|
2329
|
+
},
|
|
2330
|
+
children: [
|
|
2331
|
+
/* @__PURE__ */ jsx(
|
|
2332
|
+
"span",
|
|
2333
|
+
{
|
|
2334
|
+
"aria-hidden": "true",
|
|
2335
|
+
style: {
|
|
2336
|
+
width: launcherMode === "floating" ? "0.5rem" : "0.42rem",
|
|
2337
|
+
height: launcherMode === "floating" ? "0.5rem" : "0.42rem",
|
|
2338
|
+
borderRadius: "999px",
|
|
2339
|
+
background: launcherMode === "floating" ? "rgba(255,255,255,0.96)" : "#f59e0b",
|
|
2340
|
+
boxShadow: launcherMode === "floating" ? "0 0 0 3px rgba(255,255,255,0.22)" : "0 0 0 3px rgba(245, 158, 11, 0.18)"
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
),
|
|
2344
|
+
/* @__PURE__ */ jsx("span", { children: launcherLabel })
|
|
2345
|
+
]
|
|
2346
|
+
}
|
|
2347
|
+
),
|
|
2348
|
+
/* @__PURE__ */ jsxs(
|
|
2349
|
+
"span",
|
|
2350
|
+
{
|
|
2351
|
+
style: {
|
|
2352
|
+
display: "inline-flex",
|
|
2353
|
+
alignItems: "center",
|
|
2354
|
+
gap: "0.36rem",
|
|
2355
|
+
padding: launcherMode === "floating" ? "0.2rem 0.42rem" : "0.21rem 0.5rem",
|
|
2356
|
+
minWidth: launcherMode === "floating" ? void 0 : "3.8rem",
|
|
2357
|
+
borderRadius: "999px",
|
|
2358
|
+
background: launcherMode === "floating" ? "rgba(15, 23, 42, 0.18)" : inlineBadgeBackground,
|
|
2359
|
+
border: launcherMode === "floating" ? "1px solid rgba(255,255,255,0.18)" : inlineBadgeBorder,
|
|
2360
|
+
fontSize: launcherMode === "floating" ? "0.62rem" : "0.61rem",
|
|
2361
|
+
fontWeight: launcherMode === "floating" ? 700 : 800,
|
|
2362
|
+
lineHeight: 1,
|
|
2363
|
+
letterSpacing: "0.08em",
|
|
2364
|
+
justifyContent: "center",
|
|
2365
|
+
boxShadow: launcherMode === "floating" ? void 0 : `inset 0 1px 0 rgba(255,255,255,0.08), 0 6px 16px ${progressToneColor(indicator.tone)}22`
|
|
2366
|
+
},
|
|
2367
|
+
children: [
|
|
2368
|
+
/* @__PURE__ */ jsx(
|
|
2369
|
+
"span",
|
|
2370
|
+
{
|
|
2371
|
+
"aria-hidden": "true",
|
|
2372
|
+
style: {
|
|
2373
|
+
width: "0.42rem",
|
|
2374
|
+
height: "0.42rem",
|
|
2375
|
+
borderRadius: "999px",
|
|
2376
|
+
background: progressToneColor(indicator.tone),
|
|
2377
|
+
boxShadow: `0 0 0 ${progressActive ? "4px" : "3px"} ${progressToneColor(indicator.tone)}22`,
|
|
2378
|
+
transform: `scale(${progressActive ? 1.12 : successFlash ? 1.18 : 1})`,
|
|
2379
|
+
transition: "transform 180ms ease, box-shadow 220ms ease"
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
),
|
|
2383
|
+
/* @__PURE__ */ jsx("span", { children: indicator.label })
|
|
2384
|
+
]
|
|
2385
|
+
}
|
|
2386
|
+
)
|
|
2387
|
+
]
|
|
1765
2388
|
}
|
|
1766
2389
|
),
|
|
1767
2390
|
state.open ? /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -1778,66 +2401,274 @@ function SponsorRelayFab(props) {
|
|
|
1778
2401
|
}
|
|
1779
2402
|
),
|
|
1780
2403
|
/* @__PURE__ */ jsxs("aside", { style: panelStyle, children: [
|
|
1781
|
-
/* @__PURE__ */ jsxs(
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
2404
|
+
/* @__PURE__ */ jsxs(
|
|
2405
|
+
"div",
|
|
2406
|
+
{
|
|
2407
|
+
style: {
|
|
2408
|
+
display: "flex",
|
|
2409
|
+
justifyContent: "space-between",
|
|
2410
|
+
gap: "0.75rem",
|
|
2411
|
+
alignItems: "center"
|
|
2412
|
+
},
|
|
2413
|
+
children: [
|
|
2414
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2415
|
+
/* @__PURE__ */ jsx(
|
|
2416
|
+
"div",
|
|
2417
|
+
{
|
|
2418
|
+
style: {
|
|
2419
|
+
color: "#9fb2ca",
|
|
2420
|
+
fontSize: "0.72rem",
|
|
2421
|
+
textTransform: "uppercase",
|
|
2422
|
+
letterSpacing: "0.08em"
|
|
2423
|
+
},
|
|
2424
|
+
children: "Aleph VM credit deployer"
|
|
2425
|
+
}
|
|
2426
|
+
),
|
|
2427
|
+
/* @__PURE__ */ jsx(
|
|
2428
|
+
"h2",
|
|
2429
|
+
{
|
|
2430
|
+
style: {
|
|
2431
|
+
margin: "0.2rem 0 0",
|
|
2432
|
+
fontFamily: '"Epilogue", sans-serif'
|
|
2433
|
+
},
|
|
2434
|
+
children: "Sponsor Relay"
|
|
2435
|
+
}
|
|
2436
|
+
)
|
|
2437
|
+
] }),
|
|
2438
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => void controller.refresh(), children: state.busy.refreshing ? "Syncing" : "Refresh" })
|
|
2439
|
+
]
|
|
2440
|
+
}
|
|
2441
|
+
),
|
|
1788
2442
|
/* @__PURE__ */ jsx("p", { style: { color: "#9fb2ca" }, children: state.statusText }),
|
|
1789
2443
|
state.errorText ? /* @__PURE__ */ jsx("p", { style: { color: "#ffd9d9" }, children: state.errorText }) : null,
|
|
1790
|
-
/* @__PURE__ */ jsxs(
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
{
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
2444
|
+
state.deploymentProgress.stage !== "idle" ? /* @__PURE__ */ jsxs(
|
|
2445
|
+
"div",
|
|
2446
|
+
{
|
|
2447
|
+
style: {
|
|
2448
|
+
marginTop: "0.85rem",
|
|
2449
|
+
padding: "0.75rem 0.8rem",
|
|
2450
|
+
borderRadius: "1rem",
|
|
2451
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
2452
|
+
background: "linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.03))",
|
|
2453
|
+
boxShadow: "inset 0 1px 0 rgba(255,255,255,0.04)"
|
|
2454
|
+
},
|
|
2455
|
+
children: [
|
|
2456
|
+
/* @__PURE__ */ jsxs(
|
|
2457
|
+
"div",
|
|
2458
|
+
{
|
|
2459
|
+
style: {
|
|
2460
|
+
display: "flex",
|
|
2461
|
+
justifyContent: "space-between",
|
|
2462
|
+
gap: "0.75rem",
|
|
2463
|
+
alignItems: "center"
|
|
2464
|
+
},
|
|
2465
|
+
children: [
|
|
2466
|
+
/* @__PURE__ */ jsxs(
|
|
2467
|
+
"div",
|
|
2468
|
+
{
|
|
2469
|
+
style: {
|
|
2470
|
+
display: "flex",
|
|
2471
|
+
gap: "0.5rem",
|
|
2472
|
+
alignItems: "center",
|
|
2473
|
+
minWidth: 0
|
|
2474
|
+
},
|
|
2475
|
+
children: [
|
|
2476
|
+
/* @__PURE__ */ jsx(
|
|
2477
|
+
"span",
|
|
2478
|
+
{
|
|
2479
|
+
style: {
|
|
2480
|
+
display: "inline-flex",
|
|
2481
|
+
alignItems: "center",
|
|
2482
|
+
justifyContent: "center",
|
|
2483
|
+
minWidth: "3.9rem",
|
|
2484
|
+
padding: "0.22rem 0.45rem",
|
|
2485
|
+
borderRadius: "999px",
|
|
2486
|
+
background: `${progressToneColor(state.deploymentProgress.status)}22`,
|
|
2487
|
+
color: progressToneColor(
|
|
2488
|
+
state.deploymentProgress.status
|
|
2489
|
+
),
|
|
2490
|
+
fontSize: "0.64rem",
|
|
2491
|
+
fontWeight: 800,
|
|
2492
|
+
letterSpacing: "0.08em",
|
|
2493
|
+
textTransform: "uppercase"
|
|
2494
|
+
},
|
|
2495
|
+
children: progressBadgeLabel(state.deploymentProgress.stage)
|
|
2496
|
+
}
|
|
2497
|
+
),
|
|
2498
|
+
/* @__PURE__ */ jsx(
|
|
2499
|
+
"strong",
|
|
2500
|
+
{
|
|
2501
|
+
style: {
|
|
2502
|
+
fontSize: "0.84rem",
|
|
2503
|
+
lineHeight: 1.2,
|
|
2504
|
+
whiteSpace: "nowrap",
|
|
2505
|
+
overflow: "hidden",
|
|
2506
|
+
textOverflow: "ellipsis"
|
|
2507
|
+
},
|
|
2508
|
+
children: state.deploymentProgress.label
|
|
2509
|
+
}
|
|
2510
|
+
)
|
|
2511
|
+
]
|
|
2512
|
+
}
|
|
2513
|
+
),
|
|
2514
|
+
/* @__PURE__ */ jsxs(
|
|
2515
|
+
"span",
|
|
2516
|
+
{
|
|
2517
|
+
style: {
|
|
2518
|
+
fontSize: "0.72rem",
|
|
2519
|
+
color: "#9fb2ca",
|
|
2520
|
+
fontFamily: '"DM Mono", monospace'
|
|
2521
|
+
},
|
|
2522
|
+
children: [
|
|
2523
|
+
String(
|
|
2524
|
+
Math.round(state.deploymentProgress.progress)
|
|
2525
|
+
).padStart(3, " "),
|
|
2526
|
+
"%"
|
|
2527
|
+
]
|
|
2528
|
+
}
|
|
2529
|
+
)
|
|
2530
|
+
]
|
|
2531
|
+
}
|
|
2532
|
+
),
|
|
2533
|
+
/* @__PURE__ */ jsx(
|
|
2534
|
+
"div",
|
|
2535
|
+
{
|
|
2536
|
+
style: {
|
|
2537
|
+
marginTop: "0.5rem",
|
|
2538
|
+
width: "100%",
|
|
2539
|
+
height: "0.34rem",
|
|
2540
|
+
borderRadius: "999px",
|
|
2541
|
+
background: "rgba(255,255,255,0.08)",
|
|
2542
|
+
overflow: "hidden"
|
|
2543
|
+
},
|
|
2544
|
+
children: /* @__PURE__ */ jsx(
|
|
2545
|
+
"div",
|
|
2546
|
+
{
|
|
2547
|
+
style: {
|
|
2548
|
+
width: `${Math.max(0, Math.min(100, state.deploymentProgress.progress))}%`,
|
|
2549
|
+
height: "100%",
|
|
2550
|
+
borderRadius: "999px",
|
|
2551
|
+
background: progressToneColor(
|
|
2552
|
+
state.deploymentProgress.status
|
|
2553
|
+
),
|
|
2554
|
+
transition: "width 180ms ease"
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
)
|
|
2558
|
+
}
|
|
2559
|
+
),
|
|
2560
|
+
/* @__PURE__ */ jsxs(
|
|
2561
|
+
"div",
|
|
2562
|
+
{
|
|
2563
|
+
style: {
|
|
2564
|
+
marginTop: "0.45rem",
|
|
2565
|
+
display: "grid",
|
|
2566
|
+
gap: "0.28rem"
|
|
2567
|
+
},
|
|
2568
|
+
children: [
|
|
2569
|
+
state.deploymentProgress.itemHash ? /* @__PURE__ */ jsxs(
|
|
2570
|
+
"div",
|
|
2571
|
+
{
|
|
2572
|
+
style: {
|
|
2573
|
+
color: "#9fb2ca",
|
|
2574
|
+
fontSize: "0.7rem",
|
|
2575
|
+
fontFamily: '"DM Mono", monospace',
|
|
2576
|
+
whiteSpace: "nowrap",
|
|
2577
|
+
overflow: "hidden",
|
|
2578
|
+
textOverflow: "ellipsis"
|
|
2579
|
+
},
|
|
2580
|
+
children: [
|
|
2581
|
+
"hash ",
|
|
2582
|
+
shortHash(state.deploymentProgress.itemHash, 10, 8)
|
|
2583
|
+
]
|
|
2584
|
+
}
|
|
2585
|
+
) : null,
|
|
2586
|
+
state.deploymentProgress.detail ? /* @__PURE__ */ jsx(
|
|
2587
|
+
"div",
|
|
2588
|
+
{
|
|
2589
|
+
style: {
|
|
2590
|
+
color: "#9fb2ca",
|
|
2591
|
+
fontSize: "0.72rem",
|
|
2592
|
+
lineHeight: 1.3,
|
|
2593
|
+
fontFamily: state.deploymentProgress.detail.includes("0x") || state.deploymentProgress.detail.includes("Qm") ? '"DM Mono", monospace' : void 0
|
|
2594
|
+
},
|
|
2595
|
+
children: state.deploymentProgress.detail
|
|
2596
|
+
}
|
|
2597
|
+
) : null,
|
|
2598
|
+
state.deploymentProgress.error ? /* @__PURE__ */ jsx(
|
|
2599
|
+
"div",
|
|
2600
|
+
{
|
|
2601
|
+
style: {
|
|
2602
|
+
color: "#ffd9d9",
|
|
2603
|
+
fontSize: "0.72rem",
|
|
2604
|
+
lineHeight: 1.3
|
|
2605
|
+
},
|
|
2606
|
+
children: state.deploymentProgress.error
|
|
2607
|
+
}
|
|
2608
|
+
) : null
|
|
2609
|
+
]
|
|
2610
|
+
}
|
|
2611
|
+
)
|
|
2612
|
+
]
|
|
2613
|
+
}
|
|
2614
|
+
) : null,
|
|
2615
|
+
/* @__PURE__ */ jsxs(
|
|
2616
|
+
"div",
|
|
2617
|
+
{
|
|
2618
|
+
style: { display: "grid", gap: "0.75rem", marginTop: "0.9rem" },
|
|
2619
|
+
children: [
|
|
2620
|
+
/* @__PURE__ */ jsx(
|
|
2621
|
+
"input",
|
|
2622
|
+
{
|
|
2623
|
+
style: fieldStyle,
|
|
2624
|
+
value: state.manifestUrl,
|
|
2625
|
+
onChange: (event) => controller.setManifestUrl(event.currentTarget.value),
|
|
2626
|
+
placeholder: "Manifest URL"
|
|
2627
|
+
}
|
|
2628
|
+
),
|
|
2629
|
+
/* @__PURE__ */ jsx(
|
|
2630
|
+
"input",
|
|
2631
|
+
{
|
|
2632
|
+
style: fieldStyle,
|
|
2633
|
+
value: state.instanceName,
|
|
2634
|
+
onChange: (event) => controller.setInstanceName(event.currentTarget.value),
|
|
2635
|
+
placeholder: "Instance name"
|
|
2636
|
+
}
|
|
2637
|
+
),
|
|
2638
|
+
/* @__PURE__ */ jsx(
|
|
2639
|
+
"select",
|
|
2640
|
+
{
|
|
2641
|
+
style: fieldStyle,
|
|
2642
|
+
value: state.pricingSummary.tier?.id ?? state.tierId,
|
|
2643
|
+
onChange: (event) => controller.setTierId(event.currentTarget.value),
|
|
2644
|
+
children: (state.pricingSummary.pricing?.tiers ?? []).map((tier) => /* @__PURE__ */ jsx("option", { value: tier.id, children: tier.id }, tier.id))
|
|
2645
|
+
}
|
|
2646
|
+
),
|
|
2647
|
+
/* @__PURE__ */ jsx(
|
|
2648
|
+
"textarea",
|
|
2649
|
+
{
|
|
2650
|
+
style: fieldStyle,
|
|
2651
|
+
rows: 3,
|
|
2652
|
+
value: state.sshPublicKey,
|
|
2653
|
+
onChange: (event) => controller.setSshPublicKey(event.currentTarget.value),
|
|
2654
|
+
placeholder: "SSH public key"
|
|
2655
|
+
}
|
|
2656
|
+
),
|
|
2657
|
+
/* @__PURE__ */ jsxs("details", { children: [
|
|
2658
|
+
/* @__PURE__ */ jsx("summary", { children: "Paste Manifest" }),
|
|
2659
|
+
/* @__PURE__ */ jsx(
|
|
2660
|
+
"textarea",
|
|
2661
|
+
{
|
|
2662
|
+
style: { ...fieldStyle, marginTop: "0.65rem" },
|
|
2663
|
+
rows: 7,
|
|
2664
|
+
value: state.manifestJson,
|
|
2665
|
+
onChange: (event) => controller.setManifestJson(event.currentTarget.value)
|
|
2666
|
+
}
|
|
2667
|
+
)
|
|
2668
|
+
] })
|
|
2669
|
+
]
|
|
2670
|
+
}
|
|
2671
|
+
),
|
|
1841
2672
|
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: "0.55rem", marginTop: "1rem" }, children: [
|
|
1842
2673
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1843
2674
|
formatNumber(state.pricingSummary.availableCredits, 0),
|
|
@@ -1863,40 +2694,68 @@ function SponsorRelayFab(props) {
|
|
|
1863
2694
|
"Latest deployment: ",
|
|
1864
2695
|
shortHash(state.lastDeploymentHash)
|
|
1865
2696
|
] }) : null,
|
|
1866
|
-
state.showInstances ? /* @__PURE__ */ jsx(
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
entry.
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
2697
|
+
state.showInstances ? /* @__PURE__ */ jsx(
|
|
2698
|
+
"div",
|
|
2699
|
+
{
|
|
2700
|
+
style: { marginTop: "1rem", display: "grid", gap: "0.7rem" },
|
|
2701
|
+
children: state.instances.map((entry) => /* @__PURE__ */ jsxs("details", { open: true, children: [
|
|
2702
|
+
/* @__PURE__ */ jsx("summary", { children: (entry.instance.content?.metadata?.name ?? "relay") + " \xB7 " + shortHash(entry.instance.item_hash) }),
|
|
2703
|
+
/* @__PURE__ */ jsxs(
|
|
2704
|
+
"div",
|
|
2705
|
+
{
|
|
2706
|
+
style: {
|
|
2707
|
+
display: "grid",
|
|
2708
|
+
gap: "0.35rem",
|
|
2709
|
+
marginTop: "0.55rem"
|
|
2710
|
+
},
|
|
2711
|
+
children: [
|
|
2712
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2713
|
+
"Status: ",
|
|
2714
|
+
entry.details.messageStatus
|
|
2715
|
+
] }),
|
|
2716
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2717
|
+
"Host IPv4: ",
|
|
2718
|
+
entry.details.hostIpv4 ?? "-"
|
|
2719
|
+
] }),
|
|
2720
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2721
|
+
"IPv6: ",
|
|
2722
|
+
entry.details.ipv6 ?? "-"
|
|
2723
|
+
] }),
|
|
2724
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2725
|
+
"VM IPv4: ",
|
|
2726
|
+
entry.details.vmIpv4 ?? "-"
|
|
2727
|
+
] }),
|
|
2728
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2729
|
+
"SSH: ",
|
|
2730
|
+
entry.details.sshCommand ?? "-"
|
|
2731
|
+
] }),
|
|
2732
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2733
|
+
"Ports: ",
|
|
2734
|
+
joinMappedPorts(entry.details.mappedPorts)
|
|
2735
|
+
] }),
|
|
2736
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2737
|
+
"Submitted:",
|
|
2738
|
+
" ",
|
|
2739
|
+
formatDateTime(
|
|
2740
|
+
entry.instance.reception_time ?? entry.instance.time
|
|
2741
|
+
)
|
|
2742
|
+
] }),
|
|
2743
|
+
/* @__PURE__ */ jsx(
|
|
2744
|
+
"button",
|
|
2745
|
+
{
|
|
2746
|
+
type: "button",
|
|
2747
|
+
onClick: () => void controller.deleteInstance(
|
|
2748
|
+
entry.instance.item_hash
|
|
2749
|
+
),
|
|
2750
|
+
children: state.busy.deletingInstanceHash === entry.instance.item_hash ? "Deleting\u2026" : "Delete"
|
|
2751
|
+
}
|
|
2752
|
+
)
|
|
2753
|
+
]
|
|
2754
|
+
}
|
|
2755
|
+
)
|
|
2756
|
+
] }, entry.instance.item_hash))
|
|
2757
|
+
}
|
|
2758
|
+
) : null
|
|
1900
2759
|
] })
|
|
1901
2760
|
] }) : null
|
|
1902
2761
|
] });
|