dsh-config-manager 0.1.13 → 0.1.14
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/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/lib/client.d.ts +76 -73
- package/lib/client.js +688 -694
- package/lib/client.js.map +1 -1
- package/package.json +2 -2
- package/src/client/ConfigManagerSection.tsx +33 -8
- package/src/client/client-types.ts +4 -0
- package/src/client/index.ts +5 -11
- package/src/client/locales.ts +2 -0
- package/src/client/sync/SyncSettingsView.tsx +9 -23
- package/src/client/sync/sync-api.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-config-manager",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DSH Config Manager
|
|
3
|
+
"version": "0.1.14",
|
|
4
|
+
"description": "DSH Config Manager — backup / export / import / migrate DSH configuration (dual-face Cordis plugin: host engine + web UI). Manifest shape mirrors @linxin666/dsh-ssh@0.1.12.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
7
7
|
"deepseek-harness",
|
|
@@ -16,6 +16,7 @@ import { runStore, type MainView } from './run-store.ts'
|
|
|
16
16
|
import { ExportView } from './export/ExportView.tsx'
|
|
17
17
|
import { ImportWizardView } from './import/ImportWizardView.tsx'
|
|
18
18
|
import { SnapshotsPanel } from './snapshots/SnapshotsPanel.tsx'
|
|
19
|
+
import { SyncSettingsView } from './sync/SyncSettingsView.tsx'
|
|
19
20
|
import css from './config-manager.module.css'
|
|
20
21
|
|
|
21
22
|
export type ConfigManagerSectionProps =
|
|
@@ -24,14 +25,15 @@ export type ConfigManagerSectionProps =
|
|
|
24
25
|
& { t: TranslateNS<'config-manager'> }
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* 设置页容器:Export / Import / Snapshots
|
|
28
|
-
* Export/Import 状态在模块级 store(切 tab
|
|
28
|
+
* 设置页容器:Export / Import / Snapshots / Sync 四视图切换。
|
|
29
|
+
* Export/Import 状态在模块级 store(切 tab 不丢失);快照恢复与远程同步为低频显式
|
|
29
30
|
* 操作,其状态组件内自持(local state,不进 sessionStorage)。
|
|
30
31
|
*/
|
|
31
|
-
export function ConfigManagerSection({ api, t }: ConfigManagerSectionProps) {
|
|
32
|
+
export function ConfigManagerSection({ api, syncApi, syncT, t }: ConfigManagerSectionProps) {
|
|
32
33
|
const state = useSyncExternalStore(runStore.subscribe, runStore.getSnapshot)
|
|
33
34
|
const view = state.view
|
|
34
35
|
const [snapshotsOpen, setSnapshotsOpen] = useState(false)
|
|
36
|
+
const [syncOpen, setSyncOpen] = useState(false)
|
|
35
37
|
|
|
36
38
|
// m2-resume:挂载时重新订阅进行中的 run(刷新 / 重开面板后服务端继续执行,
|
|
37
39
|
// 这里经 /runs 找回活跃 runId 再轮询 /progress);卸载时停止轮询,重开再订阅。
|
|
@@ -44,10 +46,21 @@ export function ConfigManagerSection({ api, t }: ConfigManagerSectionProps) {
|
|
|
44
46
|
|
|
45
47
|
const setView = (next: MainView): void => {
|
|
46
48
|
setSnapshotsOpen(false)
|
|
49
|
+
setSyncOpen(false)
|
|
47
50
|
runStore.patch({ view: next })
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
const
|
|
53
|
+
const openSnapshots = (): void => {
|
|
54
|
+
setSnapshotsOpen(true)
|
|
55
|
+
setSyncOpen(false)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const openSync = (): void => {
|
|
59
|
+
setSyncOpen(true)
|
|
60
|
+
setSnapshotsOpen(false)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const activeTab: MainView | 'snapshots' | 'sync' = syncOpen ? 'sync' : snapshotsOpen ? 'snapshots' : view
|
|
51
64
|
|
|
52
65
|
return (
|
|
53
66
|
<div className={css.section}>
|
|
@@ -79,16 +92,28 @@ export function ConfigManagerSection({ api, t }: ConfigManagerSectionProps) {
|
|
|
79
92
|
aria-selected={activeTab === 'snapshots'}
|
|
80
93
|
data-active={snapshotsOpen ? '' : undefined}
|
|
81
94
|
className={css.viewTab}
|
|
82
|
-
onClick={
|
|
95
|
+
onClick={openSnapshots}
|
|
83
96
|
>
|
|
84
97
|
{t('view.snapshots')}
|
|
85
98
|
</button>
|
|
99
|
+
<button
|
|
100
|
+
type="button"
|
|
101
|
+
role="tab"
|
|
102
|
+
aria-selected={activeTab === 'sync'}
|
|
103
|
+
data-active={syncOpen ? '' : undefined}
|
|
104
|
+
className={css.viewTab}
|
|
105
|
+
onClick={openSync}
|
|
106
|
+
>
|
|
107
|
+
{t('view.sync')}
|
|
108
|
+
</button>
|
|
86
109
|
</div>
|
|
87
110
|
</div>
|
|
88
111
|
<div className={css.sectionBody}>
|
|
89
|
-
{
|
|
90
|
-
? <
|
|
91
|
-
:
|
|
112
|
+
{syncOpen
|
|
113
|
+
? <SyncSettingsView api={syncApi} t={syncT} />
|
|
114
|
+
: snapshotsOpen
|
|
115
|
+
? <SnapshotsPanel api={api} t={t} />
|
|
116
|
+
: view === 'export' ? <ExportView api={api} t={t} /> : <ImportWizardView api={api} t={t} />}
|
|
92
117
|
</div>
|
|
93
118
|
</div>
|
|
94
119
|
)
|
|
@@ -18,4 +18,8 @@ export type { TranslateNS }
|
|
|
18
18
|
/** 本插件 Client 半的注入业务面:每个 settings.section 注册项都拿到同一个 api 实例 */
|
|
19
19
|
export interface ConfigManagerSectionInjected {
|
|
20
20
|
api: import('./api.ts').ConfigManagerApi
|
|
21
|
+
/** 远程同步 API(备份与迁移页第 4 个 tab 使用,主 section 注册时注入) */
|
|
22
|
+
syncApi: import('./sync/sync-api.ts').SyncApi
|
|
23
|
+
/** 远程同步 locale(config-manager-sync 命名空间,主 section 注册时注入) */
|
|
24
|
+
syncT: import('@deepseek-ai/dsh-client-ui-slots').TranslateNS<'config-manager-sync'>
|
|
21
25
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -66,22 +66,16 @@ export function apply(ctx: ClientContext): void {
|
|
|
66
66
|
const syncT = ctx.locale.bind(SYNC_NS)
|
|
67
67
|
const syncApi = new SyncApi()
|
|
68
68
|
|
|
69
|
+
// 单一 settings.section:备份与迁移页(内部 Export/Import/Snapshots/Sync 四 tab)。
|
|
70
|
+
// 远程同步不再注册独立设置页 —— 并入主 section 的 inject 面(syncApi/syncT),
|
|
71
|
+
// 由 ConfigManagerSection 渲染第 4 个 tab。避免第二个 settings.section 注册在
|
|
72
|
+
// 目标 DSH 渲染 section 列表时抛错导致整页空白。
|
|
69
73
|
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
70
74
|
name: 'settings.section',
|
|
71
75
|
id: 'config-manager',
|
|
72
76
|
order: 60,
|
|
73
77
|
label: () => t('section.label'),
|
|
74
78
|
locale: NS,
|
|
75
|
-
inject: () => ({ api }),
|
|
79
|
+
inject: () => ({ api, syncApi, syncT }),
|
|
76
80
|
}, ConfigManagerSection))
|
|
77
|
-
|
|
78
|
-
// m-sync-ui:远程同步独立设置页(不触碰 ConfigManagerSection 的 tab 容器)。
|
|
79
|
-
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
80
|
-
name: 'settings.section',
|
|
81
|
-
id: 'config-manager-sync',
|
|
82
|
-
order: 70,
|
|
83
|
-
label: () => syncT('section.label'),
|
|
84
|
-
locale: SYNC_NS,
|
|
85
|
-
inject: () => ({ api: syncApi }),
|
|
86
|
-
}, SyncSettingsView))
|
|
87
81
|
}
|
package/src/client/locales.ts
CHANGED
|
@@ -12,6 +12,7 @@ export const zh = {
|
|
|
12
12
|
'view.export': '导出备份',
|
|
13
13
|
'view.import': '导入恢复',
|
|
14
14
|
'view.snapshots': '快照恢复',
|
|
15
|
+
'view.sync': '远程同步',
|
|
15
16
|
// 公共
|
|
16
17
|
'common.close': '关闭',
|
|
17
18
|
'common.cancel': '取消',
|
|
@@ -128,6 +129,7 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
128
129
|
'view.export': 'Export',
|
|
129
130
|
'view.import': 'Import',
|
|
130
131
|
'view.snapshots': 'Snapshots & Restore',
|
|
132
|
+
'view.sync': 'Remote Sync',
|
|
131
133
|
'common.close': 'Close',
|
|
132
134
|
'common.cancel': 'Cancel',
|
|
133
135
|
'common.back': 'Back',
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 远程同步面板(备份与迁移页的第 4 个 tab 内容)。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 独立设置页壳(sectionHeader/close/自身 tab)已移除 —— tab 容器由
|
|
5
|
+
* ConfigManagerSection 统一渲染,本组件只输出内容体:
|
|
5
6
|
* - 仓库配置表单:repoUrl(必填)+ 认证 token(可选,写入 DSH credentials 的提示)
|
|
6
7
|
* + gitBin(可选);
|
|
7
8
|
* - 私有仓库强制提示横幅(常驻);
|
|
@@ -16,7 +17,6 @@
|
|
|
16
17
|
*/
|
|
17
18
|
import { useEffect, useState } from 'react'
|
|
18
19
|
import type { ChangeEvent } from 'react'
|
|
19
|
-
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
20
20
|
import type { TranslateNS } from '../client-types.ts'
|
|
21
21
|
import type { SyncPullReport, SyncPushReport } from '../../sync/sync-engine.ts'
|
|
22
22
|
import { Badge, Banner, Button, Card, SectionTitle, Spinner } from '../common/ui.tsx'
|
|
@@ -29,15 +29,11 @@ import {
|
|
|
29
29
|
} from './sync-view.ts'
|
|
30
30
|
import css from '../config-manager.module.css'
|
|
31
31
|
|
|
32
|
-
export interface
|
|
32
|
+
export interface SyncSettingsViewProps {
|
|
33
33
|
api: SyncApi
|
|
34
|
+
t: TranslateNS<'config-manager-sync'>
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
export type SyncSettingsViewProps =
|
|
37
|
-
& PropsRuntime<'settings.section'>
|
|
38
|
-
& SyncSettingsSectionInjected
|
|
39
|
-
& { t: TranslateNS<'config-manager-sync'> }
|
|
40
|
-
|
|
41
37
|
interface SyncUiState {
|
|
42
38
|
loading: boolean
|
|
43
39
|
loadError: string | null
|
|
@@ -65,7 +61,7 @@ const initial: SyncUiState = {
|
|
|
65
61
|
error: null,
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
export function SyncSettingsView({
|
|
64
|
+
export function SyncSettingsView({ api, t }: SyncSettingsViewProps) {
|
|
69
65
|
const [state, setState] = useState<SyncUiState>(initial)
|
|
70
66
|
const patch = (p: Partial<SyncUiState>): void => setState((s) => ({ ...s, ...p }))
|
|
71
67
|
|
|
@@ -120,16 +116,8 @@ export function SyncSettingsView({ close, api, t }: SyncSettingsViewProps) {
|
|
|
120
116
|
const pullView = pullReportView(state.pullReport)
|
|
121
117
|
|
|
122
118
|
return (
|
|
123
|
-
<div className={css.
|
|
124
|
-
<
|
|
125
|
-
<div className={css.viewTabs}>
|
|
126
|
-
<span role="tab" aria-selected="true" data-active className={css.viewTab}>{t('section.label')}</span>
|
|
127
|
-
</div>
|
|
128
|
-
<button type="button" className={css.iconButton} title={t('common.close')} aria-label={t('common.close')} onClick={close}>×</button>
|
|
129
|
-
</div>
|
|
130
|
-
<div className={css.sectionBody}>
|
|
131
|
-
<div className={css.viewBody}>
|
|
132
|
-
<SectionTitle title={t('section.label')} subtitle={t('section.description')} />
|
|
119
|
+
<div className={css.viewBody}>
|
|
120
|
+
<SectionTitle title={t('section.label')} subtitle={t('section.description')} />
|
|
133
121
|
|
|
134
122
|
{/* 私有仓库强制提示 */}
|
|
135
123
|
<Banner kind="warn">{PRIVATE_REPO_HINT}</Banner>
|
|
@@ -254,8 +242,6 @@ export function SyncSettingsView({ close, api, t }: SyncSettingsViewProps) {
|
|
|
254
242
|
{pullView.previewHint !== '' && <Banner kind="info">{pullView.previewHint}</Banner>}
|
|
255
243
|
</Card>
|
|
256
244
|
)}
|
|
257
|
-
</div>
|
|
258
|
-
</div>
|
|
259
245
|
</div>
|
|
260
246
|
)
|
|
261
|
-
}
|
|
247
|
+
}
|
|
@@ -112,7 +112,7 @@ async function postJson<T>(path: string, body: unknown): Promise<T> {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
/**
|
|
115
|
+
/** 远程同步浏览器半数据入口(备份与迁移页第 4 个 tab 的注入业务面) */
|
|
116
116
|
export class SyncApi {
|
|
117
117
|
/** 读取同步状态(配置 / 凭据 / 上次同步时间 / 分区数) */
|
|
118
118
|
async status(): Promise<SyncStatusResponse> {
|