@mindexec/cli 0.2.455 → 0.2.457
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 +77 -77
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/scripts/remote-fleet-render-smoke.mjs +24 -46
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +4 -4
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +253 -261
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +1326 -1323
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +25 -6
- package/wwwroot/_framework/{MindExecution.Core.3y861y22o4.dll → MindExecution.Core.speado072l.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.182clfthnx.dll → MindExecution.Kernel.mjy31ssdac.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.ghxhrm0vf5.dll → MindExecution.Plugins.Admin.vbjjmdaao2.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.doimlros51.dll → MindExecution.Plugins.Business.0cr5jc6wqe.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.hp54u7s3y5.dll → MindExecution.Plugins.Concept.m7p666e0jd.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.wjfnb1nk3b.dll → MindExecution.Plugins.Directory.kmdtirnljl.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.447psj7gxo.dll → MindExecution.Plugins.PlanMaster.m1pfeozacj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.7f551zknhn.dll → MindExecution.Plugins.YouTube.nvsc9q4s6b.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.aftyr3f4lo.dll → MindExecution.Shared.9jaznballd.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.tkj3z0fg8f.dll → MindExecution.Web.k5jxwawryl.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +1 -1
- package/wwwroot/service-worker-assets.js +27 -27
- package/wwwroot/service-worker.js +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// File: mind-map-css3d-manager.js
|
|
2
|
-
// [Refactor] Owns CSS3DObject creation, DOM cloning, and event binding.
|
|
3
|
-
(function () {
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
// ▼▼▼ [Perf] Debug logging (disable in production) ▼▼▼
|
|
1
|
+
// File: mind-map-css3d-manager.js
|
|
2
|
+
// [Refactor] Owns CSS3DObject creation, DOM cloning, and event binding.
|
|
3
|
+
(function () {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
// ▼▼▼ [Perf] Debug logging (disable in production) ▼▼▼
|
|
7
7
|
const DEBUG = false;
|
|
8
8
|
const log = DEBUG ? console.log.bind(console) : () => { };
|
|
9
9
|
const warn = DEBUG ? console.warn.bind(console) : () => { };
|
|
@@ -46,8 +46,9 @@
|
|
|
46
46
|
const CSS3D_ONLY_NODE_RENDERING = true;
|
|
47
47
|
const CSV_TABLE_MAX_RENDER_ROWS = 500;
|
|
48
48
|
const CSV_TABLE_MAX_RENDER_COLUMNS = 80;
|
|
49
|
-
const REMOTE_FLEET_DISPLAY_NAME = '
|
|
50
|
-
const REMOTE_FLEET_LEGACY_DISPLAY_NAME = '
|
|
49
|
+
const REMOTE_FLEET_DISPLAY_NAME = 'Remote Work Console';
|
|
50
|
+
const REMOTE_FLEET_LEGACY_DISPLAY_NAME = 'Multi Desktop Monitor';
|
|
51
|
+
const REMOTE_FLEET_LEGACY_DISPLAY_NAME_V0 = 'Remote Fleet Monitor';
|
|
51
52
|
const _cssVideoProxyStateByVideo = new WeakMap();
|
|
52
53
|
|
|
53
54
|
function syncMindCanvasPlatformRenderClasses() {
|
|
@@ -355,12 +356,12 @@
|
|
|
355
356
|
renderCsvTableContent
|
|
356
357
|
};
|
|
357
358
|
// ▲▲▲ [Perf] ▲▲▲
|
|
358
|
-
|
|
359
|
-
// ▼▼▼ [New] 기본 마크다운 스타일 주입 ▼▼▼
|
|
359
|
+
|
|
360
|
+
// ▼▼▼ [New] 기본 마크다운 스타일 주입 ▼▼▼
|
|
360
361
|
function injectMarkdownStyles() {
|
|
361
|
-
// ▼▼▼ [FIX] 기존 스타일 제거 후 새로 주입 (업데이트 보장) ▼▼▼
|
|
362
|
-
const existingStyle = document.getElementById('mind-map-markdown-styles');
|
|
363
|
-
if (existingStyle) existingStyle.remove();
|
|
362
|
+
// ▼▼▼ [FIX] 기존 스타일 제거 후 새로 주입 (업데이트 보장) ▼▼▼
|
|
363
|
+
const existingStyle = document.getElementById('mind-map-markdown-styles');
|
|
364
|
+
if (existingStyle) existingStyle.remove();
|
|
364
365
|
const style = document.createElement('style');
|
|
365
366
|
style.id = 'mind-map-markdown-styles';
|
|
366
367
|
style.textContent = `
|
|
@@ -388,17 +389,17 @@
|
|
|
388
389
|
.markdown-body h2 { font-size: 1.4em; font-weight: bold; margin-top: 1em; margin-bottom: 0.5em; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }
|
|
389
390
|
.markdown-body h3 { font-size: 1.2em; font-weight: bold; margin-top: 1em; margin-bottom: 0.5em; }
|
|
390
391
|
.markdown-body p { margin-bottom: 0.8em; white-space: normal; }
|
|
391
|
-
.markdown-body ul { padding-left: 1.5em; margin-bottom: 1em; list-style-type: disc; }
|
|
392
|
-
.markdown-body ol { padding-left: 1.5em; margin-bottom: 1em; list-style-type: decimal; }
|
|
393
|
-
.markdown-body li { margin-bottom: 0.25em; }
|
|
394
|
-
.markdown-body blockquote { border-left: 4px solid #dfe2e5; padding: 0 1em; color: #6a737d; margin: 0 0 1em 0; }
|
|
395
|
-
.markdown-body code { font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; background-color: rgba(27,31,35,0.05); padding: 0.2em 0.4em; border-radius: 3px; font-size: 85%; }
|
|
396
|
-
.markdown-body pre { background-color: #f6f8fa; padding: 12px; overflow: auto; border-radius: 3px; margin-bottom: 1em; }
|
|
397
|
-
.markdown-body pre code { background-color: transparent; padding: 0; font-size: 100%; }
|
|
398
|
-
.markdown-body a { color: #0366d6; text-decoration: none; }
|
|
399
|
-
.markdown-body a:hover { text-decoration: underline; }
|
|
400
|
-
.markdown-body img { max-width: 100%; box-sizing: content-box; background-color: #fff; }
|
|
401
|
-
.markdown-body table { border-spacing: 0; border-collapse: collapse; width: 100%; margin-bottom: 1em; }
|
|
392
|
+
.markdown-body ul { padding-left: 1.5em; margin-bottom: 1em; list-style-type: disc; }
|
|
393
|
+
.markdown-body ol { padding-left: 1.5em; margin-bottom: 1em; list-style-type: decimal; }
|
|
394
|
+
.markdown-body li { margin-bottom: 0.25em; }
|
|
395
|
+
.markdown-body blockquote { border-left: 4px solid #dfe2e5; padding: 0 1em; color: #6a737d; margin: 0 0 1em 0; }
|
|
396
|
+
.markdown-body code { font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; background-color: rgba(27,31,35,0.05); padding: 0.2em 0.4em; border-radius: 3px; font-size: 85%; }
|
|
397
|
+
.markdown-body pre { background-color: #f6f8fa; padding: 12px; overflow: auto; border-radius: 3px; margin-bottom: 1em; }
|
|
398
|
+
.markdown-body pre code { background-color: transparent; padding: 0; font-size: 100%; }
|
|
399
|
+
.markdown-body a { color: #0366d6; text-decoration: none; }
|
|
400
|
+
.markdown-body a:hover { text-decoration: underline; }
|
|
401
|
+
.markdown-body img { max-width: 100%; box-sizing: content-box; background-color: #fff; }
|
|
402
|
+
.markdown-body table { border-spacing: 0; border-collapse: collapse; width: 100%; margin-bottom: 1em; }
|
|
402
403
|
.markdown-body table th, .markdown-body table td { padding: 6px 13px; border: 1px solid #dfe2e5; }
|
|
403
404
|
.markdown-body table th { font-weight: 600; background-color: #f6f8fa; }
|
|
404
405
|
.markdown-body hr { height: 0.25em; padding: 0; margin: 24px 0; background-color: #e1e4e8; border: 0; }
|
|
@@ -597,10 +598,10 @@
|
|
|
597
598
|
}
|
|
598
599
|
/* Force list markers to be visible */
|
|
599
600
|
.markdown-body ul li { list-style-type: disc; }
|
|
600
|
-
.markdown-body ol li { list-style-type: decimal; }
|
|
601
|
-
|
|
602
|
-
/* ▼▼▼ [NEW] 슬림 스크롤바 스타일 - 모든 텍스트/노트/코드 영역 (Razor + JS 동적노드 전체) ▼▼▼ */
|
|
603
|
-
/* 1. Firefox 대응 + 여백 최소화 (속성 선택자로 모든 노드 잡기) */
|
|
601
|
+
.markdown-body ol li { list-style-type: decimal; }
|
|
602
|
+
|
|
603
|
+
/* ▼▼▼ [NEW] 슬림 스크롤바 스타일 - 모든 텍스트/노트/코드 영역 (Razor + JS 동적노드 전체) ▼▼▼ */
|
|
604
|
+
/* 1. Firefox 대응 + 여백 최소화 (속성 선택자로 모든 노드 잡기) */
|
|
604
605
|
.note-textarea,
|
|
605
606
|
.note-content,
|
|
606
607
|
.markdown-body,
|
|
@@ -659,7 +660,7 @@
|
|
|
659
660
|
width: 8px !important;
|
|
660
661
|
height: 8px !important;
|
|
661
662
|
}
|
|
662
|
-
|
|
663
|
+
|
|
663
664
|
.note-textarea::-webkit-scrollbar-thumb,
|
|
664
665
|
.note-content::-webkit-scrollbar-thumb,
|
|
665
666
|
.markdown-body::-webkit-scrollbar-thumb,
|
|
@@ -750,7 +751,7 @@
|
|
|
750
751
|
.map-node-code .code-body::-webkit-scrollbar-thumb:active {
|
|
751
752
|
background: rgba(0, 0, 0, 0.45) !important;
|
|
752
753
|
}
|
|
753
|
-
|
|
754
|
+
|
|
754
755
|
/* 3. 노트 편집기는 렌더링 markdown과 같은 타이포그래피/박스 모델을 유지 */
|
|
755
756
|
.map-node-note .note-textarea,
|
|
756
757
|
.map-node-note textarea.note-textarea {
|
|
@@ -788,7 +789,7 @@
|
|
|
788
789
|
color: transparent !important;
|
|
789
790
|
text-shadow: 0 0 0 #ffffff !important;
|
|
790
791
|
}
|
|
791
|
-
|
|
792
|
+
|
|
792
793
|
.prose, [id^="node-response-"]:not(.image-content):not(.video-content):not(.embed-content) {
|
|
793
794
|
padding-right: 14px !important;
|
|
794
795
|
}
|
|
@@ -809,8 +810,8 @@
|
|
|
809
810
|
overflow-wrap: inherit !important;
|
|
810
811
|
}
|
|
811
812
|
/* ▲▲▲ [NEW] ▲▲▲ */
|
|
812
|
-
|
|
813
|
-
/* ▼▼▼ [NEW] CSS3D 텍스트 앨리어싱 개선 ▼▼▼ */
|
|
813
|
+
|
|
814
|
+
/* ▼▼▼ [NEW] CSS3D 텍스트 앨리어싱 개선 ▼▼▼ */
|
|
814
815
|
.css3d-resolution-wrapper,
|
|
815
816
|
.css3d-dynamic-node,
|
|
816
817
|
[id^="css3d-node-"],
|
|
@@ -13458,7 +13459,7 @@
|
|
|
13458
13459
|
|
|
13459
13460
|
function getRemoteFleetDisplayTitle(value) {
|
|
13460
13461
|
const title = String(value ?? '').trim();
|
|
13461
|
-
if (!title || title === REMOTE_FLEET_LEGACY_DISPLAY_NAME) {
|
|
13462
|
+
if (!title || title === REMOTE_FLEET_LEGACY_DISPLAY_NAME || title === REMOTE_FLEET_LEGACY_DISPLAY_NAME_V0) {
|
|
13462
13463
|
return REMOTE_FLEET_DISPLAY_NAME;
|
|
13463
13464
|
}
|
|
13464
13465
|
return title;
|
|
@@ -13552,7 +13553,7 @@
|
|
|
13552
13553
|
|
|
13553
13554
|
const titleBlock = document.createElement('div');
|
|
13554
13555
|
titleBlock.className = 'template-card__title-block';
|
|
13555
|
-
titleBlock.appendChild(createTemplateCardText('div', 'template-card__eyebrow', 'Remote'));
|
|
13556
|
+
titleBlock.appendChild(createTemplateCardText('div', 'template-card__eyebrow', 'Remote Work'));
|
|
13556
13557
|
titleBlock.appendChild(createTemplateCardText('div', 'template-card__title', title));
|
|
13557
13558
|
header.appendChild(titleBlock);
|
|
13558
13559
|
shell.appendChild(header);
|
|
@@ -14605,7 +14606,7 @@
|
|
|
14605
14606
|
const REMOTE_FLEET_MONITOR_REFRESH_MS = 10000;
|
|
14606
14607
|
const REMOTE_FLEET_EMPTY_MONITOR_REFRESH_MS = 2500;
|
|
14607
14608
|
const REMOTE_FLEET_LIVE_REFRESH_MS = 30000;
|
|
14608
|
-
const REMOTE_FLEET_MONITOR_LIVE_FPS =
|
|
14609
|
+
const REMOTE_FLEET_MONITOR_LIVE_FPS = 2;
|
|
14609
14610
|
const REMOTE_FLEET_LIVE_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_MONITOR_LIVE_FPS);
|
|
14610
14611
|
const REMOTE_FLEET_CONTROL_LIVE_FPS = 30;
|
|
14611
14612
|
const REMOTE_FLEET_CONTROL_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_CONTROL_LIVE_FPS);
|
|
@@ -15690,12 +15691,13 @@
|
|
|
15690
15691
|
}
|
|
15691
15692
|
session.bodies.add(bodyView);
|
|
15692
15693
|
session.getDeviceIds = getDeviceIds;
|
|
15693
|
-
|
|
15694
|
+
const fps = Math.max(1, Math.min(30, Number(options.fps || REMOTE_FLEET_MONITOR_LIVE_FPS) || REMOTE_FLEET_MONITOR_LIVE_FPS));
|
|
15695
|
+
session.options = { fps, width: Number(options.width || 1920) || 1920, height: Number(options.height || 1080) || 1080, tileWidth: Number(options.tileWidth || 320) || 320, tileHeight: Number(options.tileHeight || 180) || 180 };
|
|
15694
15696
|
const fallback = () => {
|
|
15695
15697
|
if (session.fallbackStarted) return;
|
|
15696
15698
|
session.fallbackStarted = true;
|
|
15697
15699
|
try { session.ws?.close?.(); } catch { /* encoder failure fallback */ }
|
|
15698
|
-
session.bodies.forEach(body => startRemoteFleetBinaryFrameSocket(body, session.getDeviceIds, { autoStartLive: true, fps:
|
|
15700
|
+
session.bodies.forEach(body => startRemoteFleetBinaryFrameSocket(body, session.getDeviceIds, { autoStartLive: true, fps: session.options.fps, maxWidth: 960, maxHeight: 540, quality: 60, mode: 'mode2-lzo', streamPurpose: 'wall' }));
|
|
15699
15701
|
window.RuntimeTrace?.emit?.('remote.atlas.fallback', { nodeId: session.nodeId, mode: 'mode2-lzo' });
|
|
15700
15702
|
};
|
|
15701
15703
|
session.fallback = fallback;
|
|
@@ -15709,7 +15711,7 @@
|
|
|
15709
15711
|
ws.binaryType = 'arraybuffer';
|
|
15710
15712
|
ws.onopen = () => {
|
|
15711
15713
|
session.wsOpening = false;
|
|
15712
|
-
ws.send(JSON.stringify({ type: 'configure', deviceIds: getRemoteFleetBinaryFrameDeviceIds(session), fps:
|
|
15714
|
+
ws.send(JSON.stringify({ type: 'configure', deviceIds: getRemoteFleetBinaryFrameDeviceIds(session), fps: session.options.fps, width: session.options.width, height: session.options.height, tileWidth: session.options.tileWidth, tileHeight: session.options.tileHeight }));
|
|
15713
15715
|
window.RuntimeTrace?.emit?.('remote.atlas.wsOpen', { nodeId: session.nodeId });
|
|
15714
15716
|
};
|
|
15715
15717
|
ws.onmessage = event => {
|
|
@@ -17273,16 +17275,6 @@
|
|
|
17273
17275
|
}
|
|
17274
17276
|
|
|
17275
17277
|
binarySession.controlSessions.add(controlSession);
|
|
17276
|
-
binarySession.liveOptions = {
|
|
17277
|
-
...(binarySession.liveOptions || {}),
|
|
17278
|
-
autoStartLive: true,
|
|
17279
|
-
fps: REMOTE_FLEET_CONTROL_LIVE_FPS,
|
|
17280
|
-
maxWidth: 1280,
|
|
17281
|
-
maxHeight: 720,
|
|
17282
|
-
quality: 65,
|
|
17283
|
-
mode: 'mode3-h264-hw',
|
|
17284
|
-
streamPurpose: 'control'
|
|
17285
|
-
};
|
|
17286
17278
|
controlSession.binaryFrameSession = binarySession;
|
|
17287
17279
|
controlSession.binaryFramePreferred = true;
|
|
17288
17280
|
refreshRemoteFleetBinaryFrameSubscription(binarySession, true);
|
|
@@ -17368,7 +17360,7 @@
|
|
|
17368
17360
|
session.canvas.dataset.remoteFleetFrameSeq = String(frameSeq || 0);
|
|
17369
17361
|
session.canvas.style.display = 'block';
|
|
17370
17362
|
session.lastControlFrameAt = Date.now();
|
|
17371
|
-
session.status.textContent =
|
|
17363
|
+
session.status.textContent = `${session.statusLabel || 'Control'} ${Number(session.fps || REMOTE_FLEET_CONTROL_LIVE_FPS)}fps`;
|
|
17372
17364
|
session.placeholder?.remove?.();
|
|
17373
17365
|
session.placeholder = null;
|
|
17374
17366
|
}
|
|
@@ -17403,7 +17395,7 @@
|
|
|
17403
17395
|
session.canvas.dataset.remoteFleetFrameUrl = String(frame.frameUrl || '');
|
|
17404
17396
|
session.canvas.style.display = 'block';
|
|
17405
17397
|
session.lastControlFrameAt = Date.now();
|
|
17406
|
-
session.status.textContent =
|
|
17398
|
+
session.status.textContent = `${session.statusLabel || 'Control'} ${Number(session.fps || REMOTE_FLEET_CONTROL_LIVE_FPS)}fps`;
|
|
17407
17399
|
session.placeholder?.remove?.();
|
|
17408
17400
|
session.placeholder = null;
|
|
17409
17401
|
if (typeof bitmap.close === 'function') {
|
|
@@ -18152,7 +18144,9 @@
|
|
|
18152
18144
|
wasLiveActive: false,
|
|
18153
18145
|
startedStream: false,
|
|
18154
18146
|
streamId: '',
|
|
18155
|
-
controlLeaseId: `
|
|
18147
|
+
controlLeaseId: `observe-node-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
18148
|
+
statusLabel: 'Observe',
|
|
18149
|
+
fps: REMOTE_FLEET_MONITOR_LIVE_FPS,
|
|
18156
18150
|
timer: null,
|
|
18157
18151
|
moveTimer: null,
|
|
18158
18152
|
pendingMove: null,
|
|
@@ -18170,25 +18164,21 @@
|
|
|
18170
18164
|
};
|
|
18171
18165
|
|
|
18172
18166
|
bodyView._remoteFleetControlNodeSession = session;
|
|
18173
|
-
bindRemoteFleetControlInput(session, {
|
|
18174
|
-
captureOverlayEvents: false,
|
|
18175
|
-
windowKeyboardCapture: false
|
|
18176
|
-
});
|
|
18177
|
-
ensureRemoteFleetControlInputSocket(session);
|
|
18178
18167
|
startRemoteFleetBinaryFrameSocket(bodyView, () => [normalizedDeviceId], {
|
|
18179
18168
|
autoStartLive: true,
|
|
18180
|
-
fps:
|
|
18181
|
-
maxWidth:
|
|
18182
|
-
maxHeight:
|
|
18183
|
-
quality:
|
|
18184
|
-
mode: '
|
|
18169
|
+
fps: REMOTE_FLEET_MONITOR_LIVE_FPS,
|
|
18170
|
+
maxWidth: 960,
|
|
18171
|
+
maxHeight: 540,
|
|
18172
|
+
quality: 60,
|
|
18173
|
+
mode: 'mode2-lzo',
|
|
18174
|
+
streamPurpose: 'wall'
|
|
18185
18175
|
});
|
|
18186
18176
|
attachRemoteFleetControlBinaryFrameSession(session, bodyView);
|
|
18187
18177
|
stage.focus?.({ preventScroll: true });
|
|
18188
18178
|
if (status) {
|
|
18189
|
-
status.textContent = `
|
|
18179
|
+
status.textContent = `Observe ${REMOTE_FLEET_MONITOR_LIVE_FPS}fps`;
|
|
18190
18180
|
}
|
|
18191
|
-
window.RuntimeTrace?.emit?.('remote.
|
|
18181
|
+
window.RuntimeTrace?.emit?.('remote.observe.nodeOpened', {
|
|
18192
18182
|
nodeId: normalizedNodeId,
|
|
18193
18183
|
deviceId: normalizedDeviceId
|
|
18194
18184
|
});
|
|
@@ -18440,7 +18430,7 @@
|
|
|
18440
18430
|
|
|
18441
18431
|
if (!device || !deviceId) {
|
|
18442
18432
|
const empty = document.createElement('div');
|
|
18443
|
-
empty.textContent = lastError || 'Remote
|
|
18433
|
+
empty.textContent = lastError || 'Remote workstation snapshot is unavailable.';
|
|
18444
18434
|
empty.style.cssText = `
|
|
18445
18435
|
flex: 1 1 auto;
|
|
18446
18436
|
display: flex;
|
|
@@ -18456,7 +18446,7 @@
|
|
|
18456
18446
|
text-align: center;
|
|
18457
18447
|
background: rgba(255, 255, 255, 0.74);
|
|
18458
18448
|
`;
|
|
18459
|
-
const refreshButton = createRemoteFleetButton('Refresh', 'Refresh this remote
|
|
18449
|
+
const refreshButton = createRemoteFleetButton('Refresh', 'Refresh this remote workstation', 'refresh-device');
|
|
18460
18450
|
refreshButton.style.height = '32px';
|
|
18461
18451
|
refreshButton.addEventListener('click', async event => {
|
|
18462
18452
|
event.preventDefault();
|
|
@@ -18579,7 +18569,7 @@
|
|
|
18579
18569
|
controlStage.dataset.remoteFleetControlNodeStage = 'true';
|
|
18580
18570
|
controlStage.dataset.deviceId = deviceId;
|
|
18581
18571
|
controlStage.tabIndex = 0;
|
|
18582
|
-
controlStage.title = `${name} remote
|
|
18572
|
+
controlStage.title = `${name} observation and remote work`;
|
|
18583
18573
|
controlStage.style.cssText = `
|
|
18584
18574
|
position: relative;
|
|
18585
18575
|
flex: 1 1 auto;
|
|
@@ -18589,7 +18579,7 @@
|
|
|
18589
18579
|
border-radius: 0;
|
|
18590
18580
|
background: #020617;
|
|
18591
18581
|
border: 1px solid rgba(15, 23, 42, 0.20);
|
|
18592
|
-
cursor:
|
|
18582
|
+
cursor: default;
|
|
18593
18583
|
touch-action: none;
|
|
18594
18584
|
outline: none;
|
|
18595
18585
|
`;
|
|
@@ -18637,7 +18627,7 @@
|
|
|
18637
18627
|
`;
|
|
18638
18628
|
const controlPlaceholder = document.createElement('div');
|
|
18639
18629
|
controlPlaceholder.dataset.remoteFleetControlNodePlaceholder = 'true';
|
|
18640
|
-
controlPlaceholder.textContent = connected ? 'Waiting for
|
|
18630
|
+
controlPlaceholder.textContent = connected ? 'Waiting for observation frame' : 'Offline';
|
|
18641
18631
|
controlPlaceholder.style.cssText = `
|
|
18642
18632
|
position: absolute;
|
|
18643
18633
|
inset: 0;
|
|
@@ -18672,7 +18662,7 @@
|
|
|
18672
18662
|
if (session && restoredControlSurface) {
|
|
18673
18663
|
session.lastControlFrameSeq = Number(preservedControlSurface?.seq || session.lastControlFrameSeq || 0) || 0;
|
|
18674
18664
|
session.lastControlFrameAt = Date.now();
|
|
18675
|
-
controlStatus.textContent = `
|
|
18665
|
+
controlStatus.textContent = `Observe ${REMOTE_FLEET_MONITOR_LIVE_FPS}fps`;
|
|
18676
18666
|
window.RuntimeTrace?.emit?.('remote.control.surfaceRestored', {
|
|
18677
18667
|
nodeId,
|
|
18678
18668
|
deviceId,
|
|
@@ -18692,7 +18682,7 @@
|
|
|
18692
18682
|
}
|
|
18693
18683
|
}
|
|
18694
18684
|
|
|
18695
|
-
const refreshButton = createRemoteFleetButton('Refresh', 'Refresh this remote
|
|
18685
|
+
const refreshButton = createRemoteFleetButton('Refresh', 'Refresh this remote workstation', 'refresh-device');
|
|
18696
18686
|
refreshButton.style.height = '26px';
|
|
18697
18687
|
actions.appendChild(refreshButton);
|
|
18698
18688
|
if (connected && thumbnailEnabled) {
|
|
@@ -18733,8 +18723,8 @@
|
|
|
18733
18723
|
right: 8px;
|
|
18734
18724
|
top: 42px;
|
|
18735
18725
|
z-index: 6;
|
|
18736
|
-
width: min(
|
|
18737
|
-
display:
|
|
18726
|
+
width: min(520px, calc(100% - 16px));
|
|
18727
|
+
display: grid;
|
|
18738
18728
|
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
18739
18729
|
gap: 6px;
|
|
18740
18730
|
align-items: stretch;
|
|
@@ -18995,7 +18985,7 @@
|
|
|
18995
18985
|
const recentTaskBatches = parseRemoteFleetRecentTaskBatches(nodeModel);
|
|
18996
18986
|
const latestTaskBatchKey = getRemoteFleetTaskBatchKey(latestTaskBatch);
|
|
18997
18987
|
const latestTaskBatchActive = isRemoteFleetTaskBatchActive(latestTaskBatch);
|
|
18998
|
-
const showTaskSummarySurfaces =
|
|
18988
|
+
const showTaskSummarySurfaces = true;
|
|
18999
18989
|
if (latestTaskBatchKey && bodyView.dataset.remoteFleetTaskFollowKey !== latestTaskBatchKey) {
|
|
19000
18990
|
bodyView.dataset.remoteFleetTaskFollowKey = latestTaskBatchKey;
|
|
19001
18991
|
bodyView.dataset.remoteFleetTaskFollowTicks = '0';
|
|
@@ -19147,7 +19137,7 @@
|
|
|
19147
19137
|
const searchInput = document.createElement('input');
|
|
19148
19138
|
searchInput.type = 'search';
|
|
19149
19139
|
searchInput.value = searchState;
|
|
19150
|
-
searchInput.placeholder = '';
|
|
19140
|
+
searchInput.placeholder = 'Find a computer or task';
|
|
19151
19141
|
searchInput.dataset.remoteFleetSearch = 'true';
|
|
19152
19142
|
searchInput.autocomplete = 'off';
|
|
19153
19143
|
searchInput.spellcheck = false;
|
|
@@ -19220,11 +19210,11 @@
|
|
|
19220
19210
|
filterRow.appendChild(groupSelect);
|
|
19221
19211
|
filterRow.appendChild(densitySelect);
|
|
19222
19212
|
filterRow.appendChild(matchCount);
|
|
19223
|
-
filterRow.dataset.remoteFleetAdvancedFilters = '
|
|
19213
|
+
filterRow.dataset.remoteFleetAdvancedFilters = 'visible';
|
|
19224
19214
|
|
|
19225
19215
|
const taskRow = document.createElement('div');
|
|
19226
19216
|
taskRow.style.cssText = `
|
|
19227
|
-
display:
|
|
19217
|
+
display: grid;
|
|
19228
19218
|
grid-template-columns: minmax(0, 1fr) auto auto auto;
|
|
19229
19219
|
gap: 8px;
|
|
19230
19220
|
align-items: stretch;
|
|
@@ -19232,7 +19222,7 @@
|
|
|
19232
19222
|
`;
|
|
19233
19223
|
const taskInput = document.createElement('textarea');
|
|
19234
19224
|
taskInput.dataset.remoteFleetTaskInput = 'true';
|
|
19235
|
-
taskInput.placeholder = '';
|
|
19225
|
+
taskInput.placeholder = 'Describe the work: inspect Git, run tests, build, deploy, or summarize results';
|
|
19236
19226
|
taskInput.rows = 2;
|
|
19237
19227
|
taskInput.style.cssText = `
|
|
19238
19228
|
width: 100%;
|
|
@@ -19294,7 +19284,7 @@
|
|
|
19294
19284
|
taskRow.appendChild(aiToggleLabel);
|
|
19295
19285
|
taskRow.appendChild(sendVisibleButton);
|
|
19296
19286
|
taskRow.appendChild(sendConnectedButton);
|
|
19297
|
-
taskRow.dataset.remoteFleetTaskComposer = '
|
|
19287
|
+
taskRow.dataset.remoteFleetTaskComposer = 'visible';
|
|
19298
19288
|
|
|
19299
19289
|
const taskFeedback = document.createElement('div');
|
|
19300
19290
|
taskFeedback.dataset.remoteFleetTaskFeedback = 'true';
|
|
@@ -19313,6 +19303,8 @@
|
|
|
19313
19303
|
text-overflow: ellipsis;
|
|
19314
19304
|
white-space: nowrap;
|
|
19315
19305
|
`;
|
|
19306
|
+
bodyView.appendChild(filterRow);
|
|
19307
|
+
bodyView.appendChild(taskRow);
|
|
19316
19308
|
bodyView.appendChild(taskFeedback);
|
|
19317
19309
|
|
|
19318
19310
|
if (showTaskSummarySurfaces && latestTaskBatch) {
|
|
@@ -19670,7 +19662,7 @@
|
|
|
19670
19662
|
card.dataset.remoteFleetAction = 'select-device';
|
|
19671
19663
|
card.setAttribute('role', 'button');
|
|
19672
19664
|
card.setAttribute('aria-pressed', isSelected ? 'true' : 'false');
|
|
19673
|
-
card.setAttribute('aria-label', `Open remote
|
|
19665
|
+
card.setAttribute('aria-label', `Open remote workstation for ${name}`);
|
|
19674
19666
|
card.tabIndex = 0;
|
|
19675
19667
|
card.title = getRemoteFleetDeviceTooltip(device);
|
|
19676
19668
|
card.style.cssText = `
|
|
@@ -20188,11 +20180,11 @@
|
|
|
20188
20180
|
}
|
|
20189
20181
|
setTaskFeedback('');
|
|
20190
20182
|
} else {
|
|
20191
|
-
setTaskFeedback(result?.error || result?.Error || 'Remote
|
|
20183
|
+
setTaskFeedback(result?.error || result?.Error || 'Remote workstation node failed.', 'error');
|
|
20192
20184
|
}
|
|
20193
20185
|
})
|
|
20194
20186
|
.catch(error => {
|
|
20195
|
-
setTaskFeedback(error?.message || 'Remote
|
|
20187
|
+
setTaskFeedback(error?.message || 'Remote workstation node failed.', 'error');
|
|
20196
20188
|
})
|
|
20197
20189
|
.finally(() => {
|
|
20198
20190
|
delete card.dataset.remoteFleetOpeningControlNode;
|
|
@@ -21112,7 +21104,7 @@
|
|
|
21112
21104
|
* ▼▼▼ [New] text/markdown 노드를 위한 동적 DOM 요소 생성 ▼▼▼
|
|
21113
21105
|
* Blazor 템플릿이 없는 노드 타입을 위해 JS에서 직접 DOM 생성
|
|
21114
21106
|
*/
|
|
21115
|
-
// Expose helper to create markdown content consistently
|
|
21107
|
+
// Expose helper to create markdown content consistently
|
|
21116
21108
|
function createMarkdownContent(content, isCodeNode = false) {
|
|
21117
21109
|
const wrapper = document.createElement('div');
|
|
21118
21110
|
const normalizedContent = typeof content === 'string' ? content : String(content || '');
|
|
@@ -21169,22 +21161,22 @@
|
|
|
21169
21161
|
contentEl.textContent = nextText;
|
|
21170
21162
|
}
|
|
21171
21163
|
}
|
|
21172
|
-
|
|
21173
|
-
function getCachedMarkdownHtml(nodeModel, content) {
|
|
21174
|
-
if (!nodeModel) return null;
|
|
21175
|
-
if (nodeModel._cachedMarkdownSource === content && nodeModel._cachedMarkdownHtml) {
|
|
21176
|
-
return nodeModel._cachedMarkdownHtml;
|
|
21177
|
-
}
|
|
21178
|
-
return null;
|
|
21179
|
-
}
|
|
21180
|
-
|
|
21181
|
-
function setCachedMarkdownHtml(nodeModel, content, html) {
|
|
21182
|
-
if (!nodeModel) return;
|
|
21183
|
-
nodeModel._cachedMarkdownSource = content;
|
|
21184
|
-
nodeModel._cachedMarkdownHtml = html;
|
|
21185
|
-
}
|
|
21186
|
-
|
|
21187
|
-
// HTML 이스케이프 헬퍼 - kept for compatibility
|
|
21164
|
+
|
|
21165
|
+
function getCachedMarkdownHtml(nodeModel, content) {
|
|
21166
|
+
if (!nodeModel) return null;
|
|
21167
|
+
if (nodeModel._cachedMarkdownSource === content && nodeModel._cachedMarkdownHtml) {
|
|
21168
|
+
return nodeModel._cachedMarkdownHtml;
|
|
21169
|
+
}
|
|
21170
|
+
return null;
|
|
21171
|
+
}
|
|
21172
|
+
|
|
21173
|
+
function setCachedMarkdownHtml(nodeModel, content, html) {
|
|
21174
|
+
if (!nodeModel) return;
|
|
21175
|
+
nodeModel._cachedMarkdownSource = content;
|
|
21176
|
+
nodeModel._cachedMarkdownHtml = html;
|
|
21177
|
+
}
|
|
21178
|
+
|
|
21179
|
+
// HTML 이스케이프 헬퍼 - kept for compatibility
|
|
21188
21180
|
function escapeHtml(text) {
|
|
21189
21181
|
const div = document.createElement('div');
|
|
21190
21182
|
div.textContent = text;
|
|
@@ -23193,7 +23185,7 @@
|
|
|
23193
23185
|
ensurePromptCopyDelegation();
|
|
23194
23186
|
|
|
23195
23187
|
// ... (logging)
|
|
23196
|
-
|
|
23188
|
+
|
|
23197
23189
|
// 컨테이너 생성
|
|
23198
23190
|
const container = document.createElement('div');
|
|
23199
23191
|
container.id = `node-${nodeModel.id}`;
|
|
@@ -23217,7 +23209,7 @@
|
|
|
23217
23209
|
color: #1f2937;
|
|
23218
23210
|
box-shadow: none;
|
|
23219
23211
|
`;
|
|
23220
|
-
|
|
23212
|
+
|
|
23221
23213
|
// 콘텐츠 래퍼 생성
|
|
23222
23214
|
const contentWrapper = document.createElement('div');
|
|
23223
23215
|
contentWrapper.className = isCsvTableNode
|
|
@@ -23316,12 +23308,12 @@
|
|
|
23316
23308
|
// 응답 영역 생성
|
|
23317
23309
|
const responseDiv = document.createElement('div');
|
|
23318
23310
|
responseDiv.id = `node-response-${nodeModel.id}`;
|
|
23319
|
-
|
|
23320
|
-
// [FIX] 'note' type should also render markdown
|
|
23311
|
+
|
|
23312
|
+
// [FIX] 'note' type should also render markdown
|
|
23321
23313
|
const isCodeNode = contentTypeLower === 'code';
|
|
23322
23314
|
// Variable isNoteNode declared above
|
|
23323
23315
|
const isMarkdownType = ['text', 'markdown'].includes(contentTypeLower); // Removed 'note'
|
|
23324
|
-
|
|
23316
|
+
|
|
23325
23317
|
if (isCsvTableNode) {
|
|
23326
23318
|
responseDiv.className = 'node-response csv-table-scroll';
|
|
23327
23319
|
responseDiv.style.cssText = `
|
|
@@ -23387,44 +23379,44 @@
|
|
|
23387
23379
|
padding-right: 14px;
|
|
23388
23380
|
box-sizing: border-box;
|
|
23389
23381
|
`;
|
|
23390
|
-
|
|
23391
|
-
// 1. Save Metadata
|
|
23392
|
-
responseDiv.dataset.src = content;
|
|
23393
|
-
responseDiv.dataset.nodeId = nodeModel.id;
|
|
23394
|
-
|
|
23395
|
-
// 2. Render Markdown or Text
|
|
23396
|
-
const cachedHtml = getCachedMarkdownHtml(nodeModel, content);
|
|
23397
|
-
if (cachedHtml) {
|
|
23398
|
-
responseDiv.innerHTML = cachedHtml;
|
|
23399
|
-
} else if (typeof marked !== 'undefined' && content) {
|
|
23400
|
-
const options = { breaks: true, gfm: true };
|
|
23401
|
-
try {
|
|
23402
|
-
if (typeof marked.parse === 'function') {
|
|
23403
|
-
responseDiv.innerHTML = marked.parse(content, options);
|
|
23404
|
-
} else if (typeof marked === 'function') {
|
|
23405
|
-
responseDiv.innerHTML = marked(content, options);
|
|
23406
|
-
} else {
|
|
23407
|
-
responseDiv.innerText = content;
|
|
23408
|
-
}
|
|
23409
|
-
setCachedMarkdownHtml(nodeModel, content, responseDiv.innerHTML);
|
|
23410
|
-
} catch {
|
|
23411
|
-
responseDiv.innerText = content;
|
|
23412
|
-
}
|
|
23413
|
-
} else {
|
|
23414
|
-
responseDiv.innerText = content;
|
|
23415
|
-
}
|
|
23416
|
-
|
|
23417
|
-
// 3. (Removed) Click Event Listener
|
|
23418
|
-
// Centralized interaction logic in mind-map-interactions.js handles selection and editing.
|
|
23419
|
-
// Also pointer-events are none by default, so this wouldn't fire.
|
|
23420
|
-
|
|
23421
|
-
// Prevent drag interference (optional, but harmless)
|
|
23422
|
-
responseDiv.ondragstart = (e) => {
|
|
23423
|
-
if (e.target.tagName !== 'A' && !e.target.closest('a')) {
|
|
23424
|
-
e.preventDefault();
|
|
23425
|
-
}
|
|
23426
|
-
};
|
|
23427
|
-
|
|
23382
|
+
|
|
23383
|
+
// 1. Save Metadata
|
|
23384
|
+
responseDiv.dataset.src = content;
|
|
23385
|
+
responseDiv.dataset.nodeId = nodeModel.id;
|
|
23386
|
+
|
|
23387
|
+
// 2. Render Markdown or Text
|
|
23388
|
+
const cachedHtml = getCachedMarkdownHtml(nodeModel, content);
|
|
23389
|
+
if (cachedHtml) {
|
|
23390
|
+
responseDiv.innerHTML = cachedHtml;
|
|
23391
|
+
} else if (typeof marked !== 'undefined' && content) {
|
|
23392
|
+
const options = { breaks: true, gfm: true };
|
|
23393
|
+
try {
|
|
23394
|
+
if (typeof marked.parse === 'function') {
|
|
23395
|
+
responseDiv.innerHTML = marked.parse(content, options);
|
|
23396
|
+
} else if (typeof marked === 'function') {
|
|
23397
|
+
responseDiv.innerHTML = marked(content, options);
|
|
23398
|
+
} else {
|
|
23399
|
+
responseDiv.innerText = content;
|
|
23400
|
+
}
|
|
23401
|
+
setCachedMarkdownHtml(nodeModel, content, responseDiv.innerHTML);
|
|
23402
|
+
} catch {
|
|
23403
|
+
responseDiv.innerText = content;
|
|
23404
|
+
}
|
|
23405
|
+
} else {
|
|
23406
|
+
responseDiv.innerText = content;
|
|
23407
|
+
}
|
|
23408
|
+
|
|
23409
|
+
// 3. (Removed) Click Event Listener
|
|
23410
|
+
// Centralized interaction logic in mind-map-interactions.js handles selection and editing.
|
|
23411
|
+
// Also pointer-events are none by default, so this wouldn't fire.
|
|
23412
|
+
|
|
23413
|
+
// Prevent drag interference (optional, but harmless)
|
|
23414
|
+
responseDiv.ondragstart = (e) => {
|
|
23415
|
+
if (e.target.tagName !== 'A' && !e.target.closest('a')) {
|
|
23416
|
+
e.preventDefault();
|
|
23417
|
+
}
|
|
23418
|
+
};
|
|
23419
|
+
|
|
23428
23420
|
} else if (isMarkdownType) {
|
|
23429
23421
|
responseDiv.className = 'node-response markdown-body mind-map-text-scrollable-view';
|
|
23430
23422
|
// ▼▼▼ [FIX] 텍스트 선택을 위한 스타일 설정 ▼▼▼
|
|
@@ -23442,15 +23434,15 @@
|
|
|
23442
23434
|
user-select: text;
|
|
23443
23435
|
-webkit-user-select: text;
|
|
23444
23436
|
`;
|
|
23445
|
-
// ▲▲▲ [FIX] ▲▲▲
|
|
23446
|
-
const cachedHtml = getCachedMarkdownHtml(nodeModel, content);
|
|
23447
|
-
if (cachedHtml) {
|
|
23448
|
-
responseDiv.innerHTML = cachedHtml;
|
|
23449
|
-
} else {
|
|
23450
|
-
const html = createMarkdownContent(content);
|
|
23451
|
-
responseDiv.innerHTML = html;
|
|
23452
|
-
setCachedMarkdownHtml(nodeModel, content, html);
|
|
23453
|
-
}
|
|
23437
|
+
// ▲▲▲ [FIX] ▲▲▲
|
|
23438
|
+
const cachedHtml = getCachedMarkdownHtml(nodeModel, content);
|
|
23439
|
+
if (cachedHtml) {
|
|
23440
|
+
responseDiv.innerHTML = cachedHtml;
|
|
23441
|
+
} else {
|
|
23442
|
+
const html = createMarkdownContent(content);
|
|
23443
|
+
responseDiv.innerHTML = html;
|
|
23444
|
+
setCachedMarkdownHtml(nodeModel, content, html);
|
|
23445
|
+
}
|
|
23454
23446
|
} else if (contentTypeLower === 'image') {
|
|
23455
23447
|
responseDiv.className = 'node-response image-content';
|
|
23456
23448
|
responseDiv.style.cssText = `width: 100%; height: 100%; display: ${hasContent ? 'block' : 'none'}; position: relative; overflow: hidden; pointer-events: none; padding: 0 !important; margin: 0 !important; background: transparent; border: 0 !important; scrollbar-width: none;`;
|
|
@@ -23534,15 +23526,15 @@
|
|
|
23534
23526
|
|
|
23535
23527
|
return container;
|
|
23536
23528
|
}
|
|
23537
|
-
|
|
23538
|
-
// HTML 이스케이프 헬퍼
|
|
23539
|
-
function escapeHtml(text) {
|
|
23540
|
-
const div = document.createElement('div');
|
|
23541
|
-
div.textContent = text;
|
|
23542
|
-
return div.innerHTML;
|
|
23543
|
-
}
|
|
23544
|
-
// ▲▲▲ [New] ▲▲▲
|
|
23545
|
-
|
|
23529
|
+
|
|
23530
|
+
// HTML 이스케이프 헬퍼
|
|
23531
|
+
function escapeHtml(text) {
|
|
23532
|
+
const div = document.createElement('div');
|
|
23533
|
+
div.textContent = text;
|
|
23534
|
+
return div.innerHTML;
|
|
23535
|
+
}
|
|
23536
|
+
// ▲▲▲ [New] ▲▲▲
|
|
23537
|
+
|
|
23546
23538
|
function getNodeViewContentInfo(nodeModel) {
|
|
23547
23539
|
const contentTypeLower = String(nodeModel?.contentType ?? nodeModel?.ContentType ?? '').toLowerCase();
|
|
23548
23540
|
const remoteFleetMonitor = isRemoteFleetMonitorNode(nodeModel);
|
|
@@ -23800,7 +23792,7 @@
|
|
|
23800
23792
|
console.error('[MindMapCss3DManager] CSS3DObject not available');
|
|
23801
23793
|
return null;
|
|
23802
23794
|
}
|
|
23803
|
-
|
|
23795
|
+
|
|
23804
23796
|
const resolvedNodeId = getNodeId(nodeModel);
|
|
23805
23797
|
const templateId = `node-${resolvedNodeId}`;
|
|
23806
23798
|
let templateElement = document.getElementById(templateId);
|
|
@@ -23822,60 +23814,60 @@
|
|
|
23822
23814
|
|| contentTypeLower === 'embed') {
|
|
23823
23815
|
templateElement = null;
|
|
23824
23816
|
}
|
|
23825
|
-
|
|
23826
|
-
let isDynamicallyCreated = false;
|
|
23827
|
-
// text/markdown 타입은 Blazor 템플릿이 없으므로 동적 생성
|
|
23828
|
-
if (!templateElement) {
|
|
23829
|
-
// text/markdown type has no Blazor template, so create dynamically.
|
|
23830
|
-
// [FIX] 'note' type also falls back to dynamic creation if not found (or if we force dynamic for consistent MD)
|
|
23831
|
-
// But usually 'note' comes from Razor. If missing, we create it.
|
|
23817
|
+
|
|
23818
|
+
let isDynamicallyCreated = false;
|
|
23819
|
+
// text/markdown 타입은 Blazor 템플릿이 없으므로 동적 생성
|
|
23820
|
+
if (!templateElement) {
|
|
23821
|
+
// text/markdown type has no Blazor template, so create dynamically.
|
|
23822
|
+
// [FIX] 'note' type also falls back to dynamic creation if not found (or if we force dynamic for consistent MD)
|
|
23823
|
+
// But usually 'note' comes from Razor. If missing, we create it.
|
|
23832
23824
|
const dynamicTypes = ['text', 'markdown', 'code', 'note', 'memo', CSV_TABLE_CONTENT_TYPE, 'templatelauncher', 'image', 'video', 'embed'];
|
|
23833
23825
|
|
|
23834
23826
|
if (remoteFleetMonitor || dynamicTypes.includes(contentTypeLower)) {
|
|
23835
23827
|
log(`[MindMapCss3DManager] Deferring dynamic DOM element for ${visualContentTypeLower || contentTypeLower} node ${resolvedNodeId} to shared NodeView`);
|
|
23836
23828
|
templateElement = document.createElement('div');
|
|
23837
23829
|
isDynamicallyCreated = true;
|
|
23838
|
-
} else {
|
|
23839
|
-
// 경고 로그 제한 (초기 로딩 시 템플릿이 아직 렌더링되지 않은 경우 스팸 방지)
|
|
23840
|
-
if (!window._templateWarningCount) window._templateWarningCount = 0;
|
|
23841
|
-
if (window._templateWarningCount < 5) {
|
|
23830
|
+
} else {
|
|
23831
|
+
// 경고 로그 제한 (초기 로딩 시 템플릿이 아직 렌더링되지 않은 경우 스팸 방지)
|
|
23832
|
+
if (!window._templateWarningCount) window._templateWarningCount = 0;
|
|
23833
|
+
if (window._templateWarningCount < 5) {
|
|
23842
23834
|
warn(`[MindMapCss3DManager] Template not found for node ${resolvedNodeId} (async templates pending). Template ID: ${templateId}`);
|
|
23843
|
-
window._templateWarningCount++;
|
|
23844
|
-
if (window._templateWarningCount === 5) {
|
|
23845
|
-
warn(`[MindMapCss3DManager] ... suppressing further template warnings. Templates will be available after async render.`);
|
|
23846
|
-
}
|
|
23847
|
-
}
|
|
23848
|
-
return null;
|
|
23849
|
-
}
|
|
23850
|
-
}
|
|
23851
|
-
// ▲▲▲ [New] ▲▲▲
|
|
23852
|
-
|
|
23835
|
+
window._templateWarningCount++;
|
|
23836
|
+
if (window._templateWarningCount === 5) {
|
|
23837
|
+
warn(`[MindMapCss3DManager] ... suppressing further template warnings. Templates will be available after async render.`);
|
|
23838
|
+
}
|
|
23839
|
+
}
|
|
23840
|
+
return null;
|
|
23841
|
+
}
|
|
23842
|
+
}
|
|
23843
|
+
// ▲▲▲ [New] ▲▲▲
|
|
23844
|
+
|
|
23853
23845
|
const existingCss3dId = `css3d-node-${resolvedNodeId}`;
|
|
23854
23846
|
const nodeEntry = module.nodeObjectsById.get(resolvedNodeId);
|
|
23855
|
-
|
|
23856
|
-
if (nodeEntry && nodeEntry.cssObject) {
|
|
23847
|
+
|
|
23848
|
+
if (nodeEntry && nodeEntry.cssObject) {
|
|
23857
23849
|
warn(`[MindMapCss3DManager] CSS3D object already exists in memory for node ${resolvedNodeId}. Returning existing object.`);
|
|
23858
|
-
return nodeEntry.cssObject;
|
|
23859
|
-
}
|
|
23860
|
-
|
|
23861
|
-
const existingCss3dElement = document.getElementById(existingCss3dId);
|
|
23862
|
-
if (existingCss3dElement) {
|
|
23863
|
-
warn(`[MindMapCss3DManager] Removing duplicate CSS3D element from DOM: ${existingCss3dId}`);
|
|
23864
|
-
if (existingCss3dElement.parentElement) {
|
|
23865
|
-
existingCss3dElement.parentElement.removeChild(existingCss3dElement);
|
|
23866
|
-
}
|
|
23867
|
-
}
|
|
23868
|
-
|
|
23869
|
-
// (It lives in a hidden div, so it is not visible.)
|
|
23870
|
-
/*
|
|
23871
|
-
const razorMapNode = document.querySelector(`#${templateId}`);
|
|
23872
|
-
if (razorMapNode && razorMapNode.parentElement) {
|
|
23873
|
-
console.warn(`[MindMapCss3DManager] Removing Razor-generated MapNode from DOM: ${templateId}`);
|
|
23874
|
-
razorMapNode.parentElement.removeChild(razorMapNode);
|
|
23875
|
-
}
|
|
23876
|
-
*/
|
|
23877
|
-
// ▲▲▲ [Critical fix] ▲▲▲
|
|
23878
|
-
|
|
23850
|
+
return nodeEntry.cssObject;
|
|
23851
|
+
}
|
|
23852
|
+
|
|
23853
|
+
const existingCss3dElement = document.getElementById(existingCss3dId);
|
|
23854
|
+
if (existingCss3dElement) {
|
|
23855
|
+
warn(`[MindMapCss3DManager] Removing duplicate CSS3D element from DOM: ${existingCss3dId}`);
|
|
23856
|
+
if (existingCss3dElement.parentElement) {
|
|
23857
|
+
existingCss3dElement.parentElement.removeChild(existingCss3dElement);
|
|
23858
|
+
}
|
|
23859
|
+
}
|
|
23860
|
+
|
|
23861
|
+
// (It lives in a hidden div, so it is not visible.)
|
|
23862
|
+
/*
|
|
23863
|
+
const razorMapNode = document.querySelector(`#${templateId}`);
|
|
23864
|
+
if (razorMapNode && razorMapNode.parentElement) {
|
|
23865
|
+
console.warn(`[MindMapCss3DManager] Removing Razor-generated MapNode from DOM: ${templateId}`);
|
|
23866
|
+
razorMapNode.parentElement.removeChild(razorMapNode);
|
|
23867
|
+
}
|
|
23868
|
+
*/
|
|
23869
|
+
// ▲▲▲ [Critical fix] ▲▲▲
|
|
23870
|
+
|
|
23879
23871
|
const nodeView = createNodeViewElement(module, nodeModel, {
|
|
23880
23872
|
hostKind: NODE_VIEW_HOST_CSS3D,
|
|
23881
23873
|
idPrefix: 'css3d-node'
|
|
@@ -23900,31 +23892,31 @@
|
|
|
23900
23892
|
}
|
|
23901
23893
|
clonedElement.style.display = '';
|
|
23902
23894
|
clonedElement.style.transformOrigin = '0% 0%';
|
|
23903
|
-
|
|
23904
|
-
// ▼▼▼ [Clarity] Scale factor for high-resolution rendering ▼▼▼
|
|
23895
|
+
|
|
23896
|
+
// ▼▼▼ [Clarity] Scale factor for high-resolution rendering ▼▼▼
|
|
23905
23897
|
const resolutionScale = nodeView.resolutionScale;
|
|
23906
23898
|
applyCss3dResolutionLayout(clonedElement, width, height, resolutionScale, {
|
|
23907
23899
|
resetLayoutTransform: true
|
|
23908
23900
|
});
|
|
23909
23901
|
clonedElement.style.borderRadius = '0px';
|
|
23910
|
-
|
|
23911
|
-
// to the inner element, the node shifts down-right.
|
|
23912
|
-
// Remove it so the element sits at the wrapper origin (0,0).
|
|
23913
|
-
clonedElement.style.position = 'absolute';
|
|
23914
|
-
clonedElement.style.left = '0px';
|
|
23915
|
-
clonedElement.style.top = '0px';
|
|
23916
|
-
// ▲▲▲ [Changed] ▲▲▲
|
|
23917
|
-
|
|
23902
|
+
|
|
23903
|
+
// to the inner element, the node shifts down-right.
|
|
23904
|
+
// Remove it so the element sits at the wrapper origin (0,0).
|
|
23905
|
+
clonedElement.style.position = 'absolute';
|
|
23906
|
+
clonedElement.style.left = '0px';
|
|
23907
|
+
clonedElement.style.top = '0px';
|
|
23908
|
+
// ▲▲▲ [Changed] ▲▲▲
|
|
23909
|
+
|
|
23918
23910
|
clonedElement.style.transition = 'none';
|
|
23919
23911
|
clonedElement.style.webkitTransition = 'none';
|
|
23920
|
-
|
|
23921
|
-
// ▼▼▼ [Perf] GPU acceleration for smooth zoom/pan ▼▼▼
|
|
23922
|
-
// 초기에는 꺼둠 (auto). 카메라 이동 시 mind-map-core.js가 setWillChange(true) 호출
|
|
23912
|
+
|
|
23913
|
+
// ▼▼▼ [Perf] GPU acceleration for smooth zoom/pan ▼▼▼
|
|
23914
|
+
// 초기에는 꺼둠 (auto). 카메라 이동 시 mind-map-core.js가 setWillChange(true) 호출
|
|
23923
23915
|
clonedElement.style.willChange = 'auto'; // 'transform';
|
|
23924
23916
|
clonedElement.style.backfaceVisibility = isMediaNode ? 'visible' : 'hidden';
|
|
23925
23917
|
clonedElement.style.webkitBackfaceVisibility = isMediaNode ? 'visible' : 'hidden';
|
|
23926
23918
|
// ▲▲▲ [Perf] ▲▲▲
|
|
23927
|
-
|
|
23919
|
+
|
|
23928
23920
|
const wrapper = document.createElement('div');
|
|
23929
23921
|
const wrapperTypeClass = `node-type-${visualContentTypeLower || 'unknown'}`;
|
|
23930
23922
|
wrapper.className = `css3d-resolution-wrapper lod-high ${wrapperTypeClass}`;
|
|
@@ -23937,10 +23929,10 @@
|
|
|
23937
23929
|
wrapper.dataset.nodeId = resolvedNodeId;
|
|
23938
23930
|
wrapper.style.transition = CSS3D_WRAPPER_TRANSITION;
|
|
23939
23931
|
wrapper.style.webkitTransition = CSS3D_WRAPPER_WEBKIT_TRANSITION;
|
|
23940
|
-
|
|
23941
|
-
wrapper.style.transformOrigin = '0 0';
|
|
23942
|
-
// ▲▲▲ [Critical fix] ▲▲▲
|
|
23943
|
-
|
|
23932
|
+
|
|
23933
|
+
wrapper.style.transformOrigin = '0 0';
|
|
23934
|
+
// ▲▲▲ [Critical fix] ▲▲▲
|
|
23935
|
+
|
|
23944
23936
|
// ▼▼▼ [Fix] 외부 스크롤바 방지 - 내부 콘텐츠 스크롤바만 표시 ▼▼▼
|
|
23945
23937
|
wrapper.style.overflow = allowsExternalNodeChrome ? 'visible' : 'hidden';
|
|
23946
23938
|
if (allowsExternalNodeChrome) {
|
|
@@ -23949,14 +23941,14 @@
|
|
|
23949
23941
|
wrapper.style.containIntrinsicSize = 'auto';
|
|
23950
23942
|
}
|
|
23951
23943
|
// ▲▲▲ [Fix] ▲▲▲
|
|
23952
|
-
|
|
23953
|
-
// ▼▼▼ [Perf] GPU acceleration for smooth zoom/pan ▼▼▼
|
|
23944
|
+
|
|
23945
|
+
// ▼▼▼ [Perf] GPU acceleration for smooth zoom/pan ▼▼▼
|
|
23954
23946
|
wrapper.style.willChange = 'auto'; // 'transform';
|
|
23955
23947
|
wrapper.style.backfaceVisibility = isMediaNode ? 'visible' : 'hidden';
|
|
23956
23948
|
wrapper.style.webkitBackfaceVisibility = isMediaNode ? 'visible' : 'hidden';
|
|
23957
23949
|
wrapper.style.transformStyle = isMediaNode ? 'flat' : '';
|
|
23958
23950
|
// ▲▲▲ [Perf] ▲▲▲
|
|
23959
|
-
|
|
23951
|
+
|
|
23960
23952
|
if (contentTypeLower === 'image' || contentTypeLower === 'video') {
|
|
23961
23953
|
wrapper.style.pointerEvents = 'auto'; // [Fix] Changed from none to auto for resize handle detection
|
|
23962
23954
|
clonedElement.style.pointerEvents = 'none';
|
|
@@ -24033,10 +24025,10 @@
|
|
|
24033
24025
|
}
|
|
24034
24026
|
|
|
24035
24027
|
// ... (event listeners) ...
|
|
24036
|
-
|
|
24037
|
-
const css3dObj = new CSS3DObjectCtor(wrapper);
|
|
24038
|
-
css3dObj.scale.set(1 / resolutionScale, 1 / resolutionScale, 1 / resolutionScale);
|
|
24039
|
-
css3dObj.visible = false;
|
|
24028
|
+
|
|
24029
|
+
const css3dObj = new CSS3DObjectCtor(wrapper);
|
|
24030
|
+
css3dObj.scale.set(1 / resolutionScale, 1 / resolutionScale, 1 / resolutionScale);
|
|
24031
|
+
css3dObj.visible = false;
|
|
24040
24032
|
css3dObj.userData.nodeId = resolvedNodeId;
|
|
24041
24033
|
css3dObj.userData.worldWidth = width;
|
|
24042
24034
|
css3dObj.userData.worldHeight = height;
|
|
@@ -24046,10 +24038,10 @@
|
|
|
24046
24038
|
}
|
|
24047
24039
|
|
|
24048
24040
|
// ▼▼▼ [Fix] nodeModel의 위치 정보를 사용하여 초기 위치 설정 ▼▼▼
|
|
24049
|
-
// 호출자가 위치를 따로 설정하지 않아도 올바른 위치에 생성됩니다.
|
|
24050
|
-
// Z 오프셋 0: 그리드(Z=0)와 동일한 평면에 배치하여 원근/시차 완전 제거
|
|
24051
|
-
const posX = nodeModel.positionX ?? nodeModel.PositionX ?? 0;
|
|
24052
|
-
const posY = nodeModel.positionY ?? nodeModel.PositionY ?? 0;
|
|
24041
|
+
// 호출자가 위치를 따로 설정하지 않아도 올바른 위치에 생성됩니다.
|
|
24042
|
+
// Z 오프셋 0: 그리드(Z=0)와 동일한 평면에 배치하여 원근/시차 완전 제거
|
|
24043
|
+
const posX = nodeModel.positionX ?? nodeModel.PositionX ?? 0;
|
|
24044
|
+
const posY = nodeModel.positionY ?? nodeModel.PositionY ?? 0;
|
|
24053
24045
|
const posZ = (nodeModel.positionZ ?? nodeModel.PositionZ ?? 0); // [Fix] Z Offset 제거 (0으로 통일)
|
|
24054
24046
|
css3dObj.position.set(posX, posY, posZ);
|
|
24055
24047
|
// ▲▲▲ [Fix] ▲▲▲
|
|
@@ -24062,7 +24054,7 @@
|
|
|
24062
24054
|
|
|
24063
24055
|
return css3dObj;
|
|
24064
24056
|
}
|
|
24065
|
-
|
|
24057
|
+
|
|
24066
24058
|
function syncCss3dContent(nodeModel, cssObject) {
|
|
24067
24059
|
if (!nodeModel || !cssObject || !cssObject.element) return;
|
|
24068
24060
|
const nodeId = String(getNodeId(nodeModel) || '').trim();
|
|
@@ -24147,7 +24139,7 @@
|
|
|
24147
24139
|
});
|
|
24148
24140
|
}
|
|
24149
24141
|
}
|
|
24150
|
-
|
|
24142
|
+
|
|
24151
24143
|
const prompt = nodeModel.prompt ?? nodeModel.Prompt ?? '';
|
|
24152
24144
|
if (contentTypeLower === 'image' || contentTypeLower === 'video' || contentTypeLower === 'embed') {
|
|
24153
24145
|
restoreCss3dMediaOverlayState(nodeModel, cssObject);
|
|
@@ -24506,19 +24498,19 @@
|
|
|
24506
24498
|
renderBusinessAutomationChrome(resolveBusinessAutomationChromeContainer(el), nodeModel);
|
|
24507
24499
|
}
|
|
24508
24500
|
// Reusable objects for Frustum Culling (avoid GC)
|
|
24509
|
-
const _frustum = new THREE.Frustum();
|
|
24510
|
-
const _projScreenMatrix = new THREE.Matrix4();
|
|
24511
|
-
const _worldPos = new THREE.Vector3();
|
|
24512
|
-
const _worldQuat = new THREE.Quaternion();
|
|
24513
|
-
const _worldScale = new THREE.Vector3();
|
|
24514
|
-
const _nodeBox = new THREE.Box3(); // 바운딩 박스용
|
|
24515
|
-
|
|
24516
|
-
|
|
24517
|
-
// ▼▼▼ [New] Minimal update loop - only syncs positions when dirty ▼▼▼
|
|
24518
|
-
// 그리드와 동일한 Z 평면(Z=0)에 배치하여 원근/시차 완전 제거
|
|
24519
|
-
// [Fix] CSS3D 노드도 Z=0으로 완전 평탄화하여 카메라 이동 시 그리드와 정렬 유지
|
|
24520
|
-
const CSS3D_Z_OFFSET = 0;
|
|
24521
|
-
|
|
24501
|
+
const _frustum = new THREE.Frustum();
|
|
24502
|
+
const _projScreenMatrix = new THREE.Matrix4();
|
|
24503
|
+
const _worldPos = new THREE.Vector3();
|
|
24504
|
+
const _worldQuat = new THREE.Quaternion();
|
|
24505
|
+
const _worldScale = new THREE.Vector3();
|
|
24506
|
+
const _nodeBox = new THREE.Box3(); // 바운딩 박스용
|
|
24507
|
+
|
|
24508
|
+
|
|
24509
|
+
// ▼▼▼ [New] Minimal update loop - only syncs positions when dirty ▼▼▼
|
|
24510
|
+
// 그리드와 동일한 Z 평면(Z=0)에 배치하여 원근/시차 완전 제거
|
|
24511
|
+
// [Fix] CSS3D 노드도 Z=0으로 완전 평탄화하여 카메라 이동 시 그리드와 정렬 유지
|
|
24512
|
+
const CSS3D_Z_OFFSET = 0;
|
|
24513
|
+
|
|
24522
24514
|
function syncCssPositionFromGl(module, nodeEntry, targetZ) {
|
|
24523
24515
|
const glObject = nodeEntry.glObject;
|
|
24524
24516
|
const cssPos = nodeEntry.cssObject.position;
|
|
@@ -24622,8 +24614,8 @@
|
|
|
24622
24614
|
dirtyIds?.clear?.();
|
|
24623
24615
|
module._cssParentRepairNeeded = false;
|
|
24624
24616
|
}
|
|
24625
|
-
// ▲▲▲ [New] ▲▲▲
|
|
24626
|
-
|
|
24617
|
+
// ▲▲▲ [New] ▲▲▲
|
|
24618
|
+
|
|
24627
24619
|
// ▼▼▼ [New] 일괄 will-change 제어 (성능 최적화) ▼▼▼
|
|
24628
24620
|
let _willChangeState = null; // null = unknown, true = enabled, false = disabled
|
|
24629
24621
|
let _willChangeTouchedIds = new Set();
|
|
@@ -24818,10 +24810,10 @@
|
|
|
24818
24810
|
}
|
|
24819
24811
|
if (el.style.willChange !== value) el.style.willChange = value;
|
|
24820
24812
|
});
|
|
24821
|
-
|
|
24822
|
-
// Razor 템플릿 기반 요소 (id가 css3d-node-로 시작하는 것들)
|
|
24823
|
-
// (위의 createCss3dObject에서 clonedElement에 해당)
|
|
24824
|
-
// querySelectorAll로 잡을 수 있음
|
|
24813
|
+
|
|
24814
|
+
// Razor 템플릿 기반 요소 (id가 css3d-node-로 시작하는 것들)
|
|
24815
|
+
// (위의 createCss3dObject에서 clonedElement에 해당)
|
|
24816
|
+
// querySelectorAll로 잡을 수 있음
|
|
24825
24817
|
const clonedElements = document.querySelectorAll('[id^="css3d-node-"]');
|
|
24826
24818
|
clonedElements.forEach(el => {
|
|
24827
24819
|
if (effectiveEnabled && shouldPreserveAgentMotionCssElement(el)) {
|
|
@@ -24831,9 +24823,9 @@
|
|
|
24831
24823
|
if (el.style.willChange !== value) el.style.willChange = value;
|
|
24832
24824
|
});
|
|
24833
24825
|
}
|
|
24834
|
-
// ▲▲▲ [New] ▲▲▲
|
|
24835
|
-
|
|
24836
|
-
// Expose MindMapCss3DManager globally
|
|
24826
|
+
// ▲▲▲ [New] ▲▲▲
|
|
24827
|
+
|
|
24828
|
+
// Expose MindMapCss3DManager globally
|
|
24837
24829
|
window.MindMapCss3DManager = {
|
|
24838
24830
|
activateSelectableTextOverlay: activateSelectableTextOverlay,
|
|
24839
24831
|
activateNativeTextSelectionSource: activateNativeTextSelectionSource,
|
|
@@ -24912,6 +24904,6 @@
|
|
|
24912
24904
|
hideBusinessAutomationFloatingTooltipForNode: hideBusinessAutomationFloatingTooltipForNode,
|
|
24913
24905
|
update: update // Export
|
|
24914
24906
|
};
|
|
24915
|
-
|
|
24916
|
-
console.log('✓ mind-map-css3d-manager.js loaded (Note editing fixed)');
|
|
24917
|
-
})();
|
|
24907
|
+
|
|
24908
|
+
console.log('✓ mind-map-css3d-manager.js loaded (Note editing fixed)');
|
|
24909
|
+
})();
|