fix: 將 God-Mode 的唯讀預覽變更成平坦化 (Flatten) 設計
This commit is contained in:
parent
05fdccf235
commit
d53f90efff
|
|
@ -400,10 +400,17 @@ function showCliPreviewModal(cliScript) {
|
||||||
document.getElementById('btn-side-cancel').style.display = 'inline-block';
|
document.getElementById('btn-side-cancel').style.display = 'inline-block';
|
||||||
document.getElementById('btn-side-confirm').style.display = 'inline-block';
|
document.getElementById('btn-side-confirm').style.display = 'inline-block';
|
||||||
document.getElementById('btn-side-close').style.display = 'none';
|
document.getElementById('btn-side-close').style.display = 'none';
|
||||||
|
document.getElementById('btn-side-close').textContent = '關閉';
|
||||||
document.getElementById('side-cli-textarea').style.display = 'block';
|
document.getElementById('side-cli-textarea').style.display = 'block';
|
||||||
document.getElementById('side-execution-result').style.display = 'none';
|
document.getElementById('side-execution-result').style.display = 'none';
|
||||||
|
|
||||||
document.getElementById('side-cli-textarea').value = cliScript;
|
const textarea = document.getElementById('side-cli-textarea');
|
||||||
|
textarea.value = cliScript;
|
||||||
|
|
||||||
|
// 👇 確保正常模式可以編輯,並明確恢復深色主題
|
||||||
|
textarea.readOnly = false;
|
||||||
|
textarea.style.backgroundColor = '#1e1e1e'; // 恢復成標準的深色背景 (您可以依喜好微調顏色碼)
|
||||||
|
textarea.style.color = '#ecf0f1'; // 確保字體是清晰的淺灰色
|
||||||
|
|
||||||
// 🌟 修改:遍歷所有樹狀圖容器進行縮放
|
// 🌟 修改:遍歷所有樹狀圖容器進行縮放
|
||||||
leftPanes.forEach(pane => pane.style.width = 'calc(50% - 11px)');
|
leftPanes.forEach(pane => pane.style.width = 'calc(50% - 11px)');
|
||||||
|
|
@ -631,81 +638,114 @@ function transformNoToActive(elementId, newCommand) {
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 💻 開發者工具:預覽節點完整指令 (唯讀 Debug 模式)
|
// 💻 開發者工具:預覽節點完整指令 (唯讀 Debug 模式)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
export function previewNodeCLI(btnElement, rootPath) {
|
export async function previewNodeCLI(btnElement, rootPath) {
|
||||||
// 1. 定位當前點擊的容器
|
// 1. 定位當前點擊的容器
|
||||||
let container = btnElement.closest('details');
|
let container = btnElement.closest('details');
|
||||||
if (!container) {
|
if (container) {
|
||||||
const leafNode = btnElement.closest('.tree-leaf-node');
|
const elementId = container.id.replace('details-', '');
|
||||||
if (leafNode) container = leafNode.querySelector('.leaf-container');
|
// 確保延遲渲染的內容已經載入 (Lazy Load)
|
||||||
|
if (container.dataset.loaded !== 'true') {
|
||||||
|
await window.lazyLoadFolder(elementId, false);
|
||||||
}
|
}
|
||||||
if (!container) return;
|
}
|
||||||
|
const targetNode = container || btnElement.closest('.tree-leaf-node');
|
||||||
|
if (!targetNode) return;
|
||||||
|
|
||||||
let cliOutput = `! =========================================\n`;
|
// 2. 收集所有子節點資料
|
||||||
cliOutput += `! 🔍 [Debug] 節點預覽: ${rootPath}\n`;
|
const leafNodes = targetNode.querySelectorAll('.leaf-container');
|
||||||
cliOutput += `! =========================================\n`;
|
const interfaceGroups = {};
|
||||||
cliOutput += `${rootPath.replace(/::/g, ' ')}\n`;
|
|
||||||
|
|
||||||
// 2. 找出該節點下所有的葉節點 (包含自己)
|
leafNodes.forEach(node => {
|
||||||
const allLeaves = container.classList.contains('leaf-container')
|
const path = node.getAttribute('data-path') || "";
|
||||||
? [container]
|
const val = node.getAttribute('data-original');
|
||||||
: Array.from(container.querySelectorAll('.leaf-container'));
|
if (!path) return;
|
||||||
|
|
||||||
if (allLeaves.length === 1 && allLeaves[0] === container) {
|
const parts = path.split('::');
|
||||||
// 情況 A:它自己就是最底層的葉節點
|
const paramName = parts.pop();
|
||||||
const val = container.getAttribute('data-original');
|
// 移除虛擬陣列索引 [0], [1] 等,還原真實介面路徑
|
||||||
if (val) cliOutput += ` ${val}\n`;
|
let interfacePath = parts.join(' ').replace(/\s*\[\d+\]/g, '');
|
||||||
|
|
||||||
|
if (!interfaceGroups[interfacePath]) {
|
||||||
|
interfaceGroups[interfacePath] = [];
|
||||||
|
}
|
||||||
|
interfaceGroups[interfacePath].push({ param: paramName, val: val });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 補強邏輯:處理使用者直接點擊葉節點的情況
|
||||||
|
if (Object.keys(interfaceGroups).length === 0 && targetNode.classList.contains('tree-leaf-node')) {
|
||||||
|
const singleNode = targetNode.querySelector('.leaf-container');
|
||||||
|
if (singleNode) {
|
||||||
|
const path = singleNode.getAttribute('data-path');
|
||||||
|
const val = singleNode.getAttribute('data-original');
|
||||||
|
const parts = path.split('::');
|
||||||
|
const paramName = parts.pop();
|
||||||
|
let interfacePath = parts.join(' ').replace(/\s*\[\d+\]/g, '');
|
||||||
|
interfaceGroups[interfacePath] = [{ param: paramName, val: val }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(interfaceGroups).length === 0) {
|
||||||
|
return alert("此節點下沒有任何數值可供預覽!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 在前端組裝平坦化 CLI (模擬真實設備指令)
|
||||||
|
let cliLines = [];
|
||||||
|
cliLines.push("! --- Read-Only Configuration Preview ---");
|
||||||
|
for (const [interfacePath, params] of Object.entries(interfaceGroups)) {
|
||||||
|
cliLines.push(`! Node: ${interfacePath || 'Global'}`);
|
||||||
|
params.forEach(({param, val}) => {
|
||||||
|
if (/^\[\d+\]$/.test(param)) {
|
||||||
|
// 陣列元素本身就是值
|
||||||
|
if (val) {
|
||||||
|
cliLines.push(interfacePath ? `${interfacePath} ${val}` : val);
|
||||||
|
}
|
||||||
|
} else if (param === 'no') {
|
||||||
|
// 處理 no 指令
|
||||||
|
cliLines.push(interfacePath ? `${interfacePath} no ${val}` : `no ${val}`);
|
||||||
} else {
|
} else {
|
||||||
// 情況 B:它是一個資料夾,遞迴列出所有子項目的相對路徑與值
|
// 一般鍵值對 (若 val 為空,代表是單純的 flag 指令)
|
||||||
allLeaves.forEach(leaf => {
|
let line = interfacePath ? `${interfacePath} ${param}` : param;
|
||||||
const leafPath = leaf.getAttribute('data-path');
|
if (val) line += ` ${val}`;
|
||||||
const leafVal = leaf.getAttribute('data-original');
|
cliLines.push(line);
|
||||||
|
|
||||||
if (leafPath && leafVal !== null) {
|
|
||||||
const relativePath = leafPath.replace(rootPath, '').replace(/^::/, '').replace(/::/g, ' ');
|
|
||||||
cliOutput += ` ${relativePath} ${leafVal}\n`;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
cliLines.push("!");
|
||||||
|
}
|
||||||
|
const finalScript = cliLines.join('\n');
|
||||||
|
|
||||||
|
// 4. 顯示唯讀預覽面板
|
||||||
|
showReadOnlyCliPreviewModal(finalScript, rootPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
cliOutput += `exit\n`;
|
// 專為 God-Mode 設計的唯讀面板 UI
|
||||||
|
function showReadOnlyCliPreviewModal(cliScript, rootPath) {
|
||||||
// 3. 呼叫現有的樹狀圖側邊欄 (Side Pane) 顯示
|
|
||||||
// 🌟 修改:改用 class 統一控制所有樹狀圖容器
|
|
||||||
const leftPanes = document.querySelectorAll('.tree-view-instance');
|
const leftPanes = document.querySelectorAll('.tree-view-instance');
|
||||||
const resizer = document.getElementById('drag-resizer');
|
const resizer = document.getElementById('drag-resizer');
|
||||||
const rightPane = document.getElementById('side-cli-preview');
|
const rightPane = document.getElementById('side-cli-preview');
|
||||||
|
|
||||||
if (!rightPane) {
|
document.getElementById('side-pane-title').innerHTML = `🔍 [唯讀預覽] ${rootPath}`;
|
||||||
console.error("找不到側邊欄元素 'side-cli-preview'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 設定標題與樣式
|
|
||||||
document.getElementById('side-pane-title').innerHTML = '🔍 節點指令預覽 (唯讀)';
|
|
||||||
document.getElementById('side-pane-title').style.color = '#3498db';
|
document.getElementById('side-pane-title').style.color = '#3498db';
|
||||||
|
|
||||||
// 隱藏「確認寫入」按鈕,只顯示「取消/關閉」按鈕
|
// 隱藏執行按鈕,只保留關閉
|
||||||
document.getElementById('btn-side-confirm').style.display = 'none';
|
document.getElementById('btn-side-confirm').style.display = 'none';
|
||||||
document.getElementById('btn-side-cancel').style.display = 'inline-block';
|
document.getElementById('btn-side-cancel').style.display = 'none';
|
||||||
document.getElementById('btn-side-close').style.display = 'none';
|
const closeBtn = document.getElementById('btn-side-close');
|
||||||
|
closeBtn.style.display = 'inline-block';
|
||||||
|
closeBtn.textContent = '關閉預覽';
|
||||||
|
|
||||||
// 顯示 Textarea 並填入內容
|
|
||||||
const textarea = document.getElementById('side-cli-textarea');
|
const textarea = document.getElementById('side-cli-textarea');
|
||||||
textarea.style.display = 'block';
|
textarea.style.display = 'block';
|
||||||
textarea.value = cliOutput;
|
textarea.value = cliScript;
|
||||||
textarea.style.backgroundColor = '#1e1e1e'; // 終端機深色背景
|
textarea.readOnly = true; // 強制唯讀
|
||||||
textarea.style.color = '#d4d4d4';
|
textarea.style.backgroundColor = '#2c3e50'; // 改變背景色提示唯讀狀態
|
||||||
|
|
||||||
document.getElementById('side-execution-result').style.display = 'none';
|
document.getElementById('side-execution-result').style.display = 'none';
|
||||||
|
|
||||||
// 展開側邊欄
|
|
||||||
// 🌟 修改:遍歷所有樹狀圖容器進行縮放
|
|
||||||
leftPanes.forEach(pane => pane.style.width = 'calc(50% - 11px)');
|
leftPanes.forEach(pane => pane.style.width = 'calc(50% - 11px)');
|
||||||
rightPane.style.width = 'calc(50% - 11px)';
|
rightPane.style.width = 'calc(50% - 11px)';
|
||||||
if (resizer) resizer.style.display = 'flex';
|
if (resizer) resizer.style.display = 'flex';
|
||||||
rightPane.style.display = 'block';
|
if (rightPane) rightPane.style.display = 'block';
|
||||||
|
|
||||||
// 初始化拖拉分隔線 (如果尚未初始化)
|
|
||||||
if (!window.isResizerInitialized && typeof initResizer === 'function') {
|
if (!window.isResizerInitialized && typeof initResizer === 'function') {
|
||||||
initResizer();
|
initResizer();
|
||||||
window.isResizerInitialized = true;
|
window.isResizerInitialized = true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue