dsh-manage-session 0.4.8 → 0.5.3

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 (43) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.en.md +4 -0
  3. package/README.md +4 -0
  4. package/cordis.patch.yml +6 -1
  5. package/dsh.plugin.json +22 -22
  6. package/lib/client.js +3848 -202
  7. package/lib/index.d.ts +759 -29
  8. package/lib/index.js +2604 -93
  9. package/locale/de.json +6 -0
  10. package/locale/en.json +6 -0
  11. package/locale/es.json +6 -0
  12. package/locale/fr.json +6 -0
  13. package/locale/it.json +6 -0
  14. package/locale/ja.json +6 -0
  15. package/locale/ko.json +6 -0
  16. package/locale/ru.json +6 -0
  17. package/locale/zh.json +6 -0
  18. package/package.json +43 -32
  19. package/src/client/bridge-scope.ts +213 -0
  20. package/src/client/index.ts +154 -26
  21. package/src/client/locales.ts +857 -223
  22. package/src/client/panel.tsx +139 -118
  23. package/src/client/search/card.tsx +563 -0
  24. package/src/client/search/host-api.ts +208 -0
  25. package/src/client/search/locales.ts +780 -0
  26. package/src/client/search/manage.tsx +400 -0
  27. package/src/client/search/panel.tsx +815 -0
  28. package/src/client/search/platform.ts +136 -0
  29. package/src/config.ts +54 -5
  30. package/src/host/history/archive-source.ts +48 -0
  31. package/src/host/history/archive.ts +56 -1
  32. package/src/host/history/favorites.ts +71 -0
  33. package/src/host/index/archive-source.ts +90 -0
  34. package/src/host/index/engine.ts +571 -0
  35. package/src/host/index/extract.ts +272 -0
  36. package/src/host/index/peers.ts +62 -0
  37. package/src/host/index/rebuild.ts +368 -0
  38. package/src/host/index/schema.ts +136 -0
  39. package/src/host/index/snapshot.ts +135 -0
  40. package/src/host/index/sync.ts +286 -0
  41. package/src/host/registry/archive-registry.ts +317 -0
  42. package/src/host/settings-bridge.ts +237 -0
  43. package/src/index.ts +1421 -532
