@xcanwin/manyoyo 6.1.3 → 6.2.0
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/lib/web/frontend/app.css +190 -218
- package/lib/web/frontend/app.html +19 -39
- package/lib/web/frontend/app.js +236 -253
- package/lib/web/frontend/chat-behavior.js +23 -4
- package/package.json +1 -1
package/lib/web/frontend/app.js
CHANGED
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
loadingMessages: false,
|
|
48
48
|
loadingSessionDetail: false,
|
|
49
49
|
mobileSidebarOpen: false,
|
|
50
|
-
mobileActionsOpen: false,
|
|
51
50
|
workspaceSwitcherOpen: false,
|
|
51
|
+
composerOptionsOpen: false,
|
|
52
52
|
configModalOpen: false,
|
|
53
53
|
createModalOpen: false,
|
|
54
54
|
agentTemplateModalOpen: false,
|
|
@@ -123,8 +123,6 @@
|
|
|
123
123
|
const sessionList = document.getElementById('sessionList');
|
|
124
124
|
const sessionCount = document.getElementById('sessionCount');
|
|
125
125
|
const mobileSessionToggle = document.getElementById('mobileSessionToggle');
|
|
126
|
-
const mobileActionsToggle = document.getElementById('mobileActionsToggle');
|
|
127
|
-
const headerActions = document.getElementById('headerActions');
|
|
128
126
|
const viewActivityBtn = document.getElementById('viewActivityBtn');
|
|
129
127
|
const workspaceSwitcherToggle = document.getElementById('workspaceSwitcherToggle');
|
|
130
128
|
const workspaceSwitcherPanel = document.getElementById('workspaceSwitcherPanel');
|
|
@@ -133,12 +131,10 @@
|
|
|
133
131
|
const viewDetailBtn = document.getElementById('viewDetailBtn');
|
|
134
132
|
const viewConfigBtn = document.getElementById('viewConfigBtn');
|
|
135
133
|
const viewCheckBtn = document.getElementById('viewCheckBtn');
|
|
136
|
-
const addAgentBtn = document.getElementById('addAgentBtn');
|
|
137
134
|
const mobileSidebarClose = document.getElementById('mobileSidebarClose');
|
|
138
135
|
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
|
139
136
|
const openConfigBtn = document.getElementById('openConfigBtn');
|
|
140
137
|
const openCreateBtn = document.getElementById('openCreateBtn');
|
|
141
|
-
const openCreateMenuBtn = document.getElementById('openCreateMenuBtn');
|
|
142
138
|
const configModal = document.getElementById('configModal');
|
|
143
139
|
const configModalTitle = document.getElementById('configModalTitle');
|
|
144
140
|
const configPath = document.getElementById('configPath');
|
|
@@ -181,12 +177,12 @@
|
|
|
181
177
|
const directoryPickerError = document.getElementById('directoryPickerError');
|
|
182
178
|
const directoryPickerCancelBtn = document.getElementById('directoryPickerCancelBtn');
|
|
183
179
|
const directoryPickerSelectBtn = document.getElementById('directoryPickerSelectBtn');
|
|
184
|
-
const activeTitle = document.getElementById('activeTitle');
|
|
185
|
-
const activeMeta = document.getElementById('activeMeta');
|
|
186
180
|
const activityCommandBtn = document.getElementById('activityCommandBtn');
|
|
187
181
|
const activityAgentBtn = document.getElementById('activityAgentBtn');
|
|
188
182
|
const agentTemplateBtn = document.getElementById('agentTemplateBtn');
|
|
189
183
|
const activityModelChip = document.getElementById('activityModelChip');
|
|
184
|
+
const composerOptionsToggle = document.getElementById('composerOptionsToggle');
|
|
185
|
+
const composerOptionsPanel = document.getElementById('composerOptionsPanel');
|
|
190
186
|
const messagesNode = document.getElementById('messages');
|
|
191
187
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
192
188
|
const filesPanel = document.getElementById('filesPanel');
|
|
@@ -199,10 +195,7 @@
|
|
|
199
195
|
const terminalScreen = document.getElementById('terminalScreen');
|
|
200
196
|
const composer = document.getElementById('composer');
|
|
201
197
|
const commandInput = document.getElementById('commandInput');
|
|
202
|
-
const composerHint = document.getElementById('composerHint');
|
|
203
|
-
const sendState = document.getElementById('sendState');
|
|
204
198
|
const sendBtn = document.getElementById('sendBtn');
|
|
205
|
-
const stopBtn = document.getElementById('stopBtn');
|
|
206
199
|
const agentTemplateModal = document.getElementById('agentTemplateModal');
|
|
207
200
|
const agentTemplatePrimary = document.getElementById('agentTemplatePrimary');
|
|
208
201
|
const containerCliSelect = document.getElementById('containerCliSelect');
|
|
@@ -218,9 +211,6 @@
|
|
|
218
211
|
const externalLinkUrl = document.getElementById('externalLinkUrl');
|
|
219
212
|
const externalLinkCancelBtn = document.getElementById('externalLinkCancelBtn');
|
|
220
213
|
const externalLinkOpenBtn = document.getElementById('externalLinkOpenBtn');
|
|
221
|
-
const refreshBtn = document.getElementById('refreshBtn');
|
|
222
|
-
const removeBtn = document.getElementById('removeBtn');
|
|
223
|
-
const removeAllBtn = document.getElementById('removeAllBtn');
|
|
224
214
|
const MOBILE_LAYOUT_MEDIA = window.matchMedia('(max-width: 980px)');
|
|
225
215
|
const MOBILE_COMPACT_MEDIA = window.matchMedia('(max-width: 640px)');
|
|
226
216
|
const TERMINAL_FIT_DEBOUNCE_MS = 60;
|
|
@@ -328,7 +318,7 @@
|
|
|
328
318
|
return Promise.reject(new Error('clipboard unavailable'));
|
|
329
319
|
}
|
|
330
320
|
|
|
331
|
-
function appendMessageCopyActions(
|
|
321
|
+
function appendMessageCopyActions(container, items) {
|
|
332
322
|
const actions = document.createElement('div');
|
|
333
323
|
actions.className = 'msg-actions';
|
|
334
324
|
items.forEach(function (item) {
|
|
@@ -352,7 +342,7 @@
|
|
|
352
342
|
});
|
|
353
343
|
actions.appendChild(btn);
|
|
354
344
|
});
|
|
355
|
-
|
|
345
|
+
container.appendChild(actions);
|
|
356
346
|
}
|
|
357
347
|
|
|
358
348
|
function stringifyPrettyJson(value) {
|
|
@@ -605,7 +595,7 @@
|
|
|
605
595
|
const hasError = traceEvents.some(function (event) {
|
|
606
596
|
return event && event.kind === 'error';
|
|
607
597
|
});
|
|
608
|
-
const defaultOpen = hasError
|
|
598
|
+
const defaultOpen = hasError;
|
|
609
599
|
const toggle = document.createElement('details');
|
|
610
600
|
toggle.className = 'trace-flow-toggle';
|
|
611
601
|
toggle.open = traceFlowExpandedState.has(messageId) ? traceFlowExpandedState.get(messageId) : defaultOpen;
|
|
@@ -632,7 +622,7 @@
|
|
|
632
622
|
return 'AGENT 实时回复';
|
|
633
623
|
}
|
|
634
624
|
if (message && message.streamTrace) {
|
|
635
|
-
return 'AGENT
|
|
625
|
+
return 'AGENT 回复';
|
|
636
626
|
}
|
|
637
627
|
if (message && message.mode === 'agent') {
|
|
638
628
|
return 'AGENT 回复';
|
|
@@ -1635,17 +1625,6 @@
|
|
|
1635
1625
|
return '自动';
|
|
1636
1626
|
}
|
|
1637
1627
|
|
|
1638
|
-
function buildActiveMeta(session) {
|
|
1639
|
-
if (!session) {
|
|
1640
|
-
return '会话不可用';
|
|
1641
|
-
}
|
|
1642
|
-
const status = sessionStatusInfo(session.status);
|
|
1643
|
-
const messageCount = safeMessageCount(session.messageCount);
|
|
1644
|
-
const updatedAt = formatDateTime(session.updatedAt) || '暂无更新';
|
|
1645
|
-
const containerName = session.containerName || '未绑定容器';
|
|
1646
|
-
return `${containerName} · ${status.label} · ${messageCount} 条对话 · ${updatedAt}`;
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
1628
|
function buildMessageMetaLines(message) {
|
|
1650
1629
|
const lines = [];
|
|
1651
1630
|
const timeText = formatDateTime(message && message.timestamp);
|
|
@@ -1980,18 +1959,6 @@
|
|
|
1980
1959
|
setMobileSessionPanel(false);
|
|
1981
1960
|
}
|
|
1982
1961
|
|
|
1983
|
-
function setMobileActionsMenu(open) {
|
|
1984
|
-
state.mobileActionsOpen = Boolean(open);
|
|
1985
|
-
document.body.classList.toggle('mobile-actions-open', state.mobileActionsOpen);
|
|
1986
|
-
if (mobileActionsToggle) {
|
|
1987
|
-
mobileActionsToggle.setAttribute('aria-expanded', state.mobileActionsOpen ? 'true' : 'false');
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
function closeMobileActionsMenu() {
|
|
1992
|
-
setMobileActionsMenu(false);
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
1962
|
function setWorkspaceSwitcherMenu(open) {
|
|
1996
1963
|
state.workspaceSwitcherOpen = Boolean(open);
|
|
1997
1964
|
document.body.classList.toggle('workspace-switcher-open', state.workspaceSwitcherOpen);
|
|
@@ -2007,6 +1974,21 @@
|
|
|
2007
1974
|
setWorkspaceSwitcherMenu(false);
|
|
2008
1975
|
}
|
|
2009
1976
|
|
|
1977
|
+
function setComposerOptionsMenu(open) {
|
|
1978
|
+
state.composerOptionsOpen = Boolean(open);
|
|
1979
|
+
document.body.classList.toggle('composer-options-open', state.composerOptionsOpen);
|
|
1980
|
+
if (composerOptionsToggle) {
|
|
1981
|
+
composerOptionsToggle.setAttribute('aria-expanded', state.composerOptionsOpen ? 'true' : 'false');
|
|
1982
|
+
}
|
|
1983
|
+
if (composerOptionsPanel) {
|
|
1984
|
+
composerOptionsPanel.hidden = !state.composerOptionsOpen;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
function closeComposerOptionsMenu() {
|
|
1989
|
+
setComposerOptionsMenu(false);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
2010
1992
|
const VIEW_LABELS = {
|
|
2011
1993
|
activity: '活动',
|
|
2012
1994
|
terminal: '终端',
|
|
@@ -2274,31 +2256,17 @@
|
|
|
2274
2256
|
}
|
|
2275
2257
|
}
|
|
2276
2258
|
|
|
2277
|
-
function syncComposerExpanded() {
|
|
2278
|
-
if (!composer || !commandInput) {
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
// 判定条件必须是"焦点是否还在 composer 内部"而不是"是否等于 commandInput":
|
|
2282
|
-
// 点击 Agent/命令 切换或 CLI/模型 按钮时,commandInput 会先 blur,
|
|
2283
|
-
// 若立刻按 commandInput 是否聚焦来收起,会在 mousedown 与 click 之间把工具栏收起,
|
|
2284
|
-
// 导致按钮的点击事件因布局变化而落空(点了没反应)。
|
|
2285
|
-
const focused = composer.contains(document.activeElement);
|
|
2286
|
-
const hasDraft = Boolean(commandInput.value && commandInput.value.trim());
|
|
2287
|
-
const expanded = window.ManyoyoChatBehavior.shouldExpandComposer({ focused, hasDraft });
|
|
2288
|
-
composer.classList.toggle('is-expanded', expanded);
|
|
2289
|
-
}
|
|
2290
|
-
|
|
2291
2259
|
function syncUi() {
|
|
2292
2260
|
if (!state.active) {
|
|
2293
|
-
|
|
2294
|
-
activeMeta.textContent = '请选择左侧会话';
|
|
2261
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle('');
|
|
2295
2262
|
if (isComposerMode()) {
|
|
2296
2263
|
commandInput.value = '';
|
|
2297
2264
|
}
|
|
2298
2265
|
} else {
|
|
2299
2266
|
const activeSession = getActiveSession();
|
|
2300
|
-
|
|
2301
|
-
|
|
2267
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle(
|
|
2268
|
+
activeSession && activeSession.agentName ? activeSession.agentName : state.active
|
|
2269
|
+
);
|
|
2302
2270
|
}
|
|
2303
2271
|
|
|
2304
2272
|
const activityTab = state.activeTab === 'activity';
|
|
@@ -2377,16 +2345,15 @@
|
|
|
2377
2345
|
|
|
2378
2346
|
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
2379
2347
|
const busy = state.loadingSessions || state.loadingMessages || state.sending || state.creatingAgent;
|
|
2380
|
-
|
|
2381
|
-
if (
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
|
|
2348
|
+
const showStop = agentMode && activeAgentRunning;
|
|
2349
|
+
if (showStop) {
|
|
2350
|
+
sendBtn.disabled = !activityTab || !state.active || state.agentRun.stopping;
|
|
2351
|
+
sendBtn.textContent = state.agentRun.stopping ? '停止中…' : '停止';
|
|
2352
|
+
sendBtn.classList.add('danger-outline');
|
|
2353
|
+
} else {
|
|
2354
|
+
sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && !agentEnabled);
|
|
2355
|
+
sendBtn.textContent = '发送';
|
|
2356
|
+
sendBtn.classList.remove('danger-outline');
|
|
2390
2357
|
}
|
|
2391
2358
|
if (agentTemplateBtn) {
|
|
2392
2359
|
agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
|
|
@@ -2397,18 +2364,9 @@
|
|
|
2397
2364
|
? '输入提示词,例如:请帮我分析当前项目结构并给出重构建议'
|
|
2398
2365
|
: '输入容器命令,例如: ls -la';
|
|
2399
2366
|
}
|
|
2400
|
-
if (composerHint) {
|
|
2401
|
-
composerHint.textContent = agentMode
|
|
2402
|
-
? 'Enter 发送提示词 · Shift/Alt + Enter 换行 · 执行中可停止'
|
|
2403
|
-
: 'Enter 发送 · Shift/Alt + Enter 换行';
|
|
2404
|
-
}
|
|
2405
|
-
syncComposerExpanded();
|
|
2406
2367
|
if (openCreateBtn) {
|
|
2407
2368
|
openCreateBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2408
2369
|
}
|
|
2409
|
-
if (openCreateMenuBtn) {
|
|
2410
|
-
openCreateMenuBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2411
|
-
}
|
|
2412
2370
|
if (openConfigBtn) {
|
|
2413
2371
|
openConfigBtn.disabled = state.configLoading || state.configSaving;
|
|
2414
2372
|
}
|
|
@@ -2435,24 +2393,6 @@
|
|
|
2435
2393
|
if (createCancelBtn) {
|
|
2436
2394
|
createCancelBtn.disabled = state.createSubmitting;
|
|
2437
2395
|
}
|
|
2438
|
-
if (sendState) {
|
|
2439
|
-
if (!state.active) {
|
|
2440
|
-
sendState.textContent = '未选择会话';
|
|
2441
|
-
sendState.classList.remove('is-active');
|
|
2442
|
-
} else if (state.creatingAgent) {
|
|
2443
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2444
|
-
sendState.classList.add('is-active');
|
|
2445
|
-
} else if (activeAgentRunning && agentMode) {
|
|
2446
|
-
sendState.textContent = state.agentRun.stopping ? '正在停止 Agent…' : 'Agent 执行中';
|
|
2447
|
-
sendState.classList.add('is-active');
|
|
2448
|
-
} else if (busy) {
|
|
2449
|
-
sendState.textContent = '处理中';
|
|
2450
|
-
sendState.classList.add('is-active');
|
|
2451
|
-
} else {
|
|
2452
|
-
sendState.textContent = agentMode ? 'Agent 就绪' : '命令就绪';
|
|
2453
|
-
sendState.classList.remove('is-active');
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
2396
|
if (configModal) {
|
|
2457
2397
|
configModal.hidden = !state.configModalOpen;
|
|
2458
2398
|
}
|
|
@@ -2493,25 +2433,10 @@
|
|
|
2493
2433
|
'modal-open',
|
|
2494
2434
|
state.configModalOpen || state.createModalOpen || state.directoryPicker.open || state.agentTemplateModalOpen || state.externalLinkModalOpen
|
|
2495
2435
|
);
|
|
2496
|
-
if (!state.active) {
|
|
2497
|
-
sendState.textContent = '未选择会话';
|
|
2498
|
-
} else if (state.creatingAgent) {
|
|
2499
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2500
|
-
} else if (agentMode && !agentEnabled) {
|
|
2501
|
-
sendState.textContent = '当前会话未配置 AGENT 模板';
|
|
2502
|
-
} else if (state.sending) {
|
|
2503
|
-
sendState.textContent = '发送中...';
|
|
2504
|
-
} else if (state.loadingSessions || state.loadingMessages) {
|
|
2505
|
-
sendState.textContent = '加载中...';
|
|
2506
|
-
} else {
|
|
2507
|
-
sendState.textContent = '就绪';
|
|
2508
|
-
}
|
|
2509
|
-
sendState.classList.toggle('is-active', state.sending || state.creatingAgent);
|
|
2510
2436
|
if (composer) {
|
|
2511
2437
|
composer.hidden = !activityTab;
|
|
2512
2438
|
}
|
|
2513
2439
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
2514
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
2515
2440
|
renderSessionDetailPanels();
|
|
2516
2441
|
}
|
|
2517
2442
|
|
|
@@ -3134,6 +3059,122 @@
|
|
|
3134
3059
|
return findLatestCreatedSessionName(remaining, removedRef.containerName);
|
|
3135
3060
|
}
|
|
3136
3061
|
|
|
3062
|
+
let openTreeNodeMenu = null;
|
|
3063
|
+
|
|
3064
|
+
function closeOpenTreeNodeMenu() {
|
|
3065
|
+
if (openTreeNodeMenu) {
|
|
3066
|
+
const menu = openTreeNodeMenu;
|
|
3067
|
+
openTreeNodeMenu = null;
|
|
3068
|
+
menu.close();
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
function createTreeNodeMenu(items) {
|
|
3073
|
+
const wrap = document.createElement('div');
|
|
3074
|
+
wrap.className = 'tree-node-menu';
|
|
3075
|
+
|
|
3076
|
+
const trigger = document.createElement('button');
|
|
3077
|
+
trigger.type = 'button';
|
|
3078
|
+
trigger.className = 'secondary tree-node-menu-trigger';
|
|
3079
|
+
trigger.setAttribute('aria-haspopup', 'true');
|
|
3080
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3081
|
+
trigger.setAttribute('aria-label', '更多操作');
|
|
3082
|
+
trigger.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><circle cx="3" cy="8" r="1.4"></circle><circle cx="8" cy="8" r="1.4"></circle><circle cx="13" cy="8" r="1.4"></circle></svg>';
|
|
3083
|
+
|
|
3084
|
+
const panel = document.createElement('div');
|
|
3085
|
+
panel.className = 'tree-node-menu-panel';
|
|
3086
|
+
panel.hidden = true;
|
|
3087
|
+
|
|
3088
|
+
function close() {
|
|
3089
|
+
panel.hidden = true;
|
|
3090
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3091
|
+
wrap.classList.remove('is-open');
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
trigger.addEventListener('click', function (event) {
|
|
3095
|
+
event.stopPropagation();
|
|
3096
|
+
if (panel.hidden) {
|
|
3097
|
+
closeOpenTreeNodeMenu();
|
|
3098
|
+
panel.hidden = false;
|
|
3099
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
3100
|
+
wrap.classList.add('is-open');
|
|
3101
|
+
openTreeNodeMenu = { wrap, close };
|
|
3102
|
+
} else {
|
|
3103
|
+
close();
|
|
3104
|
+
openTreeNodeMenu = null;
|
|
3105
|
+
}
|
|
3106
|
+
});
|
|
3107
|
+
|
|
3108
|
+
(Array.isArray(items) ? items : []).forEach(function (item) {
|
|
3109
|
+
const itemBtn = document.createElement('button');
|
|
3110
|
+
itemBtn.type = 'button';
|
|
3111
|
+
itemBtn.className = 'tree-node-menu-panel-item' + (item.danger ? ' is-danger' : '');
|
|
3112
|
+
itemBtn.textContent = item.label;
|
|
3113
|
+
itemBtn.addEventListener('click', function (event) {
|
|
3114
|
+
event.stopPropagation();
|
|
3115
|
+
close();
|
|
3116
|
+
openTreeNodeMenu = null;
|
|
3117
|
+
if (typeof item.onClick === 'function') {
|
|
3118
|
+
item.onClick();
|
|
3119
|
+
}
|
|
3120
|
+
});
|
|
3121
|
+
panel.appendChild(itemBtn);
|
|
3122
|
+
});
|
|
3123
|
+
|
|
3124
|
+
wrap.appendChild(trigger);
|
|
3125
|
+
wrap.appendChild(panel);
|
|
3126
|
+
return wrap;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
async function removeContainerByName(containerName) {
|
|
3130
|
+
const target = String(containerName || '').trim();
|
|
3131
|
+
if (!target) return;
|
|
3132
|
+
const yes = confirm('确认删除容器 ' + target + ' ?');
|
|
3133
|
+
if (!yes) return;
|
|
3134
|
+
try {
|
|
3135
|
+
const wasActiveContainer = parseSessionKey(state.active).containerName === target;
|
|
3136
|
+
if (parseSessionKey(state.terminal.sessionName).containerName === target
|
|
3137
|
+
&& (state.terminal.connected || state.terminal.connecting)) {
|
|
3138
|
+
disconnectTerminal('容器删除,终端已断开', true);
|
|
3139
|
+
}
|
|
3140
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove', {
|
|
3141
|
+
method: 'POST'
|
|
3142
|
+
});
|
|
3143
|
+
await refreshSessions({
|
|
3144
|
+
preferredName: wasActiveContainer ? target : (state.active || ''),
|
|
3145
|
+
withLoading: true,
|
|
3146
|
+
reloadMessages: wasActiveContainer
|
|
3147
|
+
});
|
|
3148
|
+
} catch (e) {
|
|
3149
|
+
alert(e.message);
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
async function removeAgentSessionByName(sessionName, agentLabel) {
|
|
3154
|
+
const target = String(sessionName || '').trim();
|
|
3155
|
+
if (!target) return;
|
|
3156
|
+
const yes = confirm('确认删除 AGENT ' + (agentLabel || target) + ' ?');
|
|
3157
|
+
if (!yes) return;
|
|
3158
|
+
const isActive = target === state.active;
|
|
3159
|
+
try {
|
|
3160
|
+
const containerName = parseSessionKey(target).containerName;
|
|
3161
|
+
const fallbackSessionName = isActive
|
|
3162
|
+
? findPreferredSessionNameAfterRemoval(state.sessions, target)
|
|
3163
|
+
: '';
|
|
3164
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove-with-history', {
|
|
3165
|
+
method: 'POST'
|
|
3166
|
+
});
|
|
3167
|
+
await refreshSessions({
|
|
3168
|
+
preferredName: isActive ? (fallbackSessionName || '') : (state.active || ''),
|
|
3169
|
+
preferredContainerName: containerName,
|
|
3170
|
+
withLoading: true,
|
|
3171
|
+
reloadMessages: isActive
|
|
3172
|
+
});
|
|
3173
|
+
} catch (e) {
|
|
3174
|
+
alert(e.message);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3137
3178
|
function createDisclosureButton(expanded, label) {
|
|
3138
3179
|
const button = document.createElement('button');
|
|
3139
3180
|
button.type = 'button';
|
|
@@ -3272,18 +3313,21 @@
|
|
|
3272
3313
|
const status = sessionStatusInfo(containerGroup && containerGroup.status);
|
|
3273
3314
|
const historyClassName = status.tone === 'history' ? 'tree-node-tone-history' : '';
|
|
3274
3315
|
const containerName = String(containerGroup && containerGroup.containerName ? containerGroup.containerName : '').trim() || '未命名容器';
|
|
3275
|
-
const
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3316
|
+
const containerMenu = createTreeNodeMenu([
|
|
3317
|
+
{
|
|
3318
|
+
label: '新建 AGENT',
|
|
3319
|
+
onClick: function () {
|
|
3320
|
+
createAgentSession(containerName);
|
|
3321
|
+
}
|
|
3322
|
+
},
|
|
3323
|
+
{
|
|
3324
|
+
label: '删除容器',
|
|
3325
|
+
danger: true,
|
|
3326
|
+
onClick: function () {
|
|
3327
|
+
removeContainerByName(containerName);
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
]);
|
|
3287
3331
|
|
|
3288
3332
|
return {
|
|
3289
3333
|
kind: 'container',
|
|
@@ -3294,18 +3338,28 @@
|
|
|
3294
3338
|
disclosureLabel: containerName,
|
|
3295
3339
|
expanded: isContainerExpanded(containerGroup),
|
|
3296
3340
|
hasActive: containerContainsActiveSession(containerGroup),
|
|
3297
|
-
overlayNode:
|
|
3341
|
+
overlayNode: containerMenu,
|
|
3298
3342
|
onToggle: function (expanded) {
|
|
3299
3343
|
setSidebarContainerExpanded(containerGroup.containerName, expanded);
|
|
3300
3344
|
},
|
|
3301
3345
|
children: (Array.isArray(containerGroup.sessions) ? containerGroup.sessions : []).map(function (session) {
|
|
3346
|
+
const agentTitle = session.agentName || session.name;
|
|
3302
3347
|
return {
|
|
3303
3348
|
kind: 'agent',
|
|
3304
|
-
title:
|
|
3349
|
+
title: agentTitle,
|
|
3305
3350
|
meta: formatDateTime(session.updatedAt) || '暂无更新',
|
|
3306
3351
|
className: historyClassName,
|
|
3307
3352
|
active: state.active === session.name,
|
|
3308
|
-
sessionName: session.name
|
|
3353
|
+
sessionName: session.name,
|
|
3354
|
+
overlayNode: createTreeNodeMenu([
|
|
3355
|
+
{
|
|
3356
|
+
label: '删除 AGENT',
|
|
3357
|
+
danger: true,
|
|
3358
|
+
onClick: function () {
|
|
3359
|
+
removeAgentSessionByName(session.name, agentTitle);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
])
|
|
3309
3363
|
};
|
|
3310
3364
|
})
|
|
3311
3365
|
};
|
|
@@ -3493,10 +3547,12 @@
|
|
|
3493
3547
|
}
|
|
3494
3548
|
|
|
3495
3549
|
function getMessageRenderKey(msg, index) {
|
|
3550
|
+
const pairedTrace = msg && msg.pairedTrace ? msg.pairedTrace : null;
|
|
3551
|
+
const tracePart = pairedTrace ? `|paired:${String(pairedTrace.content || '')}` : '';
|
|
3496
3552
|
if (msg && msg.id && msg.streamingReply) {
|
|
3497
3553
|
const content = msg.content ? String(msg.content) : '';
|
|
3498
3554
|
const timestamp = msg.timestamp ? String(msg.timestamp) : '';
|
|
3499
|
-
return `id:${msg.id}|streaming|${timestamp}|${content}`;
|
|
3555
|
+
return `id:${msg.id}|streaming|${timestamp}|${content}${tracePart}`;
|
|
3500
3556
|
}
|
|
3501
3557
|
if (msg && msg.id && msg.streamTrace) {
|
|
3502
3558
|
const content = msg.content ? String(msg.content) : '';
|
|
@@ -3505,7 +3561,7 @@
|
|
|
3505
3561
|
return `id:${msg.id}|trace|${timestamp}|${content}|${running}`;
|
|
3506
3562
|
}
|
|
3507
3563
|
if (msg && msg.id) {
|
|
3508
|
-
return `id:${msg.id}`;
|
|
3564
|
+
return `id:${msg.id}${tracePart}`;
|
|
3509
3565
|
}
|
|
3510
3566
|
const role = msg && msg.role ? String(msg.role) : '';
|
|
3511
3567
|
const mode = msg && msg.mode ? String(msg.mode) : '';
|
|
@@ -3513,7 +3569,7 @@
|
|
|
3513
3569
|
const exitCode = msg && typeof msg.exitCode === 'number' ? String(msg.exitCode) : '';
|
|
3514
3570
|
const pending = msg && msg.pending ? '1' : '0';
|
|
3515
3571
|
const content = msg && msg.content ? String(msg.content) : '';
|
|
3516
|
-
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}`;
|
|
3572
|
+
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}${tracePart}`;
|
|
3517
3573
|
}
|
|
3518
3574
|
|
|
3519
3575
|
function resolveMessageOrigin(msg) {
|
|
@@ -3550,13 +3606,12 @@
|
|
|
3550
3606
|
const bubble = document.createElement('div');
|
|
3551
3607
|
bubble.className = 'bubble';
|
|
3552
3608
|
|
|
3609
|
+
if (msg && msg.pairedTrace) {
|
|
3610
|
+
appendStructuredTraceContent(bubble, msg.pairedTrace);
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3553
3613
|
const isStreamingReply = Boolean(msg && msg.streamingReply);
|
|
3554
|
-
const shouldRenderStructuredTrace = Boolean(
|
|
3555
|
-
msg
|
|
3556
|
-
&& msg.streamTrace
|
|
3557
|
-
&& Array.isArray(msg.traceEvents)
|
|
3558
|
-
&& msg.traceEvents.length
|
|
3559
|
-
);
|
|
3614
|
+
const shouldRenderStructuredTrace = Boolean(msg && msg.streamTrace);
|
|
3560
3615
|
const shouldRenderMarkdown = Boolean(!msg.streamTrace && !msg.streamingReply && markdownRenderer && markdownRenderer.shouldRenderMessage(msg));
|
|
3561
3616
|
if (isStreamingReply) {
|
|
3562
3617
|
bubble.classList.add('streaming-reply');
|
|
@@ -3596,7 +3651,7 @@
|
|
|
3596
3651
|
if (renderedMarkdown) {
|
|
3597
3652
|
markdownNode.innerHTML = renderedMarkdown;
|
|
3598
3653
|
bubble.appendChild(markdownNode);
|
|
3599
|
-
appendMessageCopyActions(
|
|
3654
|
+
appendMessageCopyActions(bubble, [
|
|
3600
3655
|
{ label: '复制文本', getText: function () { return markdownNode.innerText || markdownNode.textContent || ''; } },
|
|
3601
3656
|
{ label: '复制 Markdown', getText: function () { return msg.content; } }
|
|
3602
3657
|
]);
|
|
@@ -3606,7 +3661,7 @@
|
|
|
3606
3661
|
} else {
|
|
3607
3662
|
appendPlainMessageContent(bubble, msg.content);
|
|
3608
3663
|
if (msg.role === 'user') {
|
|
3609
|
-
appendMessageCopyActions(
|
|
3664
|
+
appendMessageCopyActions(bubble, [
|
|
3610
3665
|
{ label: '复制', getText: function () { return msg.content; } }
|
|
3611
3666
|
]);
|
|
3612
3667
|
}
|
|
@@ -3617,7 +3672,8 @@
|
|
|
3617
3672
|
return row;
|
|
3618
3673
|
}
|
|
3619
3674
|
|
|
3620
|
-
function renderMessages(
|
|
3675
|
+
function renderMessages(rawMessages, options) {
|
|
3676
|
+
const messages = window.ManyoyoChatBehavior.mergeTraceIntoReply(rawMessages);
|
|
3621
3677
|
const renderOptions = options && typeof options === 'object' ? options : {};
|
|
3622
3678
|
const stickToBottom = renderOptions.stickToBottom === true || isMessagesNearBottom(40);
|
|
3623
3679
|
|
|
@@ -4149,15 +4205,9 @@
|
|
|
4149
4205
|
});
|
|
4150
4206
|
}
|
|
4151
4207
|
|
|
4152
|
-
if (openCreateMenuBtn) {
|
|
4153
|
-
openCreateMenuBtn.addEventListener('click', function () {
|
|
4154
|
-
closeMobileActionsMenu();
|
|
4155
|
-
openCreateModal();
|
|
4156
|
-
});
|
|
4157
|
-
}
|
|
4158
|
-
|
|
4159
4208
|
if (agentTemplateBtn) {
|
|
4160
4209
|
agentTemplateBtn.addEventListener('click', function () {
|
|
4210
|
+
closeComposerOptionsMenu();
|
|
4161
4211
|
openAgentTemplateModal().catch(function (e) {
|
|
4162
4212
|
alert(e && e.message ? e.message : '加载 Agent 模板失败');
|
|
4163
4213
|
});
|
|
@@ -4349,10 +4399,29 @@
|
|
|
4349
4399
|
composer.addEventListener('submit', async function (event) {
|
|
4350
4400
|
event.preventDefault();
|
|
4351
4401
|
if (!state.active) return;
|
|
4352
|
-
if (state.sending) return;
|
|
4353
|
-
if (state.loadingSessions || state.loadingMessages) return;
|
|
4354
4402
|
if (state.activeTab !== 'activity') return;
|
|
4403
|
+
|
|
4355
4404
|
const mode = state.mode === 'agent' ? 'agent' : 'command';
|
|
4405
|
+
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
4406
|
+
if (mode === 'agent' && activeAgentRunning) {
|
|
4407
|
+
if (state.agentRun.stopping) return;
|
|
4408
|
+
state.agentRun.stopping = true;
|
|
4409
|
+
syncUi();
|
|
4410
|
+
try {
|
|
4411
|
+
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4412
|
+
method: 'POST',
|
|
4413
|
+
body: JSON.stringify({})
|
|
4414
|
+
});
|
|
4415
|
+
} catch (e) {
|
|
4416
|
+
alert(e.message);
|
|
4417
|
+
state.agentRun.stopping = false;
|
|
4418
|
+
syncUi();
|
|
4419
|
+
}
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
if (state.sending) return;
|
|
4424
|
+
if (state.loadingSessions || state.loadingMessages) return;
|
|
4356
4425
|
if (mode === 'agent' && !isActiveAgentEnabled()) {
|
|
4357
4426
|
syncUi();
|
|
4358
4427
|
return;
|
|
@@ -4420,40 +4489,9 @@
|
|
|
4420
4489
|
} finally {
|
|
4421
4490
|
state.sending = false;
|
|
4422
4491
|
syncUi();
|
|
4423
|
-
commandInput.focus();
|
|
4424
4492
|
}
|
|
4425
4493
|
});
|
|
4426
4494
|
|
|
4427
|
-
if (stopBtn) {
|
|
4428
|
-
stopBtn.addEventListener('click', async function () {
|
|
4429
|
-
if (!state.active || !isAgentRunActiveForSession(state.active) || state.agentRun.stopping) {
|
|
4430
|
-
return;
|
|
4431
|
-
}
|
|
4432
|
-
state.agentRun.stopping = true;
|
|
4433
|
-
syncUi();
|
|
4434
|
-
try {
|
|
4435
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4436
|
-
method: 'POST',
|
|
4437
|
-
body: JSON.stringify({})
|
|
4438
|
-
});
|
|
4439
|
-
} catch (e) {
|
|
4440
|
-
alert(e.message);
|
|
4441
|
-
state.agentRun.stopping = false;
|
|
4442
|
-
syncUi();
|
|
4443
|
-
}
|
|
4444
|
-
});
|
|
4445
|
-
}
|
|
4446
|
-
|
|
4447
|
-
if (composer) {
|
|
4448
|
-
composer.addEventListener('focusin', syncComposerExpanded);
|
|
4449
|
-
composer.addEventListener('focusout', function () {
|
|
4450
|
-
// 延后到下一个宏任务再判断,让浏览器先把焦点落到新的目标元素上
|
|
4451
|
-
// (比如 composer 内的 CLI/Agent 按钮),避免过早收起导致点击落空。
|
|
4452
|
-
window.setTimeout(syncComposerExpanded, 0);
|
|
4453
|
-
});
|
|
4454
|
-
}
|
|
4455
|
-
commandInput.addEventListener('input', syncComposerExpanded);
|
|
4456
|
-
|
|
4457
4495
|
commandInput.addEventListener('keydown', function (event) {
|
|
4458
4496
|
if (event.key !== 'Enter' || event.isComposing) {
|
|
4459
4497
|
return;
|
|
@@ -4476,6 +4514,7 @@
|
|
|
4476
4514
|
activityCommandBtn.addEventListener('click', function () {
|
|
4477
4515
|
state.mode = 'command';
|
|
4478
4516
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4517
|
+
closeComposerOptionsMenu();
|
|
4479
4518
|
syncUi();
|
|
4480
4519
|
commandInput.focus();
|
|
4481
4520
|
});
|
|
@@ -4485,11 +4524,18 @@
|
|
|
4485
4524
|
activityAgentBtn.addEventListener('click', function () {
|
|
4486
4525
|
state.mode = 'agent';
|
|
4487
4526
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4527
|
+
closeComposerOptionsMenu();
|
|
4488
4528
|
syncUi();
|
|
4489
4529
|
commandInput.focus();
|
|
4490
4530
|
});
|
|
4491
4531
|
}
|
|
4492
4532
|
|
|
4533
|
+
if (composerOptionsToggle) {
|
|
4534
|
+
composerOptionsToggle.addEventListener('click', function () {
|
|
4535
|
+
setComposerOptionsMenu(!state.composerOptionsOpen);
|
|
4536
|
+
});
|
|
4537
|
+
}
|
|
4538
|
+
|
|
4493
4539
|
if (viewActivityBtn) {
|
|
4494
4540
|
viewActivityBtn.addEventListener('click', function () {
|
|
4495
4541
|
closeWorkspaceSwitcherMenu();
|
|
@@ -4533,11 +4579,6 @@
|
|
|
4533
4579
|
});
|
|
4534
4580
|
}
|
|
4535
4581
|
|
|
4536
|
-
refreshBtn.addEventListener('click', function () {
|
|
4537
|
-
closeMobileActionsMenu();
|
|
4538
|
-
loadSessions(state.active).catch(function (e) { alert(e.message); });
|
|
4539
|
-
});
|
|
4540
|
-
|
|
4541
4582
|
const TERM_KEY_SEQUENCES = {
|
|
4542
4583
|
esc: '\x1b',
|
|
4543
4584
|
tab: '\x09',
|
|
@@ -4579,12 +4620,6 @@
|
|
|
4579
4620
|
});
|
|
4580
4621
|
}
|
|
4581
4622
|
|
|
4582
|
-
if (mobileActionsToggle) {
|
|
4583
|
-
mobileActionsToggle.addEventListener('click', function () {
|
|
4584
|
-
setMobileActionsMenu(!state.mobileActionsOpen);
|
|
4585
|
-
});
|
|
4586
|
-
}
|
|
4587
|
-
|
|
4588
4623
|
if (workspaceSwitcherToggle) {
|
|
4589
4624
|
workspaceSwitcherToggle.addEventListener('click', function () {
|
|
4590
4625
|
setWorkspaceSwitcherMenu(!state.workspaceSwitcherOpen);
|
|
@@ -4603,18 +4638,6 @@
|
|
|
4603
4638
|
});
|
|
4604
4639
|
}
|
|
4605
4640
|
|
|
4606
|
-
if (addAgentBtn) {
|
|
4607
|
-
addAgentBtn.addEventListener('click', function () {
|
|
4608
|
-
const activeSession = getActiveSession();
|
|
4609
|
-
const targetContainer = activeSession ? getSessionContainerName(activeSession) : '';
|
|
4610
|
-
if (!targetContainer) {
|
|
4611
|
-
return;
|
|
4612
|
-
}
|
|
4613
|
-
closeMobileActionsMenu();
|
|
4614
|
-
createAgentSession(targetContainer);
|
|
4615
|
-
});
|
|
4616
|
-
}
|
|
4617
|
-
|
|
4618
4641
|
if (configModal) {
|
|
4619
4642
|
configModal.addEventListener('click', function (event) {
|
|
4620
4643
|
if (event.target === configModal && !state.configSaving) {
|
|
@@ -4682,17 +4705,19 @@
|
|
|
4682
4705
|
if (event.key === 'Escape' && state.mobileSidebarOpen) {
|
|
4683
4706
|
closeMobileSessionPanel();
|
|
4684
4707
|
}
|
|
4685
|
-
if (event.key === 'Escape' && state.mobileActionsOpen) {
|
|
4686
|
-
closeMobileActionsMenu();
|
|
4687
|
-
}
|
|
4688
4708
|
if (event.key === 'Escape' && state.workspaceSwitcherOpen) {
|
|
4689
4709
|
closeWorkspaceSwitcherMenu();
|
|
4690
4710
|
}
|
|
4711
|
+
if (event.key === 'Escape' && state.composerOptionsOpen) {
|
|
4712
|
+
closeComposerOptionsMenu();
|
|
4713
|
+
}
|
|
4714
|
+
if (event.key === 'Escape' && openTreeNodeMenu) {
|
|
4715
|
+
closeOpenTreeNodeMenu();
|
|
4716
|
+
}
|
|
4691
4717
|
});
|
|
4692
4718
|
|
|
4693
4719
|
function onLayoutMediaChange() {
|
|
4694
4720
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
4695
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
4696
4721
|
if (state.activeTab === 'terminal' && state.terminal.terminalReady) {
|
|
4697
4722
|
scheduleTerminalFit(false);
|
|
4698
4723
|
}
|
|
@@ -4736,64 +4761,22 @@
|
|
|
4736
4761
|
|
|
4737
4762
|
document.addEventListener('click', function (event) {
|
|
4738
4763
|
const target = event.target;
|
|
4739
|
-
if (state.mobileActionsOpen) {
|
|
4740
|
-
if (mobileActionsToggle && mobileActionsToggle.contains(target)) return;
|
|
4741
|
-
if (headerActions && headerActions.contains(target)) return;
|
|
4742
|
-
closeMobileActionsMenu();
|
|
4743
|
-
}
|
|
4744
4764
|
if (state.workspaceSwitcherOpen) {
|
|
4745
4765
|
if (workspaceSwitcherToggle && workspaceSwitcherToggle.contains(target)) return;
|
|
4746
4766
|
if (workspaceSwitcherPanel && workspaceSwitcherPanel.contains(target)) return;
|
|
4747
4767
|
closeWorkspaceSwitcherMenu();
|
|
4748
4768
|
}
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
closeMobileActionsMenu();
|
|
4754
|
-
const activeSession = getActiveSession();
|
|
4755
|
-
const targetContainer = activeSession && activeSession.containerName ? activeSession.containerName : state.active;
|
|
4756
|
-
const yes = confirm('确认删除容器 ' + targetContainer + ' ?');
|
|
4757
|
-
if (!yes) return;
|
|
4758
|
-
try {
|
|
4759
|
-
const current = state.active;
|
|
4760
|
-
if (state.terminal.sessionName === current && (state.terminal.connected || state.terminal.connecting)) {
|
|
4761
|
-
disconnectTerminal('容器删除,终端已断开', true);
|
|
4762
|
-
}
|
|
4763
|
-
await api('/api/sessions/' + encodeURIComponent(current) + '/remove', {
|
|
4764
|
-
method: 'POST'
|
|
4765
|
-
});
|
|
4766
|
-
await loadSessions(current);
|
|
4767
|
-
} catch (e) {
|
|
4768
|
-
alert(e.message);
|
|
4769
|
+
if (state.composerOptionsOpen) {
|
|
4770
|
+
if (composerOptionsToggle && composerOptionsToggle.contains(target)) return;
|
|
4771
|
+
if (composerOptionsPanel && composerOptionsPanel.contains(target)) return;
|
|
4772
|
+
closeComposerOptionsMenu();
|
|
4769
4773
|
}
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
removeAllBtn.addEventListener('click', async function () {
|
|
4773
|
-
if (!state.active) return;
|
|
4774
|
-
closeMobileActionsMenu();
|
|
4775
|
-
const activeSession = getActiveSession();
|
|
4776
|
-
const targetAgent = activeSession && activeSession.agentName ? activeSession.agentName : state.active;
|
|
4777
|
-
const yes = confirm('确认删除 AGENT ' + targetAgent + ' ?');
|
|
4778
|
-
if (!yes) return;
|
|
4779
|
-
try {
|
|
4780
|
-
const current = state.active;
|
|
4781
|
-
const targetContainerName = activeSession && activeSession.containerName ? activeSession.containerName : '';
|
|
4782
|
-
const fallbackSessionName = findPreferredSessionNameAfterRemoval(state.sessions, current);
|
|
4783
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/remove-with-history', {
|
|
4784
|
-
method: 'POST'
|
|
4785
|
-
});
|
|
4786
|
-
await refreshSessions({
|
|
4787
|
-
preferredName: fallbackSessionName || '',
|
|
4788
|
-
preferredContainerName: targetContainerName,
|
|
4789
|
-
withLoading: true,
|
|
4790
|
-
reloadMessages: true
|
|
4791
|
-
});
|
|
4792
|
-
} catch (e) {
|
|
4793
|
-
alert(e.message);
|
|
4774
|
+
if (openTreeNodeMenu && !openTreeNodeMenu.wrap.contains(target)) {
|
|
4775
|
+
closeOpenTreeNodeMenu();
|
|
4794
4776
|
}
|
|
4795
4777
|
});
|
|
4796
4778
|
|
|
4779
|
+
|
|
4797
4780
|
if (externalLinkCancelBtn) {
|
|
4798
4781
|
externalLinkCancelBtn.addEventListener('click', function () {
|
|
4799
4782
|
closeExternalLinkModalView();
|