@mindexec/cli 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/package.json +6 -4
- package/remote-hub.js +737 -0
- package/scripts/remote-hub-smoke.mjs +146 -0
- package/server.js +144 -28
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +11 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +732 -2
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +3 -1
- package/wwwroot/_framework/MindExecution.Core.rydw4mhsbd.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.gwwc40sc45.dll → MindExecution.Kernel.8sz1fl3k6s.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.0jgrn1sckv.dll → MindExecution.Plugins.Admin.iltai5c3i9.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.13mme2qcag.dll → MindExecution.Plugins.Business.mscgb1gwpf.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.9al2g3v3f9.dll → MindExecution.Plugins.Concept.s888y8snr4.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.3w4t6n3se0.dll → MindExecution.Plugins.Directory.281klijdzl.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.vfmfbygv5y.dll → MindExecution.Plugins.PlanMaster.2gy2ozelqp.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.32jyiqs383.dll → MindExecution.Plugins.YouTube.1v8o9nnlzq.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.7ttmykvopx.dll → MindExecution.Shared.04anisxh35.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Web.0qdidsf6sl.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +1 -1
- package/wwwroot/service-worker-assets.js +26 -26
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Core.1q1trifbuu.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.ozzcqp30uy.dll +0 -0
|
@@ -3400,6 +3400,7 @@
|
|
|
3400
3400
|
const MEDIA_GENERATION_STATUS_METADATA_KEY = 'MediaGenerationStatus';
|
|
3401
3401
|
const MEDIA_GENERATION_STATUS_MESSAGE_METADATA_KEY = 'MediaGenerationStatusMessage';
|
|
3402
3402
|
const BUSINESS_AUTOMATION_SEMANTIC_TYPE = 'BusinessAutomationNode';
|
|
3403
|
+
const REMOTE_FLEET_SEMANTIC_TYPE = 'RemoteFleetMonitor';
|
|
3403
3404
|
const AUTOMATION_NODE_KIND_METADATA_KEY = 'AutomationNodeKind';
|
|
3404
3405
|
const AUTOMATION_NODE_LABEL_METADATA_KEY = 'AutomationNodeLabel';
|
|
3405
3406
|
const AUTOMATION_NODE_DESCRIPTION_METADATA_KEY = 'AutomationNodeDescription';
|
|
@@ -3569,6 +3570,10 @@
|
|
|
3569
3570
|
return getNodeSemanticType(nodeModel) === BUSINESS_AUTOMATION_SEMANTIC_TYPE;
|
|
3570
3571
|
}
|
|
3571
3572
|
|
|
3573
|
+
function isRemoteFleetMonitorNode(nodeModel) {
|
|
3574
|
+
return getNodeSemanticType(nodeModel) === REMOTE_FLEET_SEMANTIC_TYPE;
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3572
3577
|
function isBusinessAutomationContextSourceNode(nodeModel) {
|
|
3573
3578
|
if (!nodeModel || isBusinessAutomationNode(nodeModel)) {
|
|
3574
3579
|
return false;
|
|
@@ -3582,7 +3587,8 @@
|
|
|
3582
3587
|
const semanticType = getNodeSemanticType(nodeModel);
|
|
3583
3588
|
return semanticType === 'MindCanvasAgent'
|
|
3584
3589
|
|| semanticType === 'AgentCommand'
|
|
3585
|
-
|| semanticType === BUSINESS_AUTOMATION_SEMANTIC_TYPE
|
|
3590
|
+
|| semanticType === BUSINESS_AUTOMATION_SEMANTIC_TYPE
|
|
3591
|
+
|| semanticType === REMOTE_FLEET_SEMANTIC_TYPE;
|
|
3586
3592
|
}
|
|
3587
3593
|
|
|
3588
3594
|
function allowsMemoExternalChrome(nodeModel) {
|
|
@@ -11834,6 +11840,18 @@
|
|
|
11834
11840
|
function renderMemoBodyView(bodyView, nodeModel, content) {
|
|
11835
11841
|
if (!bodyView) return;
|
|
11836
11842
|
|
|
11843
|
+
if (isRemoteFleetMonitorNode(nodeModel)) {
|
|
11844
|
+
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
11845
|
+
return;
|
|
11846
|
+
}
|
|
11847
|
+
|
|
11848
|
+
bodyView.classList.remove('map-node-remote-fleet__body');
|
|
11849
|
+
bodyView.style.cssText = `
|
|
11850
|
+
flex: 1 1 auto;
|
|
11851
|
+
min-height: 0;
|
|
11852
|
+
pointer-events: auto;
|
|
11853
|
+
`;
|
|
11854
|
+
|
|
11837
11855
|
const nextValue = String(content || '');
|
|
11838
11856
|
bodyView.dataset.src = nextValue;
|
|
11839
11857
|
|
|
@@ -11916,6 +11934,715 @@
|
|
|
11916
11934
|
}, 220);
|
|
11917
11935
|
}
|
|
11918
11936
|
|
|
11937
|
+
function getRemoteFleetMetadataValue(nodeModel, key, fallback = '') {
|
|
11938
|
+
const metadata = getNodeMetadata(nodeModel) || {};
|
|
11939
|
+
const value = metadata[key];
|
|
11940
|
+
return value === undefined || value === null ? fallback : String(value);
|
|
11941
|
+
}
|
|
11942
|
+
|
|
11943
|
+
function parseRemoteFleetDevices(nodeModel) {
|
|
11944
|
+
const raw = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetDevicesJson', '[]');
|
|
11945
|
+
if (!raw.trim()) {
|
|
11946
|
+
return [];
|
|
11947
|
+
}
|
|
11948
|
+
|
|
11949
|
+
try {
|
|
11950
|
+
const parsed = JSON.parse(raw);
|
|
11951
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
11952
|
+
} catch {
|
|
11953
|
+
return [];
|
|
11954
|
+
}
|
|
11955
|
+
}
|
|
11956
|
+
|
|
11957
|
+
function formatRemoteFleetNumber(value, digits = 0) {
|
|
11958
|
+
const number = Number(value);
|
|
11959
|
+
return Number.isFinite(number) ? number.toFixed(digits) : '-';
|
|
11960
|
+
}
|
|
11961
|
+
|
|
11962
|
+
function formatRemoteFleetPercent(value) {
|
|
11963
|
+
const number = Number(value);
|
|
11964
|
+
if (!Number.isFinite(number)) {
|
|
11965
|
+
return '-';
|
|
11966
|
+
}
|
|
11967
|
+
|
|
11968
|
+
return `${Math.round(Math.max(0, Math.min(1, number)) * 100)}%`;
|
|
11969
|
+
}
|
|
11970
|
+
|
|
11971
|
+
function formatRemoteFleetDuration(seconds) {
|
|
11972
|
+
const value = Number(seconds);
|
|
11973
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
11974
|
+
return '-';
|
|
11975
|
+
}
|
|
11976
|
+
|
|
11977
|
+
const days = Math.floor(value / 86400);
|
|
11978
|
+
const hours = Math.floor((value % 86400) / 3600);
|
|
11979
|
+
const minutes = Math.floor((value % 3600) / 60);
|
|
11980
|
+
if (days > 0) {
|
|
11981
|
+
return `${days}d ${hours}h`;
|
|
11982
|
+
}
|
|
11983
|
+
if (hours > 0) {
|
|
11984
|
+
return `${hours}h ${minutes}m`;
|
|
11985
|
+
}
|
|
11986
|
+
return `${minutes}m`;
|
|
11987
|
+
}
|
|
11988
|
+
|
|
11989
|
+
function formatRemoteFleetAge(value) {
|
|
11990
|
+
const timestamp = Date.parse(String(value || ''));
|
|
11991
|
+
if (!Number.isFinite(timestamp)) {
|
|
11992
|
+
return '-';
|
|
11993
|
+
}
|
|
11994
|
+
|
|
11995
|
+
const seconds = Math.max(0, Math.round((Date.now() - timestamp) / 1000));
|
|
11996
|
+
if (seconds < 60) {
|
|
11997
|
+
return 'now';
|
|
11998
|
+
}
|
|
11999
|
+
if (seconds < 3600) {
|
|
12000
|
+
return `${Math.floor(seconds / 60)}m ago`;
|
|
12001
|
+
}
|
|
12002
|
+
if (seconds < 86400) {
|
|
12003
|
+
return `${Math.floor(seconds / 3600)}h ago`;
|
|
12004
|
+
}
|
|
12005
|
+
return `${Math.floor(seconds / 86400)}d ago`;
|
|
12006
|
+
}
|
|
12007
|
+
|
|
12008
|
+
function createRemoteFleetStat(label, value, tone = 'default') {
|
|
12009
|
+
const item = document.createElement('div');
|
|
12010
|
+
item.style.cssText = `
|
|
12011
|
+
display: flex;
|
|
12012
|
+
flex-direction: column;
|
|
12013
|
+
gap: 2px;
|
|
12014
|
+
min-width: 0;
|
|
12015
|
+
padding: 8px 10px;
|
|
12016
|
+
border-radius: 8px;
|
|
12017
|
+
background: ${tone === 'online' ? 'rgba(16, 185, 129, 0.10)' : 'rgba(15, 23, 42, 0.05)'};
|
|
12018
|
+
border: 1px solid ${tone === 'online' ? 'rgba(16, 185, 129, 0.22)' : 'rgba(148, 163, 184, 0.22)'};
|
|
12019
|
+
`;
|
|
12020
|
+
|
|
12021
|
+
const labelEl = document.createElement('span');
|
|
12022
|
+
labelEl.textContent = label;
|
|
12023
|
+
labelEl.style.cssText = `
|
|
12024
|
+
color: #64748b;
|
|
12025
|
+
font-size: 10px;
|
|
12026
|
+
font-weight: 800;
|
|
12027
|
+
letter-spacing: 0;
|
|
12028
|
+
text-transform: uppercase;
|
|
12029
|
+
`;
|
|
12030
|
+
|
|
12031
|
+
const valueEl = document.createElement('strong');
|
|
12032
|
+
valueEl.textContent = value;
|
|
12033
|
+
valueEl.style.cssText = `
|
|
12034
|
+
color: ${tone === 'online' ? '#047857' : '#0f172a'};
|
|
12035
|
+
font-size: 18px;
|
|
12036
|
+
line-height: 1.1;
|
|
12037
|
+
font-weight: 900;
|
|
12038
|
+
letter-spacing: 0;
|
|
12039
|
+
overflow: hidden;
|
|
12040
|
+
text-overflow: ellipsis;
|
|
12041
|
+
white-space: nowrap;
|
|
12042
|
+
`;
|
|
12043
|
+
|
|
12044
|
+
item.appendChild(labelEl);
|
|
12045
|
+
item.appendChild(valueEl);
|
|
12046
|
+
return item;
|
|
12047
|
+
}
|
|
12048
|
+
|
|
12049
|
+
function createRemoteFleetButton(label, title, action) {
|
|
12050
|
+
const button = document.createElement('button');
|
|
12051
|
+
button.type = 'button';
|
|
12052
|
+
button.dataset.remoteFleetAction = action;
|
|
12053
|
+
button.textContent = label;
|
|
12054
|
+
button.title = title || label;
|
|
12055
|
+
button.setAttribute('aria-label', title || label);
|
|
12056
|
+
button.style.cssText = `
|
|
12057
|
+
display: inline-flex;
|
|
12058
|
+
align-items: center;
|
|
12059
|
+
justify-content: center;
|
|
12060
|
+
min-width: 0;
|
|
12061
|
+
height: 28px;
|
|
12062
|
+
padding: 0 10px;
|
|
12063
|
+
border-radius: 7px;
|
|
12064
|
+
border: 1px solid rgba(37, 99, 235, 0.32);
|
|
12065
|
+
background: #ffffff;
|
|
12066
|
+
color: #1d4ed8;
|
|
12067
|
+
font-size: 11px;
|
|
12068
|
+
font-weight: 800;
|
|
12069
|
+
letter-spacing: 0;
|
|
12070
|
+
cursor: pointer;
|
|
12071
|
+
pointer-events: auto;
|
|
12072
|
+
`;
|
|
12073
|
+
return button;
|
|
12074
|
+
}
|
|
12075
|
+
|
|
12076
|
+
async function syncRemoteFleetNodeStateFromResult(result) {
|
|
12077
|
+
const nodeState = result?.nodeState || result?.refresh?.nodeState;
|
|
12078
|
+
if (nodeState && window.mindMap?.syncNodeStates) {
|
|
12079
|
+
await window.mindMap.syncNodeStates([nodeState]);
|
|
12080
|
+
}
|
|
12081
|
+
}
|
|
12082
|
+
|
|
12083
|
+
function renderRemoteFleetMonitor(bodyView, nodeModel) {
|
|
12084
|
+
if (!bodyView) return;
|
|
12085
|
+
|
|
12086
|
+
const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
|
|
12087
|
+
const devices = parseRemoteFleetDevices(nodeModel);
|
|
12088
|
+
const total = Number(getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetDeviceCount', devices.length));
|
|
12089
|
+
const connected = Number(getRemoteFleetMetadataValue(
|
|
12090
|
+
nodeModel,
|
|
12091
|
+
'RemoteFleetConnectedDeviceCount',
|
|
12092
|
+
devices.filter(device => device?.connected === true || device?.Connected === true).length));
|
|
12093
|
+
const endpoint = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubEndpoint', '127.0.0.1:5197');
|
|
12094
|
+
const command = getRemoteFleetMetadataValue(
|
|
12095
|
+
nodeModel,
|
|
12096
|
+
'RemoteFleetConnectCommand',
|
|
12097
|
+
`npx @mindexec/remote connect --manager ${endpoint} --pair <pair-token>`);
|
|
12098
|
+
const hubStatus = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetHubStatus', 'offline');
|
|
12099
|
+
const refreshedAt = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetLastRefreshAtUtc', '');
|
|
12100
|
+
const lastError = getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetLastError', '');
|
|
12101
|
+
|
|
12102
|
+
bodyView.dataset.src = `remote-fleet:${refreshedAt}:${devices.length}:${connected}`;
|
|
12103
|
+
bodyView.classList.add('map-node-remote-fleet__body');
|
|
12104
|
+
bodyView.innerHTML = '';
|
|
12105
|
+
bodyView.style.cssText = `
|
|
12106
|
+
flex: 1 1 auto;
|
|
12107
|
+
min-height: 0;
|
|
12108
|
+
pointer-events: auto;
|
|
12109
|
+
display: flex;
|
|
12110
|
+
flex-direction: column;
|
|
12111
|
+
gap: 10px;
|
|
12112
|
+
padding: 12px 14px 14px;
|
|
12113
|
+
overflow: hidden;
|
|
12114
|
+
background: linear-gradient(180deg, rgba(248, 250, 252, 0.96), rgba(241, 245, 249, 0.92));
|
|
12115
|
+
`;
|
|
12116
|
+
|
|
12117
|
+
const top = document.createElement('div');
|
|
12118
|
+
top.style.cssText = `
|
|
12119
|
+
display: grid;
|
|
12120
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
12121
|
+
gap: 8px;
|
|
12122
|
+
flex: 0 0 auto;
|
|
12123
|
+
`;
|
|
12124
|
+
top.appendChild(createRemoteFleetStat('Hub', hubStatus === 'online' ? 'Online' : 'Offline', hubStatus === 'online' ? 'online' : 'default'));
|
|
12125
|
+
top.appendChild(createRemoteFleetStat('Connected', `${Number.isFinite(connected) ? connected : 0}/${Number.isFinite(total) ? total : devices.length}`, connected > 0 ? 'online' : 'default'));
|
|
12126
|
+
top.appendChild(createRemoteFleetStat('Mode', 'All', 'default'));
|
|
12127
|
+
top.appendChild(createRemoteFleetStat('Paging', 'None', 'default'));
|
|
12128
|
+
bodyView.appendChild(top);
|
|
12129
|
+
|
|
12130
|
+
const commandRow = document.createElement('div');
|
|
12131
|
+
commandRow.style.cssText = `
|
|
12132
|
+
display: grid;
|
|
12133
|
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
12134
|
+
gap: 8px;
|
|
12135
|
+
align-items: center;
|
|
12136
|
+
flex: 0 0 auto;
|
|
12137
|
+
`;
|
|
12138
|
+
|
|
12139
|
+
const commandText = document.createElement('code');
|
|
12140
|
+
commandText.textContent = command;
|
|
12141
|
+
commandText.style.cssText = `
|
|
12142
|
+
min-width: 0;
|
|
12143
|
+
overflow: hidden;
|
|
12144
|
+
text-overflow: ellipsis;
|
|
12145
|
+
white-space: nowrap;
|
|
12146
|
+
padding: 8px 10px;
|
|
12147
|
+
border-radius: 7px;
|
|
12148
|
+
background: rgba(15, 23, 42, 0.92);
|
|
12149
|
+
color: #e2e8f0;
|
|
12150
|
+
font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
|
|
12151
|
+
font-size: 11px;
|
|
12152
|
+
line-height: 1.2;
|
|
12153
|
+
`;
|
|
12154
|
+
commandText.title = command;
|
|
12155
|
+
|
|
12156
|
+
const copyButton = createRemoteFleetButton('Copy', 'Copy agent command', 'copy-command');
|
|
12157
|
+
const refreshButton = createRemoteFleetButton('Refresh', 'Refresh remote devices', 'refresh');
|
|
12158
|
+
commandRow.appendChild(commandText);
|
|
12159
|
+
commandRow.appendChild(copyButton);
|
|
12160
|
+
commandRow.appendChild(refreshButton);
|
|
12161
|
+
bodyView.appendChild(commandRow);
|
|
12162
|
+
|
|
12163
|
+
const taskRow = document.createElement('div');
|
|
12164
|
+
taskRow.style.cssText = `
|
|
12165
|
+
display: grid;
|
|
12166
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
12167
|
+
gap: 8px;
|
|
12168
|
+
align-items: stretch;
|
|
12169
|
+
flex: 0 0 auto;
|
|
12170
|
+
`;
|
|
12171
|
+
const taskInput = document.createElement('textarea');
|
|
12172
|
+
taskInput.dataset.remoteFleetTaskInput = 'true';
|
|
12173
|
+
taskInput.placeholder = 'Task for remote agents';
|
|
12174
|
+
taskInput.rows = 2;
|
|
12175
|
+
taskInput.style.cssText = `
|
|
12176
|
+
width: 100%;
|
|
12177
|
+
min-width: 0;
|
|
12178
|
+
height: 54px;
|
|
12179
|
+
resize: none;
|
|
12180
|
+
border-radius: 7px;
|
|
12181
|
+
border: 1px solid rgba(148, 163, 184, 0.34);
|
|
12182
|
+
background: rgba(255, 255, 255, 0.92);
|
|
12183
|
+
color: #0f172a;
|
|
12184
|
+
padding: 8px 10px;
|
|
12185
|
+
font-size: 12px;
|
|
12186
|
+
line-height: 1.35;
|
|
12187
|
+
font-weight: 700;
|
|
12188
|
+
letter-spacing: 0;
|
|
12189
|
+
outline: none;
|
|
12190
|
+
pointer-events: auto;
|
|
12191
|
+
`;
|
|
12192
|
+
const sendConnectedButton = createRemoteFleetButton('Send connected', 'Dispatch task to all connected task-capable devices', 'task-connected');
|
|
12193
|
+
sendConnectedButton.style.height = '54px';
|
|
12194
|
+
taskRow.appendChild(taskInput);
|
|
12195
|
+
taskRow.appendChild(sendConnectedButton);
|
|
12196
|
+
bodyView.appendChild(taskRow);
|
|
12197
|
+
|
|
12198
|
+
const taskFeedback = document.createElement('div');
|
|
12199
|
+
taskFeedback.dataset.remoteFleetTaskFeedback = 'true';
|
|
12200
|
+
taskFeedback.style.cssText = `
|
|
12201
|
+
display: none;
|
|
12202
|
+
flex: 0 0 auto;
|
|
12203
|
+
min-height: 22px;
|
|
12204
|
+
padding: 5px 8px;
|
|
12205
|
+
border-radius: 7px;
|
|
12206
|
+
background: rgba(37, 99, 235, 0.08);
|
|
12207
|
+
color: #1d4ed8;
|
|
12208
|
+
font-size: 11px;
|
|
12209
|
+
font-weight: 800;
|
|
12210
|
+
line-height: 1.25;
|
|
12211
|
+
overflow: hidden;
|
|
12212
|
+
text-overflow: ellipsis;
|
|
12213
|
+
white-space: nowrap;
|
|
12214
|
+
`;
|
|
12215
|
+
bodyView.appendChild(taskFeedback);
|
|
12216
|
+
|
|
12217
|
+
if (lastError.trim()) {
|
|
12218
|
+
const errorEl = document.createElement('div');
|
|
12219
|
+
errorEl.textContent = lastError;
|
|
12220
|
+
errorEl.style.cssText = `
|
|
12221
|
+
flex: 0 0 auto;
|
|
12222
|
+
padding: 8px 10px;
|
|
12223
|
+
border-radius: 7px;
|
|
12224
|
+
background: rgba(248, 113, 113, 0.12);
|
|
12225
|
+
color: #991b1b;
|
|
12226
|
+
font-size: 12px;
|
|
12227
|
+
line-height: 1.35;
|
|
12228
|
+
font-weight: 700;
|
|
12229
|
+
overflow-wrap: break-word;
|
|
12230
|
+
`;
|
|
12231
|
+
bodyView.appendChild(errorEl);
|
|
12232
|
+
}
|
|
12233
|
+
|
|
12234
|
+
const grid = document.createElement('div');
|
|
12235
|
+
grid.style.cssText = `
|
|
12236
|
+
flex: 1 1 auto;
|
|
12237
|
+
min-height: 0;
|
|
12238
|
+
overflow-y: auto;
|
|
12239
|
+
overflow-x: hidden;
|
|
12240
|
+
display: grid;
|
|
12241
|
+
grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
|
|
12242
|
+
align-content: start;
|
|
12243
|
+
gap: 8px;
|
|
12244
|
+
padding-right: 4px;
|
|
12245
|
+
`;
|
|
12246
|
+
|
|
12247
|
+
if (devices.length === 0) {
|
|
12248
|
+
const empty = document.createElement('div');
|
|
12249
|
+
empty.textContent = 'No devices connected yet.';
|
|
12250
|
+
empty.style.cssText = `
|
|
12251
|
+
grid-column: 1 / -1;
|
|
12252
|
+
display: flex;
|
|
12253
|
+
align-items: center;
|
|
12254
|
+
min-height: 94px;
|
|
12255
|
+
padding: 14px;
|
|
12256
|
+
border-radius: 8px;
|
|
12257
|
+
border: 1px dashed rgba(100, 116, 139, 0.36);
|
|
12258
|
+
color: #475569;
|
|
12259
|
+
font-size: 13px;
|
|
12260
|
+
font-weight: 800;
|
|
12261
|
+
background: rgba(255, 255, 255, 0.74);
|
|
12262
|
+
`;
|
|
12263
|
+
grid.appendChild(empty);
|
|
12264
|
+
} else {
|
|
12265
|
+
devices.forEach(device => {
|
|
12266
|
+
const connectedDevice = device?.connected === true || device?.Connected === true;
|
|
12267
|
+
const name = String(device?.name || device?.Name || device?.hostname || device?.Hostname || device?.deviceId || device?.DeviceId || 'device');
|
|
12268
|
+
const platform = [device?.platform || device?.Platform, device?.arch || device?.Arch]
|
|
12269
|
+
.filter(Boolean)
|
|
12270
|
+
.join(' / ') || 'unknown';
|
|
12271
|
+
const release = String(device?.release || device?.Release || '');
|
|
12272
|
+
const deviceId = String(device?.deviceId || device?.DeviceId || '');
|
|
12273
|
+
const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
|
|
12274
|
+
const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
|
|
12275
|
+
const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
|
|
12276
|
+
const hasThumbnail = /^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(thumbnailDataUrl);
|
|
12277
|
+
const taskEnabled = device?.computerAgentEnabled === true || device?.ComputerAgentEnabled === true;
|
|
12278
|
+
const latestTaskStatus = String(device?.latestTaskStatus || device?.LatestTaskStatus || '');
|
|
12279
|
+
const latestTaskTitle = String(device?.latestTaskTitle || device?.LatestTaskTitle || '');
|
|
12280
|
+
const latestTaskUpdatedAt = String(device?.latestTaskUpdatedAt || device?.LatestTaskUpdatedAt || '');
|
|
12281
|
+
const latestTaskError = String(device?.latestTaskError || device?.LatestTaskError || '');
|
|
12282
|
+
const latestTaskResult = String(device?.latestTaskResultSummary || device?.LatestTaskResultSummary || '');
|
|
12283
|
+
const card = document.createElement('article');
|
|
12284
|
+
card.dataset.deviceId = deviceId;
|
|
12285
|
+
card.style.cssText = `
|
|
12286
|
+
display: flex;
|
|
12287
|
+
flex-direction: column;
|
|
12288
|
+
gap: 8px;
|
|
12289
|
+
min-width: 0;
|
|
12290
|
+
min-height: 134px;
|
|
12291
|
+
padding: 10px;
|
|
12292
|
+
border-radius: 8px;
|
|
12293
|
+
background: #ffffff;
|
|
12294
|
+
border: 1px solid ${connectedDevice ? 'rgba(16, 185, 129, 0.34)' : 'rgba(148, 163, 184, 0.28)'};
|
|
12295
|
+
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
|
|
12296
|
+
`;
|
|
12297
|
+
|
|
12298
|
+
const preview = document.createElement('div');
|
|
12299
|
+
preview.style.cssText = `
|
|
12300
|
+
position: relative;
|
|
12301
|
+
width: 100%;
|
|
12302
|
+
aspect-ratio: 16 / 9;
|
|
12303
|
+
overflow: hidden;
|
|
12304
|
+
border-radius: 7px;
|
|
12305
|
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
12306
|
+
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
12307
|
+
`;
|
|
12308
|
+
if (hasThumbnail) {
|
|
12309
|
+
const image = document.createElement('img');
|
|
12310
|
+
image.src = thumbnailDataUrl;
|
|
12311
|
+
image.alt = `${name} thumbnail`;
|
|
12312
|
+
image.loading = 'lazy';
|
|
12313
|
+
image.decoding = 'async';
|
|
12314
|
+
image.style.cssText = `
|
|
12315
|
+
width: 100%;
|
|
12316
|
+
height: 100%;
|
|
12317
|
+
object-fit: cover;
|
|
12318
|
+
display: block;
|
|
12319
|
+
`;
|
|
12320
|
+
preview.appendChild(image);
|
|
12321
|
+
} else {
|
|
12322
|
+
const placeholder = document.createElement('div');
|
|
12323
|
+
placeholder.textContent = thumbnailEnabled ? 'No frame yet' : 'Status only';
|
|
12324
|
+
placeholder.style.cssText = `
|
|
12325
|
+
position: absolute;
|
|
12326
|
+
inset: 0;
|
|
12327
|
+
display: flex;
|
|
12328
|
+
align-items: center;
|
|
12329
|
+
justify-content: center;
|
|
12330
|
+
color: rgba(226, 232, 240, 0.78);
|
|
12331
|
+
font-size: 11px;
|
|
12332
|
+
font-weight: 900;
|
|
12333
|
+
letter-spacing: 0;
|
|
12334
|
+
`;
|
|
12335
|
+
preview.appendChild(placeholder);
|
|
12336
|
+
}
|
|
12337
|
+
if (thumbnailCapturedAt) {
|
|
12338
|
+
const badge = document.createElement('span');
|
|
12339
|
+
badge.textContent = formatRemoteFleetAge(thumbnailCapturedAt);
|
|
12340
|
+
badge.style.cssText = `
|
|
12341
|
+
position: absolute;
|
|
12342
|
+
right: 6px;
|
|
12343
|
+
bottom: 6px;
|
|
12344
|
+
max-width: calc(100% - 12px);
|
|
12345
|
+
padding: 3px 6px;
|
|
12346
|
+
border-radius: 999px;
|
|
12347
|
+
background: rgba(15, 23, 42, 0.74);
|
|
12348
|
+
color: #e2e8f0;
|
|
12349
|
+
font-size: 9px;
|
|
12350
|
+
font-weight: 900;
|
|
12351
|
+
line-height: 1;
|
|
12352
|
+
overflow: hidden;
|
|
12353
|
+
text-overflow: ellipsis;
|
|
12354
|
+
white-space: nowrap;
|
|
12355
|
+
`;
|
|
12356
|
+
preview.appendChild(badge);
|
|
12357
|
+
}
|
|
12358
|
+
card.appendChild(preview);
|
|
12359
|
+
|
|
12360
|
+
const cardHeader = document.createElement('div');
|
|
12361
|
+
cardHeader.style.cssText = 'display:flex;align-items:flex-start;gap:8px;min-width:0;';
|
|
12362
|
+
const dot = document.createElement('span');
|
|
12363
|
+
dot.style.cssText = `
|
|
12364
|
+
flex: 0 0 auto;
|
|
12365
|
+
width: 9px;
|
|
12366
|
+
height: 9px;
|
|
12367
|
+
margin-top: 4px;
|
|
12368
|
+
border-radius: 999px;
|
|
12369
|
+
background: ${connectedDevice ? '#10b981' : '#94a3b8'};
|
|
12370
|
+
box-shadow: 0 0 0 4px ${connectedDevice ? 'rgba(16,185,129,0.14)' : 'rgba(148,163,184,0.14)'};
|
|
12371
|
+
`;
|
|
12372
|
+
|
|
12373
|
+
const titleBox = document.createElement('div');
|
|
12374
|
+
titleBox.style.cssText = 'min-width:0;display:flex;flex-direction:column;gap:2px;';
|
|
12375
|
+
const title = document.createElement('strong');
|
|
12376
|
+
title.textContent = name;
|
|
12377
|
+
title.title = name;
|
|
12378
|
+
title.style.cssText = `
|
|
12379
|
+
color: #0f172a;
|
|
12380
|
+
font-size: 13px;
|
|
12381
|
+
font-weight: 900;
|
|
12382
|
+
line-height: 1.2;
|
|
12383
|
+
overflow: hidden;
|
|
12384
|
+
text-overflow: ellipsis;
|
|
12385
|
+
white-space: nowrap;
|
|
12386
|
+
letter-spacing: 0;
|
|
12387
|
+
`;
|
|
12388
|
+
const subtitle = document.createElement('span');
|
|
12389
|
+
subtitle.textContent = release ? `${platform} ${release}` : platform;
|
|
12390
|
+
subtitle.title = subtitle.textContent;
|
|
12391
|
+
subtitle.style.cssText = `
|
|
12392
|
+
color: #64748b;
|
|
12393
|
+
font-size: 11px;
|
|
12394
|
+
line-height: 1.2;
|
|
12395
|
+
overflow: hidden;
|
|
12396
|
+
text-overflow: ellipsis;
|
|
12397
|
+
white-space: nowrap;
|
|
12398
|
+
letter-spacing: 0;
|
|
12399
|
+
`;
|
|
12400
|
+
titleBox.appendChild(title);
|
|
12401
|
+
titleBox.appendChild(subtitle);
|
|
12402
|
+
cardHeader.appendChild(dot);
|
|
12403
|
+
cardHeader.appendChild(titleBox);
|
|
12404
|
+
card.appendChild(cardHeader);
|
|
12405
|
+
|
|
12406
|
+
const metrics = document.createElement('div');
|
|
12407
|
+
metrics.style.cssText = `
|
|
12408
|
+
display: grid;
|
|
12409
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
12410
|
+
gap: 6px;
|
|
12411
|
+
`;
|
|
12412
|
+
const addMetric = (label, value) => {
|
|
12413
|
+
const metric = document.createElement('div');
|
|
12414
|
+
metric.style.cssText = `
|
|
12415
|
+
min-width: 0;
|
|
12416
|
+
padding: 6px 7px;
|
|
12417
|
+
border-radius: 7px;
|
|
12418
|
+
background: rgba(241, 245, 249, 0.84);
|
|
12419
|
+
`;
|
|
12420
|
+
const labelEl = document.createElement('div');
|
|
12421
|
+
labelEl.textContent = label;
|
|
12422
|
+
labelEl.style.cssText = 'color:#64748b;font-size:9px;font-weight:800;letter-spacing:0;text-transform:uppercase;';
|
|
12423
|
+
const valueEl = document.createElement('div');
|
|
12424
|
+
valueEl.textContent = value;
|
|
12425
|
+
valueEl.title = value;
|
|
12426
|
+
valueEl.style.cssText = 'color:#0f172a;font-size:12px;font-weight:900;letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
|
|
12427
|
+
metric.appendChild(labelEl);
|
|
12428
|
+
metric.appendChild(valueEl);
|
|
12429
|
+
metrics.appendChild(metric);
|
|
12430
|
+
};
|
|
12431
|
+
addMetric('Seen', formatRemoteFleetAge(device?.lastSeenAt || device?.LastSeenAt));
|
|
12432
|
+
addMetric('Uptime', formatRemoteFleetDuration(device?.uptimeSec ?? device?.UptimeSec));
|
|
12433
|
+
addMetric('Mem', formatRemoteFleetPercent(device?.usedMemRatio ?? device?.UsedMemRatio));
|
|
12434
|
+
addMetric('Load', formatRemoteFleetNumber(device?.load1 ?? device?.Load1, 2));
|
|
12435
|
+
card.appendChild(metrics);
|
|
12436
|
+
|
|
12437
|
+
if (latestTaskStatus || latestTaskTitle || latestTaskResult || latestTaskError) {
|
|
12438
|
+
const taskBox = document.createElement('div');
|
|
12439
|
+
const taskTone = latestTaskError || latestTaskStatus === 'failed'
|
|
12440
|
+
? 'error'
|
|
12441
|
+
: (latestTaskStatus === 'completed' ? 'done' : 'pending');
|
|
12442
|
+
taskBox.style.cssText = `
|
|
12443
|
+
display: flex;
|
|
12444
|
+
flex-direction: column;
|
|
12445
|
+
gap: 3px;
|
|
12446
|
+
min-width: 0;
|
|
12447
|
+
padding: 7px 8px;
|
|
12448
|
+
border-radius: 7px;
|
|
12449
|
+
background: ${taskTone === 'error' ? 'rgba(248, 113, 113, 0.12)' : taskTone === 'done' ? 'rgba(16, 185, 129, 0.10)' : 'rgba(37, 99, 235, 0.08)'};
|
|
12450
|
+
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)'};
|
|
12451
|
+
`;
|
|
12452
|
+
const taskLine = document.createElement('div');
|
|
12453
|
+
taskLine.textContent = `${latestTaskStatus || 'task'}${latestTaskUpdatedAt ? ` - ${formatRemoteFleetAge(latestTaskUpdatedAt)}` : ''}`;
|
|
12454
|
+
taskLine.style.cssText = `
|
|
12455
|
+
color: ${taskTone === 'error' ? '#991b1b' : taskTone === 'done' ? '#047857' : '#1d4ed8'};
|
|
12456
|
+
font-size: 10px;
|
|
12457
|
+
font-weight: 900;
|
|
12458
|
+
line-height: 1.2;
|
|
12459
|
+
overflow: hidden;
|
|
12460
|
+
text-overflow: ellipsis;
|
|
12461
|
+
white-space: nowrap;
|
|
12462
|
+
letter-spacing: 0;
|
|
12463
|
+
`;
|
|
12464
|
+
const taskSummary = document.createElement('div');
|
|
12465
|
+
taskSummary.textContent = latestTaskError || latestTaskResult || latestTaskTitle || 'Task queued';
|
|
12466
|
+
taskSummary.title = taskSummary.textContent;
|
|
12467
|
+
taskSummary.style.cssText = `
|
|
12468
|
+
color: #334155;
|
|
12469
|
+
font-size: 10px;
|
|
12470
|
+
font-weight: 700;
|
|
12471
|
+
line-height: 1.25;
|
|
12472
|
+
overflow: hidden;
|
|
12473
|
+
display: -webkit-box;
|
|
12474
|
+
-webkit-line-clamp: 2;
|
|
12475
|
+
-webkit-box-orient: vertical;
|
|
12476
|
+
letter-spacing: 0;
|
|
12477
|
+
`;
|
|
12478
|
+
taskBox.appendChild(taskLine);
|
|
12479
|
+
taskBox.appendChild(taskSummary);
|
|
12480
|
+
card.appendChild(taskBox);
|
|
12481
|
+
}
|
|
12482
|
+
|
|
12483
|
+
const actions = document.createElement('div');
|
|
12484
|
+
actions.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto;';
|
|
12485
|
+
const status = document.createElement('span');
|
|
12486
|
+
status.textContent = connectedDevice ? 'Connected' : 'Offline';
|
|
12487
|
+
status.style.cssText = `
|
|
12488
|
+
min-width: 0;
|
|
12489
|
+
color: ${connectedDevice ? '#047857' : '#64748b'};
|
|
12490
|
+
font-size: 11px;
|
|
12491
|
+
font-weight: 900;
|
|
12492
|
+
overflow: hidden;
|
|
12493
|
+
text-overflow: ellipsis;
|
|
12494
|
+
white-space: nowrap;
|
|
12495
|
+
`;
|
|
12496
|
+
actions.appendChild(status);
|
|
12497
|
+
if (connectedDevice && deviceId) {
|
|
12498
|
+
if (taskEnabled) {
|
|
12499
|
+
const taskButton = createRemoteFleetButton('Task', 'Dispatch task to this device', 'task-device');
|
|
12500
|
+
taskButton.dataset.deviceId = deviceId;
|
|
12501
|
+
taskButton.style.height = '24px';
|
|
12502
|
+
taskButton.style.fontSize = '10px';
|
|
12503
|
+
actions.appendChild(taskButton);
|
|
12504
|
+
}
|
|
12505
|
+
if (thumbnailEnabled) {
|
|
12506
|
+
const thumbnailButton = createRemoteFleetButton('Shot', 'Request thumbnail', 'thumbnail-device');
|
|
12507
|
+
thumbnailButton.dataset.deviceId = deviceId;
|
|
12508
|
+
thumbnailButton.style.height = '24px';
|
|
12509
|
+
thumbnailButton.style.fontSize = '10px';
|
|
12510
|
+
actions.appendChild(thumbnailButton);
|
|
12511
|
+
}
|
|
12512
|
+
const pingButton = createRemoteFleetButton('Ping', 'Ping device', 'ping-device');
|
|
12513
|
+
pingButton.dataset.deviceId = deviceId;
|
|
12514
|
+
pingButton.style.height = '24px';
|
|
12515
|
+
pingButton.style.fontSize = '10px';
|
|
12516
|
+
actions.appendChild(pingButton);
|
|
12517
|
+
}
|
|
12518
|
+
card.appendChild(actions);
|
|
12519
|
+
grid.appendChild(card);
|
|
12520
|
+
});
|
|
12521
|
+
}
|
|
12522
|
+
|
|
12523
|
+
bodyView.appendChild(grid);
|
|
12524
|
+
|
|
12525
|
+
const footer = document.createElement('div');
|
|
12526
|
+
footer.textContent = `Endpoint ${endpoint} · refreshed ${formatRemoteFleetAge(refreshedAt)}`;
|
|
12527
|
+
footer.style.cssText = `
|
|
12528
|
+
flex: 0 0 auto;
|
|
12529
|
+
color: #64748b;
|
|
12530
|
+
font-size: 11px;
|
|
12531
|
+
font-weight: 700;
|
|
12532
|
+
line-height: 1.2;
|
|
12533
|
+
overflow: hidden;
|
|
12534
|
+
text-overflow: ellipsis;
|
|
12535
|
+
white-space: nowrap;
|
|
12536
|
+
`;
|
|
12537
|
+
bodyView.appendChild(footer);
|
|
12538
|
+
|
|
12539
|
+
copyButton.addEventListener('click', event => {
|
|
12540
|
+
event.preventDefault();
|
|
12541
|
+
event.stopPropagation();
|
|
12542
|
+
navigator.clipboard?.writeText?.(command).catch(() => { });
|
|
12543
|
+
});
|
|
12544
|
+
|
|
12545
|
+
const setTaskFeedback = (message, tone = 'info') => {
|
|
12546
|
+
taskFeedback.textContent = message || '';
|
|
12547
|
+
taskFeedback.style.display = message ? 'block' : 'none';
|
|
12548
|
+
taskFeedback.style.background = tone === 'error'
|
|
12549
|
+
? 'rgba(248, 113, 113, 0.12)'
|
|
12550
|
+
: tone === 'success'
|
|
12551
|
+
? 'rgba(16, 185, 129, 0.10)'
|
|
12552
|
+
: 'rgba(37, 99, 235, 0.08)';
|
|
12553
|
+
taskFeedback.style.color = tone === 'error'
|
|
12554
|
+
? '#991b1b'
|
|
12555
|
+
: tone === 'success'
|
|
12556
|
+
? '#047857'
|
|
12557
|
+
: '#1d4ed8';
|
|
12558
|
+
};
|
|
12559
|
+
|
|
12560
|
+
const readTaskInstruction = () => String(taskInput.value || '').trim();
|
|
12561
|
+
|
|
12562
|
+
sendConnectedButton.addEventListener('click', async event => {
|
|
12563
|
+
event.preventDefault();
|
|
12564
|
+
event.stopPropagation();
|
|
12565
|
+
const instruction = readTaskInstruction();
|
|
12566
|
+
if (!instruction) {
|
|
12567
|
+
setTaskFeedback('Write a task first.', 'error');
|
|
12568
|
+
taskInput.focus();
|
|
12569
|
+
return;
|
|
12570
|
+
}
|
|
12571
|
+
|
|
12572
|
+
sendConnectedButton.disabled = true;
|
|
12573
|
+
setTaskFeedback('Dispatching task to connected devices...');
|
|
12574
|
+
try {
|
|
12575
|
+
const result = await invokeDotNetAsync('DispatchRemoteFleetTaskFromJs', nodeId, '', instruction);
|
|
12576
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
12577
|
+
if (result?.success) {
|
|
12578
|
+
setTaskFeedback(`Queued ${result.queued || result.total || 1} remote task(s).`, 'success');
|
|
12579
|
+
} else {
|
|
12580
|
+
setTaskFeedback(result?.error || 'Task dispatch failed.', 'error');
|
|
12581
|
+
}
|
|
12582
|
+
} finally {
|
|
12583
|
+
sendConnectedButton.disabled = false;
|
|
12584
|
+
}
|
|
12585
|
+
});
|
|
12586
|
+
|
|
12587
|
+
refreshButton.addEventListener('click', async event => {
|
|
12588
|
+
event.preventDefault();
|
|
12589
|
+
event.stopPropagation();
|
|
12590
|
+
refreshButton.disabled = true;
|
|
12591
|
+
const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
|
|
12592
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
12593
|
+
refreshButton.disabled = false;
|
|
12594
|
+
});
|
|
12595
|
+
|
|
12596
|
+
grid.querySelectorAll('[data-remote-fleet-action="ping-device"]').forEach(button => {
|
|
12597
|
+
button.addEventListener('click', async event => {
|
|
12598
|
+
event.preventDefault();
|
|
12599
|
+
event.stopPropagation();
|
|
12600
|
+
button.disabled = true;
|
|
12601
|
+
const result = await invokeDotNetAsync('PingRemoteFleetDeviceFromJs', nodeId, button.dataset.deviceId || '');
|
|
12602
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
12603
|
+
button.disabled = false;
|
|
12604
|
+
});
|
|
12605
|
+
});
|
|
12606
|
+
|
|
12607
|
+
grid.querySelectorAll('[data-remote-fleet-action="task-device"]').forEach(button => {
|
|
12608
|
+
button.addEventListener('click', async event => {
|
|
12609
|
+
event.preventDefault();
|
|
12610
|
+
event.stopPropagation();
|
|
12611
|
+
const instruction = readTaskInstruction();
|
|
12612
|
+
if (!instruction) {
|
|
12613
|
+
setTaskFeedback('Write a task first.', 'error');
|
|
12614
|
+
taskInput.focus();
|
|
12615
|
+
return;
|
|
12616
|
+
}
|
|
12617
|
+
|
|
12618
|
+
button.disabled = true;
|
|
12619
|
+
setTaskFeedback('Dispatching task to device...');
|
|
12620
|
+
try {
|
|
12621
|
+
const result = await invokeDotNetAsync('DispatchRemoteFleetTaskFromJs', nodeId, button.dataset.deviceId || '', instruction);
|
|
12622
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
12623
|
+
if (result?.success) {
|
|
12624
|
+
setTaskFeedback('Queued remote task.', 'success');
|
|
12625
|
+
} else {
|
|
12626
|
+
setTaskFeedback(result?.error || 'Task dispatch failed.', 'error');
|
|
12627
|
+
}
|
|
12628
|
+
} finally {
|
|
12629
|
+
button.disabled = false;
|
|
12630
|
+
}
|
|
12631
|
+
});
|
|
12632
|
+
});
|
|
12633
|
+
|
|
12634
|
+
grid.querySelectorAll('[data-remote-fleet-action="thumbnail-device"]').forEach(button => {
|
|
12635
|
+
button.addEventListener('click', async event => {
|
|
12636
|
+
event.preventDefault();
|
|
12637
|
+
event.stopPropagation();
|
|
12638
|
+
button.disabled = true;
|
|
12639
|
+
const result = await invokeDotNetAsync('RequestRemoteFleetThumbnailFromJs', nodeId, button.dataset.deviceId || '');
|
|
12640
|
+
await syncRemoteFleetNodeStateFromResult(result);
|
|
12641
|
+
button.disabled = false;
|
|
12642
|
+
});
|
|
12643
|
+
});
|
|
12644
|
+
}
|
|
12645
|
+
|
|
11919
12646
|
function bindMemoNodeEvents(container, nodeModel) {
|
|
11920
12647
|
if (!container || !nodeModel) return;
|
|
11921
12648
|
ensureMindCanvasAgentConsoleResize(container, nodeModel);
|
|
@@ -12147,11 +12874,12 @@
|
|
|
12147
12874
|
const agentStyledMemo = isAgentStyledMemoNode(nodeModel);
|
|
12148
12875
|
const mindCanvasAgent = isMindCanvasAgentNode(nodeModel);
|
|
12149
12876
|
const businessAutomation = isBusinessAutomationNode(nodeModel);
|
|
12877
|
+
const remoteFleet = isRemoteFleetMonitorNode(nodeModel);
|
|
12150
12878
|
const externalChrome = allowsMemoExternalChrome(nodeModel);
|
|
12151
12879
|
|
|
12152
12880
|
const container = document.createElement('div');
|
|
12153
12881
|
container.id = `node-${nodeModel.id}`;
|
|
12154
|
-
container.className = `map-node css3d-dynamic-node map-node-memo${agentStyledMemo ? ' map-node-agent' : ''}${businessAutomation ? ' map-node-automation' : ''}`;
|
|
12882
|
+
container.className = `map-node css3d-dynamic-node map-node-memo${agentStyledMemo ? ' map-node-agent' : ''}${businessAutomation ? ' map-node-automation' : ''}${remoteFleet ? ' map-node-remote-fleet' : ''}`;
|
|
12155
12883
|
container.dataset.nodeId = nodeModel.id;
|
|
12156
12884
|
container.dataset.semanticType = getNodeSemanticType(nodeModel);
|
|
12157
12885
|
container.dataset.agentConsoleOpen = isMindCanvasAgentConsoleOpen(nodeModel) ? 'true' : 'false';
|
|
@@ -15290,10 +16018,12 @@
|
|
|
15290
16018
|
const iconKey = getMemoIconKey(nodeModel);
|
|
15291
16019
|
const agentStyledMemo = isAgentStyledMemoNode(nodeModel);
|
|
15292
16020
|
const businessAutomation = isBusinessAutomationNode(nodeModel);
|
|
16021
|
+
const remoteFleet = isRemoteFleetMonitorNode(nodeModel);
|
|
15293
16022
|
const externalChrome = allowsMemoExternalChrome(nodeModel);
|
|
15294
16023
|
|
|
15295
16024
|
memoEl.classList.toggle('map-node-agent', agentStyledMemo);
|
|
15296
16025
|
memoEl.classList.toggle('map-node-automation', businessAutomation);
|
|
16026
|
+
memoEl.classList.toggle('map-node-remote-fleet', remoteFleet);
|
|
15297
16027
|
memoEl.dataset.semanticType = getNodeSemanticType(nodeModel);
|
|
15298
16028
|
memoEl.dataset.agentPlanOpen = getRenderedMindCanvasAgentPlanOpen(memoEl, nodeModel) ? 'true' : 'false';
|
|
15299
16029
|
memoEl.dataset.agentConsoleOpen = getRenderedMindCanvasAgentConsoleOpen(memoEl, nodeModel) ? 'true' : 'false';
|