From 574c1c996718a52975fc3addc31f3f912b9ec14b Mon Sep 17 00:00:00 2001 From: agent Date: Fri, 10 Apr 2026 11:50:57 +0800 Subject: [PATCH] =?UTF-8?q?release(secrets-mcp):=200.5.15=20=E2=80=94=20?= =?UTF-8?q?=E5=88=97=E8=AE=BE=E7=BD=AE=E9=9D=A2=E6=9D=BF=E9=94=9A=E5=AE=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E7=A7=BB=E9=99=A4=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E5=AF=86=E6=96=87=E9=9A=90=E8=97=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- crates/secrets-mcp/Cargo.toml | 2 +- crates/secrets-mcp/templates/entries.html | 232 +++++++++++++++++----- crates/secrets-mcp/templates/i18n.js | 4 + 4 files changed, 192 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59c6240..fb36b8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2065,7 +2065,7 @@ dependencies = [ [[package]] name = "secrets-mcp" -version = "0.5.14" +version = "0.5.15" dependencies = [ "anyhow", "askama", diff --git a/crates/secrets-mcp/Cargo.toml b/crates/secrets-mcp/Cargo.toml index bde14d7..d00bd66 100644 --- a/crates/secrets-mcp/Cargo.toml +++ b/crates/secrets-mcp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secrets-mcp" -version = "0.5.14" +version = "0.5.15" edition.workspace = true [[bin]] diff --git a/crates/secrets-mcp/templates/entries.html b/crates/secrets-mcp/templates/entries.html index 9ddd06c..ea066f5 100644 --- a/crates/secrets-mcp/templates/entries.html +++ b/crates/secrets-mcp/templates/entries.html @@ -73,8 +73,7 @@ border-color: rgba(56,139,253,0.3); color: #fff; } - .filter-bar { - display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px; + .filter-bar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px; margin-bottom: 18px; padding: 16px; background: #0d1117; border: 1px solid rgba(240,246,252,0.08); border-radius: 12px; } @@ -114,6 +113,29 @@ color: #8b949e; font-size: 13px; text-decoration: none; cursor: pointer; } .btn-clear:hover { border-color: rgba(56,139,253,0.45); color: #fff; } + .btn-col-toggle { + padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(240,246,252,0.12); + background: transparent; color: #8b949e; font-size: 16px; cursor: pointer; + } + .btn-col-toggle:hover { border-color: rgba(56,139,253,0.45); color: #fff; } + .col-menu { position: relative; } + .col-panel { + display: none; position: absolute; top: calc(100% + 6px); right: 0; z-index: 20; + background: #161b22; border: 1px solid rgba(240,246,252,0.12); border-radius: 10px; + padding: 10px 14px; min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,0.4); + } + .col-panel.open { display: block; } + .col-panel-group { font-size: 11px; color: #6e7681; text-transform: uppercase; letter-spacing: 0.5px; margin: 8px 0 4px; } + .col-panel-group:first-child { margin-top: 0; } + .col-panel-item { + display: flex; align-items: center; gap: 8px; padding: 4px 0; + font-size: 13px; color: #c9d1d9; cursor: pointer; user-select: none; + } + .col-panel-item input[type="checkbox"] { + accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; + } + .col-panel-item.disabled { color: #6e7681; cursor: default; } + .col-panel-item.disabled input[type="checkbox"] { cursor: default; } .empty { color: #8b949e; font-size: 14px; padding: 20px 0; } .table-wrap { overflow: auto; @@ -123,10 +145,18 @@ } table { width: 100%; - min-width: 960px; + min-width: 1100px; border-collapse: separate; border-spacing: 0; + table-layout: fixed; } + col[data-col="name"] { width: 220px; } + col[data-col="type"] { width: 120px; } + col[data-col="notes"] { width: 320px; } + col[data-col="tags"] { width: 220px; } + col[data-col="relations"] { width: 220px; } + col[data-col="secrets"] { width: 320px; } + col[data-col="actions"] { width: 132px; } th, td { text-align: left; vertical-align: middle; padding: 14px 12px; border-top: 1px solid rgba(240,246,252,0.08); } th { color: #8b949e; @@ -142,13 +172,21 @@ } td { font-size: 13px; line-height: 1.45; color: #c9d1d9; } tbody tr:nth-child(2n) td { background: rgba(255, 255, 255, 0.01); } + tbody tr:nth-child(2n) td.col-name { background: #0f1620; } .mono { font-family: 'JetBrains Mono', monospace; } - .col-type { min-width: 108px; width: 1%; text-align: center; vertical-align: middle; } - .col-name { min-width: 180px; max-width: 260px; text-align: center; vertical-align: middle; } - .col-tags { min-width: 160px; max-width: 220px; } - .col-secrets { min-width: 220px; max-width: 420px; vertical-align: middle; } + .col-type { text-align: center; vertical-align: middle; } + .col-secrets { vertical-align: middle; } .col-secrets .secret-list { max-height: 120px; overflow: auto; } - .col-actions { min-width: 132px; width: 1%; text-align: center; vertical-align: middle; } + .col-actions { text-align: right; vertical-align: middle; } + .col-name { position: sticky; left: 0; z-index: 1; background: #0d1117; overflow: hidden; } + th.col-name { z-index: 3; background: #111827; } + .col-name::after { + content: ''; position: absolute; top: 0; right: -8px; bottom: 0; width: 8px; + background: linear-gradient(to right, rgba(0,0,0,0.15), transparent); + pointer-events: none; + } + th[data-col="actions"], td[data-col="actions"] { text-align: right; } + [data-col].col-hidden { display: none !important; } .cell-name, .cell-tags-val { overflow-wrap: anywhere; word-break: break-word; @@ -199,6 +237,17 @@ border-left: 1px solid rgba(240,246,252,0.08); padding-left: 6px; } + a.secret-chip { + color: var(--accent); + text-decoration: none; + cursor: pointer; + transition: color 0.15s, border-color 0.15s, background 0.15s; + } + a.secret-chip:hover { + color: var(--accent-hover); + border-color: var(--accent); + background: rgba(88,166,255,0.12); + } .btn-unlink-secret { border: none; background: transparent; @@ -357,6 +406,9 @@ content: attr(data-label); } .col-name, .col-type, .col-actions { text-align: left; } + .col-name { position: static; } + .col-name::after { display: none; } + .col-panel { position: fixed; left: 12px; right: 12px; width: auto; } th, td { vertical-align: top; } .row-actions { justify-content: flex-start; } .detail, .notes-scroll, .secret-list { max-width: none; } @@ -404,7 +456,7 @@ padding: 7px 10px; word-break: break-all; white-space: pre-wrap; max-height: 140px; overflow: auto; color: #c9d1d9; line-height: 1.5; } - .view-secret-value.masked { letter-spacing: 2px; user-select: none; filter: blur(4px); } + .btn-icon { padding: 6px 10px; border-radius: 8px; font-size: 12px; cursor: pointer; border: 1px solid rgba(240,246,252,0.12); background: #161b22; color: #8b949e; @@ -497,6 +549,10 @@
清空 +
+ +
+
@@ -505,25 +561,34 @@ {% else %}
+ + + + + + + + + - - - - - - - + + + + + + + {% for entry in entries %} - - - - - + + + + - -
名称类型备注标签关联密文操作名称类型备注标签关联密文操作
{{ entry.name }}{{ entry.entry_type }}{% if !entry.notes.is_empty() %}
{{ entry.notes }}
{% endif %}
{{ entry.tags }} + {{ entry.name }}{{ entry.entry_type }}{% if !entry.notes.is_empty() %}
{{ entry.notes }}
{% endif %}
{{ entry.tags }}
{% for parent in entry.parents %} @@ -539,7 +604,7 @@ {% endfor %}
+
{% for s in entry.secrets %} @@ -549,7 +614,7 @@ {% endfor %}
+
@@ -627,6 +692,9 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option I18N_PAGE = { 'zh-CN': { pageTitle: 'Secrets — 条目', + columnSettings: '显示列', + fixedColumns: '固定列', + optionalColumns: '可选列', navTrash: '回收站', entriesTitle: '我的条目', allTab: '全部', @@ -694,8 +762,6 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option viewDecryptError: '解密失败,请确认密码短语与加密时一致。', viewCopy: '复制', viewCopied: '已复制', - viewShow: '显示', - viewHide: '隐藏', viewLoading: '解密中…', viewSaveChanges: '保存更改', viewChangesSaved: '已保存', @@ -706,6 +772,9 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option }, 'zh-TW': { pageTitle: 'Secrets — 條目', + columnSettings: '顯示列', + fixedColumns: '固定列', + optionalColumns: '可選列', navTrash: '回收站', entriesTitle: '我的條目', allTab: '全部', @@ -773,8 +842,6 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option viewDecryptError: '解密失敗,請確認密碼短語與加密時一致。', viewCopy: '複製', viewCopied: '已複製', - viewShow: '顯示', - viewHide: '隱藏', viewLoading: '解密中…', viewSaveChanges: '儲存變更', viewChangesSaved: '已儲存', @@ -785,6 +852,9 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option }, en: { pageTitle: 'Secrets — Entries', + columnSettings: 'Columns', + fixedColumns: 'Fixed', + optionalColumns: 'Optional', navTrash: 'Trash', entriesTitle: 'My entries', allTab: 'All', @@ -852,8 +922,6 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option viewDecryptError: 'Decryption failed. Please verify your passphrase matches the one used when encrypting.', viewCopy: 'Copy', viewCopied: 'Copied', - viewShow: 'Show', - viewHide: 'Hide', viewLoading: 'Decrypting…', viewSaveChanges: 'Save changes', viewChangesSaved: 'Saved', @@ -885,8 +953,96 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option if (td) td.setAttribute('data-label', t(map[sel])); }); }); + rebuildColPanel(); }; + var COL_ORDER = ['name', 'type', 'notes', 'tags', 'relations', 'secrets', 'actions']; + var COL_ALWAYS_ON = { name: true, actions: true }; + var COL_DEFAULTS = { name: true, type: true, notes: false, tags: true, relations: true, secrets: false, actions: true }; + var COL_STORAGE_KEY = 'entries_col_vis'; + var colPanel = document.getElementById('col-panel'); + var colToggleBtn = document.getElementById('col-toggle-btn'); + + function getColVis() { + try { + var saved = localStorage.getItem(COL_STORAGE_KEY); + if (saved) { var parsed = JSON.parse(saved); if (parsed && typeof parsed === 'object') return parsed; } + } catch (e) {} + var defaults = {}; + COL_ORDER.forEach(function (col) { defaults[col] = COL_DEFAULTS[col]; }); + return defaults; + } + + function saveColVis(vis) { + try { localStorage.setItem(COL_STORAGE_KEY, JSON.stringify(vis)); } catch (e) {} + } + + function applyColVis(vis) { + COL_ORDER.forEach(function (col) { + var visible = vis[col] !== false; + document.querySelectorAll('[data-col="' + col + '"]').forEach(function (el) { + if (visible) { + el.classList.remove('col-hidden'); + } else { + el.classList.add('col-hidden'); + } + }); + }); + } + + function rebuildColPanel() { + var vis = getColVis(); + colPanel.innerHTML = ''; + var fixedCols = ['name', 'actions']; + var optionalCols = COL_ORDER.filter(function (c) { return fixedCols.indexOf(c) === -1; }); + + function renderGroup(cols, groupKey) { + var groupLabel = document.createElement('div'); + groupLabel.className = 'col-panel-group'; + groupLabel.textContent = t(groupKey); + colPanel.appendChild(groupLabel); + cols.forEach(function (col) { + var item = document.createElement('label'); + item.className = 'col-panel-item'; + var cb = document.createElement('input'); + cb.type = 'checkbox'; + var i18nKey = 'col' + col.charAt(0).toUpperCase() + col.slice(1); + cb.checked = vis[col] !== false; + if (COL_ALWAYS_ON[col]) { + cb.disabled = true; + item.classList.add('disabled'); + } + cb.addEventListener('change', function () { + vis[col] = cb.checked; + saveColVis(vis); + applyColVis(vis); + }); + var span = document.createElement('span'); + span.textContent = t(i18nKey) || col; + item.appendChild(cb); + item.appendChild(span); + colPanel.appendChild(item); + }); + } + + renderGroup(fixedCols, 'fixedColumns'); + renderGroup(optionalCols, 'optionalColumns'); + } + + var colMenu = document.querySelector('.col-menu'); + colToggleBtn.addEventListener('click', function (e) { + e.stopPropagation(); + colPanel.classList.toggle('open'); + }); + document.addEventListener('click', function (e) { + if (!colMenu.contains(e.target)) { + colPanel.classList.remove('open'); + } + }); + + applyColVis(getColVis()); + rebuildColPanel(); + var editOverlay = document.getElementById('edit-overlay'); var editError = document.getElementById('edit-error'); var editFolder = document.getElementById('edit-folder'); @@ -1023,9 +1179,6 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option var raw = secrets[name]; var valueStr = (raw === null || raw === undefined) ? '' : (typeof raw === 'object') ? JSON.stringify(raw, null, 2) : String(raw); - var isPassword = (name === 'password' || name === 'passwd' || name === 'secret'); - var masked = isPassword; - var schema = schemaMap[name] || {}; var secretId = schema.id || ''; var secretType = schema.secret_type || 'text'; @@ -1104,19 +1257,6 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option cancelBtn.textContent = t('modalCancel'); cancelBtn.hidden = true; - if (isPassword) { - var toggleBtn = document.createElement('button'); - toggleBtn.type = 'button'; - toggleBtn.className = 'btn-icon btn-toggle-mask'; - toggleBtn.textContent = t('viewShow'); - toggleBtn.addEventListener('click', function () { - masked = !masked; - valueEl.classList.toggle('masked', masked); - toggleBtn.textContent = masked ? t('viewShow') : t('viewHide'); - }); - actions.appendChild(toggleBtn); - } - var copyBtn = document.createElement('button'); copyBtn.type = 'button'; copyBtn.className = 'btn-icon'; @@ -1145,7 +1285,7 @@ var SECRET_TYPE_OPTIONS = JSON.parse(document.getElementById('secret-type-option var valueWrap = document.createElement('div'); valueWrap.className = 'view-secret-value-wrap'; var valueEl = document.createElement('div'); - valueEl.className = 'view-secret-value' + (masked ? ' masked' : ''); + valueEl.className = 'view-secret-value'; valueEl.textContent = valueStr; valueWrap.appendChild(valueEl); row.appendChild(valueWrap); diff --git a/crates/secrets-mcp/templates/i18n.js b/crates/secrets-mcp/templates/i18n.js index 1cd726f..e1e461b 100644 --- a/crates/secrets-mcp/templates/i18n.js +++ b/crates/secrets-mcp/templates/i18n.js @@ -65,6 +65,10 @@ function applyLang() { var key = el.getAttribute('data-i18n-ph'); el.placeholder = t(key); }); + document.querySelectorAll('[data-i18n-title]').forEach(function (el) { + var key = el.getAttribute('data-i18n-title'); + el.title = t(key); + }); document.querySelectorAll('.lang-btn').forEach(function (btn) { var map = { 'zh-CN': '简', 'zh-TW': '繁', en: 'EN' }; btn.classList.toggle('active', btn.textContent === map[currentLang]);