@mindexec/cli 0.2.23 → 0.2.25
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 +1 -1
- package/remote-hub.js +134 -1
- package/scripts/remote-fleet-render-smoke.mjs +87 -53
- package/scripts/remote-http-smoke.mjs +219 -39
- package/scripts/remote-hub-smoke.mjs +139 -0
- package/server.js +20 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +18 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +670 -395
- package/wwwroot/_framework/{Microsoft.CSharp.qrvp77qmhs.dll → Microsoft.CSharp.8bsm8vx6su.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Core.6rfnfdndxq.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.badrt1tkvv.dll → MindExecution.Kernel.z56elxihok.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.73w1bvz4r1.dll → MindExecution.Plugins.Admin.p5cs4ap87v.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.dvd82y422m.dll → MindExecution.Plugins.Business.s35og5uz44.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.m3ukc0xvom.dll → MindExecution.Plugins.Concept.zczca3fsxz.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.23tm2uvfvu.dll → MindExecution.Plugins.Directory.y74f55e8x3.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.8nrc7ge4ob.dll → MindExecution.Plugins.PlanMaster.jpdwbefrh1.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.3ox59073d8.dll → MindExecution.Plugins.YouTube.8nz4wv2nsj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.va1gxp0crd.dll → MindExecution.Shared.v6ani8nfp8.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Web.0cs29v57jl.dll +0 -0
- package/wwwroot/_framework/{System.Collections.x53e19vfsj.dll → System.Collections.23yxgetbju.dll} +0 -0
- package/wwwroot/_framework/{System.Collections.Concurrent.y1zmvuyipi.dll → System.Collections.Concurrent.vow3rm1dku.dll} +0 -0
- package/wwwroot/_framework/{System.Collections.Immutable.ug3j698qms.dll → System.Collections.Immutable.ap9596utv5.dll} +0 -0
- package/wwwroot/_framework/{System.Collections.NonGeneric.h66hj3863h.dll → System.Collections.NonGeneric.npjkaz40oc.dll} +0 -0
- package/wwwroot/_framework/{System.Collections.Specialized.umr3y27ntj.dll → System.Collections.Specialized.ugkjbs6p02.dll} +0 -0
- package/wwwroot/_framework/{System.ComponentModel.Annotations.tz6gnt4ebt.dll → System.ComponentModel.Annotations.clwo0z2oyu.dll} +0 -0
- package/wwwroot/_framework/{System.ComponentModel.Primitives.j7tiphu4rg.dll → System.ComponentModel.Primitives.end4v0xe2c.dll} +0 -0
- package/wwwroot/_framework/{System.ComponentModel.TypeConverter.ujlztox1gx.dll → System.ComponentModel.TypeConverter.tgtp5sm4iv.dll} +0 -0
- package/wwwroot/_framework/{System.ComponentModel.x9xz0ojfb6.dll → System.ComponentModel.wupoltkk1t.dll} +0 -0
- package/wwwroot/_framework/{System.Console.ijzpqmj7ne.dll → System.Console.9dik0wogo2.dll} +0 -0
- package/wwwroot/_framework/{System.Data.Common.1r0sqffq1p.dll → System.Data.Common.4v8jejsiu0.dll} +0 -0
- package/wwwroot/_framework/{System.Diagnostics.DiagnosticSource.9upoqwq09o.dll → System.Diagnostics.DiagnosticSource.e2q75ondtq.dll} +0 -0
- package/wwwroot/_framework/{System.Diagnostics.Process.m99azzntjm.dll → System.Diagnostics.Process.9736yjnxs8.dll} +0 -0
- package/wwwroot/_framework/{System.Diagnostics.TraceSource.pl7wv26myr.dll → System.Diagnostics.TraceSource.h9al53gbbw.dll} +0 -0
- package/wwwroot/_framework/{System.Diagnostics.Tracing.crlhfx6tut.dll → System.Diagnostics.Tracing.h4bcp2fo98.dll} +0 -0
- package/wwwroot/_framework/{System.Drawing.mi7d8hwowb.dll → System.Drawing.64oovy8qts.dll} +0 -0
- package/wwwroot/_framework/{System.Drawing.Primitives.22e4y9ikq9.dll → System.Drawing.Primitives.o6jiqpgbgl.dll} +0 -0
- package/wwwroot/_framework/{System.Formats.Asn1.jx23sjiqnn.dll → System.Formats.Asn1.rylx5ipd40.dll} +0 -0
- package/wwwroot/_framework/{System.IO.Compression.6fyoii3uej.dll → System.IO.Compression.iceabaupns.dll} +0 -0
- package/wwwroot/_framework/{System.IO.Pipelines.vg77t4cd4d.dll → System.IO.Pipelines.uw8csd3mlz.dll} +0 -0
- package/wwwroot/_framework/{System.Linq.Expressions.24xqiypwdt.dll → System.Linq.Expressions.ty95ava37f.dll} +0 -0
- package/wwwroot/_framework/{System.Linq.Queryable.hvd01d6rsa.dll → System.Linq.Queryable.hs2195jrwy.dll} +0 -0
- package/wwwroot/_framework/{System.Linq.1bkoxlqgmq.dll → System.Linq.hssodjwmlf.dll} +0 -0
- package/wwwroot/_framework/{System.Memory.8dx3lwgym4.dll → System.Memory.1k78n7wdxb.dll} +0 -0
- package/wwwroot/_framework/{System.Net.Http.eitrz660my.dll → System.Net.Http.3br8rfql4c.dll} +0 -0
- package/wwwroot/_framework/{System.Net.Http.Json.3mhdm9l1rf.dll → System.Net.Http.Json.860wbh17d8.dll} +0 -0
- package/wwwroot/_framework/{System.Net.NetworkInformation.3pkuofcv9r.dll → System.Net.NetworkInformation.e3wr00853o.dll} +0 -0
- package/wwwroot/_framework/{System.Net.Ping.8clj5pklrp.dll → System.Net.Ping.r5cw4mf1a4.dll} +0 -0
- package/wwwroot/_framework/{System.Net.Primitives.qrp4wcjz1p.dll → System.Net.Primitives.ksxwiwlvhu.dll} +0 -0
- package/wwwroot/_framework/{System.Net.WebSockets.qp6u31zvm5.dll → System.Net.WebSockets.6rt3n3gl2q.dll} +0 -0
- package/wwwroot/_framework/{System.Net.WebSockets.Client.2u6pv01g69.dll → System.Net.WebSockets.Client.z3usrzo7rz.dll} +0 -0
- package/wwwroot/_framework/{System.Numerics.Vectors.kc7ufp2j4l.dll → System.Numerics.Vectors.lbdzx8reja.dll} +0 -0
- package/wwwroot/_framework/{System.ObjectModel.qv82fot1ib.dll → System.ObjectModel.yct1gdirzf.dll} +0 -0
- package/wwwroot/_framework/{System.Private.CoreLib.rkafq04oma.dll → System.Private.CoreLib.ns29bor93l.dll} +0 -0
- package/wwwroot/_framework/{System.Private.Uri.t9542hmr6j.dll → System.Private.Uri.zp9kmg0z93.dll} +0 -0
- package/wwwroot/_framework/{System.Private.Xml.Linq.n8n3ptrbwu.dll → System.Private.Xml.Linq.lgv2n0akl4.dll} +0 -0
- package/wwwroot/_framework/{System.Private.Xml.rxd3tytisn.dll → System.Private.Xml.dpsk8g304y.dll} +0 -0
- package/wwwroot/_framework/{System.Reflection.Emit.ILGeneration.stxyk8zoo1.dll → System.Reflection.Emit.ILGeneration.1tcuz2cmbk.dll} +0 -0
- package/wwwroot/_framework/{System.Reflection.Emit.Lightweight.6xrd5v8vg0.dll → System.Reflection.Emit.Lightweight.ddt2wylovg.dll} +0 -0
- package/wwwroot/_framework/{System.Reflection.Emit.9tjhp6y0j3.dll → System.Reflection.Emit.d8vkadiwhg.dll} +0 -0
- package/wwwroot/_framework/{System.Reflection.Primitives.wgn8fpwwvv.dll → System.Reflection.Primitives.cpsl71xd1z.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.InteropServices.te07xr2we9.dll → System.Runtime.InteropServices.31vjgsfk1o.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.InteropServices.JavaScript.sliym526xh.dll → System.Runtime.InteropServices.JavaScript.pn2wvizzet.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.InteropServices.RuntimeInformation.oji7zut14z.dll → System.Runtime.InteropServices.RuntimeInformation.l5rk496q70.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.Intrinsics.507y4h8nzq.dll → System.Runtime.Intrinsics.0zee9qcqfy.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.Loader.v7gk4bse0k.dll → System.Runtime.Loader.xw2jr9wl92.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.Numerics.eqy5xjv3nd.dll → System.Runtime.Numerics.ezj1dfyvbj.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.Serialization.Formatters.zpkrub8lab.dll → System.Runtime.Serialization.Formatters.0y019e9zkr.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.Serialization.Primitives.vhkpnbxjip.dll → System.Runtime.Serialization.Primitives.bia5wb62c8.dll} +0 -0
- package/wwwroot/_framework/{System.Runtime.jn319d5nyg.dll → System.Runtime.h9cduidfkh.dll} +0 -0
- package/wwwroot/_framework/{System.Security.Claims.0ztig1q9vo.dll → System.Security.Claims.2r18wim2rl.dll} +0 -0
- package/wwwroot/_framework/{System.Security.Cryptography.vttizqc9ho.dll → System.Security.Cryptography.qqgybpoucx.dll} +0 -0
- package/wwwroot/_framework/{System.Text.Encoding.Extensions.utdd47ny8f.dll → System.Text.Encoding.Extensions.9t3hs6kyll.dll} +0 -0
- package/wwwroot/_framework/{System.Text.Encodings.Web.wah8r1zoe0.dll → System.Text.Encodings.Web.wftjfh2crk.dll} +0 -0
- package/wwwroot/_framework/{System.Text.Json.kxlfxj0wrs.dll → System.Text.Json.4s25e3op6i.dll} +0 -0
- package/wwwroot/_framework/{System.Text.RegularExpressions.dbqn58klox.dll → System.Text.RegularExpressions.cvkox11l6l.dll} +0 -0
- package/wwwroot/_framework/{System.Threading.Channels.hfa7j0uv2w.dll → System.Threading.Channels.419493szqu.dll} +0 -0
- package/wwwroot/_framework/{System.Threading.Thread.caul0pdqul.dll → System.Threading.Thread.xhmys87xh5.dll} +0 -0
- package/wwwroot/_framework/{System.Threading.42ao9vi047.dll → System.Threading.b66vzsz9g1.dll} +0 -0
- package/wwwroot/_framework/{System.Transactions.Local.fimi2hamzo.dll → System.Transactions.Local.7zfffdvnwf.dll} +0 -0
- package/wwwroot/_framework/{System.Web.HttpUtility.gq8yz50p2e.dll → System.Web.HttpUtility.9up6xfbtuq.dll} +0 -0
- package/wwwroot/_framework/{System.Xml.Linq.kitin4zjoj.dll → System.Xml.Linq.n5rzv9nbf7.dll} +0 -0
- package/wwwroot/_framework/{System.Xml.ReaderWriter.kzvw3qgxb0.dll → System.Xml.ReaderWriter.ag8pilllob.dll} +0 -0
- package/wwwroot/_framework/{System.Xml.XDocument.c539ki6cuq.dll → System.Xml.XDocument.sn51jas17n.dll} +0 -0
- package/wwwroot/_framework/{System.m05i39uvk9.dll → System.brmz7yk5qh.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +161 -161
- package/wwwroot/_framework/dotnet.js +1 -1
- package/wwwroot/_framework/{dotnet.native.vz0adxojrz.wasm → dotnet.native.boem75ye5i.wasm} +0 -0
- package/wwwroot/_framework/{dotnet.native.xsn1d6x2kd.js → dotnet.native.qc8g39g30v.js} +1 -1
- package/wwwroot/_framework/{dotnet.runtime.dstopyvqzi.js → dotnet.runtime.opaiwunc3t.js} +1 -1
- package/wwwroot/_framework/{netstandard.0xet7jg7ky.dll → netstandard.yvr3prsx0x.dll} +0 -0
- package/wwwroot/index.html +1 -1
- package/wwwroot/service-worker-assets.js +166 -166
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Core.c9fyqe953v.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.jmawk7z8d3.dll +0 -0
|
@@ -12139,6 +12139,25 @@
|
|
|
12139
12139
|
return `${Math.floor(seconds / 86400)}d ago`;
|
|
12140
12140
|
}
|
|
12141
12141
|
|
|
12142
|
+
function formatRemoteFleetTimeUntil(value) {
|
|
12143
|
+
const timestamp = Date.parse(String(value || ''));
|
|
12144
|
+
if (!Number.isFinite(timestamp)) {
|
|
12145
|
+
return '-';
|
|
12146
|
+
}
|
|
12147
|
+
|
|
12148
|
+
const seconds = Math.round((timestamp - Date.now()) / 1000);
|
|
12149
|
+
if (seconds <= 0) {
|
|
12150
|
+
return 'expired';
|
|
12151
|
+
}
|
|
12152
|
+
if (seconds < 60) {
|
|
12153
|
+
return `${seconds}s left`;
|
|
12154
|
+
}
|
|
12155
|
+
if (seconds < 3600) {
|
|
12156
|
+
return `${Math.floor(seconds / 60)}m left`;
|
|
12157
|
+
}
|
|
12158
|
+
return `${Math.floor(seconds / 3600)}h left`;
|
|
12159
|
+
}
|
|
12160
|
+
|
|
12142
12161
|
function createRemoteFleetStat(label, value, tone = 'default', key = '') {
|
|
12143
12162
|
const item = document.createElement('div');
|
|
12144
12163
|
if (key) {
|
|
@@ -12244,6 +12263,142 @@
|
|
|
12244
12263
|
const REMOTE_FLEET_TASK_FOLLOW_INITIAL_MS = 250;
|
|
12245
12264
|
const REMOTE_FLEET_TASK_FOLLOW_REFRESH_MS = 2000;
|
|
12246
12265
|
const REMOTE_FLEET_TASK_FOLLOW_MAX_TICKS = 60;
|
|
12266
|
+
const REMOTE_FLEET_HOST_LEASE_REFRESH_MS = 10000;
|
|
12267
|
+
const remoteFleetHostLeaseTimers = new Map();
|
|
12268
|
+
const remoteFleetLocalHostTargets = new Map();
|
|
12269
|
+
|
|
12270
|
+
function findRemoteFleetBodyByNodeId(nodeId) {
|
|
12271
|
+
const id = String(nodeId || '').trim();
|
|
12272
|
+
if (!id) return null;
|
|
12273
|
+
return Array.from(document.querySelectorAll('.map-node-remote-fleet__body[data-node-id]'))
|
|
12274
|
+
.find(body => String(body.dataset.nodeId || '').trim() === id) || null;
|
|
12275
|
+
}
|
|
12276
|
+
|
|
12277
|
+
function stopRemoteFleetHostLeaseTimer(nodeId) {
|
|
12278
|
+
const id = String(nodeId || '').trim();
|
|
12279
|
+
if (!id) return;
|
|
12280
|
+
const entry = remoteFleetHostLeaseTimers.get(id);
|
|
12281
|
+
if (entry?.timer) {
|
|
12282
|
+
clearInterval(entry.timer);
|
|
12283
|
+
}
|
|
12284
|
+
remoteFleetHostLeaseTimers.delete(id);
|
|
12285
|
+
}
|
|
12286
|
+
|
|
12287
|
+
function startRemoteFleetHostLeaseTimer(nodeId, renewCallback) {
|
|
12288
|
+
const id = String(nodeId || '').trim();
|
|
12289
|
+
if (!id || typeof renewCallback !== 'function') return;
|
|
12290
|
+
const existing = remoteFleetHostLeaseTimers.get(id);
|
|
12291
|
+
if (existing) {
|
|
12292
|
+
existing.renewCallback = renewCallback;
|
|
12293
|
+
return;
|
|
12294
|
+
}
|
|
12295
|
+
|
|
12296
|
+
const entry = { renewCallback, timer: null };
|
|
12297
|
+
const timer = setInterval(async () => {
|
|
12298
|
+
const currentBody = findRemoteFleetBodyByNodeId(id);
|
|
12299
|
+
if (!currentBody || currentBody.dataset.remoteFleetHostState !== 'hosting') {
|
|
12300
|
+
stopRemoteFleetHostLeaseTimer(id);
|
|
12301
|
+
return;
|
|
12302
|
+
}
|
|
12303
|
+
|
|
12304
|
+
try {
|
|
12305
|
+
await entry.renewCallback();
|
|
12306
|
+
} catch {
|
|
12307
|
+
stopRemoteFleetHostLeaseTimer(id);
|
|
12308
|
+
}
|
|
12309
|
+
}, REMOTE_FLEET_HOST_LEASE_REFRESH_MS);
|
|
12310
|
+
|
|
12311
|
+
timer?.unref?.();
|
|
12312
|
+
entry.timer = timer;
|
|
12313
|
+
remoteFleetHostLeaseTimers.set(id, entry);
|
|
12314
|
+
}
|
|
12315
|
+
|
|
12316
|
+
function getRemoteFleetNodeStateId(nodeState) {
|
|
12317
|
+
return String(nodeState?.nodeId ?? nodeState?.NodeId ?? nodeState?.id ?? nodeState?.Id ?? '').trim();
|
|
12318
|
+
}
|
|
12319
|
+
|
|
12320
|
+
function ensureRemoteFleetNodeStateMetadata(nodeState) {
|
|
12321
|
+
if (!nodeState || typeof nodeState !== 'object') return null;
|
|
12322
|
+
const metadata = nodeState.metadata && typeof nodeState.metadata === 'object'
|
|
12323
|
+
? nodeState.metadata
|
|
12324
|
+
: nodeState.Metadata && typeof nodeState.Metadata === 'object'
|
|
12325
|
+
? nodeState.Metadata
|
|
12326
|
+
: {};
|
|
12327
|
+
nodeState.metadata = metadata;
|
|
12328
|
+
nodeState.Metadata = metadata;
|
|
12329
|
+
return metadata;
|
|
12330
|
+
}
|
|
12331
|
+
|
|
12332
|
+
function readRemoteFleetObjectField(source, camelKey, pascalKey, fallback = '') {
|
|
12333
|
+
const value = source?.[camelKey] ?? source?.[pascalKey] ?? fallback;
|
|
12334
|
+
return value === undefined || value === null ? fallback : value;
|
|
12335
|
+
}
|
|
12336
|
+
|
|
12337
|
+
function isRemoteFleetResultSuccess(result) {
|
|
12338
|
+
return result?.success === true || result?.Success === true || result?.ok === true || result?.Ok === true;
|
|
12339
|
+
}
|
|
12340
|
+
|
|
12341
|
+
function isRemoteFleetResultActive(result) {
|
|
12342
|
+
return result?.active === true || result?.Active === true;
|
|
12343
|
+
}
|
|
12344
|
+
|
|
12345
|
+
function isRemoteFleetResultExplicitlyInactive(result) {
|
|
12346
|
+
return result?.active === false || result?.Active === false;
|
|
12347
|
+
}
|
|
12348
|
+
|
|
12349
|
+
function rememberRemoteFleetLocalHostTarget(nodeId, enabled, result) {
|
|
12350
|
+
const id = String(nodeId || '').trim();
|
|
12351
|
+
if (!id) return;
|
|
12352
|
+
if (enabled !== true) {
|
|
12353
|
+
if (isRemoteFleetResultSuccess(result)) {
|
|
12354
|
+
remoteFleetLocalHostTargets.delete(id);
|
|
12355
|
+
stopRemoteFleetHostLeaseTimer(id);
|
|
12356
|
+
}
|
|
12357
|
+
return;
|
|
12358
|
+
}
|
|
12359
|
+
|
|
12360
|
+
if (!isRemoteFleetResultSuccess(result) || isRemoteFleetResultExplicitlyInactive(result)) {
|
|
12361
|
+
return;
|
|
12362
|
+
}
|
|
12363
|
+
|
|
12364
|
+
const hostTarget = result?.hostTarget || result?.HostTarget || {};
|
|
12365
|
+
const now = new Date();
|
|
12366
|
+
const expiresAt = String(readRemoteFleetObjectField(hostTarget, 'expiresAt', 'ExpiresAt', '') || '').trim()
|
|
12367
|
+
|| new Date(now.getTime() + 60000).toISOString();
|
|
12368
|
+
remoteFleetLocalHostTargets.set(id, {
|
|
12369
|
+
nodeId: id,
|
|
12370
|
+
leaseId: String(readRemoteFleetObjectField(hostTarget, 'leaseId', 'LeaseId', '') || '').trim(),
|
|
12371
|
+
endpoint: String(readRemoteFleetObjectField(hostTarget, 'endpoint', 'Endpoint', '') || '').trim(),
|
|
12372
|
+
activatedAt: String(readRemoteFleetObjectField(hostTarget, 'activatedAt', 'ActivatedAt', '') || '').trim() || now.toISOString(),
|
|
12373
|
+
updatedAt: String(readRemoteFleetObjectField(hostTarget, 'updatedAt', 'UpdatedAt', '') || '').trim() || now.toISOString(),
|
|
12374
|
+
expiresAt
|
|
12375
|
+
});
|
|
12376
|
+
}
|
|
12377
|
+
|
|
12378
|
+
function applyRemoteFleetLocalHostTarget(nodeState) {
|
|
12379
|
+
const nodeId = getRemoteFleetNodeStateId(nodeState);
|
|
12380
|
+
if (!nodeId) return nodeState;
|
|
12381
|
+
const localHost = remoteFleetLocalHostTargets.get(nodeId);
|
|
12382
|
+
if (!localHost) return nodeState;
|
|
12383
|
+
|
|
12384
|
+
const expiresTime = Date.parse(localHost.expiresAt);
|
|
12385
|
+
if (!Number.isFinite(expiresTime) || expiresTime <= Date.now()) {
|
|
12386
|
+
remoteFleetLocalHostTargets.delete(nodeId);
|
|
12387
|
+
stopRemoteFleetHostLeaseTimer(nodeId);
|
|
12388
|
+
return nodeState;
|
|
12389
|
+
}
|
|
12390
|
+
|
|
12391
|
+
const metadata = ensureRemoteFleetNodeStateMetadata(nodeState);
|
|
12392
|
+
if (!metadata) return nodeState;
|
|
12393
|
+
metadata.RemoteFleetHostTargetState = 'hosting';
|
|
12394
|
+
metadata.RemoteFleetHostTargetNodeId = nodeId;
|
|
12395
|
+
metadata.RemoteFleetHostTargetLeaseId = localHost.leaseId;
|
|
12396
|
+
metadata.RemoteFleetHostTargetEndpoint = localHost.endpoint || metadata.RemoteFleetHubEndpoint || metadata.remoteFleetHubEndpoint || '';
|
|
12397
|
+
metadata.RemoteFleetHostTargetActivatedAtUtc = localHost.activatedAt;
|
|
12398
|
+
metadata.RemoteFleetHostTargetUpdatedAtUtc = localHost.updatedAt;
|
|
12399
|
+
metadata.RemoteFleetHostTargetExpiresAtUtc = localHost.expiresAt;
|
|
12400
|
+
return nodeState;
|
|
12401
|
+
}
|
|
12247
12402
|
|
|
12248
12403
|
function clearRemoteFleetTimers(bodyView) {
|
|
12249
12404
|
if (!bodyView) return;
|
|
@@ -12259,6 +12414,10 @@
|
|
|
12259
12414
|
clearTimeout(bodyView._remoteFleetTaskFollowTimer);
|
|
12260
12415
|
bodyView._remoteFleetTaskFollowTimer = null;
|
|
12261
12416
|
}
|
|
12417
|
+
if (bodyView._remoteFleetHostLeaseTimer) {
|
|
12418
|
+
clearInterval(bodyView._remoteFleetHostLeaseTimer);
|
|
12419
|
+
bodyView._remoteFleetHostLeaseTimer = null;
|
|
12420
|
+
}
|
|
12262
12421
|
}
|
|
12263
12422
|
|
|
12264
12423
|
function getRemoteFleetDeviceField(device, camelKey, pascalKey, fallback = '') {
|
|
@@ -12455,7 +12614,7 @@
|
|
|
12455
12614
|
async function syncRemoteFleetNodeStateFromResult(result) {
|
|
12456
12615
|
const nodeState = result?.nodeState || result?.refresh?.nodeState;
|
|
12457
12616
|
if (nodeState && window.mindMap?.syncNodeStates) {
|
|
12458
|
-
await window.mindMap.syncNodeStates([nodeState]);
|
|
12617
|
+
await window.mindMap.syncNodeStates([applyRemoteFleetLocalHostTarget(nodeState)]);
|
|
12459
12618
|
}
|
|
12460
12619
|
}
|
|
12461
12620
|
|
|
@@ -12997,6 +13156,16 @@
|
|
|
12997
13156
|
if (focusedDevice) {
|
|
12998
13157
|
bodyView.dataset.remoteFleetFocusDeviceId = getRemoteFleetDeviceId(focusedDevice);
|
|
12999
13158
|
}
|
|
13159
|
+
const selectedState = bodyView.dataset.remoteFleetSelectedDeviceId || focusState || '';
|
|
13160
|
+
const selectedDevice = devices.find(device => getRemoteFleetDeviceId(device) === selectedState)
|
|
13161
|
+
|| focusedDevice
|
|
13162
|
+
|| devices[0]
|
|
13163
|
+
|| null;
|
|
13164
|
+
if (selectedDevice) {
|
|
13165
|
+
bodyView.dataset.remoteFleetSelectedDeviceId = getRemoteFleetDeviceId(selectedDevice);
|
|
13166
|
+
} else {
|
|
13167
|
+
delete bodyView.dataset.remoteFleetSelectedDeviceId;
|
|
13168
|
+
}
|
|
13000
13169
|
const total = Number(getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetDeviceCount', devices.length));
|
|
13001
13170
|
const connected = Number(getRemoteFleetMetadataValue(
|
|
13002
13171
|
nodeModel,
|
|
@@ -13005,15 +13174,24 @@
|
|
|
13005
13174
|
const taskCapableCount = devices.filter(device => isRemoteFleetDeviceConnected(device) && isRemoteFleetDeviceTaskCapable(device)).length;
|
|
13006
13175
|
const aiCapableCount = devices.filter(device => isRemoteFleetDeviceConnected(device) && isRemoteFleetDeviceAiCapable(device)).length;
|
|
13007
13176
|
const endpoint = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubEndpoint', '127.0.0.1:5197');
|
|
13008
|
-
const
|
|
13009
|
-
|
|
13010
|
-
'RemoteFleetConnectCommand',
|
|
13011
|
-
`npx @mindexec/remote connect --manager ${endpoint} --pair <pair-token>`);
|
|
13177
|
+
const managerPackage = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetManagerPackage', '@mindexec/cli');
|
|
13178
|
+
const managerVersion = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetManagerVersion', '');
|
|
13012
13179
|
const hubStatus = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubStatus', 'offline');
|
|
13013
13180
|
const refreshedAt = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetLastRefreshAtUtc', '');
|
|
13014
13181
|
const lastError = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetLastError', '');
|
|
13182
|
+
const hostTargetState = String(getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHostTargetState', 'inactive')).trim().toLowerCase();
|
|
13183
|
+
const hostTargetNodeId = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHostTargetNodeId', '');
|
|
13184
|
+
const hostTargetEndpoint = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHostTargetEndpoint', endpoint);
|
|
13185
|
+
const hostTargetExpiresAt = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHostTargetExpiresAtUtc', '');
|
|
13186
|
+
const isHostingTarget = hostTargetState === 'hosting';
|
|
13187
|
+
const otherMonitorHosting = hostTargetState === 'other-monitor';
|
|
13188
|
+
|
|
13189
|
+
if (!isHostingTarget) {
|
|
13190
|
+
stopRemoteFleetHostLeaseTimer(nodeId);
|
|
13191
|
+
}
|
|
13015
13192
|
|
|
13016
13193
|
bodyView.dataset.src = `remote-fleet:${refreshedAt}:${devices.length}:${connected}`;
|
|
13194
|
+
bodyView.dataset.remoteFleetHostState = hostTargetState;
|
|
13017
13195
|
bodyView.classList.add('map-node-remote-fleet__body');
|
|
13018
13196
|
bodyView.innerHTML = '';
|
|
13019
13197
|
bodyView.style.cssText = `
|
|
@@ -13028,86 +13206,116 @@
|
|
|
13028
13206
|
background: linear-gradient(180deg, rgba(248, 250, 252, 0.96), rgba(241, 245, 249, 0.92));
|
|
13029
13207
|
`;
|
|
13030
13208
|
|
|
13031
|
-
const
|
|
13032
|
-
|
|
13033
|
-
display:
|
|
13034
|
-
|
|
13035
|
-
|
|
13209
|
+
const headerRow = document.createElement('div');
|
|
13210
|
+
headerRow.style.cssText = `
|
|
13211
|
+
display: flex;
|
|
13212
|
+
align-items: flex-start;
|
|
13213
|
+
justify-content: space-between;
|
|
13214
|
+
gap: 10px;
|
|
13036
13215
|
flex: 0 0 auto;
|
|
13216
|
+
min-width: 0;
|
|
13037
13217
|
`;
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13218
|
+
const headerMeta = document.createElement('div');
|
|
13219
|
+
headerMeta.style.cssText = `
|
|
13220
|
+
min-width: 0;
|
|
13221
|
+
display: flex;
|
|
13222
|
+
flex-direction: column;
|
|
13223
|
+
gap: 4px;
|
|
13224
|
+
`;
|
|
13225
|
+
const managerRow = document.createElement('div');
|
|
13226
|
+
managerRow.dataset.remoteFleetManagerVersion = 'true';
|
|
13227
|
+
managerRow.textContent = `${managerPackage}${managerVersion ? ` ${managerVersion}` : ''} - ${endpoint}`;
|
|
13228
|
+
managerRow.title = managerRow.textContent;
|
|
13229
|
+
managerRow.style.cssText = `
|
|
13050
13230
|
flex: 0 0 auto;
|
|
13231
|
+
min-width: 0;
|
|
13232
|
+
overflow: hidden;
|
|
13233
|
+
text-overflow: ellipsis;
|
|
13234
|
+
white-space: nowrap;
|
|
13235
|
+
color: #475569;
|
|
13236
|
+
font-size: 10px;
|
|
13237
|
+
font-weight: 850;
|
|
13238
|
+
line-height: 1.2;
|
|
13239
|
+
letter-spacing: 0;
|
|
13051
13240
|
`;
|
|
13052
13241
|
|
|
13053
|
-
const
|
|
13054
|
-
|
|
13055
|
-
|
|
13242
|
+
const hostStatusRow = document.createElement('div');
|
|
13243
|
+
hostStatusRow.dataset.remoteFleetHostState = 'true';
|
|
13244
|
+
const hostStatusText = isHostingTarget
|
|
13245
|
+
? 'Host: Active'
|
|
13246
|
+
: otherMonitorHosting
|
|
13247
|
+
? 'Host: Other monitor'
|
|
13248
|
+
: 'Host: Inactive';
|
|
13249
|
+
const hostLeaseText = isHostingTarget && hostTargetExpiresAt
|
|
13250
|
+
? ` - lease ${formatRemoteFleetTimeUntil(hostTargetExpiresAt)}`
|
|
13251
|
+
: '';
|
|
13252
|
+
hostStatusRow.textContent = `${hostStatusText}${hostLeaseText}`;
|
|
13253
|
+
hostStatusRow.title = otherMonitorHosting
|
|
13254
|
+
? `Active host monitor: ${hostTargetNodeId || 'unknown'}`
|
|
13255
|
+
: `Endpoint ${hostTargetEndpoint || endpoint}`;
|
|
13256
|
+
hostStatusRow.style.cssText = `
|
|
13257
|
+
flex: 0 0 auto;
|
|
13056
13258
|
min-width: 0;
|
|
13057
13259
|
overflow: hidden;
|
|
13058
13260
|
text-overflow: ellipsis;
|
|
13059
13261
|
white-space: nowrap;
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
color: #e2e8f0;
|
|
13064
|
-
font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
|
13065
|
-
font-size: 11px;
|
|
13262
|
+
color: ${isHostingTarget ? '#047857' : otherMonitorHosting ? '#7c2d12' : '#64748b'};
|
|
13263
|
+
font-size: 10px;
|
|
13264
|
+
font-weight: 900;
|
|
13066
13265
|
line-height: 1.2;
|
|
13266
|
+
letter-spacing: 0;
|
|
13067
13267
|
`;
|
|
13068
|
-
|
|
13268
|
+
headerMeta.appendChild(managerRow);
|
|
13269
|
+
headerMeta.appendChild(hostStatusRow);
|
|
13069
13270
|
|
|
13070
|
-
const
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
autoMonitorLabel.title = 'Refresh stale thumbnails on a bounded timer';
|
|
13074
|
-
autoMonitorLabel.style.cssText = `
|
|
13271
|
+
const hostActions = document.createElement('div');
|
|
13272
|
+
hostActions.style.cssText = `
|
|
13273
|
+
flex: 0 0 auto;
|
|
13075
13274
|
display: inline-flex;
|
|
13076
13275
|
align-items: center;
|
|
13077
|
-
justify-content:
|
|
13276
|
+
justify-content: flex-end;
|
|
13078
13277
|
gap: 6px;
|
|
13079
|
-
height: 34px;
|
|
13080
|
-
padding: 0 9px;
|
|
13081
|
-
border-radius: 7px;
|
|
13082
|
-
border: 1px solid rgba(14, 165, 233, 0.28);
|
|
13083
|
-
background: ${autoMonitorState ? 'rgba(240, 249, 255, 0.92)' : 'rgba(248, 250, 252, 0.92)'};
|
|
13084
|
-
color: ${autoMonitorState ? '#0369a1' : '#475569'};
|
|
13085
|
-
font-size: 11px;
|
|
13086
|
-
font-weight: 900;
|
|
13087
|
-
letter-spacing: 0;
|
|
13088
|
-
cursor: pointer;
|
|
13089
|
-
pointer-events: auto;
|
|
13090
|
-
user-select: none;
|
|
13091
13278
|
`;
|
|
13092
|
-
const
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13279
|
+
const hostButton = createRemoteFleetButton(
|
|
13280
|
+
isHostingTarget ? 'Hosting' : 'Set Host',
|
|
13281
|
+
isHostingTarget
|
|
13282
|
+
? 'Renew this monitor as the active host target for remote agents.'
|
|
13283
|
+
: 'Set this monitor as the active host target for remote agents.',
|
|
13284
|
+
'set-host');
|
|
13285
|
+
hostButton.dataset.remoteFleetHostActive = isHostingTarget ? 'true' : 'false';
|
|
13286
|
+
hostButton.style.height = '30px';
|
|
13287
|
+
hostButton.style.minWidth = '78px';
|
|
13288
|
+
hostButton.style.borderColor = isHostingTarget ? 'rgba(16, 185, 129, 0.38)' : 'rgba(37, 99, 235, 0.32)';
|
|
13289
|
+
hostButton.style.background = isHostingTarget ? 'rgba(236, 253, 245, 0.96)' : '#ffffff';
|
|
13290
|
+
hostButton.style.color = isHostingTarget ? '#047857' : '#1d4ed8';
|
|
13291
|
+
let stopHostButton = null;
|
|
13292
|
+
if (isHostingTarget) {
|
|
13293
|
+
stopHostButton = createRemoteFleetButton('Stop', 'Stop using this monitor as the host target.', 'stop-host');
|
|
13294
|
+
stopHostButton.style.height = '30px';
|
|
13295
|
+
stopHostButton.style.borderColor = 'rgba(239, 68, 68, 0.30)';
|
|
13296
|
+
stopHostButton.style.color = '#b91c1c';
|
|
13297
|
+
stopHostButton.style.background = 'rgba(254, 242, 242, 0.94)';
|
|
13298
|
+
}
|
|
13299
|
+
hostActions.appendChild(hostButton);
|
|
13300
|
+
if (stopHostButton) {
|
|
13301
|
+
hostActions.appendChild(stopHostButton);
|
|
13302
|
+
}
|
|
13303
|
+
headerRow.appendChild(headerMeta);
|
|
13304
|
+
headerRow.appendChild(hostActions);
|
|
13305
|
+
bodyView.appendChild(headerRow);
|
|
13306
|
+
|
|
13307
|
+
const top = document.createElement('div');
|
|
13308
|
+
top.style.cssText = `
|
|
13309
|
+
display: grid;
|
|
13310
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
13311
|
+
gap: 8px;
|
|
13312
|
+
flex: 0 0 auto;
|
|
13101
13313
|
`;
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
commandRow.appendChild(autoMonitorLabel);
|
|
13108
|
-
commandRow.appendChild(copyButton);
|
|
13109
|
-
commandRow.appendChild(refreshButton);
|
|
13110
|
-
bodyView.appendChild(commandRow);
|
|
13314
|
+
top.appendChild(createRemoteFleetStat('Hub', hubStatus === 'online' ? 'Online' : 'Offline', hubStatus === 'online' ? 'online' : 'default'));
|
|
13315
|
+
top.appendChild(createRemoteFleetStat('Connected', `${Number.isFinite(connected) ? connected : 0}/${Number.isFinite(total) ? total : devices.length}`, connected > 0 ? 'online' : 'default'));
|
|
13316
|
+
top.appendChild(createRemoteFleetStat('Task', String(taskCapableCount), taskCapableCount > 0 ? 'online' : 'default'));
|
|
13317
|
+
top.appendChild(createRemoteFleetStat('AI', String(aiCapableCount), aiCapableCount > 0 ? 'online' : 'default'));
|
|
13318
|
+
bodyView.appendChild(top);
|
|
13111
13319
|
|
|
13112
13320
|
const filterRow = document.createElement('div');
|
|
13113
13321
|
filterRow.style.cssText = `
|
|
@@ -13197,7 +13405,7 @@
|
|
|
13197
13405
|
|
|
13198
13406
|
const taskRow = document.createElement('div');
|
|
13199
13407
|
taskRow.style.cssText = `
|
|
13200
|
-
display:
|
|
13408
|
+
display: none;
|
|
13201
13409
|
grid-template-columns: minmax(0, 1fr) auto auto auto;
|
|
13202
13410
|
gap: 8px;
|
|
13203
13411
|
align-items: stretch;
|
|
@@ -13205,7 +13413,7 @@
|
|
|
13205
13413
|
`;
|
|
13206
13414
|
const taskInput = document.createElement('textarea');
|
|
13207
13415
|
taskInput.dataset.remoteFleetTaskInput = 'true';
|
|
13208
|
-
taskInput.placeholder = '
|
|
13416
|
+
taskInput.placeholder = '';
|
|
13209
13417
|
taskInput.rows = 2;
|
|
13210
13418
|
taskInput.style.cssText = `
|
|
13211
13419
|
width: 100%;
|
|
@@ -13267,7 +13475,7 @@
|
|
|
13267
13475
|
taskRow.appendChild(aiToggleLabel);
|
|
13268
13476
|
taskRow.appendChild(sendVisibleButton);
|
|
13269
13477
|
taskRow.appendChild(sendConnectedButton);
|
|
13270
|
-
|
|
13478
|
+
taskRow.dataset.remoteFleetTaskComposer = 'hidden';
|
|
13271
13479
|
|
|
13272
13480
|
const taskFeedback = document.createElement('div');
|
|
13273
13481
|
taskFeedback.dataset.remoteFleetTaskFeedback = 'true';
|
|
@@ -13606,14 +13814,299 @@
|
|
|
13606
13814
|
bodyView.appendChild(errorEl);
|
|
13607
13815
|
}
|
|
13608
13816
|
|
|
13817
|
+
const createDevicePreview = (device, mode = 'tile') => {
|
|
13818
|
+
const name = getRemoteFleetDeviceName(device);
|
|
13819
|
+
const connectedDevice = isRemoteFleetDeviceConnected(device);
|
|
13820
|
+
const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
|
|
13821
|
+
const liveStreamEnabled = device?.liveStreamEnabled === true || device?.LiveStreamEnabled === true;
|
|
13822
|
+
const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
|
|
13823
|
+
const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
|
|
13824
|
+
const liveFrameDataUrl = String(device?.liveFrameDataUrl || device?.LiveFrameDataUrl || '');
|
|
13825
|
+
const liveFrameReceivedAt = String(device?.liveFrameReceivedAt || device?.LiveFrameReceivedAt || '');
|
|
13826
|
+
const hasThumbnail = hasRemoteFleetThumbnail(device);
|
|
13827
|
+
const hasLiveFrame = hasRemoteFleetLiveFrame(device);
|
|
13828
|
+
const previewDataUrl = hasLiveFrame ? liveFrameDataUrl : thumbnailDataUrl;
|
|
13829
|
+
const previewAt = hasLiveFrame ? liveFrameReceivedAt : thumbnailCapturedAt;
|
|
13830
|
+
const isDetail = mode === 'detail';
|
|
13831
|
+
|
|
13832
|
+
const preview = document.createElement('div');
|
|
13833
|
+
preview.dataset.remoteFleetDevicePreview = mode;
|
|
13834
|
+
preview.style.cssText = `
|
|
13835
|
+
position: relative;
|
|
13836
|
+
width: 100%;
|
|
13837
|
+
aspect-ratio: 16 / 9;
|
|
13838
|
+
overflow: hidden;
|
|
13839
|
+
border-radius: ${isDetail ? '8px' : '6px'};
|
|
13840
|
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
13841
|
+
border: 1px solid rgba(15, 23, 42, ${isDetail ? '0.16' : '0.10'});
|
|
13842
|
+
`;
|
|
13843
|
+
|
|
13844
|
+
if (hasLiveFrame || hasThumbnail) {
|
|
13845
|
+
const image = document.createElement('img');
|
|
13846
|
+
image.src = previewDataUrl;
|
|
13847
|
+
image.alt = hasLiveFrame ? `${name} live frame` : `${name} thumbnail`;
|
|
13848
|
+
image.loading = 'lazy';
|
|
13849
|
+
image.decoding = 'async';
|
|
13850
|
+
image.style.cssText = `
|
|
13851
|
+
width: 100%;
|
|
13852
|
+
height: 100%;
|
|
13853
|
+
object-fit: cover;
|
|
13854
|
+
display: block;
|
|
13855
|
+
`;
|
|
13856
|
+
preview.appendChild(image);
|
|
13857
|
+
} else {
|
|
13858
|
+
const placeholder = document.createElement('div');
|
|
13859
|
+
placeholder.textContent = thumbnailEnabled || liveStreamEnabled ? 'No screen' : 'No screen';
|
|
13860
|
+
placeholder.style.cssText = `
|
|
13861
|
+
position: absolute;
|
|
13862
|
+
inset: 0;
|
|
13863
|
+
display: flex;
|
|
13864
|
+
align-items: center;
|
|
13865
|
+
justify-content: center;
|
|
13866
|
+
color: rgba(226, 232, 240, 0.80);
|
|
13867
|
+
font-size: ${isDetail ? '12px' : '10px'};
|
|
13868
|
+
font-weight: 900;
|
|
13869
|
+
letter-spacing: 0;
|
|
13870
|
+
`;
|
|
13871
|
+
preview.appendChild(placeholder);
|
|
13872
|
+
}
|
|
13873
|
+
|
|
13874
|
+
const dot = document.createElement('span');
|
|
13875
|
+
dot.style.cssText = `
|
|
13876
|
+
position: absolute;
|
|
13877
|
+
left: ${isDetail ? '9px' : '6px'};
|
|
13878
|
+
top: ${isDetail ? '9px' : '6px'};
|
|
13879
|
+
width: ${isDetail ? '10px' : '8px'};
|
|
13880
|
+
height: ${isDetail ? '10px' : '8px'};
|
|
13881
|
+
border-radius: 999px;
|
|
13882
|
+
background: ${connectedDevice ? '#10b981' : '#94a3b8'};
|
|
13883
|
+
box-shadow: 0 0 0 3px ${connectedDevice ? 'rgba(16,185,129,0.20)' : 'rgba(148,163,184,0.18)'};
|
|
13884
|
+
`;
|
|
13885
|
+
preview.appendChild(dot);
|
|
13886
|
+
|
|
13887
|
+
if (hasLiveFrame || (isDetail && previewAt)) {
|
|
13888
|
+
const badge = document.createElement('span');
|
|
13889
|
+
badge.textContent = hasLiveFrame
|
|
13890
|
+
? (isDetail && previewAt ? `LIVE ${formatRemoteFleetAge(previewAt)}` : 'LIVE')
|
|
13891
|
+
: formatRemoteFleetAge(previewAt);
|
|
13892
|
+
badge.style.cssText = `
|
|
13893
|
+
position: absolute;
|
|
13894
|
+
right: ${isDetail ? '9px' : '6px'};
|
|
13895
|
+
bottom: ${isDetail ? '9px' : '6px'};
|
|
13896
|
+
max-width: calc(100% - ${isDetail ? '18px' : '12px'});
|
|
13897
|
+
padding: ${isDetail ? '4px 7px' : '3px 6px'};
|
|
13898
|
+
border-radius: 999px;
|
|
13899
|
+
background: ${hasLiveFrame ? 'rgba(220, 38, 38, 0.84)' : 'rgba(15, 23, 42, 0.72)'};
|
|
13900
|
+
color: #e2e8f0;
|
|
13901
|
+
font-size: ${isDetail ? '9px' : '8px'};
|
|
13902
|
+
font-weight: 950;
|
|
13903
|
+
line-height: 1;
|
|
13904
|
+
overflow: hidden;
|
|
13905
|
+
text-overflow: ellipsis;
|
|
13906
|
+
white-space: nowrap;
|
|
13907
|
+
letter-spacing: 0;
|
|
13908
|
+
`;
|
|
13909
|
+
preview.appendChild(badge);
|
|
13910
|
+
}
|
|
13911
|
+
|
|
13912
|
+
return preview;
|
|
13913
|
+
};
|
|
13914
|
+
|
|
13915
|
+
const createSelectedDevicePanel = device => {
|
|
13916
|
+
const panel = document.createElement('aside');
|
|
13917
|
+
panel.dataset.remoteFleetDetailPanel = 'true';
|
|
13918
|
+
panel.style.cssText = `
|
|
13919
|
+
min-width: 0;
|
|
13920
|
+
min-height: 0;
|
|
13921
|
+
overflow-y: auto;
|
|
13922
|
+
display: flex;
|
|
13923
|
+
flex-direction: column;
|
|
13924
|
+
gap: 9px;
|
|
13925
|
+
padding: 10px;
|
|
13926
|
+
border-radius: 8px;
|
|
13927
|
+
border: 1px solid rgba(148, 163, 184, 0.28);
|
|
13928
|
+
background: rgba(255, 255, 255, 0.86);
|
|
13929
|
+
`;
|
|
13930
|
+
|
|
13931
|
+
if (!device) {
|
|
13932
|
+
const empty = document.createElement('div');
|
|
13933
|
+
empty.textContent = 'Select a screen';
|
|
13934
|
+
empty.style.cssText = 'display:flex;align-items:center;justify-content:center;min-height:120px;color:#64748b;font-size:12px;font-weight:900;';
|
|
13935
|
+
panel.appendChild(empty);
|
|
13936
|
+
return panel;
|
|
13937
|
+
}
|
|
13938
|
+
|
|
13939
|
+
const deviceId = getRemoteFleetDeviceId(device);
|
|
13940
|
+
const name = getRemoteFleetDeviceName(device);
|
|
13941
|
+
const connectedDevice = isRemoteFleetDeviceConnected(device);
|
|
13942
|
+
const platform = [device?.platform || device?.Platform, device?.arch || device?.Arch]
|
|
13943
|
+
.filter(Boolean)
|
|
13944
|
+
.join(' / ') || 'unknown';
|
|
13945
|
+
const release = String(device?.release || device?.Release || '');
|
|
13946
|
+
const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
|
|
13947
|
+
const liveStreamEnabled = device?.liveStreamEnabled === true || device?.LiveStreamEnabled === true;
|
|
13948
|
+
const liveStreamActive = isRemoteFleetLiveActive(device);
|
|
13949
|
+
const liveStreamId = String(device?.liveStreamId || device?.LiveStreamId || '');
|
|
13950
|
+
const taskEnabled = isRemoteFleetDeviceTaskCapable(device);
|
|
13951
|
+
const aiAssistEnabled = isRemoteFleetDeviceAiCapable(device);
|
|
13952
|
+
const aiModel = String(device?.aiModel || device?.AiModel || '');
|
|
13953
|
+
const latestTaskStatus = String(device?.latestTaskStatus || device?.LatestTaskStatus || '');
|
|
13954
|
+
const latestTaskTitle = String(device?.latestTaskTitle || device?.LatestTaskTitle || '');
|
|
13955
|
+
const latestTaskApproval = String(device?.latestTaskApprovalLevel || device?.LatestTaskApprovalLevel || '');
|
|
13956
|
+
const latestTaskUpdatedAt = String(device?.latestTaskUpdatedAt || device?.LatestTaskUpdatedAt || '');
|
|
13957
|
+
const latestTaskError = String(device?.latestTaskError || device?.LatestTaskError || '');
|
|
13958
|
+
const latestTaskResultModel = String(device?.latestTaskResultModel || device?.LatestTaskResultModel || '');
|
|
13959
|
+
const latestTaskResultResponseId = String(device?.latestTaskResultResponseId || device?.LatestTaskResultResponseId || '');
|
|
13960
|
+
const latestTaskResult = String(device?.latestTaskResultSummary || device?.LatestTaskResultSummary || '');
|
|
13961
|
+
const statusText = connectedDevice
|
|
13962
|
+
? (liveStreamActive ? 'Live' : (aiAssistEnabled ? `AI ${aiModel || 'ready'}` : 'Connected'))
|
|
13963
|
+
: 'Offline';
|
|
13964
|
+
|
|
13965
|
+
panel.dataset.deviceId = deviceId;
|
|
13966
|
+
panel.appendChild(createDevicePreview(device, 'detail'));
|
|
13967
|
+
|
|
13968
|
+
const header = document.createElement('div');
|
|
13969
|
+
header.style.cssText = 'display:flex;align-items:flex-start;justify-content:space-between;gap:8px;min-width:0;';
|
|
13970
|
+
const titleBox = document.createElement('div');
|
|
13971
|
+
titleBox.style.cssText = 'min-width:0;display:flex;flex-direction:column;gap:3px;';
|
|
13972
|
+
const title = document.createElement('strong');
|
|
13973
|
+
title.textContent = name;
|
|
13974
|
+
title.title = name;
|
|
13975
|
+
title.style.cssText = 'color:#0f172a;font-size:14px;font-weight:950;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;';
|
|
13976
|
+
const subtitle = document.createElement('span');
|
|
13977
|
+
subtitle.textContent = release ? `${platform} ${release}` : platform;
|
|
13978
|
+
subtitle.title = subtitle.textContent;
|
|
13979
|
+
subtitle.style.cssText = 'color:#64748b;font-size:11px;font-weight:750;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;';
|
|
13980
|
+
titleBox.appendChild(title);
|
|
13981
|
+
titleBox.appendChild(subtitle);
|
|
13982
|
+
const status = document.createElement('span');
|
|
13983
|
+
status.textContent = statusText;
|
|
13984
|
+
status.style.cssText = `
|
|
13985
|
+
flex: 0 0 auto;
|
|
13986
|
+
max-width: 82px;
|
|
13987
|
+
padding: 4px 7px;
|
|
13988
|
+
border-radius: 999px;
|
|
13989
|
+
background: ${liveStreamActive ? 'rgba(254, 226, 226, 0.92)' : (connectedDevice ? 'rgba(209, 250, 229, 0.92)' : 'rgba(226, 232, 240, 0.92)')};
|
|
13990
|
+
color: ${liveStreamActive ? '#b91c1c' : (connectedDevice ? '#047857' : '#475569')};
|
|
13991
|
+
font-size: 9px;
|
|
13992
|
+
font-weight: 950;
|
|
13993
|
+
line-height: 1;
|
|
13994
|
+
overflow: hidden;
|
|
13995
|
+
text-overflow: ellipsis;
|
|
13996
|
+
white-space: nowrap;
|
|
13997
|
+
letter-spacing: 0;
|
|
13998
|
+
`;
|
|
13999
|
+
header.appendChild(titleBox);
|
|
14000
|
+
header.appendChild(status);
|
|
14001
|
+
panel.appendChild(header);
|
|
14002
|
+
|
|
14003
|
+
const metrics = document.createElement('div');
|
|
14004
|
+
metrics.style.cssText = 'display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;';
|
|
14005
|
+
const addDetailMetric = (label, value) => {
|
|
14006
|
+
const metric = document.createElement('div');
|
|
14007
|
+
metric.style.cssText = 'min-width:0;padding:7px 8px;border-radius:7px;background:rgba(241,245,249,0.86);border:1px solid rgba(148,163,184,0.16);';
|
|
14008
|
+
const labelEl = document.createElement('div');
|
|
14009
|
+
labelEl.textContent = label;
|
|
14010
|
+
labelEl.style.cssText = 'color:#64748b;font-size:9px;font-weight:850;letter-spacing:0;text-transform:uppercase;';
|
|
14011
|
+
const valueEl = document.createElement('div');
|
|
14012
|
+
valueEl.textContent = value;
|
|
14013
|
+
valueEl.title = value;
|
|
14014
|
+
valueEl.style.cssText = 'color:#0f172a;font-size:12px;font-weight:950;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;';
|
|
14015
|
+
metric.appendChild(labelEl);
|
|
14016
|
+
metric.appendChild(valueEl);
|
|
14017
|
+
metrics.appendChild(metric);
|
|
14018
|
+
};
|
|
14019
|
+
addDetailMetric('Seen', formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt));
|
|
14020
|
+
addDetailMetric('Uptime', formatRemoteFleetDuration(device?.uptimeSec ?? device?.UptimeSec));
|
|
14021
|
+
addDetailMetric('Mem', formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio));
|
|
14022
|
+
addDetailMetric('Load', formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2));
|
|
14023
|
+
panel.appendChild(metrics);
|
|
14024
|
+
|
|
14025
|
+
if (latestTaskStatus || latestTaskTitle || latestTaskResult || latestTaskError) {
|
|
14026
|
+
const taskBox = document.createElement('div');
|
|
14027
|
+
const taskTone = latestTaskError || latestTaskStatus === 'failed'
|
|
14028
|
+
? 'error'
|
|
14029
|
+
: (latestTaskStatus === 'completed' ? 'done' : 'pending');
|
|
14030
|
+
taskBox.style.cssText = `
|
|
14031
|
+
display: flex;
|
|
14032
|
+
flex-direction: column;
|
|
14033
|
+
gap: 4px;
|
|
14034
|
+
min-width: 0;
|
|
14035
|
+
padding: 8px 9px;
|
|
14036
|
+
border-radius: 7px;
|
|
14037
|
+
background: ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.12)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.10)' : 'rgba(37, 99, 235, 0.08)'};
|
|
14038
|
+
border: 1px solid ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.24)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.20)' : 'rgba(37, 99, 235, 0.16)'};
|
|
14039
|
+
`;
|
|
14040
|
+
const taskLine = document.createElement('div');
|
|
14041
|
+
const taskModeLabel = latestTaskApproval === 'ai-assist' ? 'AI' : 'Task';
|
|
14042
|
+
taskLine.textContent = `${taskModeLabel} ${latestTaskStatus || 'task'}${latestTaskUpdatedAt ? ` - ${formatRemoteFleetAge(latestTaskUpdatedAt)}` : ''}${latestTaskResultModel ? ` - ${latestTaskResultModel}` : ''}`;
|
|
14043
|
+
taskLine.title = latestTaskResultResponseId
|
|
14044
|
+
? `${taskLine.textContent} (${latestTaskResultResponseId})`
|
|
14045
|
+
: taskLine.textContent;
|
|
14046
|
+
taskLine.style.cssText = `color:${taskTone === 'error' ? '#991b1b' : taskTone === 'done' ? '#047857' : '#1d4ed8'};font-size:10px;font-weight:950;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;`;
|
|
14047
|
+
const taskSummary = document.createElement('div');
|
|
14048
|
+
taskSummary.textContent = formatRemoteFleetTaskError(latestTaskError) || latestTaskResult || latestTaskTitle || 'Task queued';
|
|
14049
|
+
taskSummary.title = taskSummary.textContent;
|
|
14050
|
+
taskSummary.style.cssText = 'color:#334155;font-size:10px;font-weight:750;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;letter-spacing:0;';
|
|
14051
|
+
taskBox.appendChild(taskLine);
|
|
14052
|
+
taskBox.appendChild(taskSummary);
|
|
14053
|
+
panel.appendChild(taskBox);
|
|
14054
|
+
}
|
|
14055
|
+
|
|
14056
|
+
const actions = document.createElement('div');
|
|
14057
|
+
actions.style.cssText = 'display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:auto;';
|
|
14058
|
+
if (deviceId) {
|
|
14059
|
+
const pinButton = createRemoteFleetButton('Pin', 'Pin this device as a canvas node', 'pin-device');
|
|
14060
|
+
pinButton.dataset.deviceId = deviceId;
|
|
14061
|
+
actions.appendChild(pinButton);
|
|
14062
|
+
}
|
|
14063
|
+
if (connectedDevice && deviceId) {
|
|
14064
|
+
const focusButton = createRemoteFleetButton('Focus', 'Show this device in focused live panel', 'live-focus');
|
|
14065
|
+
focusButton.dataset.deviceId = deviceId;
|
|
14066
|
+
actions.appendChild(focusButton);
|
|
14067
|
+
if (liveStreamEnabled) {
|
|
14068
|
+
const liveButton = createRemoteFleetButton(liveStreamActive ? 'Stop' : 'Live', liveStreamActive ? 'Stop live stream' : 'Start focused live stream', liveStreamActive ? 'live-stop' : 'live-start');
|
|
14069
|
+
liveButton.dataset.deviceId = deviceId;
|
|
14070
|
+
liveButton.dataset.streamId = liveStreamId;
|
|
14071
|
+
if (liveStreamActive) {
|
|
14072
|
+
liveButton.style.borderColor = 'rgba(220, 38, 38, 0.32)';
|
|
14073
|
+
liveButton.style.color = '#b91c1c';
|
|
14074
|
+
}
|
|
14075
|
+
actions.appendChild(liveButton);
|
|
14076
|
+
}
|
|
14077
|
+
if (thumbnailEnabled) {
|
|
14078
|
+
const thumbnailButton = createRemoteFleetButton('Shot', 'Request thumbnail', 'thumbnail-device');
|
|
14079
|
+
thumbnailButton.dataset.deviceId = deviceId;
|
|
14080
|
+
actions.appendChild(thumbnailButton);
|
|
14081
|
+
}
|
|
14082
|
+
const pingButton = createRemoteFleetButton('Ping', 'Ping device', 'ping-device');
|
|
14083
|
+
pingButton.dataset.deviceId = deviceId;
|
|
14084
|
+
actions.appendChild(pingButton);
|
|
14085
|
+
}
|
|
14086
|
+
panel.appendChild(actions);
|
|
14087
|
+
return panel;
|
|
14088
|
+
};
|
|
14089
|
+
|
|
14090
|
+
const monitorWorkspace = document.createElement('div');
|
|
14091
|
+
monitorWorkspace.dataset.remoteFleetMonitorWorkspace = 'true';
|
|
14092
|
+
monitorWorkspace.style.cssText = `
|
|
14093
|
+
flex: 1 1 auto;
|
|
14094
|
+
min-height: 0;
|
|
14095
|
+
overflow: hidden;
|
|
14096
|
+
display: grid;
|
|
14097
|
+
grid-template-columns: minmax(0, 1fr) minmax(230px, 270px);
|
|
14098
|
+
gap: 10px;
|
|
14099
|
+
align-items: stretch;
|
|
14100
|
+
`;
|
|
14101
|
+
|
|
13609
14102
|
const grid = document.createElement('div');
|
|
14103
|
+
grid.dataset.remoteFleetDeviceGrid = 'true';
|
|
13610
14104
|
grid.style.cssText = `
|
|
13611
|
-
flex: 1 1 auto;
|
|
13612
14105
|
min-height: 0;
|
|
13613
14106
|
overflow-y: auto;
|
|
13614
14107
|
overflow-x: hidden;
|
|
13615
14108
|
display: grid;
|
|
13616
|
-
grid-template-columns: ${densityState === 'dense' ? 'repeat(auto-fill, minmax(
|
|
14109
|
+
grid-template-columns: ${densityState === 'dense' ? 'repeat(auto-fill, minmax(118px, 1fr))' : 'repeat(auto-fill, minmax(148px, 1fr))'};
|
|
13617
14110
|
align-content: start;
|
|
13618
14111
|
gap: 8px;
|
|
13619
14112
|
padding-right: 4px;
|
|
@@ -13659,32 +14152,15 @@
|
|
|
13659
14152
|
devices.forEach(device => {
|
|
13660
14153
|
const connectedDevice = isRemoteFleetDeviceConnected(device);
|
|
13661
14154
|
const name = getRemoteFleetDeviceName(device);
|
|
13662
|
-
const platform = [device?.platform || device?.Platform, device?.arch || device?.Arch]
|
|
13663
|
-
.filter(Boolean)
|
|
13664
|
-
.join(' / ') || 'unknown';
|
|
13665
|
-
const release = String(device?.release || device?.Release || '');
|
|
13666
14155
|
const deviceId = getRemoteFleetDeviceId(device);
|
|
13667
|
-
const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
|
|
13668
|
-
const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
|
|
13669
|
-
const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
|
|
13670
14156
|
const liveStreamEnabled = device?.liveStreamEnabled === true || device?.LiveStreamEnabled === true;
|
|
13671
14157
|
const liveStreamActive = isRemoteFleetLiveActive(device);
|
|
13672
|
-
const liveStreamId = String(device?.liveStreamId || device?.LiveStreamId || '');
|
|
13673
|
-
const liveFrameDataUrl = String(device?.liveFrameDataUrl || device?.LiveFrameDataUrl || '');
|
|
13674
|
-
const liveFrameReceivedAt = String(device?.liveFrameReceivedAt || device?.LiveFrameReceivedAt || '');
|
|
13675
14158
|
const hasThumbnail = hasRemoteFleetThumbnail(device);
|
|
13676
14159
|
const hasLiveFrame = hasRemoteFleetLiveFrame(device);
|
|
13677
14160
|
const taskEnabled = isRemoteFleetDeviceTaskCapable(device);
|
|
13678
14161
|
const aiAssistEnabled = isRemoteFleetDeviceAiCapable(device);
|
|
13679
|
-
const aiModel = String(device?.aiModel || device?.AiModel || '');
|
|
13680
14162
|
const latestTaskStatus = String(device?.latestTaskStatus || device?.LatestTaskStatus || '');
|
|
13681
|
-
const latestTaskTitle = String(device?.latestTaskTitle || device?.LatestTaskTitle || '');
|
|
13682
|
-
const latestTaskApproval = String(device?.latestTaskApprovalLevel || device?.LatestTaskApprovalLevel || '');
|
|
13683
|
-
const latestTaskUpdatedAt = String(device?.latestTaskUpdatedAt || device?.LatestTaskUpdatedAt || '');
|
|
13684
14163
|
const latestTaskError = String(device?.latestTaskError || device?.LatestTaskError || '');
|
|
13685
|
-
const latestTaskResultModel = String(device?.latestTaskResultModel || device?.LatestTaskResultModel || '');
|
|
13686
|
-
const latestTaskResultResponseId = String(device?.latestTaskResultResponseId || device?.LatestTaskResultResponseId || '');
|
|
13687
|
-
const latestTaskResult = String(device?.latestTaskResultSummary || device?.LatestTaskResultSummary || '');
|
|
13688
14164
|
const groupInfo = getRemoteFleetGroupInfo(device, groupState);
|
|
13689
14165
|
if (groupState !== 'none' && groupInfo.key && groupInfo.key !== lastGroupKey) {
|
|
13690
14166
|
const stat = groupStats.get(groupInfo.key) || { label: groupInfo.label, total: 0, connected: 0 };
|
|
@@ -13719,6 +14195,8 @@
|
|
|
13719
14195
|
grid.appendChild(groupHeader);
|
|
13720
14196
|
lastGroupKey = groupInfo.key;
|
|
13721
14197
|
}
|
|
14198
|
+
const selectedDeviceId = selectedDevice ? getRemoteFleetDeviceId(selectedDevice) : '';
|
|
14199
|
+
const isSelected = deviceId && deviceId === selectedDeviceId;
|
|
13722
14200
|
const card = document.createElement('article');
|
|
13723
14201
|
card.dataset.deviceId = deviceId;
|
|
13724
14202
|
card.dataset.remoteFleetSearchText = buildRemoteFleetSearchText(device);
|
|
@@ -13730,292 +14208,28 @@
|
|
|
13730
14208
|
card.dataset.remoteFleetLiveCapable = liveStreamEnabled ? 'true' : 'false';
|
|
13731
14209
|
card.dataset.remoteFleetLiveActive = liveStreamActive ? 'true' : 'false';
|
|
13732
14210
|
card.dataset.remoteFleetIssue = (!connectedDevice || latestTaskStatus === 'failed' || !!latestTaskError) ? 'true' : 'false';
|
|
14211
|
+
card.dataset.remoteFleetSelected = isSelected ? 'true' : 'false';
|
|
14212
|
+
card.dataset.remoteFleetAction = 'select-device';
|
|
14213
|
+
card.setAttribute('role', 'button');
|
|
14214
|
+
card.setAttribute('aria-label', `Show details for ${name}`);
|
|
14215
|
+
card.tabIndex = 0;
|
|
14216
|
+
card.title = name;
|
|
13733
14217
|
card.style.cssText = `
|
|
14218
|
+
position: relative;
|
|
13734
14219
|
display: flex;
|
|
13735
|
-
|
|
13736
|
-
gap: ${densityState === 'dense' ? '6px' : '8px'};
|
|
14220
|
+
align-items: stretch;
|
|
13737
14221
|
min-width: 0;
|
|
13738
|
-
min-height: ${densityState === 'dense' ? '
|
|
13739
|
-
padding:
|
|
14222
|
+
min-height: ${densityState === 'dense' ? '66px' : '84px'};
|
|
14223
|
+
padding: 2px;
|
|
13740
14224
|
border-radius: 8px;
|
|
13741
14225
|
background: #ffffff;
|
|
13742
|
-
border:
|
|
13743
|
-
box-shadow: 0 8px
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
const previewDataUrl = hasLiveFrame ? liveFrameDataUrl : thumbnailDataUrl;
|
|
13748
|
-
const previewAt = hasLiveFrame ? liveFrameReceivedAt : thumbnailCapturedAt;
|
|
13749
|
-
const preview = document.createElement('div');
|
|
13750
|
-
preview.style.cssText = `
|
|
13751
|
-
position: relative;
|
|
13752
|
-
width: 100%;
|
|
13753
|
-
aspect-ratio: 16 / 9;
|
|
13754
|
-
overflow: hidden;
|
|
13755
|
-
border-radius: 7px;
|
|
13756
|
-
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
13757
|
-
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
13758
|
-
`;
|
|
13759
|
-
if (hasLiveFrame || hasThumbnail) {
|
|
13760
|
-
const image = document.createElement('img');
|
|
13761
|
-
image.src = previewDataUrl;
|
|
13762
|
-
image.alt = hasLiveFrame ? `${name} live frame` : `${name} thumbnail`;
|
|
13763
|
-
image.loading = 'lazy';
|
|
13764
|
-
image.decoding = 'async';
|
|
13765
|
-
image.style.cssText = `
|
|
13766
|
-
width: 100%;
|
|
13767
|
-
height: 100%;
|
|
13768
|
-
object-fit: cover;
|
|
13769
|
-
display: block;
|
|
13770
|
-
`;
|
|
13771
|
-
preview.appendChild(image);
|
|
13772
|
-
} else {
|
|
13773
|
-
const placeholder = document.createElement('div');
|
|
13774
|
-
placeholder.textContent = thumbnailEnabled ? 'No frame yet' : 'Status only';
|
|
13775
|
-
placeholder.style.cssText = `
|
|
13776
|
-
position: absolute;
|
|
13777
|
-
inset: 0;
|
|
13778
|
-
display: flex;
|
|
13779
|
-
align-items: center;
|
|
13780
|
-
justify-content: center;
|
|
13781
|
-
color: rgba(226, 232, 240, 0.78);
|
|
13782
|
-
font-size: 11px;
|
|
13783
|
-
font-weight: 900;
|
|
13784
|
-
letter-spacing: 0;
|
|
13785
|
-
`;
|
|
13786
|
-
preview.appendChild(placeholder);
|
|
13787
|
-
}
|
|
13788
|
-
if (previewAt) {
|
|
13789
|
-
const badge = document.createElement('span');
|
|
13790
|
-
badge.textContent = hasLiveFrame
|
|
13791
|
-
? `LIVE ${formatRemoteFleetAge(previewAt)}`
|
|
13792
|
-
: formatRemoteFleetAge(previewAt);
|
|
13793
|
-
badge.style.cssText = `
|
|
13794
|
-
position: absolute;
|
|
13795
|
-
right: 6px;
|
|
13796
|
-
bottom: 6px;
|
|
13797
|
-
max-width: calc(100% - 12px);
|
|
13798
|
-
padding: 3px 6px;
|
|
13799
|
-
border-radius: 999px;
|
|
13800
|
-
background: ${hasLiveFrame ? 'rgba(220, 38, 38, 0.82)' : 'rgba(15, 23, 42, 0.74)'};
|
|
13801
|
-
color: #e2e8f0;
|
|
13802
|
-
font-size: 9px;
|
|
13803
|
-
font-weight: 900;
|
|
13804
|
-
line-height: 1;
|
|
13805
|
-
overflow: hidden;
|
|
13806
|
-
text-overflow: ellipsis;
|
|
13807
|
-
white-space: nowrap;
|
|
13808
|
-
`;
|
|
13809
|
-
preview.appendChild(badge);
|
|
13810
|
-
}
|
|
13811
|
-
card.appendChild(preview);
|
|
13812
|
-
}
|
|
13813
|
-
|
|
13814
|
-
const cardHeader = document.createElement('div');
|
|
13815
|
-
cardHeader.style.cssText = 'display:flex;align-items:flex-start;gap:8px;min-width:0;';
|
|
13816
|
-
const dot = document.createElement('span');
|
|
13817
|
-
dot.style.cssText = `
|
|
13818
|
-
flex: 0 0 auto;
|
|
13819
|
-
width: 9px;
|
|
13820
|
-
height: 9px;
|
|
13821
|
-
margin-top: 4px;
|
|
13822
|
-
border-radius: 999px;
|
|
13823
|
-
background: ${connectedDevice ? '#10b981' : '#94a3b8'};
|
|
13824
|
-
box-shadow: 0 0 0 4px ${connectedDevice ? 'rgba(16,185,129,0.14)' : 'rgba(148,163,184,0.14)'};
|
|
13825
|
-
`;
|
|
13826
|
-
|
|
13827
|
-
const titleBox = document.createElement('div');
|
|
13828
|
-
titleBox.style.cssText = 'min-width:0;display:flex;flex-direction:column;gap:2px;';
|
|
13829
|
-
const title = document.createElement('strong');
|
|
13830
|
-
title.textContent = name;
|
|
13831
|
-
title.title = name;
|
|
13832
|
-
title.style.cssText = `
|
|
13833
|
-
color: #0f172a;
|
|
13834
|
-
font-size: 13px;
|
|
13835
|
-
font-weight: 900;
|
|
13836
|
-
line-height: 1.2;
|
|
13837
|
-
overflow: hidden;
|
|
13838
|
-
text-overflow: ellipsis;
|
|
13839
|
-
white-space: nowrap;
|
|
13840
|
-
letter-spacing: 0;
|
|
13841
|
-
`;
|
|
13842
|
-
const subtitle = document.createElement('span');
|
|
13843
|
-
subtitle.textContent = release ? `${platform} ${release}` : platform;
|
|
13844
|
-
subtitle.title = subtitle.textContent;
|
|
13845
|
-
subtitle.style.cssText = `
|
|
13846
|
-
color: #64748b;
|
|
13847
|
-
font-size: 11px;
|
|
13848
|
-
line-height: 1.2;
|
|
13849
|
-
overflow: hidden;
|
|
13850
|
-
text-overflow: ellipsis;
|
|
13851
|
-
white-space: nowrap;
|
|
13852
|
-
letter-spacing: 0;
|
|
13853
|
-
`;
|
|
13854
|
-
titleBox.appendChild(title);
|
|
13855
|
-
titleBox.appendChild(subtitle);
|
|
13856
|
-
cardHeader.appendChild(dot);
|
|
13857
|
-
cardHeader.appendChild(titleBox);
|
|
13858
|
-
card.appendChild(cardHeader);
|
|
13859
|
-
|
|
13860
|
-
const metrics = document.createElement('div');
|
|
13861
|
-
metrics.style.cssText = `
|
|
13862
|
-
display: grid;
|
|
13863
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
13864
|
-
gap: 6px;
|
|
13865
|
-
`;
|
|
13866
|
-
const addMetric = (label, value) => {
|
|
13867
|
-
const metric = document.createElement('div');
|
|
13868
|
-
metric.style.cssText = `
|
|
13869
|
-
min-width: 0;
|
|
13870
|
-
padding: 6px 7px;
|
|
13871
|
-
border-radius: 7px;
|
|
13872
|
-
background: rgba(241, 245, 249, 0.84);
|
|
13873
|
-
`;
|
|
13874
|
-
const labelEl = document.createElement('div');
|
|
13875
|
-
labelEl.textContent = label;
|
|
13876
|
-
labelEl.style.cssText = 'color:#64748b;font-size:9px;font-weight:800;letter-spacing:0;text-transform:uppercase;';
|
|
13877
|
-
const valueEl = document.createElement('div');
|
|
13878
|
-
valueEl.textContent = value;
|
|
13879
|
-
valueEl.title = value;
|
|
13880
|
-
valueEl.style.cssText = 'color:#0f172a;font-size:12px;font-weight:900;letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
|
|
13881
|
-
metric.appendChild(labelEl);
|
|
13882
|
-
metric.appendChild(valueEl);
|
|
13883
|
-
metrics.appendChild(metric);
|
|
13884
|
-
};
|
|
13885
|
-
addMetric('Seen', formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt));
|
|
13886
|
-
addMetric('Uptime', formatRemoteFleetDuration(device?.uptimeSec ?? device?.UptimeSec));
|
|
13887
|
-
addMetric('Mem', formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio));
|
|
13888
|
-
addMetric('Load', formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2));
|
|
13889
|
-
if (densityState === 'dense') {
|
|
13890
|
-
const denseMeta = document.createElement('div');
|
|
13891
|
-
denseMeta.textContent = `Seen ${formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt)} - Mem ${formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio)} - Load ${formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2)}`;
|
|
13892
|
-
denseMeta.style.cssText = `
|
|
13893
|
-
color: #475569;
|
|
13894
|
-
font-size: 10px;
|
|
13895
|
-
font-weight: 750;
|
|
13896
|
-
line-height: 1.2;
|
|
13897
|
-
overflow: hidden;
|
|
13898
|
-
text-overflow: ellipsis;
|
|
13899
|
-
white-space: nowrap;
|
|
13900
|
-
letter-spacing: 0;
|
|
13901
|
-
`;
|
|
13902
|
-
card.appendChild(denseMeta);
|
|
13903
|
-
} else {
|
|
13904
|
-
card.appendChild(metrics);
|
|
13905
|
-
}
|
|
13906
|
-
|
|
13907
|
-
if (latestTaskStatus || latestTaskTitle || latestTaskResult || latestTaskError) {
|
|
13908
|
-
const taskBox = document.createElement('div');
|
|
13909
|
-
const taskTone = latestTaskError || latestTaskStatus === 'failed'
|
|
13910
|
-
? 'error'
|
|
13911
|
-
: (latestTaskStatus === 'completed' ? 'done' : 'pending');
|
|
13912
|
-
taskBox.style.cssText = `
|
|
13913
|
-
display: flex;
|
|
13914
|
-
flex-direction: column;
|
|
13915
|
-
gap: 3px;
|
|
13916
|
-
min-width: 0;
|
|
13917
|
-
padding: 7px 8px;
|
|
13918
|
-
border-radius: 7px;
|
|
13919
|
-
background: ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.12)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.10)' : 'rgba(37, 99, 235, 0.08)'};
|
|
13920
|
-
border: 1px solid ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.24)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.20)' : 'rgba(37, 99, 235, 0.16)'};
|
|
13921
|
-
`;
|
|
13922
|
-
const taskLine = document.createElement('div');
|
|
13923
|
-
const taskModeLabel = latestTaskApproval === 'ai-assist' ? 'AI' : 'Task';
|
|
13924
|
-
taskLine.textContent = `${taskModeLabel} ${latestTaskStatus || 'task'}${latestTaskUpdatedAt ? ` - ${formatRemoteFleetAge(latestTaskUpdatedAt)}` : ''}${latestTaskResultModel ? ` - ${latestTaskResultModel}` : ''}`;
|
|
13925
|
-
taskLine.title = latestTaskResultResponseId
|
|
13926
|
-
? `${taskLine.textContent} (${latestTaskResultResponseId})`
|
|
13927
|
-
: taskLine.textContent;
|
|
13928
|
-
taskLine.style.cssText = `
|
|
13929
|
-
color: ${taskTone === 'error' ? '#991b1b' : taskTone === 'done' ? '#047857' : '#1d4ed8'};
|
|
13930
|
-
font-size: 10px;
|
|
13931
|
-
font-weight: 900;
|
|
13932
|
-
line-height: 1.2;
|
|
13933
|
-
overflow: hidden;
|
|
13934
|
-
text-overflow: ellipsis;
|
|
13935
|
-
white-space: nowrap;
|
|
13936
|
-
letter-spacing: 0;
|
|
13937
|
-
`;
|
|
13938
|
-
const taskSummary = document.createElement('div');
|
|
13939
|
-
taskSummary.textContent = formatRemoteFleetTaskError(latestTaskError) || latestTaskResult || latestTaskTitle || 'Task queued';
|
|
13940
|
-
taskSummary.title = taskSummary.textContent;
|
|
13941
|
-
taskSummary.style.cssText = `
|
|
13942
|
-
color: #334155;
|
|
13943
|
-
font-size: 10px;
|
|
13944
|
-
font-weight: 700;
|
|
13945
|
-
line-height: 1.25;
|
|
13946
|
-
overflow: hidden;
|
|
13947
|
-
display: -webkit-box;
|
|
13948
|
-
-webkit-line-clamp: 2;
|
|
13949
|
-
-webkit-box-orient: vertical;
|
|
13950
|
-
letter-spacing: 0;
|
|
13951
|
-
`;
|
|
13952
|
-
taskBox.appendChild(taskLine);
|
|
13953
|
-
taskBox.appendChild(taskSummary);
|
|
13954
|
-
card.appendChild(taskBox);
|
|
13955
|
-
}
|
|
13956
|
-
|
|
13957
|
-
const actions = document.createElement('div');
|
|
13958
|
-
actions.style.cssText = 'display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:auto;';
|
|
13959
|
-
const status = document.createElement('span');
|
|
13960
|
-
status.textContent = connectedDevice
|
|
13961
|
-
? (liveStreamActive ? 'Live' : (aiAssistEnabled ? `AI ${aiModel || 'ready'}` : 'Connected'))
|
|
13962
|
-
: 'Offline';
|
|
13963
|
-
status.style.cssText = `
|
|
13964
|
-
min-width: 0;
|
|
13965
|
-
color: ${liveStreamActive ? '#b91c1c' : (connectedDevice ? '#047857' : '#64748b')};
|
|
13966
|
-
font-size: 11px;
|
|
13967
|
-
font-weight: 900;
|
|
13968
|
-
overflow: hidden;
|
|
13969
|
-
text-overflow: ellipsis;
|
|
13970
|
-
white-space: nowrap;
|
|
14226
|
+
border: 2px solid ${isSelected ? 'rgba(37, 99, 235, 0.76)' : (connectedDevice ? 'rgba(16, 185, 129, 0.30)' : 'rgba(148, 163, 184, 0.24)')};
|
|
14227
|
+
box-shadow: ${isSelected ? '0 0 0 3px rgba(37, 99, 235, 0.15), 0 10px 22px rgba(15, 23, 42, 0.08)' : '0 8px 18px rgba(15, 23, 42, 0.05)'};
|
|
14228
|
+
cursor: pointer;
|
|
14229
|
+
pointer-events: auto;
|
|
14230
|
+
user-select: none;
|
|
13971
14231
|
`;
|
|
13972
|
-
|
|
13973
|
-
if (deviceId) {
|
|
13974
|
-
const pinButton = createRemoteFleetButton('Pin', 'Pin this device as a canvas node', 'pin-device');
|
|
13975
|
-
pinButton.dataset.deviceId = deviceId;
|
|
13976
|
-
pinButton.style.height = '24px';
|
|
13977
|
-
pinButton.style.fontSize = '10px';
|
|
13978
|
-
actions.appendChild(pinButton);
|
|
13979
|
-
}
|
|
13980
|
-
if (connectedDevice && deviceId) {
|
|
13981
|
-
const focusButton = createRemoteFleetButton('Focus', 'Show this device in focused live panel', 'live-focus');
|
|
13982
|
-
focusButton.dataset.deviceId = deviceId;
|
|
13983
|
-
focusButton.style.height = '24px';
|
|
13984
|
-
focusButton.style.fontSize = '10px';
|
|
13985
|
-
actions.appendChild(focusButton);
|
|
13986
|
-
if (liveStreamEnabled) {
|
|
13987
|
-
const liveButton = createRemoteFleetButton(liveStreamActive ? 'Stop' : 'Live', liveStreamActive ? 'Stop live stream' : 'Start focused live stream', liveStreamActive ? 'live-stop' : 'live-start');
|
|
13988
|
-
liveButton.dataset.deviceId = deviceId;
|
|
13989
|
-
liveButton.dataset.streamId = liveStreamId;
|
|
13990
|
-
liveButton.style.height = '24px';
|
|
13991
|
-
liveButton.style.fontSize = '10px';
|
|
13992
|
-
if (liveStreamActive) {
|
|
13993
|
-
liveButton.style.borderColor = 'rgba(220, 38, 38, 0.32)';
|
|
13994
|
-
liveButton.style.color = '#b91c1c';
|
|
13995
|
-
}
|
|
13996
|
-
actions.appendChild(liveButton);
|
|
13997
|
-
}
|
|
13998
|
-
if (taskEnabled) {
|
|
13999
|
-
const taskButton = createRemoteFleetButton('Task', 'Dispatch task to this device', 'task-device');
|
|
14000
|
-
taskButton.dataset.deviceId = deviceId;
|
|
14001
|
-
taskButton.style.height = '24px';
|
|
14002
|
-
taskButton.style.fontSize = '10px';
|
|
14003
|
-
actions.appendChild(taskButton);
|
|
14004
|
-
}
|
|
14005
|
-
if (thumbnailEnabled) {
|
|
14006
|
-
const thumbnailButton = createRemoteFleetButton('Shot', 'Request thumbnail', 'thumbnail-device');
|
|
14007
|
-
thumbnailButton.dataset.deviceId = deviceId;
|
|
14008
|
-
thumbnailButton.style.height = '24px';
|
|
14009
|
-
thumbnailButton.style.fontSize = '10px';
|
|
14010
|
-
actions.appendChild(thumbnailButton);
|
|
14011
|
-
}
|
|
14012
|
-
const pingButton = createRemoteFleetButton('Ping', 'Ping device', 'ping-device');
|
|
14013
|
-
pingButton.dataset.deviceId = deviceId;
|
|
14014
|
-
pingButton.style.height = '24px';
|
|
14015
|
-
pingButton.style.fontSize = '10px';
|
|
14016
|
-
actions.appendChild(pingButton);
|
|
14017
|
-
}
|
|
14018
|
-
card.appendChild(actions);
|
|
14232
|
+
card.appendChild(createDevicePreview(device, 'tile'));
|
|
14019
14233
|
grid.appendChild(card);
|
|
14020
14234
|
});
|
|
14021
14235
|
|
|
@@ -14038,7 +14252,9 @@
|
|
|
14038
14252
|
grid.appendChild(noMatch);
|
|
14039
14253
|
}
|
|
14040
14254
|
|
|
14041
|
-
|
|
14255
|
+
monitorWorkspace.appendChild(grid);
|
|
14256
|
+
monitorWorkspace.appendChild(createSelectedDevicePanel(selectedDevice));
|
|
14257
|
+
bodyView.appendChild(monitorWorkspace);
|
|
14042
14258
|
|
|
14043
14259
|
const footer = document.createElement('div');
|
|
14044
14260
|
footer.textContent = `Endpoint ${endpoint} - all devices, no paging - group ${groupState} - ${autoMonitorState ? 'auto monitor' : 'manual'} - refreshed ${formatRemoteFleetAge(refreshedAt)}`;
|
|
@@ -14054,12 +14270,6 @@
|
|
|
14054
14270
|
`;
|
|
14055
14271
|
bodyView.appendChild(footer);
|
|
14056
14272
|
|
|
14057
|
-
copyButton.addEventListener('click', event => {
|
|
14058
|
-
event.preventDefault();
|
|
14059
|
-
event.stopPropagation();
|
|
14060
|
-
navigator.clipboard?.writeText?.(command).catch(() => { });
|
|
14061
|
-
});
|
|
14062
|
-
|
|
14063
14273
|
const setTaskFeedback = (message, tone = 'info') => {
|
|
14064
14274
|
taskFeedback.textContent = message || '';
|
|
14065
14275
|
taskFeedback.style.display = message ? 'block' : 'none';
|
|
@@ -14264,9 +14474,12 @@
|
|
|
14264
14474
|
sendConnectedButton.title = allTargetCount > 0
|
|
14265
14475
|
? `Dispatch to ${allTargetCount} connected target(s)`
|
|
14266
14476
|
: 'No connected targetable devices';
|
|
14267
|
-
|
|
14268
|
-
const
|
|
14269
|
-
|
|
14477
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="task-device"]').forEach(button => {
|
|
14478
|
+
const deviceId = String(button.dataset.deviceId || '').trim();
|
|
14479
|
+
const card = getDeviceCards().find(item => String(item.dataset.deviceId || '').trim() === deviceId);
|
|
14480
|
+
const aiCapable = button.dataset.remoteFleetAiCapable === 'true'
|
|
14481
|
+
|| card?.dataset.remoteFleetAiCapable === 'true';
|
|
14482
|
+
button.disabled = wantsAi && !aiCapable;
|
|
14270
14483
|
button.title = button.disabled ? 'AI assist is not enabled on this device' : 'Dispatch task to this device';
|
|
14271
14484
|
});
|
|
14272
14485
|
|
|
@@ -14283,19 +14496,34 @@
|
|
|
14283
14496
|
control.addEventListener(eventName, event => event.stopPropagation());
|
|
14284
14497
|
});
|
|
14285
14498
|
});
|
|
14286
|
-
[
|
|
14499
|
+
[hostButton, stopHostButton].forEach(control => {
|
|
14500
|
+
if (!control) return;
|
|
14287
14501
|
['mousedown', 'mouseup', 'click', 'dblclick', 'keydown'].forEach(eventName => {
|
|
14288
14502
|
control.addEventListener(eventName, event => event.stopPropagation());
|
|
14289
14503
|
});
|
|
14290
14504
|
});
|
|
14505
|
+
getDeviceCards().forEach(card => {
|
|
14506
|
+
['mousedown', 'mouseup', 'dblclick'].forEach(eventName => {
|
|
14507
|
+
card.addEventListener(eventName, event => event.stopPropagation());
|
|
14508
|
+
});
|
|
14509
|
+
const selectCard = event => {
|
|
14510
|
+
event.preventDefault();
|
|
14511
|
+
event.stopPropagation();
|
|
14512
|
+
const deviceId = String(card.dataset.deviceId || '').trim();
|
|
14513
|
+
if (!deviceId) return;
|
|
14514
|
+
bodyView.dataset.remoteFleetSelectedDeviceId = deviceId;
|
|
14515
|
+
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
14516
|
+
};
|
|
14517
|
+
card.addEventListener('click', selectCard);
|
|
14518
|
+
card.addEventListener('keydown', event => {
|
|
14519
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
14520
|
+
selectCard(event);
|
|
14521
|
+
});
|
|
14522
|
+
});
|
|
14291
14523
|
|
|
14292
14524
|
searchInput.addEventListener('input', applyRemoteFleetFilters);
|
|
14293
14525
|
filterSelect.addEventListener('change', applyRemoteFleetFilters);
|
|
14294
14526
|
aiToggle.addEventListener('change', applyRemoteFleetFilters);
|
|
14295
|
-
autoMonitorToggle.addEventListener('change', () => {
|
|
14296
|
-
bodyView.dataset.remoteFleetAutoMonitor = autoMonitorToggle.checked ? 'true' : 'false';
|
|
14297
|
-
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
14298
|
-
});
|
|
14299
14527
|
sortSelect.addEventListener('change', () => {
|
|
14300
14528
|
bodyView.dataset.remoteFleetSort = String(sortSelect.value || 'status');
|
|
14301
14529
|
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
@@ -14367,18 +14595,61 @@
|
|
|
14367
14595
|
}
|
|
14368
14596
|
});
|
|
14369
14597
|
|
|
14370
|
-
|
|
14371
|
-
|
|
14372
|
-
|
|
14373
|
-
|
|
14598
|
+
const setRemoteFleetHostTarget = async (enabled, options = {}) => {
|
|
14599
|
+
const quiet = options?.quiet === true;
|
|
14600
|
+
const activeButton = enabled ? hostButton : stopHostButton;
|
|
14601
|
+
if (!quiet && activeButton) {
|
|
14602
|
+
activeButton.disabled = true;
|
|
14603
|
+
}
|
|
14604
|
+
|
|
14605
|
+
if (!quiet) {
|
|
14606
|
+
setTaskFeedback(enabled ? 'Setting host target...' : 'Stopping host target...');
|
|
14607
|
+
}
|
|
14374
14608
|
try {
|
|
14375
|
-
await
|
|
14609
|
+
const result = await invokeDotNetAsync('SetRemoteFleetHostFromJs', nodeId, enabled === true);
|
|
14610
|
+
window.RuntimeTrace?.emit?.('remote.hostTarget.result', {
|
|
14611
|
+
nodeId,
|
|
14612
|
+
enabled: enabled === true,
|
|
14613
|
+
success: isRemoteFleetResultSuccess(result),
|
|
14614
|
+
active: isRemoteFleetResultActive(result),
|
|
14615
|
+
error: result?.error || result?.Error || ''
|
|
14616
|
+
});
|
|
14617
|
+
rememberRemoteFleetLocalHostTarget(nodeId, enabled === true, result);
|
|
14618
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
14619
|
+
if (quiet) {
|
|
14620
|
+
return result;
|
|
14621
|
+
}
|
|
14622
|
+
if (isRemoteFleetResultSuccess(result) && enabled !== true) {
|
|
14623
|
+
stopRemoteFleetHostLeaseTimer(nodeId);
|
|
14624
|
+
}
|
|
14625
|
+
if (isRemoteFleetResultSuccess(result)) {
|
|
14626
|
+
setTaskFeedback(enabled ? 'Host target set.' : 'Host target stopped.', 'success');
|
|
14627
|
+
} else {
|
|
14628
|
+
setTaskFeedback(result?.error || result?.Error || 'Host target update failed.', 'error');
|
|
14629
|
+
}
|
|
14630
|
+
return result;
|
|
14376
14631
|
} finally {
|
|
14377
|
-
|
|
14632
|
+
if (!quiet && activeButton) {
|
|
14633
|
+
activeButton.disabled = false;
|
|
14634
|
+
}
|
|
14378
14635
|
}
|
|
14636
|
+
};
|
|
14637
|
+
|
|
14638
|
+
hostButton.addEventListener('click', async event => {
|
|
14639
|
+
event.preventDefault();
|
|
14640
|
+
event.stopPropagation();
|
|
14641
|
+
await setRemoteFleetHostTarget(true);
|
|
14379
14642
|
});
|
|
14380
14643
|
|
|
14381
|
-
|
|
14644
|
+
if (stopHostButton) {
|
|
14645
|
+
stopHostButton.addEventListener('click', async event => {
|
|
14646
|
+
event.preventDefault();
|
|
14647
|
+
event.stopPropagation();
|
|
14648
|
+
await setRemoteFleetHostTarget(false);
|
|
14649
|
+
});
|
|
14650
|
+
}
|
|
14651
|
+
|
|
14652
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="pin-device"]').forEach(button => {
|
|
14382
14653
|
button.addEventListener('click', async event => {
|
|
14383
14654
|
event.preventDefault();
|
|
14384
14655
|
event.stopPropagation();
|
|
@@ -14456,7 +14727,7 @@
|
|
|
14456
14727
|
});
|
|
14457
14728
|
});
|
|
14458
14729
|
|
|
14459
|
-
|
|
14730
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="ping-device"]').forEach(button => {
|
|
14460
14731
|
button.addEventListener('click', async event => {
|
|
14461
14732
|
event.preventDefault();
|
|
14462
14733
|
event.stopPropagation();
|
|
@@ -14467,7 +14738,7 @@
|
|
|
14467
14738
|
});
|
|
14468
14739
|
});
|
|
14469
14740
|
|
|
14470
|
-
|
|
14741
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="task-device"]').forEach(button => {
|
|
14471
14742
|
button.addEventListener('click', async event => {
|
|
14472
14743
|
event.preventDefault();
|
|
14473
14744
|
event.stopPropagation();
|
|
@@ -14496,7 +14767,7 @@
|
|
|
14496
14767
|
});
|
|
14497
14768
|
});
|
|
14498
14769
|
|
|
14499
|
-
|
|
14770
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="thumbnail-device"]').forEach(button => {
|
|
14500
14771
|
button.addEventListener('click', async event => {
|
|
14501
14772
|
event.preventDefault();
|
|
14502
14773
|
event.stopPropagation();
|
|
@@ -14507,6 +14778,10 @@
|
|
|
14507
14778
|
});
|
|
14508
14779
|
});
|
|
14509
14780
|
|
|
14781
|
+
if (isHostingTarget) {
|
|
14782
|
+
startRemoteFleetHostLeaseTimer(nodeId, () => setRemoteFleetHostTarget(true, { quiet: true }));
|
|
14783
|
+
}
|
|
14784
|
+
|
|
14510
14785
|
if (hasActiveLiveStream) {
|
|
14511
14786
|
bodyView._remoteFleetLiveRefreshTimer = setInterval(async () => {
|
|
14512
14787
|
if (!document.body.contains(bodyView)) {
|