@mindexec/cli 0.2.24 → 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 +130 -1
- package/scripts/remote-fleet-render-smoke.mjs +80 -53
- package/scripts/remote-http-smoke.mjs +218 -40
- package/scripts/remote-hub-smoke.mjs +139 -0
- package/server.js +17 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +18 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +653 -398
- 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.qt0p5apeu2.dll → MindExecution.Kernel.z56elxihok.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.i9eswmhltm.dll → MindExecution.Plugins.Admin.p5cs4ap87v.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.1eayoj2kvc.dll → MindExecution.Plugins.Business.s35og5uz44.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.a3850nmm3d.dll → MindExecution.Plugins.Concept.zczca3fsxz.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.l3rmdlu7o7.dll → MindExecution.Plugins.Directory.y74f55e8x3.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.2x5gsi74yi.dll → MindExecution.Plugins.PlanMaster.jpdwbefrh1.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.vbl462eegw.dll → MindExecution.Plugins.YouTube.8nz4wv2nsj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.l2w05i7sd6.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.ri6sjbi2qk.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.i4ojmz00kp.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,
|
|
@@ -13007,15 +13176,22 @@
|
|
|
13007
13176
|
const endpoint = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubEndpoint', '127.0.0.1:5197');
|
|
13008
13177
|
const managerPackage = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetManagerPackage', '@mindexec/cli');
|
|
13009
13178
|
const managerVersion = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetManagerVersion', '');
|
|
13010
|
-
const command = getRemoteFleetMetadataValue(
|
|
13011
|
-
nodeModel,
|
|
13012
|
-
'RemoteFleetConnectCommand',
|
|
13013
|
-
`npx @mindexec/remote connect --manager ${endpoint} --pair <pair-token>`);
|
|
13014
13179
|
const hubStatus = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubStatus', 'offline');
|
|
13015
13180
|
const refreshedAt = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetLastRefreshAtUtc', '');
|
|
13016
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
|
+
}
|
|
13017
13192
|
|
|
13018
13193
|
bodyView.dataset.src = `remote-fleet:${refreshedAt}:${devices.length}:${connected}`;
|
|
13194
|
+
bodyView.dataset.remoteFleetHostState = hostTargetState;
|
|
13019
13195
|
bodyView.classList.add('map-node-remote-fleet__body');
|
|
13020
13196
|
bodyView.innerHTML = '';
|
|
13021
13197
|
bodyView.style.cssText = `
|
|
@@ -13030,19 +13206,22 @@
|
|
|
13030
13206
|
background: linear-gradient(180deg, rgba(248, 250, 252, 0.96), rgba(241, 245, 249, 0.92));
|
|
13031
13207
|
`;
|
|
13032
13208
|
|
|
13033
|
-
const
|
|
13034
|
-
|
|
13035
|
-
display:
|
|
13036
|
-
|
|
13037
|
-
|
|
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;
|
|
13038
13215
|
flex: 0 0 auto;
|
|
13216
|
+
min-width: 0;
|
|
13217
|
+
`;
|
|
13218
|
+
const headerMeta = document.createElement('div');
|
|
13219
|
+
headerMeta.style.cssText = `
|
|
13220
|
+
min-width: 0;
|
|
13221
|
+
display: flex;
|
|
13222
|
+
flex-direction: column;
|
|
13223
|
+
gap: 4px;
|
|
13039
13224
|
`;
|
|
13040
|
-
top.appendChild(createRemoteFleetStat('Hub', hubStatus === 'online' ? 'Online' : 'Offline', hubStatus === 'online' ? 'online' : 'default'));
|
|
13041
|
-
top.appendChild(createRemoteFleetStat('Connected', `${Number.isFinite(connected) ? connected : 0}/${Number.isFinite(total) ? total : devices.length}`, connected > 0 ? 'online' : 'default'));
|
|
13042
|
-
top.appendChild(createRemoteFleetStat('Task', String(taskCapableCount), taskCapableCount > 0 ? 'online' : 'default'));
|
|
13043
|
-
top.appendChild(createRemoteFleetStat('AI', String(aiCapableCount), aiCapableCount > 0 ? 'online' : 'default'));
|
|
13044
|
-
bodyView.appendChild(top);
|
|
13045
|
-
|
|
13046
13225
|
const managerRow = document.createElement('div');
|
|
13047
13226
|
managerRow.dataset.remoteFleetManagerVersion = 'true';
|
|
13048
13227
|
managerRow.textContent = `${managerPackage}${managerVersion ? ` ${managerVersion}` : ''} - ${endpoint}`;
|
|
@@ -13059,75 +13238,84 @@
|
|
|
13059
13238
|
line-height: 1.2;
|
|
13060
13239
|
letter-spacing: 0;
|
|
13061
13240
|
`;
|
|
13062
|
-
bodyView.appendChild(managerRow);
|
|
13063
13241
|
|
|
13064
|
-
const
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
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 = `
|
|
13070
13257
|
flex: 0 0 auto;
|
|
13071
|
-
`;
|
|
13072
|
-
|
|
13073
|
-
const commandText = document.createElement('code');
|
|
13074
|
-
commandText.textContent = command;
|
|
13075
|
-
commandText.style.cssText = `
|
|
13076
13258
|
min-width: 0;
|
|
13077
13259
|
overflow: hidden;
|
|
13078
13260
|
text-overflow: ellipsis;
|
|
13079
13261
|
white-space: nowrap;
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
color: #e2e8f0;
|
|
13084
|
-
font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
|
13085
|
-
font-size: 11px;
|
|
13262
|
+
color: ${isHostingTarget ? '#047857' : otherMonitorHosting ? '#7c2d12' : '#64748b'};
|
|
13263
|
+
font-size: 10px;
|
|
13264
|
+
font-weight: 900;
|
|
13086
13265
|
line-height: 1.2;
|
|
13266
|
+
letter-spacing: 0;
|
|
13087
13267
|
`;
|
|
13088
|
-
|
|
13268
|
+
headerMeta.appendChild(managerRow);
|
|
13269
|
+
headerMeta.appendChild(hostStatusRow);
|
|
13089
13270
|
|
|
13090
|
-
const
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
autoMonitorLabel.title = 'Refresh stale thumbnails on a bounded timer';
|
|
13094
|
-
autoMonitorLabel.style.cssText = `
|
|
13271
|
+
const hostActions = document.createElement('div');
|
|
13272
|
+
hostActions.style.cssText = `
|
|
13273
|
+
flex: 0 0 auto;
|
|
13095
13274
|
display: inline-flex;
|
|
13096
13275
|
align-items: center;
|
|
13097
|
-
justify-content:
|
|
13276
|
+
justify-content: flex-end;
|
|
13098
13277
|
gap: 6px;
|
|
13099
|
-
height: 34px;
|
|
13100
|
-
padding: 0 9px;
|
|
13101
|
-
border-radius: 7px;
|
|
13102
|
-
border: 1px solid rgba(14, 165, 233, 0.28);
|
|
13103
|
-
background: ${autoMonitorState ? 'rgba(240, 249, 255, 0.92)' : 'rgba(248, 250, 252, 0.92)'};
|
|
13104
|
-
color: ${autoMonitorState ? '#0369a1' : '#475569'};
|
|
13105
|
-
font-size: 11px;
|
|
13106
|
-
font-weight: 900;
|
|
13107
|
-
letter-spacing: 0;
|
|
13108
|
-
cursor: pointer;
|
|
13109
|
-
pointer-events: auto;
|
|
13110
|
-
user-select: none;
|
|
13111
13278
|
`;
|
|
13112
|
-
const
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
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;
|
|
13121
13313
|
`;
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
commandRow.appendChild(autoMonitorLabel);
|
|
13128
|
-
commandRow.appendChild(copyButton);
|
|
13129
|
-
commandRow.appendChild(refreshButton);
|
|
13130
|
-
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);
|
|
13131
13319
|
|
|
13132
13320
|
const filterRow = document.createElement('div');
|
|
13133
13321
|
filterRow.style.cssText = `
|
|
@@ -13217,7 +13405,7 @@
|
|
|
13217
13405
|
|
|
13218
13406
|
const taskRow = document.createElement('div');
|
|
13219
13407
|
taskRow.style.cssText = `
|
|
13220
|
-
display:
|
|
13408
|
+
display: none;
|
|
13221
13409
|
grid-template-columns: minmax(0, 1fr) auto auto auto;
|
|
13222
13410
|
gap: 8px;
|
|
13223
13411
|
align-items: stretch;
|
|
@@ -13225,7 +13413,7 @@
|
|
|
13225
13413
|
`;
|
|
13226
13414
|
const taskInput = document.createElement('textarea');
|
|
13227
13415
|
taskInput.dataset.remoteFleetTaskInput = 'true';
|
|
13228
|
-
taskInput.placeholder = '
|
|
13416
|
+
taskInput.placeholder = '';
|
|
13229
13417
|
taskInput.rows = 2;
|
|
13230
13418
|
taskInput.style.cssText = `
|
|
13231
13419
|
width: 100%;
|
|
@@ -13287,7 +13475,7 @@
|
|
|
13287
13475
|
taskRow.appendChild(aiToggleLabel);
|
|
13288
13476
|
taskRow.appendChild(sendVisibleButton);
|
|
13289
13477
|
taskRow.appendChild(sendConnectedButton);
|
|
13290
|
-
|
|
13478
|
+
taskRow.dataset.remoteFleetTaskComposer = 'hidden';
|
|
13291
13479
|
|
|
13292
13480
|
const taskFeedback = document.createElement('div');
|
|
13293
13481
|
taskFeedback.dataset.remoteFleetTaskFeedback = 'true';
|
|
@@ -13626,14 +13814,299 @@
|
|
|
13626
13814
|
bodyView.appendChild(errorEl);
|
|
13627
13815
|
}
|
|
13628
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
|
+
|
|
13629
14102
|
const grid = document.createElement('div');
|
|
14103
|
+
grid.dataset.remoteFleetDeviceGrid = 'true';
|
|
13630
14104
|
grid.style.cssText = `
|
|
13631
|
-
flex: 1 1 auto;
|
|
13632
14105
|
min-height: 0;
|
|
13633
14106
|
overflow-y: auto;
|
|
13634
14107
|
overflow-x: hidden;
|
|
13635
14108
|
display: grid;
|
|
13636
|
-
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))'};
|
|
13637
14110
|
align-content: start;
|
|
13638
14111
|
gap: 8px;
|
|
13639
14112
|
padding-right: 4px;
|
|
@@ -13679,32 +14152,15 @@
|
|
|
13679
14152
|
devices.forEach(device => {
|
|
13680
14153
|
const connectedDevice = isRemoteFleetDeviceConnected(device);
|
|
13681
14154
|
const name = getRemoteFleetDeviceName(device);
|
|
13682
|
-
const platform = [device?.platform || device?.Platform, device?.arch || device?.Arch]
|
|
13683
|
-
.filter(Boolean)
|
|
13684
|
-
.join(' / ') || 'unknown';
|
|
13685
|
-
const release = String(device?.release || device?.Release || '');
|
|
13686
14155
|
const deviceId = getRemoteFleetDeviceId(device);
|
|
13687
|
-
const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
|
|
13688
|
-
const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
|
|
13689
|
-
const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
|
|
13690
14156
|
const liveStreamEnabled = device?.liveStreamEnabled === true || device?.LiveStreamEnabled === true;
|
|
13691
14157
|
const liveStreamActive = isRemoteFleetLiveActive(device);
|
|
13692
|
-
const liveStreamId = String(device?.liveStreamId || device?.LiveStreamId || '');
|
|
13693
|
-
const liveFrameDataUrl = String(device?.liveFrameDataUrl || device?.LiveFrameDataUrl || '');
|
|
13694
|
-
const liveFrameReceivedAt = String(device?.liveFrameReceivedAt || device?.LiveFrameReceivedAt || '');
|
|
13695
14158
|
const hasThumbnail = hasRemoteFleetThumbnail(device);
|
|
13696
14159
|
const hasLiveFrame = hasRemoteFleetLiveFrame(device);
|
|
13697
14160
|
const taskEnabled = isRemoteFleetDeviceTaskCapable(device);
|
|
13698
14161
|
const aiAssistEnabled = isRemoteFleetDeviceAiCapable(device);
|
|
13699
|
-
const aiModel = String(device?.aiModel || device?.AiModel || '');
|
|
13700
14162
|
const latestTaskStatus = String(device?.latestTaskStatus || device?.LatestTaskStatus || '');
|
|
13701
|
-
const latestTaskTitle = String(device?.latestTaskTitle || device?.LatestTaskTitle || '');
|
|
13702
|
-
const latestTaskApproval = String(device?.latestTaskApprovalLevel || device?.LatestTaskApprovalLevel || '');
|
|
13703
|
-
const latestTaskUpdatedAt = String(device?.latestTaskUpdatedAt || device?.LatestTaskUpdatedAt || '');
|
|
13704
14163
|
const latestTaskError = String(device?.latestTaskError || device?.LatestTaskError || '');
|
|
13705
|
-
const latestTaskResultModel = String(device?.latestTaskResultModel || device?.LatestTaskResultModel || '');
|
|
13706
|
-
const latestTaskResultResponseId = String(device?.latestTaskResultResponseId || device?.LatestTaskResultResponseId || '');
|
|
13707
|
-
const latestTaskResult = String(device?.latestTaskResultSummary || device?.LatestTaskResultSummary || '');
|
|
13708
14164
|
const groupInfo = getRemoteFleetGroupInfo(device, groupState);
|
|
13709
14165
|
if (groupState !== 'none' && groupInfo.key && groupInfo.key !== lastGroupKey) {
|
|
13710
14166
|
const stat = groupStats.get(groupInfo.key) || { label: groupInfo.label, total: 0, connected: 0 };
|
|
@@ -13739,6 +14195,8 @@
|
|
|
13739
14195
|
grid.appendChild(groupHeader);
|
|
13740
14196
|
lastGroupKey = groupInfo.key;
|
|
13741
14197
|
}
|
|
14198
|
+
const selectedDeviceId = selectedDevice ? getRemoteFleetDeviceId(selectedDevice) : '';
|
|
14199
|
+
const isSelected = deviceId && deviceId === selectedDeviceId;
|
|
13742
14200
|
const card = document.createElement('article');
|
|
13743
14201
|
card.dataset.deviceId = deviceId;
|
|
13744
14202
|
card.dataset.remoteFleetSearchText = buildRemoteFleetSearchText(device);
|
|
@@ -13750,292 +14208,28 @@
|
|
|
13750
14208
|
card.dataset.remoteFleetLiveCapable = liveStreamEnabled ? 'true' : 'false';
|
|
13751
14209
|
card.dataset.remoteFleetLiveActive = liveStreamActive ? 'true' : 'false';
|
|
13752
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;
|
|
13753
14217
|
card.style.cssText = `
|
|
14218
|
+
position: relative;
|
|
13754
14219
|
display: flex;
|
|
13755
|
-
|
|
13756
|
-
gap: ${densityState === 'dense' ? '6px' : '8px'};
|
|
14220
|
+
align-items: stretch;
|
|
13757
14221
|
min-width: 0;
|
|
13758
|
-
min-height: ${densityState === 'dense' ? '
|
|
13759
|
-
padding:
|
|
14222
|
+
min-height: ${densityState === 'dense' ? '66px' : '84px'};
|
|
14223
|
+
padding: 2px;
|
|
13760
14224
|
border-radius: 8px;
|
|
13761
14225
|
background: #ffffff;
|
|
13762
|
-
border:
|
|
13763
|
-
box-shadow: 0 8px
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
const previewDataUrl = hasLiveFrame ? liveFrameDataUrl : thumbnailDataUrl;
|
|
13768
|
-
const previewAt = hasLiveFrame ? liveFrameReceivedAt : thumbnailCapturedAt;
|
|
13769
|
-
const preview = document.createElement('div');
|
|
13770
|
-
preview.style.cssText = `
|
|
13771
|
-
position: relative;
|
|
13772
|
-
width: 100%;
|
|
13773
|
-
aspect-ratio: 16 / 9;
|
|
13774
|
-
overflow: hidden;
|
|
13775
|
-
border-radius: 7px;
|
|
13776
|
-
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
13777
|
-
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
13778
|
-
`;
|
|
13779
|
-
if (hasLiveFrame || hasThumbnail) {
|
|
13780
|
-
const image = document.createElement('img');
|
|
13781
|
-
image.src = previewDataUrl;
|
|
13782
|
-
image.alt = hasLiveFrame ? `${name} live frame` : `${name} thumbnail`;
|
|
13783
|
-
image.loading = 'lazy';
|
|
13784
|
-
image.decoding = 'async';
|
|
13785
|
-
image.style.cssText = `
|
|
13786
|
-
width: 100%;
|
|
13787
|
-
height: 100%;
|
|
13788
|
-
object-fit: cover;
|
|
13789
|
-
display: block;
|
|
13790
|
-
`;
|
|
13791
|
-
preview.appendChild(image);
|
|
13792
|
-
} else {
|
|
13793
|
-
const placeholder = document.createElement('div');
|
|
13794
|
-
placeholder.textContent = thumbnailEnabled ? 'No frame yet' : 'Status only';
|
|
13795
|
-
placeholder.style.cssText = `
|
|
13796
|
-
position: absolute;
|
|
13797
|
-
inset: 0;
|
|
13798
|
-
display: flex;
|
|
13799
|
-
align-items: center;
|
|
13800
|
-
justify-content: center;
|
|
13801
|
-
color: rgba(226, 232, 240, 0.78);
|
|
13802
|
-
font-size: 11px;
|
|
13803
|
-
font-weight: 900;
|
|
13804
|
-
letter-spacing: 0;
|
|
13805
|
-
`;
|
|
13806
|
-
preview.appendChild(placeholder);
|
|
13807
|
-
}
|
|
13808
|
-
if (previewAt) {
|
|
13809
|
-
const badge = document.createElement('span');
|
|
13810
|
-
badge.textContent = hasLiveFrame
|
|
13811
|
-
? `LIVE ${formatRemoteFleetAge(previewAt)}`
|
|
13812
|
-
: formatRemoteFleetAge(previewAt);
|
|
13813
|
-
badge.style.cssText = `
|
|
13814
|
-
position: absolute;
|
|
13815
|
-
right: 6px;
|
|
13816
|
-
bottom: 6px;
|
|
13817
|
-
max-width: calc(100% - 12px);
|
|
13818
|
-
padding: 3px 6px;
|
|
13819
|
-
border-radius: 999px;
|
|
13820
|
-
background: ${hasLiveFrame ? 'rgba(220, 38, 38, 0.82)' : 'rgba(15, 23, 42, 0.74)'};
|
|
13821
|
-
color: #e2e8f0;
|
|
13822
|
-
font-size: 9px;
|
|
13823
|
-
font-weight: 900;
|
|
13824
|
-
line-height: 1;
|
|
13825
|
-
overflow: hidden;
|
|
13826
|
-
text-overflow: ellipsis;
|
|
13827
|
-
white-space: nowrap;
|
|
13828
|
-
`;
|
|
13829
|
-
preview.appendChild(badge);
|
|
13830
|
-
}
|
|
13831
|
-
card.appendChild(preview);
|
|
13832
|
-
}
|
|
13833
|
-
|
|
13834
|
-
const cardHeader = document.createElement('div');
|
|
13835
|
-
cardHeader.style.cssText = 'display:flex;align-items:flex-start;gap:8px;min-width:0;';
|
|
13836
|
-
const dot = document.createElement('span');
|
|
13837
|
-
dot.style.cssText = `
|
|
13838
|
-
flex: 0 0 auto;
|
|
13839
|
-
width: 9px;
|
|
13840
|
-
height: 9px;
|
|
13841
|
-
margin-top: 4px;
|
|
13842
|
-
border-radius: 999px;
|
|
13843
|
-
background: ${connectedDevice ? '#10b981' : '#94a3b8'};
|
|
13844
|
-
box-shadow: 0 0 0 4px ${connectedDevice ? 'rgba(16,185,129,0.14)' : 'rgba(148,163,184,0.14)'};
|
|
13845
|
-
`;
|
|
13846
|
-
|
|
13847
|
-
const titleBox = document.createElement('div');
|
|
13848
|
-
titleBox.style.cssText = 'min-width:0;display:flex;flex-direction:column;gap:2px;';
|
|
13849
|
-
const title = document.createElement('strong');
|
|
13850
|
-
title.textContent = name;
|
|
13851
|
-
title.title = name;
|
|
13852
|
-
title.style.cssText = `
|
|
13853
|
-
color: #0f172a;
|
|
13854
|
-
font-size: 13px;
|
|
13855
|
-
font-weight: 900;
|
|
13856
|
-
line-height: 1.2;
|
|
13857
|
-
overflow: hidden;
|
|
13858
|
-
text-overflow: ellipsis;
|
|
13859
|
-
white-space: nowrap;
|
|
13860
|
-
letter-spacing: 0;
|
|
13861
|
-
`;
|
|
13862
|
-
const subtitle = document.createElement('span');
|
|
13863
|
-
subtitle.textContent = release ? `${platform} ${release}` : platform;
|
|
13864
|
-
subtitle.title = subtitle.textContent;
|
|
13865
|
-
subtitle.style.cssText = `
|
|
13866
|
-
color: #64748b;
|
|
13867
|
-
font-size: 11px;
|
|
13868
|
-
line-height: 1.2;
|
|
13869
|
-
overflow: hidden;
|
|
13870
|
-
text-overflow: ellipsis;
|
|
13871
|
-
white-space: nowrap;
|
|
13872
|
-
letter-spacing: 0;
|
|
13873
|
-
`;
|
|
13874
|
-
titleBox.appendChild(title);
|
|
13875
|
-
titleBox.appendChild(subtitle);
|
|
13876
|
-
cardHeader.appendChild(dot);
|
|
13877
|
-
cardHeader.appendChild(titleBox);
|
|
13878
|
-
card.appendChild(cardHeader);
|
|
13879
|
-
|
|
13880
|
-
const metrics = document.createElement('div');
|
|
13881
|
-
metrics.style.cssText = `
|
|
13882
|
-
display: grid;
|
|
13883
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
13884
|
-
gap: 6px;
|
|
13885
|
-
`;
|
|
13886
|
-
const addMetric = (label, value) => {
|
|
13887
|
-
const metric = document.createElement('div');
|
|
13888
|
-
metric.style.cssText = `
|
|
13889
|
-
min-width: 0;
|
|
13890
|
-
padding: 6px 7px;
|
|
13891
|
-
border-radius: 7px;
|
|
13892
|
-
background: rgba(241, 245, 249, 0.84);
|
|
13893
|
-
`;
|
|
13894
|
-
const labelEl = document.createElement('div');
|
|
13895
|
-
labelEl.textContent = label;
|
|
13896
|
-
labelEl.style.cssText = 'color:#64748b;font-size:9px;font-weight:800;letter-spacing:0;text-transform:uppercase;';
|
|
13897
|
-
const valueEl = document.createElement('div');
|
|
13898
|
-
valueEl.textContent = value;
|
|
13899
|
-
valueEl.title = value;
|
|
13900
|
-
valueEl.style.cssText = 'color:#0f172a;font-size:12px;font-weight:900;letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
|
|
13901
|
-
metric.appendChild(labelEl);
|
|
13902
|
-
metric.appendChild(valueEl);
|
|
13903
|
-
metrics.appendChild(metric);
|
|
13904
|
-
};
|
|
13905
|
-
addMetric('Seen', formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt));
|
|
13906
|
-
addMetric('Uptime', formatRemoteFleetDuration(device?.uptimeSec ?? device?.UptimeSec));
|
|
13907
|
-
addMetric('Mem', formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio));
|
|
13908
|
-
addMetric('Load', formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2));
|
|
13909
|
-
if (densityState === 'dense') {
|
|
13910
|
-
const denseMeta = document.createElement('div');
|
|
13911
|
-
denseMeta.textContent = `Seen ${formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt)} - Mem ${formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio)} - Load ${formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2)}`;
|
|
13912
|
-
denseMeta.style.cssText = `
|
|
13913
|
-
color: #475569;
|
|
13914
|
-
font-size: 10px;
|
|
13915
|
-
font-weight: 750;
|
|
13916
|
-
line-height: 1.2;
|
|
13917
|
-
overflow: hidden;
|
|
13918
|
-
text-overflow: ellipsis;
|
|
13919
|
-
white-space: nowrap;
|
|
13920
|
-
letter-spacing: 0;
|
|
13921
|
-
`;
|
|
13922
|
-
card.appendChild(denseMeta);
|
|
13923
|
-
} else {
|
|
13924
|
-
card.appendChild(metrics);
|
|
13925
|
-
}
|
|
13926
|
-
|
|
13927
|
-
if (latestTaskStatus || latestTaskTitle || latestTaskResult || latestTaskError) {
|
|
13928
|
-
const taskBox = document.createElement('div');
|
|
13929
|
-
const taskTone = latestTaskError || latestTaskStatus === 'failed'
|
|
13930
|
-
? 'error'
|
|
13931
|
-
: (latestTaskStatus === 'completed' ? 'done' : 'pending');
|
|
13932
|
-
taskBox.style.cssText = `
|
|
13933
|
-
display: flex;
|
|
13934
|
-
flex-direction: column;
|
|
13935
|
-
gap: 3px;
|
|
13936
|
-
min-width: 0;
|
|
13937
|
-
padding: 7px 8px;
|
|
13938
|
-
border-radius: 7px;
|
|
13939
|
-
background: ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.12)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.10)' : 'rgba(37, 99, 235, 0.08)'};
|
|
13940
|
-
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)'};
|
|
13941
|
-
`;
|
|
13942
|
-
const taskLine = document.createElement('div');
|
|
13943
|
-
const taskModeLabel = latestTaskApproval === 'ai-assist' ? 'AI' : 'Task';
|
|
13944
|
-
taskLine.textContent = `${taskModeLabel} ${latestTaskStatus || 'task'}${latestTaskUpdatedAt ? ` - ${formatRemoteFleetAge(latestTaskUpdatedAt)}` : ''}${latestTaskResultModel ? ` - ${latestTaskResultModel}` : ''}`;
|
|
13945
|
-
taskLine.title = latestTaskResultResponseId
|
|
13946
|
-
? `${taskLine.textContent} (${latestTaskResultResponseId})`
|
|
13947
|
-
: taskLine.textContent;
|
|
13948
|
-
taskLine.style.cssText = `
|
|
13949
|
-
color: ${taskTone === 'error' ? '#991b1b' : taskTone === 'done' ? '#047857' : '#1d4ed8'};
|
|
13950
|
-
font-size: 10px;
|
|
13951
|
-
font-weight: 900;
|
|
13952
|
-
line-height: 1.2;
|
|
13953
|
-
overflow: hidden;
|
|
13954
|
-
text-overflow: ellipsis;
|
|
13955
|
-
white-space: nowrap;
|
|
13956
|
-
letter-spacing: 0;
|
|
13957
|
-
`;
|
|
13958
|
-
const taskSummary = document.createElement('div');
|
|
13959
|
-
taskSummary.textContent = formatRemoteFleetTaskError(latestTaskError) || latestTaskResult || latestTaskTitle || 'Task queued';
|
|
13960
|
-
taskSummary.title = taskSummary.textContent;
|
|
13961
|
-
taskSummary.style.cssText = `
|
|
13962
|
-
color: #334155;
|
|
13963
|
-
font-size: 10px;
|
|
13964
|
-
font-weight: 700;
|
|
13965
|
-
line-height: 1.25;
|
|
13966
|
-
overflow: hidden;
|
|
13967
|
-
display: -webkit-box;
|
|
13968
|
-
-webkit-line-clamp: 2;
|
|
13969
|
-
-webkit-box-orient: vertical;
|
|
13970
|
-
letter-spacing: 0;
|
|
13971
|
-
`;
|
|
13972
|
-
taskBox.appendChild(taskLine);
|
|
13973
|
-
taskBox.appendChild(taskSummary);
|
|
13974
|
-
card.appendChild(taskBox);
|
|
13975
|
-
}
|
|
13976
|
-
|
|
13977
|
-
const actions = document.createElement('div');
|
|
13978
|
-
actions.style.cssText = 'display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:auto;';
|
|
13979
|
-
const status = document.createElement('span');
|
|
13980
|
-
status.textContent = connectedDevice
|
|
13981
|
-
? (liveStreamActive ? 'Live' : (aiAssistEnabled ? `AI ${aiModel || 'ready'}` : 'Connected'))
|
|
13982
|
-
: 'Offline';
|
|
13983
|
-
status.style.cssText = `
|
|
13984
|
-
min-width: 0;
|
|
13985
|
-
color: ${liveStreamActive ? '#b91c1c' : (connectedDevice ? '#047857' : '#64748b')};
|
|
13986
|
-
font-size: 11px;
|
|
13987
|
-
font-weight: 900;
|
|
13988
|
-
overflow: hidden;
|
|
13989
|
-
text-overflow: ellipsis;
|
|
13990
|
-
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;
|
|
13991
14231
|
`;
|
|
13992
|
-
|
|
13993
|
-
if (deviceId) {
|
|
13994
|
-
const pinButton = createRemoteFleetButton('Pin', 'Pin this device as a canvas node', 'pin-device');
|
|
13995
|
-
pinButton.dataset.deviceId = deviceId;
|
|
13996
|
-
pinButton.style.height = '24px';
|
|
13997
|
-
pinButton.style.fontSize = '10px';
|
|
13998
|
-
actions.appendChild(pinButton);
|
|
13999
|
-
}
|
|
14000
|
-
if (connectedDevice && deviceId) {
|
|
14001
|
-
const focusButton = createRemoteFleetButton('Focus', 'Show this device in focused live panel', 'live-focus');
|
|
14002
|
-
focusButton.dataset.deviceId = deviceId;
|
|
14003
|
-
focusButton.style.height = '24px';
|
|
14004
|
-
focusButton.style.fontSize = '10px';
|
|
14005
|
-
actions.appendChild(focusButton);
|
|
14006
|
-
if (liveStreamEnabled) {
|
|
14007
|
-
const liveButton = createRemoteFleetButton(liveStreamActive ? 'Stop' : 'Live', liveStreamActive ? 'Stop live stream' : 'Start focused live stream', liveStreamActive ? 'live-stop' : 'live-start');
|
|
14008
|
-
liveButton.dataset.deviceId = deviceId;
|
|
14009
|
-
liveButton.dataset.streamId = liveStreamId;
|
|
14010
|
-
liveButton.style.height = '24px';
|
|
14011
|
-
liveButton.style.fontSize = '10px';
|
|
14012
|
-
if (liveStreamActive) {
|
|
14013
|
-
liveButton.style.borderColor = 'rgba(220, 38, 38, 0.32)';
|
|
14014
|
-
liveButton.style.color = '#b91c1c';
|
|
14015
|
-
}
|
|
14016
|
-
actions.appendChild(liveButton);
|
|
14017
|
-
}
|
|
14018
|
-
if (taskEnabled) {
|
|
14019
|
-
const taskButton = createRemoteFleetButton('Task', 'Dispatch task to this device', 'task-device');
|
|
14020
|
-
taskButton.dataset.deviceId = deviceId;
|
|
14021
|
-
taskButton.style.height = '24px';
|
|
14022
|
-
taskButton.style.fontSize = '10px';
|
|
14023
|
-
actions.appendChild(taskButton);
|
|
14024
|
-
}
|
|
14025
|
-
if (thumbnailEnabled) {
|
|
14026
|
-
const thumbnailButton = createRemoteFleetButton('Shot', 'Request thumbnail', 'thumbnail-device');
|
|
14027
|
-
thumbnailButton.dataset.deviceId = deviceId;
|
|
14028
|
-
thumbnailButton.style.height = '24px';
|
|
14029
|
-
thumbnailButton.style.fontSize = '10px';
|
|
14030
|
-
actions.appendChild(thumbnailButton);
|
|
14031
|
-
}
|
|
14032
|
-
const pingButton = createRemoteFleetButton('Ping', 'Ping device', 'ping-device');
|
|
14033
|
-
pingButton.dataset.deviceId = deviceId;
|
|
14034
|
-
pingButton.style.height = '24px';
|
|
14035
|
-
pingButton.style.fontSize = '10px';
|
|
14036
|
-
actions.appendChild(pingButton);
|
|
14037
|
-
}
|
|
14038
|
-
card.appendChild(actions);
|
|
14232
|
+
card.appendChild(createDevicePreview(device, 'tile'));
|
|
14039
14233
|
grid.appendChild(card);
|
|
14040
14234
|
});
|
|
14041
14235
|
|
|
@@ -14058,7 +14252,9 @@
|
|
|
14058
14252
|
grid.appendChild(noMatch);
|
|
14059
14253
|
}
|
|
14060
14254
|
|
|
14061
|
-
|
|
14255
|
+
monitorWorkspace.appendChild(grid);
|
|
14256
|
+
monitorWorkspace.appendChild(createSelectedDevicePanel(selectedDevice));
|
|
14257
|
+
bodyView.appendChild(monitorWorkspace);
|
|
14062
14258
|
|
|
14063
14259
|
const footer = document.createElement('div');
|
|
14064
14260
|
footer.textContent = `Endpoint ${endpoint} - all devices, no paging - group ${groupState} - ${autoMonitorState ? 'auto monitor' : 'manual'} - refreshed ${formatRemoteFleetAge(refreshedAt)}`;
|
|
@@ -14074,12 +14270,6 @@
|
|
|
14074
14270
|
`;
|
|
14075
14271
|
bodyView.appendChild(footer);
|
|
14076
14272
|
|
|
14077
|
-
copyButton.addEventListener('click', event => {
|
|
14078
|
-
event.preventDefault();
|
|
14079
|
-
event.stopPropagation();
|
|
14080
|
-
navigator.clipboard?.writeText?.(command).catch(() => { });
|
|
14081
|
-
});
|
|
14082
|
-
|
|
14083
14273
|
const setTaskFeedback = (message, tone = 'info') => {
|
|
14084
14274
|
taskFeedback.textContent = message || '';
|
|
14085
14275
|
taskFeedback.style.display = message ? 'block' : 'none';
|
|
@@ -14284,9 +14474,12 @@
|
|
|
14284
14474
|
sendConnectedButton.title = allTargetCount > 0
|
|
14285
14475
|
? `Dispatch to ${allTargetCount} connected target(s)`
|
|
14286
14476
|
: 'No connected targetable devices';
|
|
14287
|
-
|
|
14288
|
-
const
|
|
14289
|
-
|
|
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;
|
|
14290
14483
|
button.title = button.disabled ? 'AI assist is not enabled on this device' : 'Dispatch task to this device';
|
|
14291
14484
|
});
|
|
14292
14485
|
|
|
@@ -14303,19 +14496,34 @@
|
|
|
14303
14496
|
control.addEventListener(eventName, event => event.stopPropagation());
|
|
14304
14497
|
});
|
|
14305
14498
|
});
|
|
14306
|
-
[
|
|
14499
|
+
[hostButton, stopHostButton].forEach(control => {
|
|
14500
|
+
if (!control) return;
|
|
14307
14501
|
['mousedown', 'mouseup', 'click', 'dblclick', 'keydown'].forEach(eventName => {
|
|
14308
14502
|
control.addEventListener(eventName, event => event.stopPropagation());
|
|
14309
14503
|
});
|
|
14310
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
|
+
});
|
|
14311
14523
|
|
|
14312
14524
|
searchInput.addEventListener('input', applyRemoteFleetFilters);
|
|
14313
14525
|
filterSelect.addEventListener('change', applyRemoteFleetFilters);
|
|
14314
14526
|
aiToggle.addEventListener('change', applyRemoteFleetFilters);
|
|
14315
|
-
autoMonitorToggle.addEventListener('change', () => {
|
|
14316
|
-
bodyView.dataset.remoteFleetAutoMonitor = autoMonitorToggle.checked ? 'true' : 'false';
|
|
14317
|
-
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
14318
|
-
});
|
|
14319
14527
|
sortSelect.addEventListener('change', () => {
|
|
14320
14528
|
bodyView.dataset.remoteFleetSort = String(sortSelect.value || 'status');
|
|
14321
14529
|
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
@@ -14387,18 +14595,61 @@
|
|
|
14387
14595
|
}
|
|
14388
14596
|
});
|
|
14389
14597
|
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
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
|
+
}
|
|
14394
14608
|
try {
|
|
14395
|
-
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;
|
|
14396
14631
|
} finally {
|
|
14397
|
-
|
|
14632
|
+
if (!quiet && activeButton) {
|
|
14633
|
+
activeButton.disabled = false;
|
|
14634
|
+
}
|
|
14398
14635
|
}
|
|
14636
|
+
};
|
|
14637
|
+
|
|
14638
|
+
hostButton.addEventListener('click', async event => {
|
|
14639
|
+
event.preventDefault();
|
|
14640
|
+
event.stopPropagation();
|
|
14641
|
+
await setRemoteFleetHostTarget(true);
|
|
14399
14642
|
});
|
|
14400
14643
|
|
|
14401
|
-
|
|
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 => {
|
|
14402
14653
|
button.addEventListener('click', async event => {
|
|
14403
14654
|
event.preventDefault();
|
|
14404
14655
|
event.stopPropagation();
|
|
@@ -14476,7 +14727,7 @@
|
|
|
14476
14727
|
});
|
|
14477
14728
|
});
|
|
14478
14729
|
|
|
14479
|
-
|
|
14730
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="ping-device"]').forEach(button => {
|
|
14480
14731
|
button.addEventListener('click', async event => {
|
|
14481
14732
|
event.preventDefault();
|
|
14482
14733
|
event.stopPropagation();
|
|
@@ -14487,7 +14738,7 @@
|
|
|
14487
14738
|
});
|
|
14488
14739
|
});
|
|
14489
14740
|
|
|
14490
|
-
|
|
14741
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="task-device"]').forEach(button => {
|
|
14491
14742
|
button.addEventListener('click', async event => {
|
|
14492
14743
|
event.preventDefault();
|
|
14493
14744
|
event.stopPropagation();
|
|
@@ -14516,7 +14767,7 @@
|
|
|
14516
14767
|
});
|
|
14517
14768
|
});
|
|
14518
14769
|
|
|
14519
|
-
|
|
14770
|
+
bodyView.querySelectorAll('[data-remote-fleet-action="thumbnail-device"]').forEach(button => {
|
|
14520
14771
|
button.addEventListener('click', async event => {
|
|
14521
14772
|
event.preventDefault();
|
|
14522
14773
|
event.stopPropagation();
|
|
@@ -14527,6 +14778,10 @@
|
|
|
14527
14778
|
});
|
|
14528
14779
|
});
|
|
14529
14780
|
|
|
14781
|
+
if (isHostingTarget) {
|
|
14782
|
+
startRemoteFleetHostLeaseTimer(nodeId, () => setRemoteFleetHostTarget(true, { quiet: true }));
|
|
14783
|
+
}
|
|
14784
|
+
|
|
14530
14785
|
if (hasActiveLiveStream) {
|
|
14531
14786
|
bodyView._remoteFleetLiveRefreshTimer = setInterval(async () => {
|
|
14532
14787
|
if (!document.body.contains(bodyView)) {
|