@qodalis/vue-cli 2.0.0-beta.10 → 2.0.0-beta.12
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/dist/index.d.mts +79 -3
- package/dist/index.d.ts +79 -3
- package/dist/index.js +473 -104
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +474 -104
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -129,6 +129,7 @@ import {
|
|
|
129
129
|
ref as ref2,
|
|
130
130
|
computed,
|
|
131
131
|
inject as inject2,
|
|
132
|
+
watch,
|
|
132
133
|
h as h2,
|
|
133
134
|
onMounted as onMounted2,
|
|
134
135
|
onBeforeUnmount as onBeforeUnmount2
|
|
@@ -256,38 +257,97 @@ var CliPanel = defineComponent3({
|
|
|
256
257
|
type: Function,
|
|
257
258
|
default: void 0
|
|
258
259
|
},
|
|
260
|
+
collapsed: { type: Boolean, default: void 0 },
|
|
261
|
+
hidden: { type: Boolean, default: void 0 },
|
|
262
|
+
maximized: { type: Boolean, default: void 0 },
|
|
263
|
+
activeTabId: { type: Number, default: void 0 },
|
|
264
|
+
position: { type: String, default: void 0 },
|
|
265
|
+
height: { type: Number, default: void 0 },
|
|
266
|
+
width: { type: Number, default: void 0 },
|
|
259
267
|
style: {
|
|
260
268
|
type: Object,
|
|
261
269
|
default: void 0
|
|
262
270
|
},
|
|
263
271
|
class: { type: String, default: void 0 }
|
|
264
272
|
},
|
|
265
|
-
|
|
273
|
+
emits: [
|
|
274
|
+
"update:collapsed",
|
|
275
|
+
"update:hidden",
|
|
276
|
+
"update:maximized",
|
|
277
|
+
"update:activeTabId",
|
|
278
|
+
"update:position",
|
|
279
|
+
"update:height",
|
|
280
|
+
"update:width",
|
|
281
|
+
"close",
|
|
282
|
+
"tab-added",
|
|
283
|
+
"tab-closed",
|
|
284
|
+
"pane-split",
|
|
285
|
+
"pane-closed"
|
|
286
|
+
],
|
|
287
|
+
setup(props, { expose, emit }) {
|
|
266
288
|
const config = inject2(CliConfigKey, null);
|
|
267
|
-
const mergedOptions = computed(() => props.options
|
|
289
|
+
const mergedOptions = computed(() => props.options ? { ...config?.options, ...props.options } : config?.options);
|
|
268
290
|
const mergedModules = computed(() => props.modules ?? config?.modules);
|
|
269
291
|
const mergedProcessors = computed(() => props.processors ?? config?.processors);
|
|
270
292
|
const mergedServices = computed(() => props.services ?? config?.services);
|
|
271
293
|
const visible = ref2(true);
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
const
|
|
294
|
+
const internalCollapsed = ref2(mergedOptions.value?.isCollapsed ?? true);
|
|
295
|
+
const internalMaximized = ref2(false);
|
|
296
|
+
const internalHeight = ref2(600);
|
|
297
|
+
const internalWidth = ref2(400);
|
|
276
298
|
const prevHeight = ref2(600);
|
|
277
299
|
const prevWidth = ref2(400);
|
|
278
300
|
const initialized = ref2(false);
|
|
279
|
-
const
|
|
301
|
+
const internalHidden = ref2(props.options?.isHidden ?? false);
|
|
280
302
|
let preHideCollapsed = true;
|
|
281
|
-
const
|
|
303
|
+
const internalActiveTabId = ref2(0);
|
|
304
|
+
const internalPosition = ref2(
|
|
305
|
+
loadPanelPosition() ?? mergedOptions.value?.position ?? "bottom"
|
|
306
|
+
);
|
|
307
|
+
const resolvedCollapsed = computed(() => props.collapsed !== void 0 ? props.collapsed : internalCollapsed.value);
|
|
308
|
+
const resolvedHidden = computed(() => props.hidden !== void 0 ? props.hidden : internalHidden.value);
|
|
309
|
+
const resolvedMaximized = computed(() => props.maximized !== void 0 ? props.maximized : internalMaximized.value);
|
|
310
|
+
const resolvedActiveTabId = computed(() => props.activeTabId !== void 0 ? props.activeTabId : internalActiveTabId.value);
|
|
311
|
+
const resolvedHeight = computed(() => props.height !== void 0 ? props.height : internalHeight.value);
|
|
312
|
+
const resolvedWidth = computed(() => props.width !== void 0 ? props.width : internalWidth.value);
|
|
313
|
+
const resolvedPosition = computed(() => props.position !== void 0 ? props.position : internalPosition.value);
|
|
314
|
+
function updateCollapsed(value) {
|
|
315
|
+
internalCollapsed.value = value;
|
|
316
|
+
emit("update:collapsed", value);
|
|
317
|
+
}
|
|
318
|
+
function updateHidden(value) {
|
|
319
|
+
internalHidden.value = value;
|
|
320
|
+
emit("update:hidden", value);
|
|
321
|
+
}
|
|
322
|
+
function updateMaximized(value) {
|
|
323
|
+
internalMaximized.value = value;
|
|
324
|
+
emit("update:maximized", value);
|
|
325
|
+
}
|
|
326
|
+
function updateActiveTabId(value) {
|
|
327
|
+
internalActiveTabId.value = value;
|
|
328
|
+
emit("update:activeTabId", value);
|
|
329
|
+
}
|
|
330
|
+
function updateHeight(value) {
|
|
331
|
+
internalHeight.value = value;
|
|
332
|
+
emit("update:height", value);
|
|
333
|
+
}
|
|
334
|
+
function updateWidth(value) {
|
|
335
|
+
internalWidth.value = value;
|
|
336
|
+
emit("update:width", value);
|
|
337
|
+
}
|
|
338
|
+
function updatePosition(value) {
|
|
339
|
+
internalPosition.value = value;
|
|
340
|
+
savePanelPosition(value);
|
|
341
|
+
emit("update:position", value);
|
|
342
|
+
}
|
|
282
343
|
const closable = computed(() => mergedOptions.value?.closable ?? true);
|
|
283
344
|
const resizable = computed(() => mergedOptions.value?.resizable ?? true);
|
|
284
|
-
const isHorizontal = computed(() =>
|
|
345
|
+
const isHorizontal = computed(() => resolvedPosition.value === "left" || resolvedPosition.value === "right");
|
|
285
346
|
const hideable = computed(() => mergedOptions.value?.hideable ?? true);
|
|
286
347
|
const hideAlignment = computed(() => mergedOptions.value?.hideAlignment ?? "center");
|
|
287
348
|
const syncTheme = computed(() => mergedOptions.value?.syncTheme ?? false);
|
|
288
349
|
const themeStyles = ref2({});
|
|
289
350
|
const tabs = ref2([]);
|
|
290
|
-
const activeTabId = ref2(0);
|
|
291
351
|
const activePaneId = ref2(0);
|
|
292
352
|
let nextTabId = 1;
|
|
293
353
|
let nextPaneId = 1;
|
|
@@ -308,19 +368,120 @@ var CliPanel = defineComponent3({
|
|
|
308
368
|
};
|
|
309
369
|
const panelResizing = ref2(false);
|
|
310
370
|
let panelResizeState = { startY: 0, startHeight: 0, startX: 0, startWidth: 0 };
|
|
311
|
-
|
|
312
|
-
|
|
371
|
+
const statusExecutionState = ref2("idle");
|
|
372
|
+
const statusLastCommand = ref2(null);
|
|
373
|
+
const statusServiceCount = ref2({ running: 0, total: 0 });
|
|
374
|
+
const statusServiceDetails = ref2([]);
|
|
375
|
+
const statusServerState = ref2("none");
|
|
376
|
+
const statusServerDetails = ref2([]);
|
|
377
|
+
const statusUptime = ref2(0);
|
|
378
|
+
const statusText = ref2(null);
|
|
379
|
+
const servicesDropdownOpen = ref2(false);
|
|
380
|
+
const serversDropdownOpen = ref2(false);
|
|
381
|
+
const servicesDropdownTriggerRect = ref2(null);
|
|
382
|
+
const serversDropdownTriggerRect = ref2(null);
|
|
383
|
+
const formattedUptime = computed(() => {
|
|
384
|
+
const mins = Math.floor(statusUptime.value / 6e4);
|
|
385
|
+
if (mins < 60) return `${mins}m`;
|
|
386
|
+
const hrs = Math.floor(mins / 60);
|
|
387
|
+
return `${hrs}h${mins % 60}m`;
|
|
388
|
+
});
|
|
389
|
+
let execPollTimer;
|
|
390
|
+
let globalPollTimer;
|
|
391
|
+
function startStatusPolling() {
|
|
392
|
+
stopStatusPolling();
|
|
393
|
+
execPollTimer = setInterval(() => {
|
|
394
|
+
const tab = tabs.value.find((t) => t.id === resolvedActiveTabId.value);
|
|
395
|
+
if (!tab) return;
|
|
396
|
+
const engine = engineMap.get(tab.panes[0]?.id);
|
|
397
|
+
if (!engine) return;
|
|
398
|
+
const context = engine.getContext();
|
|
399
|
+
if (!context) return;
|
|
400
|
+
const running = !!context.isExecuting || !!context.contextProcessor;
|
|
401
|
+
statusExecutionState.value = running ? "running" : "idle";
|
|
402
|
+
const result = context.lastCommandResult;
|
|
403
|
+
statusLastCommand.value = result ? { name: result.command, success: result.success } : null;
|
|
404
|
+
const text = context.getStatusText?.();
|
|
405
|
+
statusText.value = text || null;
|
|
406
|
+
}, 300);
|
|
407
|
+
globalPollTimer = setInterval(() => {
|
|
408
|
+
const tab = tabs.value.find((t) => t.id === resolvedActiveTabId.value);
|
|
409
|
+
if (!tab) return;
|
|
410
|
+
const engine = engineMap.get(tab.panes[0]?.id);
|
|
411
|
+
if (!engine) return;
|
|
412
|
+
const context = engine.getContext();
|
|
413
|
+
if (!context) return;
|
|
414
|
+
try {
|
|
415
|
+
const services = context.backgroundServices?.list() ?? [];
|
|
416
|
+
statusServiceCount.value = { running: services.filter((s) => s.status === "running").length, total: services.length };
|
|
417
|
+
statusServiceDetails.value = services.map((s) => ({ name: s.name, status: s.status, description: s.description }));
|
|
418
|
+
} catch {
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
const serverManager = context.services?.get?.("cli-server-manager");
|
|
422
|
+
const details = [];
|
|
423
|
+
if (serverManager?.connections?.size > 0) {
|
|
424
|
+
let anyConnected = false;
|
|
425
|
+
for (const [name, conn] of serverManager.connections) {
|
|
426
|
+
if (conn.connected) anyConnected = true;
|
|
427
|
+
details.push({
|
|
428
|
+
name,
|
|
429
|
+
url: conn.config?.url ?? "",
|
|
430
|
+
connected: !!conn.connected,
|
|
431
|
+
apiVersion: conn.connected ? conn.apiVersion : void 0,
|
|
432
|
+
commandCount: conn.connected ? conn.commands?.length : void 0
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
statusServerState.value = anyConnected ? "connected" : "disconnected";
|
|
436
|
+
} else {
|
|
437
|
+
const configuredServers = engine.options?.servers;
|
|
438
|
+
if (Array.isArray(configuredServers) && configuredServers.length > 0) {
|
|
439
|
+
for (const srv of configuredServers) {
|
|
440
|
+
if (srv.enabled === false) continue;
|
|
441
|
+
details.push({
|
|
442
|
+
name: srv.name,
|
|
443
|
+
url: srv.url ?? "",
|
|
444
|
+
connected: false
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
statusServerState.value = "disconnected";
|
|
448
|
+
} else {
|
|
449
|
+
statusServerState.value = "none";
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
statusServerDetails.value = details;
|
|
453
|
+
} catch {
|
|
454
|
+
}
|
|
455
|
+
statusUptime.value = engine.startedAt ? Date.now() - engine.startedAt : 0;
|
|
456
|
+
}, 2e3);
|
|
457
|
+
}
|
|
458
|
+
function stopStatusPolling() {
|
|
459
|
+
if (execPollTimer) {
|
|
460
|
+
clearInterval(execPollTimer);
|
|
461
|
+
execPollTimer = void 0;
|
|
462
|
+
}
|
|
463
|
+
if (globalPollTimer) {
|
|
464
|
+
clearInterval(globalPollTimer);
|
|
465
|
+
globalPollTimer = void 0;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
watch(initialized, (val) => {
|
|
469
|
+
if (val) startStatusPolling();
|
|
470
|
+
else stopStatusPolling();
|
|
471
|
+
});
|
|
472
|
+
function addTab(title) {
|
|
313
473
|
const tabId = nextTabId++;
|
|
314
|
-
const
|
|
315
|
-
|
|
474
|
+
const paneId = nextPaneId++;
|
|
475
|
+
tabs.value = [...tabs.value, {
|
|
316
476
|
id: tabId,
|
|
317
|
-
title: `Terminal ${tabId}`,
|
|
477
|
+
title: title ?? `Terminal ${tabId}`,
|
|
318
478
|
isEditing: false,
|
|
319
|
-
panes: [
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
activeTabId.value = tabId;
|
|
479
|
+
panes: [{ id: paneId, widthPercent: 100 }]
|
|
480
|
+
}];
|
|
481
|
+
updateActiveTabId(tabId);
|
|
323
482
|
activePaneId.value = paneId;
|
|
483
|
+
emit("tab-added", { tabId });
|
|
484
|
+
return tabId;
|
|
324
485
|
}
|
|
325
486
|
let themeObserver;
|
|
326
487
|
function syncThemeFromEngine() {
|
|
@@ -348,8 +509,9 @@ var CliPanel = defineComponent3({
|
|
|
348
509
|
document.removeEventListener("click", closePositionDropdown);
|
|
349
510
|
});
|
|
350
511
|
function toggle() {
|
|
351
|
-
|
|
352
|
-
|
|
512
|
+
const newVal = !resolvedCollapsed.value;
|
|
513
|
+
updateCollapsed(newVal);
|
|
514
|
+
if (!newVal && !initialized.value) {
|
|
353
515
|
initialized.value = true;
|
|
354
516
|
addTab();
|
|
355
517
|
setupThemeSync();
|
|
@@ -359,58 +521,65 @@ var CliPanel = defineComponent3({
|
|
|
359
521
|
const idx = tabs.value.findIndex((t) => t.id === id);
|
|
360
522
|
if (idx === -1) return;
|
|
361
523
|
tabs.value.splice(idx, 1);
|
|
524
|
+
emit("tab-closed", { tabId: id });
|
|
362
525
|
if (tabs.value.length === 0) {
|
|
363
526
|
initialized.value = false;
|
|
364
|
-
|
|
527
|
+
updateCollapsed(true);
|
|
365
528
|
return;
|
|
366
529
|
}
|
|
367
|
-
if (
|
|
530
|
+
if (resolvedActiveTabId.value === id) {
|
|
368
531
|
const newIdx = Math.min(idx, tabs.value.length - 1);
|
|
369
532
|
selectTab(tabs.value[newIdx].id);
|
|
370
533
|
}
|
|
371
534
|
}
|
|
372
535
|
function selectTab(id) {
|
|
373
|
-
|
|
536
|
+
updateActiveTabId(id);
|
|
374
537
|
const tab = tabs.value.find((t) => t.id === id);
|
|
375
538
|
if (tab && tab.panes.length > 0) {
|
|
376
539
|
activePaneId.value = tab.panes[0].id;
|
|
377
540
|
}
|
|
378
541
|
}
|
|
379
|
-
function
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
542
|
+
function splitPane(tabId) {
|
|
543
|
+
const targetTabId = tabId ?? resolvedActiveTabId.value;
|
|
544
|
+
const paneId = nextPaneId++;
|
|
545
|
+
tabs.value = tabs.value.map((t) => {
|
|
546
|
+
if (t.id !== targetTabId) return t;
|
|
547
|
+
const newPanes = [...t.panes, { id: paneId, widthPercent: 0 }];
|
|
548
|
+
const evenWidth = 100 / newPanes.length;
|
|
549
|
+
newPanes.forEach((p) => {
|
|
550
|
+
p.widthPercent = evenWidth;
|
|
551
|
+
});
|
|
552
|
+
normalizePanes(newPanes);
|
|
553
|
+
return { ...t, panes: newPanes };
|
|
391
554
|
});
|
|
392
|
-
|
|
393
|
-
|
|
555
|
+
activePaneId.value = paneId;
|
|
556
|
+
emit("pane-split", { paneId, tabId: targetTabId });
|
|
557
|
+
return paneId;
|
|
394
558
|
}
|
|
395
|
-
function closePane(
|
|
396
|
-
const tab
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
559
|
+
function closePane(paneId) {
|
|
560
|
+
for (const tab of tabs.value) {
|
|
561
|
+
const idx = tab.panes.findIndex((p) => p.id === paneId);
|
|
562
|
+
if (idx === -1) continue;
|
|
563
|
+
if (tab.panes.length <= 1) {
|
|
564
|
+
closeTab(tab.id);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
engineMap.get(paneId)?.destroy();
|
|
568
|
+
engineMap.delete(paneId);
|
|
569
|
+
const newPanes = tab.panes.filter((p) => p.id !== paneId);
|
|
570
|
+
normalizePanes(newPanes);
|
|
571
|
+
if (activePaneId.value === paneId) {
|
|
572
|
+
activePaneId.value = newPanes[Math.min(idx, newPanes.length - 1)].id;
|
|
573
|
+
}
|
|
574
|
+
emit("pane-closed", { paneId });
|
|
575
|
+
tabs.value = tabs.value.map(
|
|
576
|
+
(t) => t.id === tab.id ? { ...t, panes: newPanes } : t
|
|
577
|
+
);
|
|
400
578
|
return;
|
|
401
579
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const total = tab.panes.reduce((s, p) => s + p.widthPercent, 0);
|
|
406
|
-
if (total > 0)
|
|
407
|
-
tab.panes.forEach((p) => {
|
|
408
|
-
p.widthPercent = p.widthPercent / total * 100;
|
|
409
|
-
});
|
|
410
|
-
normalizePanes(tab.panes);
|
|
411
|
-
if (activePaneId.value === paneId) {
|
|
412
|
-
activePaneId.value = tab.panes[Math.min(idx, tab.panes.length - 1)].id;
|
|
413
|
-
}
|
|
580
|
+
}
|
|
581
|
+
function renameTab(tabId, title) {
|
|
582
|
+
tabs.value = tabs.value.map((t) => t.id === tabId ? { ...t, title } : t);
|
|
414
583
|
}
|
|
415
584
|
function startRename(tabId) {
|
|
416
585
|
tabs.value.forEach((t) => {
|
|
@@ -438,27 +607,27 @@ var CliPanel = defineComponent3({
|
|
|
438
607
|
function onPanelResizeStart(e) {
|
|
439
608
|
if (!resizable.value) return;
|
|
440
609
|
e.preventDefault();
|
|
441
|
-
if (
|
|
610
|
+
if (resolvedCollapsed.value) toggle();
|
|
442
611
|
panelResizing.value = true;
|
|
443
612
|
panelResizeState = {
|
|
444
613
|
startY: e.clientY,
|
|
445
|
-
startHeight:
|
|
614
|
+
startHeight: resolvedHeight.value,
|
|
446
615
|
startX: e.clientX,
|
|
447
|
-
startWidth:
|
|
616
|
+
startWidth: resolvedWidth.value
|
|
448
617
|
};
|
|
449
618
|
}
|
|
450
619
|
function onPanelResizeMove(e) {
|
|
451
620
|
if (!panelResizing.value) return;
|
|
452
621
|
if (isHorizontal.value) {
|
|
453
|
-
const deltaX =
|
|
622
|
+
const deltaX = resolvedPosition.value === "left" ? e.clientX - panelResizeState.startX : panelResizeState.startX - e.clientX;
|
|
454
623
|
let next = Math.max(100, panelResizeState.startWidth + deltaX);
|
|
455
624
|
if (next > window.innerWidth) next = window.innerWidth;
|
|
456
|
-
|
|
625
|
+
updateWidth(next);
|
|
457
626
|
} else {
|
|
458
|
-
const deltaY =
|
|
627
|
+
const deltaY = resolvedPosition.value === "top" ? e.clientY - panelResizeState.startY : panelResizeState.startY - e.clientY;
|
|
459
628
|
let next = Math.max(100, panelResizeState.startHeight + deltaY);
|
|
460
629
|
if (next > window.innerHeight) next = window.innerHeight;
|
|
461
|
-
|
|
630
|
+
updateHeight(next);
|
|
462
631
|
}
|
|
463
632
|
}
|
|
464
633
|
function onPanelResizeEnd() {
|
|
@@ -522,40 +691,44 @@ var CliPanel = defineComponent3({
|
|
|
522
691
|
onBeforeUnmount2(() => {
|
|
523
692
|
document.removeEventListener("mousemove", onPaneResizeMove);
|
|
524
693
|
document.removeEventListener("mouseup", onPaneResizeEnd);
|
|
694
|
+
stopStatusPolling();
|
|
525
695
|
});
|
|
526
696
|
function toggleMaximize() {
|
|
527
|
-
if (!
|
|
697
|
+
if (!resolvedMaximized.value) {
|
|
528
698
|
if (isHorizontal.value) {
|
|
529
|
-
prevWidth.value =
|
|
530
|
-
|
|
699
|
+
prevWidth.value = resolvedWidth.value;
|
|
700
|
+
updateWidth(window.innerWidth);
|
|
531
701
|
} else {
|
|
532
|
-
prevHeight.value =
|
|
533
|
-
|
|
702
|
+
prevHeight.value = resolvedHeight.value;
|
|
703
|
+
updateHeight(window.innerHeight);
|
|
534
704
|
}
|
|
535
705
|
} else {
|
|
536
706
|
if (isHorizontal.value) {
|
|
537
|
-
|
|
707
|
+
updateWidth(prevWidth.value);
|
|
538
708
|
} else {
|
|
539
|
-
|
|
709
|
+
updateHeight(prevHeight.value);
|
|
540
710
|
}
|
|
541
711
|
}
|
|
542
|
-
|
|
712
|
+
updateMaximized(!resolvedMaximized.value);
|
|
543
713
|
}
|
|
544
714
|
function handleClose() {
|
|
545
715
|
visible.value = false;
|
|
716
|
+
emit("close");
|
|
546
717
|
props.onClose?.();
|
|
547
718
|
}
|
|
548
719
|
function handleHide() {
|
|
549
|
-
preHideCollapsed =
|
|
550
|
-
|
|
720
|
+
preHideCollapsed = resolvedCollapsed.value;
|
|
721
|
+
updateHidden(true);
|
|
551
722
|
}
|
|
552
723
|
function handleUnhide() {
|
|
553
|
-
|
|
554
|
-
|
|
724
|
+
updateHidden(false);
|
|
725
|
+
updateCollapsed(preHideCollapsed);
|
|
555
726
|
}
|
|
556
727
|
const positionDropdownOpen = ref2(false);
|
|
557
728
|
function closePositionDropdown() {
|
|
558
729
|
positionDropdownOpen.value = false;
|
|
730
|
+
servicesDropdownOpen.value = false;
|
|
731
|
+
serversDropdownOpen.value = false;
|
|
559
732
|
}
|
|
560
733
|
function togglePositionDropdown(e) {
|
|
561
734
|
e.stopPropagation();
|
|
@@ -563,21 +736,106 @@ var CliPanel = defineComponent3({
|
|
|
563
736
|
}
|
|
564
737
|
function selectPosition(pos) {
|
|
565
738
|
positionDropdownOpen.value = false;
|
|
566
|
-
|
|
567
|
-
savePanelPosition(pos);
|
|
739
|
+
updatePosition(pos);
|
|
568
740
|
}
|
|
741
|
+
function getEngine(paneId) {
|
|
742
|
+
const targetId = paneId ?? activePaneId.value;
|
|
743
|
+
return engineMap.get(targetId);
|
|
744
|
+
}
|
|
745
|
+
function getState() {
|
|
746
|
+
return {
|
|
747
|
+
collapsed: resolvedCollapsed.value,
|
|
748
|
+
hidden: resolvedHidden.value,
|
|
749
|
+
maximized: resolvedMaximized.value,
|
|
750
|
+
position: resolvedPosition.value,
|
|
751
|
+
height: resolvedHeight.value,
|
|
752
|
+
width: resolvedWidth.value,
|
|
753
|
+
activeTabId: resolvedActiveTabId.value,
|
|
754
|
+
activePaneId: activePaneId.value,
|
|
755
|
+
tabs: tabs.value.map((t) => ({
|
|
756
|
+
id: t.id,
|
|
757
|
+
title: t.title,
|
|
758
|
+
panes: t.panes.map((p) => ({ id: p.id, widthPercent: p.widthPercent }))
|
|
759
|
+
}))
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
expose({
|
|
763
|
+
open: () => {
|
|
764
|
+
if (!visible.value) {
|
|
765
|
+
visible.value = true;
|
|
766
|
+
}
|
|
767
|
+
if (resolvedHidden.value) {
|
|
768
|
+
updateHidden(false);
|
|
769
|
+
}
|
|
770
|
+
if (resolvedCollapsed.value) {
|
|
771
|
+
updateCollapsed(false);
|
|
772
|
+
if (!initialized.value) {
|
|
773
|
+
initialized.value = true;
|
|
774
|
+
addTab();
|
|
775
|
+
setupThemeSync();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
},
|
|
779
|
+
collapse: () => {
|
|
780
|
+
if (!resolvedCollapsed.value) updateCollapsed(true);
|
|
781
|
+
},
|
|
782
|
+
toggleCollapse: () => {
|
|
783
|
+
if (resolvedCollapsed.value) {
|
|
784
|
+
updateCollapsed(false);
|
|
785
|
+
if (!initialized.value) {
|
|
786
|
+
initialized.value = true;
|
|
787
|
+
addTab();
|
|
788
|
+
setupThemeSync();
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
updateCollapsed(true);
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
hide: () => {
|
|
795
|
+
if (!resolvedHidden.value) updateHidden(true);
|
|
796
|
+
},
|
|
797
|
+
unhide: () => {
|
|
798
|
+
if (resolvedHidden.value) updateHidden(false);
|
|
799
|
+
},
|
|
800
|
+
toggleHide: () => {
|
|
801
|
+
updateHidden(!resolvedHidden.value);
|
|
802
|
+
},
|
|
803
|
+
close: handleClose,
|
|
804
|
+
maximize: () => {
|
|
805
|
+
if (!resolvedMaximized.value) updateMaximized(true);
|
|
806
|
+
},
|
|
807
|
+
restore: () => {
|
|
808
|
+
if (resolvedMaximized.value) updateMaximized(false);
|
|
809
|
+
},
|
|
810
|
+
toggleMaximize: () => {
|
|
811
|
+
updateMaximized(!resolvedMaximized.value);
|
|
812
|
+
},
|
|
813
|
+
resize: (dims) => {
|
|
814
|
+
if (dims.height !== void 0) updateHeight(dims.height);
|
|
815
|
+
if (dims.width !== void 0) updateWidth(dims.width);
|
|
816
|
+
},
|
|
817
|
+
setPosition: updatePosition,
|
|
818
|
+
addTab,
|
|
819
|
+
closeTab,
|
|
820
|
+
selectTab,
|
|
821
|
+
renameTab,
|
|
822
|
+
splitPane,
|
|
823
|
+
closePane,
|
|
824
|
+
getEngine,
|
|
825
|
+
getState
|
|
826
|
+
});
|
|
569
827
|
return () => {
|
|
570
828
|
if (!visible.value) return null;
|
|
571
829
|
const wrapperClass = [
|
|
572
830
|
"cli-panel-wrapper",
|
|
573
|
-
|
|
574
|
-
|
|
831
|
+
resolvedCollapsed.value && "collapsed",
|
|
832
|
+
resolvedMaximized.value && "maximized",
|
|
575
833
|
panelResizing.value && "resizing",
|
|
576
834
|
props.class
|
|
577
835
|
].filter(Boolean).join(" ");
|
|
578
836
|
const wrapperStyle = {
|
|
579
|
-
...isHorizontal.value ? { width: `${
|
|
580
|
-
...
|
|
837
|
+
...isHorizontal.value ? { width: `${resolvedWidth.value}px` } : { height: `${resolvedHeight.value}px` },
|
|
838
|
+
...resolvedHidden.value ? { display: "none" } : {},
|
|
581
839
|
...themeStyles.value,
|
|
582
840
|
...props.style
|
|
583
841
|
};
|
|
@@ -597,6 +855,54 @@ var CliPanel = defineComponent3({
|
|
|
597
855
|
]),
|
|
598
856
|
"CLI"
|
|
599
857
|
]),
|
|
858
|
+
// Status indicators (bottom/top only)
|
|
859
|
+
resolvedPosition.value === "bottom" || resolvedPosition.value === "top" ? h2("div", { class: "cli-panel-status-indicators" }, [
|
|
860
|
+
// Execution state
|
|
861
|
+
h2("span", { class: ["cli-panel-status-item", statusExecutionState.value === "running" ? "status-running" : ""].filter(Boolean).join(" ") }, [
|
|
862
|
+
h2("span", { class: ["cli-panel-status-dot", statusExecutionState.value === "running" ? "dot-running" : "dot-idle"].join(" ") }),
|
|
863
|
+
h2("span", { class: "cli-panel-status-label" }, statusExecutionState.value)
|
|
864
|
+
]),
|
|
865
|
+
// Background services
|
|
866
|
+
statusServiceCount.value.total > 0 ? h2("span", {
|
|
867
|
+
class: "cli-panel-status-item status-clickable",
|
|
868
|
+
onClick: (e) => {
|
|
869
|
+
e.stopPropagation();
|
|
870
|
+
servicesDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
|
|
871
|
+
servicesDropdownOpen.value = !servicesDropdownOpen.value;
|
|
872
|
+
serversDropdownOpen.value = false;
|
|
873
|
+
}
|
|
874
|
+
}, [
|
|
875
|
+
h2("span", { class: "cli-panel-status-icon", innerHTML: "⚙" }),
|
|
876
|
+
h2("span", { class: "cli-panel-status-label" }, `${statusServiceCount.value.running}/${statusServiceCount.value.total} services`)
|
|
877
|
+
]) : null,
|
|
878
|
+
// Last command
|
|
879
|
+
statusLastCommand.value ? h2("span", { class: "cli-panel-status-item" }, [
|
|
880
|
+
h2("span", { class: ["cli-panel-status-icon", statusLastCommand.value.success ? "status-success" : "status-error"].join(" "), innerHTML: statusLastCommand.value.success ? "✓" : "✕" }),
|
|
881
|
+
h2("span", { class: "cli-panel-status-label" }, statusLastCommand.value.name)
|
|
882
|
+
]) : null,
|
|
883
|
+
// Server connection
|
|
884
|
+
statusServerState.value !== "none" ? h2("span", {
|
|
885
|
+
class: "cli-panel-status-item status-clickable",
|
|
886
|
+
onClick: (e) => {
|
|
887
|
+
e.stopPropagation();
|
|
888
|
+
serversDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
|
|
889
|
+
serversDropdownOpen.value = !serversDropdownOpen.value;
|
|
890
|
+
servicesDropdownOpen.value = false;
|
|
891
|
+
}
|
|
892
|
+
}, [
|
|
893
|
+
h2("span", { class: ["cli-panel-status-dot", statusServerState.value === "connected" ? "dot-idle" : "dot-error"].join(" ") }),
|
|
894
|
+
h2("span", { class: "cli-panel-status-label" }, `${statusServerDetails.value.filter((s) => s.connected).length}/${statusServerDetails.value.length} servers`)
|
|
895
|
+
]) : null,
|
|
896
|
+
// Uptime
|
|
897
|
+
statusUptime.value > 0 ? h2("span", { class: "cli-panel-status-item status-muted" }, [
|
|
898
|
+
h2("span", { class: "cli-panel-status-icon", innerHTML: "↑" }),
|
|
899
|
+
h2("span", { class: "cli-panel-status-label" }, formattedUptime.value)
|
|
900
|
+
]) : null,
|
|
901
|
+
// Custom status text
|
|
902
|
+
statusText.value ? h2("span", { class: "cli-panel-status-item status-text" }, [
|
|
903
|
+
h2("span", { class: "cli-panel-status-label" }, statusText.value)
|
|
904
|
+
]) : null
|
|
905
|
+
].filter(Boolean)) : null,
|
|
600
906
|
h2("div", { class: "cli-panel-action-buttons" }, [
|
|
601
907
|
h2("div", {
|
|
602
908
|
class: "cli-panel-btn-position-wrapper",
|
|
@@ -606,13 +912,13 @@ var CliPanel = defineComponent3({
|
|
|
606
912
|
class: "cli-panel-btn cli-panel-btn-position",
|
|
607
913
|
title: "Move panel",
|
|
608
914
|
onClick: togglePositionDropdown
|
|
609
|
-
}, [positionIcon(
|
|
915
|
+
}, [positionIcon(resolvedPosition.value)]),
|
|
610
916
|
positionDropdownOpen.value ? h2(
|
|
611
917
|
"div",
|
|
612
918
|
{ class: "cli-panel-position-dropdown" },
|
|
613
919
|
["bottom", "top", "left", "right"].map(
|
|
614
920
|
(pos) => h2("button", {
|
|
615
|
-
class: ["cli-panel-position-dropdown-item",
|
|
921
|
+
class: ["cli-panel-position-dropdown-item", resolvedPosition.value === pos ? "active" : ""].filter(Boolean).join(" "),
|
|
616
922
|
onClick: () => selectPosition(pos)
|
|
617
923
|
}, [
|
|
618
924
|
positionIcon(pos, 16),
|
|
@@ -630,20 +936,20 @@ var CliPanel = defineComponent3({
|
|
|
630
936
|
"button",
|
|
631
937
|
{
|
|
632
938
|
class: "cli-panel-btn",
|
|
633
|
-
title:
|
|
634
|
-
disabled:
|
|
939
|
+
title: resolvedMaximized.value ? "Restore" : "Maximize",
|
|
940
|
+
disabled: resolvedCollapsed.value,
|
|
635
941
|
onClick: toggleMaximize
|
|
636
942
|
},
|
|
637
|
-
[
|
|
943
|
+
[resolvedMaximized.value ? restoreIcon() : maximizeIcon()]
|
|
638
944
|
),
|
|
639
945
|
h2(
|
|
640
946
|
"button",
|
|
641
947
|
{
|
|
642
948
|
class: "cli-panel-btn",
|
|
643
|
-
title:
|
|
949
|
+
title: resolvedCollapsed.value ? "Expand" : "Collapse",
|
|
644
950
|
onClick: toggle
|
|
645
951
|
},
|
|
646
|
-
[collapseChevron(
|
|
952
|
+
[collapseChevron(resolvedPosition.value, resolvedCollapsed.value)]
|
|
647
953
|
),
|
|
648
954
|
closable.value ? h2(
|
|
649
955
|
"button",
|
|
@@ -655,9 +961,10 @@ var CliPanel = defineComponent3({
|
|
|
655
961
|
[closeIcon()]
|
|
656
962
|
) : null
|
|
657
963
|
])
|
|
658
|
-
])
|
|
964
|
+
]),
|
|
965
|
+
h2("div", { class: ["cli-panel-glow-line", statusExecutionState.value === "running" ? "glow-active" : ""].filter(Boolean).join(" ") })
|
|
659
966
|
]);
|
|
660
|
-
const contentEl = initialized.value ? h2("div", { class: "cli-panel-content", style:
|
|
967
|
+
const contentEl = initialized.value ? h2("div", { class: "cli-panel-content", style: resolvedCollapsed.value ? { display: "none" } : void 0 }, [
|
|
661
968
|
// Tab bar
|
|
662
969
|
h2("div", { class: "cli-panel-tabs" }, [
|
|
663
970
|
h2(
|
|
@@ -670,7 +977,7 @@ var CliPanel = defineComponent3({
|
|
|
670
977
|
key: tab.id,
|
|
671
978
|
class: [
|
|
672
979
|
"cli-panel-tab",
|
|
673
|
-
tab.id ===
|
|
980
|
+
tab.id === resolvedActiveTabId.value && "active"
|
|
674
981
|
].filter(Boolean).join(" "),
|
|
675
982
|
onClick: () => selectTab(tab.id),
|
|
676
983
|
onDblclick: () => startRename(tab.id),
|
|
@@ -708,6 +1015,12 @@ var CliPanel = defineComponent3({
|
|
|
708
1015
|
onDblclick: (e) => e.stopPropagation()
|
|
709
1016
|
})
|
|
710
1017
|
] : [
|
|
1018
|
+
h2("span", { class: ["cli-panel-tab-dot", (() => {
|
|
1019
|
+
if (tab.id !== resolvedActiveTabId.value) return "dot-idle";
|
|
1020
|
+
if (statusExecutionState.value === "running") return "dot-running";
|
|
1021
|
+
if (statusLastCommand.value && !statusLastCommand.value.success) return "dot-error";
|
|
1022
|
+
return "dot-idle";
|
|
1023
|
+
})()].join(" ") }),
|
|
711
1024
|
h2(
|
|
712
1025
|
"span",
|
|
713
1026
|
{
|
|
@@ -738,7 +1051,7 @@ var CliPanel = defineComponent3({
|
|
|
738
1051
|
{
|
|
739
1052
|
class: "cli-panel-add-tab",
|
|
740
1053
|
title: "New terminal",
|
|
741
|
-
onClick: addTab
|
|
1054
|
+
onClick: () => addTab()
|
|
742
1055
|
},
|
|
743
1056
|
"+"
|
|
744
1057
|
)
|
|
@@ -754,7 +1067,7 @@ var CliPanel = defineComponent3({
|
|
|
754
1067
|
key: tab.id,
|
|
755
1068
|
class: "cli-panel-instance",
|
|
756
1069
|
style: {
|
|
757
|
-
display: tab.id ===
|
|
1070
|
+
display: tab.id === resolvedActiveTabId.value ? void 0 : "none"
|
|
758
1071
|
}
|
|
759
1072
|
},
|
|
760
1073
|
[
|
|
@@ -794,7 +1107,7 @@ var CliPanel = defineComponent3({
|
|
|
794
1107
|
{
|
|
795
1108
|
class: [
|
|
796
1109
|
"cli-panel-pane",
|
|
797
|
-
pane.id === activePaneId.value && tab.id ===
|
|
1110
|
+
pane.id === activePaneId.value && tab.id === resolvedActiveTabId.value && "active-pane"
|
|
798
1111
|
].filter(
|
|
799
1112
|
Boolean
|
|
800
1113
|
).join(" "),
|
|
@@ -803,7 +1116,7 @@ var CliPanel = defineComponent3({
|
|
|
803
1116
|
},
|
|
804
1117
|
onClick: () => {
|
|
805
1118
|
activePaneId.value = pane.id;
|
|
806
|
-
|
|
1119
|
+
updateActiveTabId(tab.id);
|
|
807
1120
|
}
|
|
808
1121
|
},
|
|
809
1122
|
[
|
|
@@ -815,7 +1128,6 @@ var CliPanel = defineComponent3({
|
|
|
815
1128
|
onClick: (e) => {
|
|
816
1129
|
e.stopPropagation();
|
|
817
1130
|
closePane(
|
|
818
|
-
tab.id,
|
|
819
1131
|
pane.id
|
|
820
1132
|
);
|
|
821
1133
|
}
|
|
@@ -891,7 +1203,7 @@ var CliPanel = defineComponent3({
|
|
|
891
1203
|
{ id: paneId, widthPercent: 100, snapshot }
|
|
892
1204
|
]
|
|
893
1205
|
});
|
|
894
|
-
|
|
1206
|
+
updateActiveTabId(tabId);
|
|
895
1207
|
activePaneId.value = paneId;
|
|
896
1208
|
}
|
|
897
1209
|
},
|
|
@@ -903,7 +1215,7 @@ var CliPanel = defineComponent3({
|
|
|
903
1215
|
class: "cli-panel-context-menu-item",
|
|
904
1216
|
onClick: () => {
|
|
905
1217
|
closeContextMenu();
|
|
906
|
-
|
|
1218
|
+
splitPane(contextMenu.value.tabId);
|
|
907
1219
|
}
|
|
908
1220
|
},
|
|
909
1221
|
"Split Right"
|
|
@@ -933,7 +1245,7 @@ var CliPanel = defineComponent3({
|
|
|
933
1245
|
tabs.value = tabs.value.filter(
|
|
934
1246
|
(t) => t.id === id
|
|
935
1247
|
);
|
|
936
|
-
|
|
1248
|
+
updateActiveTabId(id);
|
|
937
1249
|
}
|
|
938
1250
|
},
|
|
939
1251
|
"Close Others"
|
|
@@ -968,16 +1280,16 @@ var CliPanel = defineComponent3({
|
|
|
968
1280
|
closeContextMenu();
|
|
969
1281
|
tabs.value = [];
|
|
970
1282
|
initialized.value = false;
|
|
971
|
-
|
|
1283
|
+
updateCollapsed(true);
|
|
972
1284
|
}
|
|
973
1285
|
},
|
|
974
1286
|
"Close All"
|
|
975
1287
|
)
|
|
976
1288
|
]
|
|
977
1289
|
) : null;
|
|
978
|
-
const hideTabEl =
|
|
1290
|
+
const hideTabEl = resolvedHidden.value ? h2("button", {
|
|
979
1291
|
class: "cli-panel-hide-tab",
|
|
980
|
-
"data-position":
|
|
1292
|
+
"data-position": resolvedPosition.value,
|
|
981
1293
|
"data-hide-align": hideAlignment.value,
|
|
982
1294
|
style: themeStyles.value,
|
|
983
1295
|
title: "Show CLI",
|
|
@@ -988,8 +1300,64 @@ var CliPanel = defineComponent3({
|
|
|
988
1300
|
h2("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
989
1301
|
]),
|
|
990
1302
|
h2("span", { class: "cli-panel-hide-tab-label" }, "CLI"),
|
|
991
|
-
hideTabChevron(
|
|
1303
|
+
hideTabChevron(resolvedPosition.value)
|
|
992
1304
|
]) : null;
|
|
1305
|
+
const servicesDropdownEl = servicesDropdownOpen.value && statusServiceCount.value.total > 0 ? h2("div", {
|
|
1306
|
+
class: "cli-panel-services-dropdown",
|
|
1307
|
+
style: (() => {
|
|
1308
|
+
const rect = servicesDropdownTriggerRect.value;
|
|
1309
|
+
if (!rect) return {};
|
|
1310
|
+
return resolvedPosition.value === "top" ? { position: "fixed", top: `${rect.bottom + 4}px`, left: `${rect.left}px`, zIndex: 1100 } : { position: "fixed", bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px`, zIndex: 1100 };
|
|
1311
|
+
})(),
|
|
1312
|
+
onClick: (e) => e.stopPropagation()
|
|
1313
|
+
}, [
|
|
1314
|
+
h2("div", { class: "cli-panel-services-dropdown-header" }, "Background Services"),
|
|
1315
|
+
h2(
|
|
1316
|
+
"div",
|
|
1317
|
+
{ class: "cli-panel-services-dropdown-list" },
|
|
1318
|
+
statusServiceDetails.value.map(
|
|
1319
|
+
(svc, i) => h2("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
|
|
1320
|
+
h2("span", { class: ["cli-panel-svc-dot", svc.status === "running" ? "svc-running" : "svc-stopped"].join(" ") }),
|
|
1321
|
+
h2("div", { class: "cli-panel-svc-info" }, [
|
|
1322
|
+
h2("span", { class: "cli-panel-svc-name" }, svc.name),
|
|
1323
|
+
svc.description ? h2("span", { class: "cli-panel-svc-desc" }, svc.description) : null
|
|
1324
|
+
].filter(Boolean)),
|
|
1325
|
+
h2("span", { class: "cli-panel-svc-status" }, svc.status)
|
|
1326
|
+
])
|
|
1327
|
+
)
|
|
1328
|
+
),
|
|
1329
|
+
statusServiceDetails.value.length === 0 ? h2("div", { class: "cli-panel-services-dropdown-empty" }, "No services registered") : null
|
|
1330
|
+
].filter(Boolean)) : null;
|
|
1331
|
+
const serversDropdownEl = serversDropdownOpen.value && statusServerState.value !== "none" ? h2("div", {
|
|
1332
|
+
class: "cli-panel-services-dropdown",
|
|
1333
|
+
style: (() => {
|
|
1334
|
+
const rect = serversDropdownTriggerRect.value;
|
|
1335
|
+
if (!rect) return {};
|
|
1336
|
+
return resolvedPosition.value === "top" ? { position: "fixed", top: `${rect.bottom + 4}px`, left: `${rect.left}px`, zIndex: 1100 } : { position: "fixed", bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px`, zIndex: 1100 };
|
|
1337
|
+
})(),
|
|
1338
|
+
onClick: (e) => e.stopPropagation()
|
|
1339
|
+
}, [
|
|
1340
|
+
h2("div", { class: "cli-panel-services-dropdown-header" }, "Server Connections"),
|
|
1341
|
+
h2(
|
|
1342
|
+
"div",
|
|
1343
|
+
{ class: "cli-panel-services-dropdown-list" },
|
|
1344
|
+
statusServerDetails.value.map(
|
|
1345
|
+
(srv, i) => h2("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
|
|
1346
|
+
h2("span", { class: ["cli-panel-svc-dot", srv.connected ? "svc-running" : "svc-stopped"].join(" ") }),
|
|
1347
|
+
h2("div", { class: "cli-panel-svc-info" }, [
|
|
1348
|
+
h2("span", { class: "cli-panel-svc-name" }, srv.name),
|
|
1349
|
+
srv.url ? h2("span", { class: "cli-panel-svc-desc" }, srv.url) : null
|
|
1350
|
+
].filter(Boolean)),
|
|
1351
|
+
h2("div", { class: "cli-panel-srv-meta" }, [
|
|
1352
|
+
h2("span", { class: "cli-panel-svc-status" }, srv.connected ? "connected" : "disconnected"),
|
|
1353
|
+
srv.apiVersion ? h2("span", { class: "cli-panel-svc-desc" }, `v${srv.apiVersion}`) : null,
|
|
1354
|
+
srv.commandCount ? h2("span", { class: "cli-panel-svc-desc" }, `${srv.commandCount} cmds`) : null
|
|
1355
|
+
].filter(Boolean))
|
|
1356
|
+
])
|
|
1357
|
+
)
|
|
1358
|
+
),
|
|
1359
|
+
statusServerDetails.value.length === 0 ? h2("div", { class: "cli-panel-services-dropdown-empty" }, "No servers configured") : null
|
|
1360
|
+
].filter(Boolean)) : null;
|
|
993
1361
|
return h2("div", {}, [
|
|
994
1362
|
hideTabEl,
|
|
995
1363
|
h2(
|
|
@@ -997,14 +1365,16 @@ var CliPanel = defineComponent3({
|
|
|
997
1365
|
{
|
|
998
1366
|
class: wrapperClass,
|
|
999
1367
|
style: wrapperStyle,
|
|
1000
|
-
"data-position":
|
|
1368
|
+
"data-position": resolvedPosition.value,
|
|
1001
1369
|
"data-resizable": String(resizable.value),
|
|
1002
1370
|
"data-closable": String(closable.value),
|
|
1003
1371
|
"data-hideable": String(hideable.value)
|
|
1004
1372
|
},
|
|
1005
1373
|
[headerEl, contentEl]
|
|
1006
1374
|
),
|
|
1007
|
-
contextMenuEl
|
|
1375
|
+
contextMenuEl,
|
|
1376
|
+
servicesDropdownEl,
|
|
1377
|
+
serversDropdownEl
|
|
1008
1378
|
]);
|
|
1009
1379
|
};
|
|
1010
1380
|
}
|