dsh-mesh-ui 0.0.15 → 0.0.17

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.
Files changed (2) hide show
  1. package/lib/client.js +51 -3
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -120,6 +120,8 @@ function nodeLabel(name) { return NODE_LABELS[String(name || '').toLowerCase()]
120
120
  // [layout-helpers-end]
121
121
  // [relay-helpers-begin] 2026-11-09 架构层:识别公网中转站(frps)与通信方式(纯函数,可单测)
122
122
  // 2026-11-10 隐私:默认不展示公网 IP/域名;局域网/回环地址保留。
123
+ // 用户在页头打开「显示公网地址」后,maskHost/maskText 直接返回原值。
124
+ var showPublicAddresses = false
123
125
  function isPrivateNetworkHost(raw) {
124
126
  var h = String(raw || '').trim().toLowerCase().replace(/^\[|\]$/g, '')
125
127
  h = h.replace(/^https?:\/\//, '').split('/')[0].replace(/:\d+$/, '')
@@ -135,6 +137,7 @@ function nodeLabel(name) { return NODE_LABELS[String(name || '').toLowerCase()]
135
137
  }
136
138
  function maskHost(raw) {
137
139
  var s = String(raw || '').trim()
140
+ if (showPublicAddresses) return s || '—'
138
141
  if (!s) return '—'
139
142
  var port = ''
140
143
  var m = /^(.*):(\d+)$/.exec(s)
@@ -142,6 +145,7 @@ function nodeLabel(name) { return NODE_LABELS[String(name || '').toLowerCase()]
142
145
  return (isPrivateNetworkHost(s) ? s : '公网地址已隐藏') + port
143
146
  }
144
147
  function maskText(value) {
148
+ if (showPublicAddresses) return value
145
149
  if (typeof value !== 'string') return value
146
150
  return value
147
151
  .replace(/https?:\/\/[^\s"'<>]+/gi, function (u) {
@@ -559,10 +563,24 @@ body.light .dm-edge-label { stroke: rgba(255,255,255,.92); }
559
563
  var s0 = useState({ scale: 1, x: 0, y: 0 }); var view = s0[0]; var setView = s0[1]
560
564
  var s1 = useState(false); var dragging = s1[0]; var setDragging = s1[1]
561
565
  // 2026-11-09:三通道筛选(局域网/公网/樱花)
562
- var filterState = useState({ lan: true, public: true, sakura: true })
566
+ // 2026-11-10:筛选状态持久化;刷新/切页面后不再丢。
567
+ var FILTER_STORE_KEY = 'dsh-mesh-ui.filters.v1'
568
+ var filterState = useState(function () {
569
+ try {
570
+ var saved = JSON.parse(window.localStorage.getItem(FILTER_STORE_KEY) || '{}') || {}
571
+ return { lan: saved.lan !== false, public: saved.public !== false, sakura: saved.sakura !== false }
572
+ } catch (_) { return { lan: true, public: true, sakura: true } }
573
+ })
563
574
  var showFilters = filterState[0]
564
575
  var setShowFilters = filterState[1]
565
- function toggleFilter(k) { setShowFilters(function (prev) { var n = Object.assign({}, prev); n[k] = !n[k]; return n }) }
576
+ function toggleFilter(k) {
577
+ setShowFilters(function (prev) {
578
+ var n = Object.assign({}, prev)
579
+ n[k] = !n[k]
580
+ try { window.localStorage.setItem(FILTER_STORE_KEY, JSON.stringify(n)) } catch (_) { /* ignore */ }
581
+ return n
582
+ })
583
+ }
566
584
  // fit 用最新布局的 ref(拖拽中不重算视角;只有初始化 / 窗口变化 / ⟲ 重置 / ⤢ 自适应才重算)
567
585
  var effRef = useRef(effLayout)
568
586
  effRef.current = effLayout
@@ -1408,7 +1426,20 @@ function deviceLinkState(data, peer, lanMap) {
1408
1426
  }
1409
1427
 
1410
1428
  function Details(props) {
1411
- return h('details', { className: 'dm-details', open: Boolean(props.open) },
1429
+ var storeKey = 'dsh-mesh-ui.details.' + encodeURIComponent(String(props.title || ''))
1430
+ var sOpen = useState(function () {
1431
+ try {
1432
+ var saved = window.localStorage.getItem(storeKey)
1433
+ return saved == null ? Boolean(props.open) : saved === '1'
1434
+ } catch (_) { return Boolean(props.open) }
1435
+ })
1436
+ var open = sOpen[0]; var setOpen = sOpen[1]
1437
+ function onToggle(event) {
1438
+ var next = Boolean(event.currentTarget.open)
1439
+ setOpen(next)
1440
+ try { window.localStorage.setItem(storeKey, next ? '1' : '0') } catch (_) { /* ignore */ }
1441
+ }
1442
+ return h('details', { className: 'dm-details', open: open, onToggle: onToggle },
1412
1443
  h('summary', null, props.title, props.badge != null ? h('span', { className: 'dm-pill muted' }, String(props.badge)) : null),
1413
1444
  h('div', { className: 'dm-body' }, props.children)
1414
1445
  )
@@ -1543,6 +1574,17 @@ function deviceLinkState(data, peer, lanMap) {
1543
1574
  var verdictState = useState(''); var verdictShown = verdictState[0]; var setVerdictShown = verdictState[1]
1544
1575
  var verdictRef = useRef({ raw: '', streak: 0 })
1545
1576
  var s5 = useState('local'); var selectedKey = s5[0]; var setSelectedKey = s5[1]
1577
+ var sPublic = useState(function () {
1578
+ try { return window.localStorage.getItem('dsh-mesh.show-public-addresses') === '1' } catch (error) { return false }
1579
+ })
1580
+ var showPublic = sPublic[0]; var setShowPublic = sPublic[1]
1581
+ showPublicAddresses = showPublic
1582
+ function toggleShowPublic(event) {
1583
+ var next = Boolean(event && event.target && event.target.checked)
1584
+ setShowPublic(next)
1585
+ showPublicAddresses = next
1586
+ try { window.localStorage.setItem('dsh-mesh.show-public-addresses', next ? '1' : '0') } catch (error) { /* ignore */ }
1587
+ }
1546
1588
  // 双栏宽度:拖动分隔条调整并记忆,窄屏由 CSS 媒体查询自动堆叠。
1547
1589
  var dragState = useState(function () {
1548
1590
  try { var saved = Number(window.localStorage.getItem('dsh-mesh-split-w')); return Number.isFinite(saved) && saved > 0 ? saved : 0 } catch (error) { return 0 }
@@ -1684,6 +1726,10 @@ function deviceLinkState(data, peer, lanMap) {
1684
1726
  }, data.warming ? '预热中' : (verdictShown || data.verdict || '?')),
1685
1727
  h('span', { className: 'dm-sub' }, (data.meshVersion ? 'mesh ' + data.meshVersion + ' · ' : '') + (data.at ? ago(data.at) : '')),
1686
1728
  h('span', { style: { flex: 1 } }),
1729
+ h('label', { className: 'dm-toggle', title: '默认隐藏公网 IP/域名;勾选后显示真实地址并记住选择' },
1730
+ h('input', { type: 'checkbox', checked: Boolean(showPublic), onChange: toggleShowPublic }),
1731
+ h('span', null, '显示公网地址')
1732
+ ),
1687
1733
  h('a', { className: 'dm-btn', href: API, target: '_blank', rel: 'noreferrer', style: { textDecoration: 'none' } }, '原始 JSON'),
1688
1734
  h('button', { className: 'dm-btn', onClick: copyJson }, copied || '复制诊断'),
1689
1735
  h('button', { className: 'dm-btn primary', onClick: function () { load(true) }, title: '立即采集一次并等待新快照(8s 冷却)' }, loading ? '采集中…' : '刷新'),
@@ -2419,6 +2465,8 @@ body[data-ds-dark-theme] .dm-dg-fs-item.active { background:rgba(88,166,255,.28)
2419
2465
  .dm-lan-node { display:flex; gap:8px; align-items:center; border-top:1px solid rgba(128,128,128,.16); padding:7px 0; font-size:12px; }
2420
2466
  .dm-lan-node:first-child { border-top:none; }
2421
2467
  .dm-lan-code { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:12px; padding:6px 8px; border-radius:8px; background:rgba(88,166,255,.1); border:1px solid rgba(88,166,255,.35); word-break:break-all; }
2468
+ .dm-toggle { display:inline-flex; align-items:center; gap:5px; font-size:11.5px; opacity:.8; cursor:pointer; user-select:none; white-space:nowrap; }
2469
+ .dm-toggle input { margin:0; }
2422
2470
 
2423
2471
  .dm-pane { min-width:0; display:flex; flex-direction:column; gap:12px; }
2424
2472
  .dm-divider { cursor:col-resize; align-self:stretch; min-height:120px; border-radius:4px; position:relative; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mesh-ui",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "DSH sidebar page for dsh-mesh: AI network topology, peer health, and delegation panel. Read-only; data is collected from the installed dsh-mesh-node package.",
5
5
  "icon": "icon.svg",
6
6
  "type": "module",