@@ -1,118 +1,139 @@
1
- /**
2
- * 会话管家面板壳:一个侧边栏入口,两个页签(养老院 / 体检)。
3
- *
4
- * 页签可见性由开关决定:`historyFiles=false` 时「养老院」消失,`healthCheck=false`
5
- * 时「体检」消失;两者都关时进入面板直接显示空壳提示(客户端也会隐藏入口)。
6
- */
7
- import { createElement, useEffect, useState, type ReactElement } from 'react'
8
- import { createPortal } from 'react-dom'
9
- import { HistoryPanel } from './history-panel.tsx'
10
- import { HealthPanel } from './health-panel.tsx'
11
- import { translate, type LocaleKey } from './locales.ts'
12
-
13
- /** 面板字典面。 */
14
- export type PanelTranslate = (key: LocaleKey, params?: Record<string, unknown>) => string
15
-
16
- /** 页签 id(导出供测试断言)。 */
17
- export const TAB_HISTORY = 'dss-tab-history'
18
- export const TAB_HEALTH = 'dss-tab-health'
19
-
20
- /** 面板入参。 */
21
- export interface StewardPanelProps {
22
- t?: PanelTranslate
23
- /** 历史文件子域是否可见。 */
24
- historyFiles: boolean
25
- /** 健康检查子域是否可见。 */
26
- healthCheck: boolean
27
- onClose: () => void
28
- }
29
-
30
- /** 会话管家对话框。 */
31
- export function StewardPanel({ t, historyFiles, healthCheck, onClose }: StewardPanelProps): ReactElement {
32
- const [tab, setTab] = useState<'history' | 'health'>(historyFiles ? 'history' : 'health')
33
-
34
- // 开关变化后收敛到仍然可见的页签。
35
- useEffect(() => {
36
- if (tab === 'history' && !historyFiles && healthCheck) setTab('health')
37
- if (tab === 'health' && !healthCheck && historyFiles) setTab('history')
38
- }, [tab, historyFiles, healthCheck])
39
-
40
- useEffect(() => {
41
- const onKey = (event: KeyboardEvent): void => { if (event.key === 'Escape') onClose() }
42
- document.addEventListener('keydown', onKey)
43
- return () => { document.removeEventListener('keydown', onKey) }
44
- }, [onClose])
45
-
46
- const tabs: ReactElement[] = []
47
- if (historyFiles) {
48
- tabs.push(createElement('button', {
49
- key: TAB_HISTORY,
50
- id: TAB_HISTORY,
51
- type: 'button',
52
- className: `dss_tab${tab === 'history' ? ' dss_tabActive' : ''}`,
53
- 'aria-selected': tab === 'history',
54
- onClick: () => { setTab('history') },
55
- }, translate(t, 'panel.tab.history')))
56
- }
57
- if (healthCheck) {
58
- tabs.push(createElement('button', {
59
- key: TAB_HEALTH,
60
- id: TAB_HEALTH,
61
- type: 'button',
62
- className: `dss_tab${tab === 'health' ? ' dss_tabActive' : ''}`,
63
- 'aria-selected': tab === 'health',
64
- onClick: () => { setTab('health') },
65
- }, translate(t, 'panel.tab.health')))
66
- }
67
-
68
- const body: ReactElement = tab === 'history' && historyFiles
69
- ? createElement(HistoryPanel, { t, onClose })
70
- : tab === 'health' && healthCheck
71
- ? createElement(HealthPanel, { t, onClose })
72
- : createElement('div', { className: 'dss_empty' }, translate(t, 'card.enabled.desc'))
73
-
74
- return createPortal(createElement('div', { key: 'steward-root' }, [
75
- createElement('div', { key: 'backdrop', className: 'dss_backdrop', onClick: onClose }),
76
- createElement('div', {
77
- key: 'panel',
78
- className: 'dss_panel',
79
- role: 'dialog',
80
- 'aria-label': translate(t, 'panel.title'),
81
- }, [
82
- createElement('div', { key: 'head', className: 'dss_dialogHead' }, [
83
- createElement('span', { key: 'title', className: 'dss_dialogTitle' }, translate(t, 'panel.title')),
84
- createElement('span', { key: 'tabs', className: 'dss_tabRow' }, tabs),
85
- createElement('button', {
86
- key: 'close',
87
- type: 'button',
88
- className: 'dss_actBtn',
89
- onClick: onClose,
90
- }, translate(t, 'panel.close')),
91
- ]),
92
- body,
93
- ]),
94
- ]), document.body)
95
- }
96
-
97
- /** 侧边栏脚部入口:宽栏带文案成行控件,收起轨道退化为 36x36 图标钮。 */
98
- export function StewardFooter(props: {
99
- onClick?: () => void
100
- title?: string
101
- label?: string
102
- wide?: boolean
103
- }): ReactElement {
104
- const wide = props.wide === true
105
- return createElement('button', {
106
- type: 'button',
107
- className: wide ? 'dss_footerEntry' : 'dss_footerEntry dss_footerEntryRail',
108
- title: props.title,
109
- 'aria-label': props.title,
110
- onClick: props.onClick,
111
- }, [
112
- createElement('span', { key: 'icon', className: 'dss_footerIcon', 'aria-hidden': true }, '🧭'),
113
- // 收起轨道里 36px 装不下文案,标签与宽栏同条件出现,与搜索入口一致。
114
- wide && props.label !== undefined
115
- ? createElement('span', { key: 'label', className: 'dss_footerLabel' }, props.label)
116
- : null,
117
- ])
118
- }
1
+ /**
2
+ * 会话管家面板壳:一个侧边栏入口,两个页签(养老院 / 体检)。
3
+ *
4
+ * 页签可见性由开关决定:`historyFiles=false` 时「养老院」消失,`healthCheck=false`
5
+ * 时「体检」消失;两者都关时进入面板直接显示空壳提示(客户端也会隐藏入口)。
6
+ */
7
+ import { createElement, useEffect, useState, type ReactElement } from 'react'
8
+ import { createPortal } from 'react-dom'
9
+ import { HistoryPanel } from './history-panel.tsx'
10
+ import { HealthPanel } from './health-panel.tsx'
11
+ import { ManageConsole } from './search/manage.tsx'
12
+ import { translate, type LocaleKey } from './locales.ts'
13
+
14
+ /** 面板字典面。 */
15
+ export type PanelTranslate = (key: LocaleKey, params?: Record<string, unknown>) => string
16
+
17
+ /** 页签 id(导出供测试断言)。 */
18
+ export const TAB_HISTORY = 'dss-tab-history'
19
+ export const TAB_HEALTH = 'dss-tab-health'
20
+ export const TAB_MANAGE = 'dss-tab-manage'
21
+
22
+ /** 面板入参。 */
23
+ export interface StewardPanelProps {
24
+ t?: PanelTranslate
25
+ /** 历史文件子域是否可见。 */
26
+ historyFiles: boolean
27
+ /** 健康检查子域是否可见。 */
28
+ healthCheck: boolean
29
+ /** 搜索子域是否启用(启用才有「管理」页签——它读统一索引语料)。 */
30
+ searchEnabled?: boolean
31
+ /** 打开会话(管理台行点击;apply 侧经 openSessionThrough 解析)。 */
32
+ openSession?: (sessionId: string) => void
33
+ onClose: () => void
34
+ }
35
+
36
+ /** 会话管家对话框。 */
37
+ export function StewardPanel({ t, historyFiles, healthCheck, searchEnabled = false, openSession, onClose }: StewardPanelProps): ReactElement {
38
+ const [tab, setTab] = useState<'history' | 'health' | 'manage'>(historyFiles ? 'history' : healthCheck ? 'health' : 'manage')
39
+
40
+ // 开关变化后收敛到仍然可见的页签。
41
+ useEffect(() => {
42
+ if (tab === 'history' && !historyFiles && (healthCheck || searchEnabled)) setTab(healthCheck ? 'health' : 'manage')
43
+ if (tab === 'health' && !healthCheck && (historyFiles || searchEnabled)) setTab(historyFiles ? 'history' : 'manage')
44
+ if (tab === 'manage' && !searchEnabled && historyFiles) setTab('history')
45
+ }, [tab, historyFiles, healthCheck, searchEnabled])
46
+
47
+ useEffect(() => {
48
+ const onKey = (event: KeyboardEvent): void => { if (event.key === 'Escape') onClose() }
49
+ document.addEventListener('keydown', onKey)
50
+ return () => { document.removeEventListener('keydown', onKey) }
51
+ }, [onClose])
52
+
53
+ const tabs: ReactElement[] = []
54
+ if (historyFiles) {
55
+ tabs.push(createElement('button', {
56
+ key: TAB_HISTORY,
57
+ id: TAB_HISTORY,
58
+ type: 'button',
59
+ className: `dss_tab${tab === 'history' ? ' dss_tabActive' : ''}`,
60
+ 'aria-selected': tab === 'history',
61
+ onClick: () => { setTab('history') },
62
+ }, translate(t, 'panel.tab.history')))
63
+ }
64
+ if (healthCheck) {
65
+ tabs.push(createElement('button', {
66
+ key: TAB_HEALTH,
67
+ id: TAB_HEALTH,
68
+ type: 'button',
69
+ className: `dss_tab${tab === 'health' ? ' dss_tabActive' : ''}`,
70
+ 'aria-selected': tab === 'health',
71
+ onClick: () => { setTab('health') },
72
+ }, translate(t, 'panel.tab.health')))
73
+ }
74
+ if (searchEnabled) {
75
+ tabs.push(createElement('button', {
76
+ key: TAB_MANAGE,
77
+ id: TAB_MANAGE,
78
+ type: 'button',
79
+ className: `dss_tab${tab === 'manage' ? ' dss_tabActive' : ''}`,
80
+ 'aria-selected': tab === 'manage',
81
+ onClick: () => { setTab('manage') },
82
+ }, translate(t, 'panel.tab.manage')))
83
+ }
84
+
85
+ const body: ReactElement = tab === 'history' && historyFiles
86
+ ? createElement(HistoryPanel, { t, onClose })
87
+ : tab === 'health' && healthCheck
88
+ ? createElement(HealthPanel, { t, onClose })
89
+ : tab === 'manage' && searchEnabled
90
+ ? createElement('div', { style: { display: 'flex', flexDirection: 'column', flex: '1 1 auto', minHeight: 0 } },
91
+ createElement(ManageConsole, { open: openSession ?? (() => {}) }))
92
+ : createElement('div', { className: 'dss_empty' }, translate(t, 'card.enabled.desc'))
93
+
94
+ return createPortal(createElement('div', { key: 'steward-root' }, [
95
+ createElement('div', { key: 'backdrop', className: 'dss_backdrop', onClick: onClose }),
96
+ createElement('div', {
97
+ key: 'panel',
98
+ className: 'dss_panel',
99
+ role: 'dialog',
100
+ 'aria-label': translate(t, 'panel.title'),
101
+ style: { display: 'flex', flexDirection: 'column' },
102
+ }, [
103
+ createElement('div', { key: 'head', className: 'dss_dialogHead' }, [
104
+ createElement('span', { key: 'title', className: 'dss_dialogTitle' }, translate(t, 'panel.title')),
105
+ createElement('span', { key: 'tabs', className: 'dss_tabRow' }, tabs),
106
+ createElement('button', {
107
+ key: 'close',
108
+ type: 'button',
109
+ className: 'dss_actBtn',
110
+ onClick: onClose,
111
+ }, translate(t, 'panel.close')),
112
+ ]),
113
+ body,
114
+ ]),
115
+ ]), document.body)
116
+ }
117
+
118
+ /** 侧边栏脚部入口:宽栏带文案成行控件,收起轨道退化为 36x36 图标钮。 */
119
+ export function StewardFooter(props: {
120
+ onClick?: () => void
121
+ title?: string
122
+ label?: string
123
+ wide?: boolean
124
+ }): ReactElement {
125
+ const wide = props.wide === true
126
+ return createElement('button', {
127
+ type: 'button',
128
+ className: wide ? 'dss_footerEntry' : 'dss_footerEntry dss_footerEntryRail',
129
+ title: props.title,
130
+ 'aria-label': props.title,
131
+ onClick: props.onClick,
132
+ }, [
133
+ createElement('span', { key: 'icon', className: 'dss_footerIcon', 'aria-hidden': true }, '🧭'),
134
+ // 收起轨道里 36px 装不下文案,标签与宽栏同条件出现,与搜索入口一致。
135
+ wide && props.label !== undefined
136
+ ? createElement('span', { key: 'label', className: 'dss_footerLabel' }, props.label)
137
+ : null,
138
+ ])
139
+ }