@xmanrui/dsh-im 4.11.0 → 4.12.0
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.en.md +2 -1
- package/README.md +2 -1
- package/lib/client.js +1209 -1033
- package/lib/index.js +241 -240
- package/package.json +1 -1
- package/plugin-src/client/channels/dingtalk/index.js +16 -5
- package/plugin-src/client/channels/feishu/index.js +45 -36
- package/plugin-src/client/channels/qq/index.js +16 -5
- package/plugin-src/client/channels/shared/collapsible-account.js +80 -0
- package/plugin-src/client/channels/shared/token-channel.js +39 -28
- package/plugin-src/client/channels/wecom/index.js +16 -5
- package/plugin-src/client/channels/weixin/index.js +16 -5
- package/plugin-src/client/channels/whatsapp/index.js +16 -5
- package/plugin-src/client/i18n.js +2 -0
- package/plugin-src/client/styles.js +12 -0
- package/src/channels/shared/i18n-en/wecom.mjs +24 -0
- package/src/channels/wecom/wecom-bridge.mjs +275 -2
- package/src/channels/wecom/wecom-cards.mjs +101 -0
- package/src/channels/wecom/wecom-runtime.mjs +2 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +78 -26
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
4
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
4
5
|
import { h } from '../../i18n.js';
|
|
5
6
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
6
7
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -256,13 +257,20 @@ export function AccountCard({
|
|
|
256
257
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
257
258
|
return h('article', { className: 'ddt-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
258
259
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
259
|
-
h(
|
|
260
|
+
h(CollapsibleAccountSection, {
|
|
261
|
+
id: `ddt-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
262
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
260
263
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
261
264
|
h('div', { className: 'ddt-avatar dim-botAvatar', 'aria-hidden': 'true' }, h(DingtalkIcon, { size: 29 })),
|
|
262
265
|
h('div', { className: 'dim-botName' },
|
|
263
266
|
h('h3', { title: account.bot.name }, account.bot.name),
|
|
264
267
|
h('p', { title: account.bot.clientIdMasked }, account.bot.clientIdMasked))),
|
|
265
|
-
h('div', {
|
|
268
|
+
h('div', {
|
|
269
|
+
className: 'dim-botCardTools',
|
|
270
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
271
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
272
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
273
|
+
},
|
|
266
274
|
h(BotStatusMeta, {
|
|
267
275
|
className: 'ddt-health',
|
|
268
276
|
dotClassName: 'ddt-dot',
|
|
@@ -277,8 +285,9 @@ export function AccountCard({
|
|
|
277
285
|
botName: account.bot.name,
|
|
278
286
|
connected: account.connected,
|
|
279
287
|
accessPolicy: account.accessPolicy,
|
|
280
|
-
})))
|
|
281
|
-
|
|
288
|
+
})))
|
|
289
|
+
},
|
|
290
|
+
h(WorkspaceEditor, {
|
|
282
291
|
workspace: account.workspace,
|
|
283
292
|
disabled: Boolean(busy),
|
|
284
293
|
onSave: onWorkspaceSave,
|
|
@@ -314,7 +323,9 @@ export function AccountCard({
|
|
|
314
323
|
feedback ? h('div', {
|
|
315
324
|
className: 'ddt-summary dim-cardFeedback',
|
|
316
325
|
role: 'status',
|
|
317
|
-
}, feedback) : null))
|
|
326
|
+
}, feedback) : null)),
|
|
327
|
+
),
|
|
328
|
+
),
|
|
318
329
|
removing ? h(RemoveConfirmation, {
|
|
319
330
|
account,
|
|
320
331
|
busy: busy === 'delete',
|
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import { FeishuLogoGlyph } from "../../channel-logos.js";
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from "../../credential-binding.js";
|
|
5
|
+
import { CollapsibleAccountSection } from "../shared/collapsible-account.js";
|
|
5
6
|
import { h } from "../../i18n.js";
|
|
6
7
|
import {
|
|
7
8
|
FEISHU_ENDPOINTS,
|
|
@@ -506,42 +507,49 @@ export function BotCard({
|
|
|
506
507
|
ref: cardRef,
|
|
507
508
|
},
|
|
508
509
|
h("div", { className: "bxf-cardBody dim-botCardBody" },
|
|
509
|
-
h(
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
h("
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
510
|
+
h(CollapsibleAccountSection, {
|
|
511
|
+
id: `bxf-settings-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
|
|
512
|
+
header: h("div", { className: "bxf-connectedTop dim-botCardTop" },
|
|
513
|
+
h("div", { className: "bxf-botIdentity dim-botIdentity" },
|
|
514
|
+
h("div", { className: "bxf-avatar dim-botAvatar", "aria-hidden": "true" },
|
|
515
|
+
h(FeishuLogoGlyph, { size: 34 })),
|
|
516
|
+
h("div", { className: "bxf-botName dim-botName" },
|
|
517
|
+
h("h3", { id: titleId, title: bot.name }, bot.name),
|
|
518
|
+
h("p", { title: bot.appIdMasked }, bot.appIdMasked ?? "应用标识已安全保存")),
|
|
519
|
+
),
|
|
520
|
+
h("div", {
|
|
521
|
+
className: "dim-botCardTools",
|
|
522
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
523
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
524
|
+
onKeyDown: (event) => { if (event.key === "Enter" || event.key === " ") event.stopPropagation(); },
|
|
525
|
+
},
|
|
526
|
+
h(BotStatusMeta, {
|
|
527
|
+
className: "bxf-healthPill",
|
|
528
|
+
dotClassName: "bxf-dot",
|
|
529
|
+
tone,
|
|
530
|
+
stateLabel: HEALTH_LABELS[stateForDisplay] ?? "状态未知",
|
|
531
|
+
lastCheckedAt: health.lastCheckedAt,
|
|
532
|
+
formatCheckedTime,
|
|
533
|
+
healthState: stateForDisplay,
|
|
534
|
+
}),
|
|
535
|
+
h(BotSettingsButton, {
|
|
536
|
+
channel: "feishu",
|
|
537
|
+
botId: connection.botId,
|
|
538
|
+
botName: bot.name,
|
|
539
|
+
connected,
|
|
540
|
+
accessPolicy: connection.accessPolicy,
|
|
541
|
+
channelSettings: {
|
|
542
|
+
groupResponseMode: connection.groupResponseMode,
|
|
543
|
+
groupTopicReply: connection.groupTopicReply,
|
|
544
|
+
groupMessagePermissionGranted: connection.groupMessagePermissionGranted,
|
|
545
|
+
},
|
|
546
|
+
}))),
|
|
547
|
+
},
|
|
548
|
+
h(WorkspaceEditor, {
|
|
549
|
+
workspace: connection.workspace,
|
|
550
|
+
disabled: Boolean(busy),
|
|
551
|
+
onSave: onWorkspaceSave,
|
|
552
|
+
}),
|
|
545
553
|
h(ModelEditor, {
|
|
546
554
|
model: connection.model,
|
|
547
555
|
disabled: Boolean(busy),
|
|
@@ -605,6 +613,7 @@ export function BotCard({
|
|
|
605
613
|
className: "bxf-healthSummary dim-cardFeedback",
|
|
606
614
|
role: "status",
|
|
607
615
|
}, testNotice) : null),
|
|
616
|
+
),
|
|
608
617
|
),
|
|
609
618
|
),
|
|
610
619
|
removing
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { QqLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -184,12 +185,19 @@ export function AccountCard({
|
|
|
184
185
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
185
186
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
186
187
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
187
|
-
h(
|
|
188
|
+
h(CollapsibleAccountSection, {
|
|
189
|
+
id: `qq-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
190
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
188
191
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
189
192
|
h('div', { className: 'ddt-avatar dim-botAvatar dqq-avatar', 'aria-hidden': 'true' }, h(QqLogoGlyph, { size: 29 })),
|
|
190
193
|
h('div', { className: 'dim-botName' },
|
|
191
194
|
h('h3', null, account.bot.name), h('p', null, account.bot.appIdMasked))),
|
|
192
|
-
h('div', {
|
|
195
|
+
h('div', {
|
|
196
|
+
className: 'dim-botCardTools',
|
|
197
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
198
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
199
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
200
|
+
},
|
|
193
201
|
h(BotStatusMeta, {
|
|
194
202
|
className: 'ddt-health',
|
|
195
203
|
dotClassName: 'ddt-dot',
|
|
@@ -204,8 +212,9 @@ export function AccountCard({
|
|
|
204
212
|
botName: account.bot.name,
|
|
205
213
|
connected: account.connected,
|
|
206
214
|
accessPolicy: account.accessPolicy,
|
|
207
|
-
})))
|
|
208
|
-
|
|
215
|
+
})))
|
|
216
|
+
},
|
|
217
|
+
h(WorkspaceEditor, {
|
|
209
218
|
workspace: account.workspace,
|
|
210
219
|
disabled: Boolean(busy),
|
|
211
220
|
onSave: onWorkspaceSave,
|
|
@@ -239,7 +248,9 @@ export function AccountCard({
|
|
|
239
248
|
className: 'ddt-summary dim-cardFeedback',
|
|
240
249
|
role: 'status',
|
|
241
250
|
'aria-live': 'polite',
|
|
242
|
-
}, feedback) : null))
|
|
251
|
+
}, feedback) : null)),
|
|
252
|
+
),
|
|
253
|
+
),
|
|
243
254
|
removing ? h(RemoveConfirmation, {
|
|
244
255
|
account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove,
|
|
245
256
|
}) : null);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapsible per-account card, shared by every IM channel.
|
|
3
|
+
*
|
|
4
|
+
* When several accounts are connected, each account's workspace / preset /
|
|
5
|
+
* context-enhancement editors make the list extremely long. This component
|
|
6
|
+
* renders the account header as the toggle itself: collapsed, the card shows
|
|
7
|
+
* only the header line; clicking the header expands the settings details.
|
|
8
|
+
*
|
|
9
|
+
* Design notes:
|
|
10
|
+
* - The whole header is the toggle (click + keyboard). Buttons rendered inside
|
|
11
|
+
* the header must call stopPropagation so they keep their own behaviour.
|
|
12
|
+
* - A chevron sits at the end of the header line as the affordance.
|
|
13
|
+
* - Height animation uses grid-template-rows: 0fr -> 1fr (pure CSS).
|
|
14
|
+
* - Full a11y: the header is a button-like region with aria-expanded /
|
|
15
|
+
* aria-controls; the details region keeps native semantics.
|
|
16
|
+
* - Honors prefers-reduced-motion.
|
|
17
|
+
* - Styles are managed by the IM settings plugin, not individual accounts.
|
|
18
|
+
*/
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
import { h } from '../../i18n.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Collapsible account card.
|
|
24
|
+
*
|
|
25
|
+
* `header` renders the always-visible header line; clicking it toggles.
|
|
26
|
+
* Any interactive control inside the header should stop the click event so it
|
|
27
|
+
* does not toggle the section (e.g. the bot settings button).
|
|
28
|
+
* `children` is the collapsed details region.
|
|
29
|
+
*/
|
|
30
|
+
export function CollapsibleAccountSection({
|
|
31
|
+
header,
|
|
32
|
+
defaultOpen = false,
|
|
33
|
+
open: controlledOpen,
|
|
34
|
+
onToggle,
|
|
35
|
+
id,
|
|
36
|
+
className = '',
|
|
37
|
+
children,
|
|
38
|
+
}) {
|
|
39
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
40
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
41
|
+
const contentId = id ? `${id}-content` : undefined;
|
|
42
|
+
|
|
43
|
+
const toggle = () => {
|
|
44
|
+
if (controlledOpen === undefined) setUncontrolledOpen((value) => !value);
|
|
45
|
+
onToggle?.(!open);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const onKeyDown = (event) => {
|
|
49
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
toggle();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return h('div', {
|
|
56
|
+
className: `dim-collapsibleAccount ${open ? 'is-open' : ''} ${className}`.trim(),
|
|
57
|
+
'data-open': open ? 'true' : 'false',
|
|
58
|
+
},
|
|
59
|
+
h('div', {
|
|
60
|
+
className: 'dim-collapsibleHead',
|
|
61
|
+
role: 'button',
|
|
62
|
+
tabIndex: 0,
|
|
63
|
+
onClick: toggle,
|
|
64
|
+
onKeyDown,
|
|
65
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
66
|
+
'aria-controls': contentId,
|
|
67
|
+
'aria-label': open ? '收起该账号的设置' : '展开该账号的设置',
|
|
68
|
+
},
|
|
69
|
+
h('div', { className: 'dim-collapsibleHeaderContent' }, header),
|
|
70
|
+
h('span', { className: 'dim-collapsibleChevron', 'aria-hidden': 'true' }),
|
|
71
|
+
),
|
|
72
|
+
h('div', {
|
|
73
|
+
id: contentId,
|
|
74
|
+
className: 'dim-collapsibleBody',
|
|
75
|
+
role: 'region',
|
|
76
|
+
},
|
|
77
|
+
h('div', { className: 'dim-collapsibleBodyInner' }, children),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { CredentialActionIcon, CredentialBindingPanel } from '../../credential-binding.js';
|
|
4
|
+
import { CollapsibleAccountSection } from './collapsible-account.js';
|
|
4
5
|
import { h } from '../../i18n.js';
|
|
5
6
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
@@ -88,33 +89,41 @@ export function createTokenChannelSettings(definition) {
|
|
|
88
89
|
const identity = account.bot.username ? `@${account.bot.username}` : account.bot.idMasked;
|
|
89
90
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
90
91
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
91
|
-
h(
|
|
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
|
-
|
|
92
|
+
h(CollapsibleAccountSection, {
|
|
93
|
+
id: `tok-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
94
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
95
|
+
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
96
|
+
h('div', { className: `ddt-avatar dim-botAvatar ${avatarClass}`, 'aria-hidden': 'true' },
|
|
97
|
+
h(LogoGlyph, { size: 29 })),
|
|
98
|
+
h('div', { className: 'dim-botName' },
|
|
99
|
+
h('h3', null, account.bot.name), h('p', null, identity))),
|
|
100
|
+
h('div', {
|
|
101
|
+
className: 'dim-botCardTools',
|
|
102
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
103
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
104
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
105
|
+
},
|
|
106
|
+
h(BotStatusMeta, {
|
|
107
|
+
className: 'ddt-health',
|
|
108
|
+
dotClassName: 'ddt-dot',
|
|
109
|
+
tone,
|
|
110
|
+
stateLabel,
|
|
111
|
+
lastCheckedAt: account.health.lastCheckedAt,
|
|
112
|
+
formatCheckedTime: checkedTime,
|
|
113
|
+
}),
|
|
114
|
+
h(BotSettingsButton, {
|
|
115
|
+
channel: channel.toLowerCase(),
|
|
116
|
+
botId: account.botId,
|
|
117
|
+
botName: account.bot.name,
|
|
118
|
+
connected: account.connected,
|
|
119
|
+
accessPolicy: account.accessPolicy,
|
|
120
|
+
}))),
|
|
121
|
+
},
|
|
122
|
+
h(WorkspaceEditor, {
|
|
123
|
+
workspace: account.workspace,
|
|
124
|
+
disabled: Boolean(busy),
|
|
125
|
+
onSave: onWorkspaceSave,
|
|
126
|
+
}),
|
|
118
127
|
h(ModelEditor, {
|
|
119
128
|
model: account.model,
|
|
120
129
|
disabled: Boolean(busy),
|
|
@@ -157,7 +166,9 @@ export function createTokenChannelSettings(definition) {
|
|
|
157
166
|
testNotice ? h('div', {
|
|
158
167
|
className: 'ddt-summary dim-cardFeedback',
|
|
159
168
|
role: 'status',
|
|
160
|
-
}, testNotice) : null))
|
|
169
|
+
}, testNotice) : null)),
|
|
170
|
+
),
|
|
171
|
+
),
|
|
161
172
|
removing ? h('div', { className: 'ddt-confirm dim-confirm', role: 'alertdialog' },
|
|
162
173
|
h('strong', null, `从 DeepSeek Harness 移除“${account.bot.name}”?`),
|
|
163
174
|
h('p', null, `这会停止消息连接,并删除本机保存的 ${credentialNoun}、机器人配置及会话映射。${platformLabel}中的机器人不会被自动删除。`),
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WecomLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -183,12 +184,19 @@ export function AccountCard({
|
|
|
183
184
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
184
185
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
185
186
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
186
|
-
h(
|
|
187
|
+
h(CollapsibleAccountSection, {
|
|
188
|
+
id: `wec-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
189
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
187
190
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
188
191
|
h('div', { className: 'ddt-avatar dim-botAvatar dwecom-avatar', 'aria-hidden': 'true' }, h(WecomLogoGlyph, { size: 29 })),
|
|
189
192
|
h('div', { className: 'dim-botName' },
|
|
190
193
|
h('h3', null, account.bot.name), h('p', null, account.bot.appIdMasked))),
|
|
191
|
-
h('div', {
|
|
194
|
+
h('div', {
|
|
195
|
+
className: 'dim-botCardTools',
|
|
196
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
197
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
198
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
199
|
+
},
|
|
192
200
|
h(BotStatusMeta, {
|
|
193
201
|
className: 'ddt-health',
|
|
194
202
|
dotClassName: 'ddt-dot',
|
|
@@ -203,8 +211,9 @@ export function AccountCard({
|
|
|
203
211
|
botName: account.bot.name,
|
|
204
212
|
connected: account.connected,
|
|
205
213
|
accessPolicy: account.accessPolicy,
|
|
206
|
-
})))
|
|
207
|
-
|
|
214
|
+
})))
|
|
215
|
+
},
|
|
216
|
+
h(WorkspaceEditor, {
|
|
208
217
|
workspace: account.workspace,
|
|
209
218
|
disabled: Boolean(busy),
|
|
210
219
|
onSave: onWorkspaceSave,
|
|
@@ -238,7 +247,9 @@ export function AccountCard({
|
|
|
238
247
|
className: 'ddt-summary dim-cardFeedback',
|
|
239
248
|
role: 'status',
|
|
240
249
|
'aria-live': 'polite',
|
|
241
|
-
}, feedback) : null))
|
|
250
|
+
}, feedback) : null)),
|
|
251
|
+
),
|
|
252
|
+
),
|
|
242
253
|
removing ? h(RemoveConfirmation, {
|
|
243
254
|
account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove,
|
|
244
255
|
}) : null);
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WeixinLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import {
|
|
7
8
|
WEIXIN_ENDPOINTS,
|
|
@@ -225,11 +226,18 @@ export function AccountCard({
|
|
|
225
226
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
226
227
|
return h('article', { className: 'dxw-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
227
228
|
h('div', { className: 'dxw-cardBody dim-botCardBody' },
|
|
228
|
-
h(
|
|
229
|
+
h(CollapsibleAccountSection, {
|
|
230
|
+
id: `dxw-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
231
|
+
header: h('div', { className: 'dxw-accountTop dim-botCardTop' },
|
|
229
232
|
h('div', { className: 'dxw-accountIdentity dim-botIdentity' },
|
|
230
233
|
h('div', { className: 'dxw-avatar dim-botAvatar', 'aria-hidden': 'true' }, h(WeixinLogoGlyph, { size: 27 })),
|
|
231
234
|
h('div', { className: 'dim-botName' }, h('h3', null, account.bot.name), h('p', null, account.bot.accountIdMasked))),
|
|
232
|
-
h('div', {
|
|
235
|
+
h('div', {
|
|
236
|
+
className: 'dim-botCardTools',
|
|
237
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
238
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
239
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
240
|
+
},
|
|
233
241
|
h(BotStatusMeta, {
|
|
234
242
|
className: 'dxw-health',
|
|
235
243
|
dotClassName: 'dxw-dot',
|
|
@@ -244,8 +252,9 @@ export function AccountCard({
|
|
|
244
252
|
botName: account.bot.name,
|
|
245
253
|
connected: account.connected,
|
|
246
254
|
accessPolicy: account.accessPolicy,
|
|
247
|
-
})))
|
|
248
|
-
|
|
255
|
+
})))
|
|
256
|
+
},
|
|
257
|
+
h(WorkspaceEditor, {
|
|
249
258
|
workspace: account.workspace,
|
|
250
259
|
disabled: Boolean(busy),
|
|
251
260
|
onSave: onWorkspaceSave,
|
|
@@ -281,7 +290,9 @@ export function AccountCard({
|
|
|
281
290
|
className: 'dxw-summary dim-cardFeedback',
|
|
282
291
|
role: 'status',
|
|
283
292
|
'aria-live': 'polite',
|
|
284
|
-
}, feedback) : null))
|
|
293
|
+
}, feedback) : null)),
|
|
294
|
+
),
|
|
295
|
+
),
|
|
285
296
|
removing ? h('div', { className: 'dxw-confirm dim-confirm', role: 'alertdialog' },
|
|
286
297
|
h('strong', null, '从此 Harness 移除这个微信账号?'),
|
|
287
298
|
h('p', null, '这会停止消息连接,并删除本机保存的 bot_token、账号配置和会话映射。其他微信账号不受影响。'),
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { WhatsappLogoGlyph } from '../../channel-logos.js';
|
|
4
4
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
5
|
+
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
5
6
|
import { h } from '../../i18n.js';
|
|
6
7
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
8
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -203,7 +204,9 @@ export function WhatsappAccountCard({
|
|
|
203
204
|
const summary = account.error?.message ?? (account.connected ? null : account.health.summary);
|
|
204
205
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
205
206
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
206
|
-
h(
|
|
207
|
+
h(CollapsibleAccountSection, {
|
|
208
|
+
id: `wsp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
209
|
+
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
207
210
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
208
211
|
h('div', {
|
|
209
212
|
className: 'ddt-avatar dim-botAvatar dwa-avatar',
|
|
@@ -211,7 +214,12 @@ export function WhatsappAccountCard({
|
|
|
211
214
|
}, h(WhatsappLogoGlyph, { size: 29 })),
|
|
212
215
|
h('div', { className: 'dim-botName' },
|
|
213
216
|
h('h3', null, account.bot.name), h('p', null, account.bot.idMasked))),
|
|
214
|
-
h('div', {
|
|
217
|
+
h('div', {
|
|
218
|
+
className: 'dim-botCardTools',
|
|
219
|
+
// The header is the collapse toggle; keep inner controls clickable.
|
|
220
|
+
onClick: (event) => { event.stopPropagation(); },
|
|
221
|
+
onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') event.stopPropagation(); },
|
|
222
|
+
},
|
|
215
223
|
h(BotStatusMeta, {
|
|
216
224
|
className: 'ddt-health',
|
|
217
225
|
dotClassName: 'ddt-dot',
|
|
@@ -226,8 +234,9 @@ export function WhatsappAccountCard({
|
|
|
226
234
|
botName: account.bot.name,
|
|
227
235
|
connected: account.connected,
|
|
228
236
|
accessPolicy: account.accessPolicy,
|
|
229
|
-
})))
|
|
230
|
-
|
|
237
|
+
})))
|
|
238
|
+
},
|
|
239
|
+
h(WorkspaceEditor, {
|
|
231
240
|
workspace: account.workspace,
|
|
232
241
|
disabled: Boolean(busy),
|
|
233
242
|
onSave: onWorkspaceSave,
|
|
@@ -264,7 +273,9 @@ export function WhatsappAccountCard({
|
|
|
264
273
|
testNotice ? h('div', {
|
|
265
274
|
className: 'ddt-summary dim-cardFeedback',
|
|
266
275
|
role: 'status',
|
|
267
|
-
}, testNotice) : null))
|
|
276
|
+
}, testNotice) : null)),
|
|
277
|
+
),
|
|
278
|
+
),
|
|
268
279
|
removing ? h(RemoveConfirmation, {
|
|
269
280
|
account,
|
|
270
281
|
busy: busy === 'delete',
|
|
@@ -227,6 +227,8 @@ const EN = Object.freeze({
|
|
|
227
227
|
'手动接入': 'Manual setup',
|
|
228
228
|
'收起凭据': 'Hide credentials',
|
|
229
229
|
'收起接入': 'Hide setup',
|
|
230
|
+
'展开该账号的设置': "Expand this account's settings",
|
|
231
|
+
'收起该账号的设置': "Collapse this account's settings",
|
|
230
232
|
'接入机器人': 'Connect bot',
|
|
231
233
|
'开始接入': 'Start setup',
|
|
232
234
|
'在线': 'online',
|
|
@@ -358,6 +358,17 @@ const CSS = String.raw`
|
|
|
358
358
|
.dim-panel .dim-botCard { position: relative; min-width: 0; width: 100%; max-width: 100%; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, #e5e6eb); border-radius: 14px; background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 3%); }
|
|
359
359
|
.dim-panel .dim-botCard::before { display: none; }
|
|
360
360
|
.dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px; }
|
|
361
|
+
.dim-collapsibleAccount { min-width: 0; display: flex; flex-direction: column; }
|
|
362
|
+
.dim-collapsibleHead { min-width: 0; display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; -webkit-user-select: none; }
|
|
363
|
+
.dim-collapsibleHead:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; border-radius: 8px; }
|
|
364
|
+
.dim-collapsibleHeaderContent { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; }
|
|
365
|
+
.dim-collapsibleChevron { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 9px; height: 9px; border-right: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); border-bottom: 1.6px solid var(--dsw-alias-label-tertiary, #8f959e); transform: rotate(-45deg); transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
|
|
366
|
+
.dim-collapsibleAccount.is-open .dim-collapsibleChevron { transform: rotate(45deg); }
|
|
367
|
+
/* Animate height without measuring content; hide collapsed controls from focus and accessibility. */
|
|
368
|
+
.dim-collapsibleBody { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s cubic-bezier(.4, 0, .2, 1); }
|
|
369
|
+
.dim-collapsibleAccount.is-open > .dim-collapsibleBody { grid-template-rows: 1fr; }
|
|
370
|
+
.dim-collapsibleBodyInner { min-height: 0; overflow: hidden; }
|
|
371
|
+
.dim-collapsibleAccount:not(.is-open) .dim-collapsibleBodyInner { visibility: hidden; }
|
|
361
372
|
.dim-panel .dim-botCardTop { min-width: 0; max-width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
362
373
|
.dim-panel .dim-botIdentity { min-width: 0; flex: 1 1 0; display: flex; align-items: center; gap: 10px; }
|
|
363
374
|
.dim-panel .dim-botAvatar { flex: none; width: 38px; height: 38px; display: grid; place-items: center; overflow: hidden; border-radius: 11px; box-shadow: none; }
|
|
@@ -634,6 +645,7 @@ const CSS = String.raw`
|
|
|
634
645
|
@media (prefers-reduced-motion: reduce) {
|
|
635
646
|
.dim-page * { transition-duration: .01ms !important; }
|
|
636
647
|
.dim-directoryPickerSpinner { animation-duration: 1.8s; }
|
|
648
|
+
.dim-collapsibleBody, .dim-collapsibleChevron { transition: none !important; }
|
|
637
649
|
}
|
|
638
650
|
`;
|
|
639
651
|
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
// English translations (wecom area). Keys are exact Chinese literals passed to t().
|
|
2
2
|
export default {
|
|
3
|
+
'/menu 或 /m 打开可点击的功能菜单': '/menu or /m Open the interactive menu',
|
|
4
|
+
'保持当前': 'Keep current',
|
|
5
|
+
'会话': 'Session',
|
|
6
|
+
'模型': 'Model',
|
|
7
|
+
'预设': 'Preset',
|
|
8
|
+
'跟随默认模型': 'Default model',
|
|
9
|
+
'跟随 Host 默认': 'Follow Host default',
|
|
10
|
+
'新会话': 'New session',
|
|
11
|
+
'上一页': 'Previous',
|
|
12
|
+
'下一页': 'Next',
|
|
13
|
+
'返回': 'Back',
|
|
14
|
+
'更多选项…': 'More options…',
|
|
15
|
+
'选择会话、模型或预设后,点击应用设置。': 'Choose a session, model or preset, then apply settings.',
|
|
16
|
+
'应用设置': 'Apply settings',
|
|
17
|
+
'工作区与任务': 'Workspace & tasks',
|
|
18
|
+
'应用选择': 'Apply selection',
|
|
19
|
+
'请选择一个选项后再应用。': 'Select one option before applying.',
|
|
20
|
+
'设置未改变。': 'Settings unchanged.',
|
|
21
|
+
'已收到操作,请查看下方结果。': 'Action received. See the result below.',
|
|
22
|
+
'重新打开菜单': 'Reopen menu',
|
|
23
|
+
'暂无可用选项。': 'No options are available.',
|
|
24
|
+
'预设仅用于之后的新会话。': 'Presets apply to future new sessions.',
|
|
25
|
+
'部分模型暂不可用,可稍后重试。': 'Some models are unavailable. Try again later.',
|
|
26
|
+
'工作区已变化,请从新菜单重新选择。': 'The workspace changed. Please select again from the new menu.',
|
|
3
27
|
// Help text (wecom-bridge.mjs)
|
|
4
28
|
'企业微信机器人已连接 DeepSeek Harness。': 'The Enterprise WeChat bot is connected to DeepSeek Harness.',
|
|
5
29
|
|