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.
- package/CHANGELOG.md +36 -0
- package/README.en.md +4 -0
- package/README.md +4 -0
- package/cordis.patch.yml +6 -1
- package/dsh.plugin.json +22 -22
- package/lib/client.js +3848 -202
- package/lib/index.d.ts +759 -29
- package/lib/index.js +2604 -93
- package/locale/de.json +6 -0
- package/locale/en.json +6 -0
- package/locale/es.json +6 -0
- package/locale/fr.json +6 -0
- package/locale/it.json +6 -0
- package/locale/ja.json +6 -0
- package/locale/ko.json +6 -0
- package/locale/ru.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +43 -32
- package/src/client/bridge-scope.ts +213 -0
- package/src/client/index.ts +154 -26
- package/src/client/locales.ts +857 -223
- package/src/client/panel.tsx +139 -118
- package/src/client/search/card.tsx +563 -0
- package/src/client/search/host-api.ts +208 -0
- package/src/client/search/locales.ts +780 -0
- package/src/client/search/manage.tsx +400 -0
- package/src/client/search/panel.tsx +815 -0
- package/src/client/search/platform.ts +136 -0
- package/src/config.ts +54 -5
- package/src/host/history/archive-source.ts +48 -0
- package/src/host/history/archive.ts +56 -1
- package/src/host/history/favorites.ts +71 -0
- package/src/host/index/archive-source.ts +90 -0
- package/src/host/index/engine.ts +571 -0
- package/src/host/index/extract.ts +272 -0
- package/src/host/index/peers.ts +62 -0
- package/src/host/index/rebuild.ts +368 -0
- package/src/host/index/schema.ts +136 -0
- package/src/host/index/snapshot.ts +135 -0
- package/src/host/index/sync.ts +286 -0
- package/src/host/registry/archive-registry.ts +317 -0
- package/src/host/settings-bridge.ts +237 -0
- package/src/index.ts +1421 -532
package/src/client/panel.tsx
CHANGED
|
@@ -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 {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
createElement('
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'aria-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
+
}
|