@xmanrui/dsh-im 4.24.0 → 4.24.1
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 +5 -1
- package/README.md +5 -1
- package/lib/client.js +407 -334
- package/lib/index.js +194 -194
- package/package.json +5 -1
- package/plugin-src/client/channel-card-meta.js +3 -9
- package/plugin-src/client/channels/dingtalk/index.js +9 -8
- package/plugin-src/client/channels/feishu/index.js +14 -13
- package/plugin-src/client/channels/qq/index.js +9 -8
- package/plugin-src/client/channels/shared/collapsible-account.js +49 -26
- package/plugin-src/client/channels/shared/token-channel.js +9 -8
- package/plugin-src/client/channels/wecom/index.js +9 -8
- package/plugin-src/client/channels/wecom-app/index.js +9 -8
- package/plugin-src/client/channels/weixin/index.js +9 -8
- package/plugin-src/client/channels/whatsapp/index.js +9 -8
- package/plugin-src/client/i18n.js +5 -0
- package/plugin-src/client/styles.js +10 -6
- package/plugin-src/client/update-panel.js +18 -8
- package/plugin-src/host/update-service.mjs +19 -14
- package/src/channels/feishu/bridge.mjs +91 -42
- package/src/channels/shared/workspace-session.mjs +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmanrui/dsh-im",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.1",
|
|
4
4
|
"description": "把十一种 IM 渠道和公网 AI Office 接入本机 DeepSeek Harness。 Connect eleven IM channels and a public AI Office to a local DeepSeek Harness.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -80,6 +80,10 @@
|
|
|
80
80
|
{
|
|
81
81
|
"name": "wings1848",
|
|
82
82
|
"url": "https://github.com/wings1848"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "Zhe (Phil) Yang",
|
|
86
|
+
"url": "https://github.com/yangzhe1991"
|
|
83
87
|
}
|
|
84
88
|
],
|
|
85
89
|
"license": "MIT",
|
|
@@ -7,7 +7,7 @@ export const BotSettingsContext = React.createContext(Object.freeze({
|
|
|
7
7
|
openBotSettings() {},
|
|
8
8
|
}));
|
|
9
9
|
|
|
10
|
-
function SettingsGlyph() {
|
|
10
|
+
export function SettingsGlyph() {
|
|
11
11
|
return h('svg', {
|
|
12
12
|
viewBox: '0 0 24 24',
|
|
13
13
|
width: 16,
|
|
@@ -32,14 +32,12 @@ export function BotSettingsButton({
|
|
|
32
32
|
channelSettings,
|
|
33
33
|
}) {
|
|
34
34
|
const { openBotSettings } = React.useContext(BotSettingsContext);
|
|
35
|
-
const tooltipId = React.useId();
|
|
36
35
|
return h('span', { className: 'dim-botSettingsAction' },
|
|
37
36
|
h('button', {
|
|
38
37
|
type: 'button',
|
|
39
38
|
className: 'dim-botSettingsButton',
|
|
40
39
|
'data-delivery-channel': channel,
|
|
41
40
|
'aria-label': '更多机器人设置',
|
|
42
|
-
'aria-describedby': tooltipId,
|
|
43
41
|
onClick: () => openBotSettings?.({
|
|
44
42
|
...(channelSettings && typeof channelSettings === 'object' ? channelSettings : {}),
|
|
45
43
|
channel,
|
|
@@ -48,12 +46,8 @@ export function BotSettingsButton({
|
|
|
48
46
|
connected: Boolean(connected),
|
|
49
47
|
accessPolicy,
|
|
50
48
|
}),
|
|
51
|
-
}, h(SettingsGlyph)),
|
|
52
|
-
h('span', {
|
|
53
|
-
id: tooltipId,
|
|
54
|
-
className: 'dim-botSettingsTooltip',
|
|
55
|
-
role: 'tooltip',
|
|
56
|
-
}, '更多机器人设置'));
|
|
49
|
+
}, h(SettingsGlyph), h('span', null, '更多设置'),
|
|
50
|
+
h('span', { className: 'dim-moreSettingsChevron', 'aria-hidden': 'true' })));
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
function messageErrorTime(value) {
|
|
@@ -3,7 +3,7 @@ import { BotName } from '../../bot-alias.js';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
6
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
6
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
7
|
import { h } from '../../i18n.js';
|
|
8
8
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
9
9
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -251,6 +251,13 @@ export function AccountCard({
|
|
|
251
251
|
return h('article', { className: 'ddt-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
252
252
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
253
253
|
h(CollapsibleAccountSection, {
|
|
254
|
+
settings: h(BotSettingsButton, {
|
|
255
|
+
channel: 'dingtalk',
|
|
256
|
+
botId: account.botId,
|
|
257
|
+
botName: account.bot.name,
|
|
258
|
+
connected: account.connected,
|
|
259
|
+
accessPolicy: account.accessPolicy,
|
|
260
|
+
}),
|
|
254
261
|
id: `ddt-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
255
262
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
256
263
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -272,13 +279,7 @@ export function AccountCard({
|
|
|
272
279
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
273
280
|
formatCheckedTime: checkedTime,
|
|
274
281
|
}),
|
|
275
|
-
h(
|
|
276
|
-
channel: 'dingtalk',
|
|
277
|
-
botId: account.botId,
|
|
278
|
-
botName: account.bot.name,
|
|
279
|
-
connected: account.connected,
|
|
280
|
-
accessPolicy: account.accessPolicy,
|
|
281
|
-
})))
|
|
282
|
+
h(AccountSettingsToggle)))
|
|
282
283
|
},
|
|
283
284
|
h(WorkspaceEditor, {
|
|
284
285
|
workspace: account.workspace,
|
|
@@ -4,7 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
|
|
5
5
|
import { FeishuLogoGlyph } from "../../channel-logos.js";
|
|
6
6
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from "../../credential-binding.js";
|
|
7
|
-
import { CollapsibleAccountSection } from "../shared/collapsible-account.js";
|
|
7
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from "../shared/collapsible-account.js";
|
|
8
8
|
import { h } from "../../i18n.js";
|
|
9
9
|
import {
|
|
10
10
|
FEISHU_ENDPOINTS,
|
|
@@ -600,6 +600,18 @@ export function BotCard({
|
|
|
600
600
|
},
|
|
601
601
|
h("div", { className: "bxf-cardBody dim-botCardBody" },
|
|
602
602
|
h(CollapsibleAccountSection, {
|
|
603
|
+
settings: h(BotSettingsButton, {
|
|
604
|
+
channel: "feishu",
|
|
605
|
+
botId: connection.botId,
|
|
606
|
+
botName: bot.name,
|
|
607
|
+
connected,
|
|
608
|
+
accessPolicy: connection.accessPolicy,
|
|
609
|
+
channelSettings: {
|
|
610
|
+
groupResponseMode: connection.groupResponseMode,
|
|
611
|
+
groupTopicReply: connection.groupTopicReply,
|
|
612
|
+
groupMessagePermissionGranted: connection.groupMessagePermissionGranted,
|
|
613
|
+
},
|
|
614
|
+
}),
|
|
603
615
|
id: `bxf-settings-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`,
|
|
604
616
|
header: h("div", { className: "bxf-connectedTop dim-botCardTop" },
|
|
605
617
|
h("div", { className: "bxf-botIdentity dim-botIdentity" },
|
|
@@ -624,18 +636,7 @@ export function BotCard({
|
|
|
624
636
|
formatCheckedTime,
|
|
625
637
|
healthState: stateForDisplay,
|
|
626
638
|
}),
|
|
627
|
-
h(
|
|
628
|
-
channel: "feishu",
|
|
629
|
-
botId: connection.botId,
|
|
630
|
-
botName: bot.name,
|
|
631
|
-
connected,
|
|
632
|
-
accessPolicy: connection.accessPolicy,
|
|
633
|
-
channelSettings: {
|
|
634
|
-
groupResponseMode: connection.groupResponseMode,
|
|
635
|
-
groupTopicReply: connection.groupTopicReply,
|
|
636
|
-
groupMessagePermissionGranted: connection.groupMessagePermissionGranted,
|
|
637
|
-
},
|
|
638
|
-
}))),
|
|
639
|
+
h(AccountSettingsToggle))),
|
|
639
640
|
},
|
|
640
641
|
h(WorkspaceEditor, {
|
|
641
642
|
workspace: connection.workspace,
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { QqLogoGlyph } from '../../channel-logos.js';
|
|
6
6
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
7
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
8
8
|
import { h } from '../../i18n.js';
|
|
9
9
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
10
10
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -189,6 +189,13 @@ export function AccountCard({
|
|
|
189
189
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
190
190
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
191
191
|
h(CollapsibleAccountSection, {
|
|
192
|
+
settings: h(BotSettingsButton, {
|
|
193
|
+
channel: 'qq',
|
|
194
|
+
botId: account.botId,
|
|
195
|
+
botName: account.bot.name,
|
|
196
|
+
connected: account.connected,
|
|
197
|
+
accessPolicy: account.accessPolicy,
|
|
198
|
+
}),
|
|
192
199
|
id: `qq-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
193
200
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
194
201
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -209,13 +216,7 @@ export function AccountCard({
|
|
|
209
216
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
210
217
|
formatCheckedTime: checkedTime,
|
|
211
218
|
}),
|
|
212
|
-
h(
|
|
213
|
-
channel: 'qq',
|
|
214
|
-
botId: account.botId,
|
|
215
|
-
botName: account.bot.name,
|
|
216
|
-
connected: account.connected,
|
|
217
|
-
accessPolicy: account.accessPolicy,
|
|
218
|
-
})))
|
|
219
|
+
h(AccountSettingsToggle)))
|
|
219
220
|
},
|
|
220
221
|
h(WorkspaceEditor, {
|
|
221
222
|
workspace: account.workspace,
|
|
@@ -3,32 +3,64 @@
|
|
|
3
3
|
*
|
|
4
4
|
* When several accounts are connected, each account's workspace / preset /
|
|
5
5
|
* context-enhancement editors make the list extremely long. This component
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* keeps one settings toggle in the existing header tools slot. Clicking the
|
|
7
|
+
* header also expands the settings details; more settings live in the body.
|
|
8
8
|
*
|
|
9
9
|
* Design notes:
|
|
10
|
-
* - The
|
|
11
|
-
*
|
|
12
|
-
* - A chevron sits at the end of the header line as the affordance.
|
|
10
|
+
* - The native toggle owns keyboard interaction. Header controls stop click
|
|
11
|
+
* propagation so editing a name cannot accidentally toggle the card.
|
|
13
12
|
* - Height animation uses grid-template-rows: 0fr -> 1fr (pure CSS).
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
13
|
+
* - The toggle exposes aria-expanded / aria-controls; the body keeps native
|
|
14
|
+
* semantics and hides collapsed controls from focus and accessibility.
|
|
16
15
|
* - Honors prefers-reduced-motion.
|
|
17
16
|
* - Styles are managed by the IM settings plugin, not individual accounts.
|
|
18
17
|
*/
|
|
19
18
|
import * as React from 'react';
|
|
20
19
|
import { h } from '../../i18n.js';
|
|
20
|
+
import { SettingsGlyph } from '../../channel-card-meta.js';
|
|
21
|
+
|
|
22
|
+
const AccountSectionContext = React.createContext(null);
|
|
23
|
+
|
|
24
|
+
/** Renders in the original settings-button slot, beside the status metadata. */
|
|
25
|
+
export function AccountSettingsToggle() {
|
|
26
|
+
const { open, toggle, contentId } = React.useContext(AccountSectionContext);
|
|
27
|
+
return h('button', {
|
|
28
|
+
type: 'button',
|
|
29
|
+
className: 'dim-accountSettingsToggle',
|
|
30
|
+
'aria-label': open ? '收起该账号的设置' : '展开该账号的设置',
|
|
31
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
32
|
+
'aria-controls': contentId,
|
|
33
|
+
onClick: (event) => {
|
|
34
|
+
event.stopPropagation();
|
|
35
|
+
toggle();
|
|
36
|
+
},
|
|
37
|
+
}, h(SettingsGlyph),
|
|
38
|
+
h('svg', {
|
|
39
|
+
className: 'dim-collapsibleChevron',
|
|
40
|
+
viewBox: '0 0 12 16',
|
|
41
|
+
width: 12,
|
|
42
|
+
height: 16,
|
|
43
|
+
fill: 'none',
|
|
44
|
+
stroke: 'currentColor',
|
|
45
|
+
strokeWidth: 1.8,
|
|
46
|
+
strokeLinecap: 'round',
|
|
47
|
+
strokeLinejoin: 'round',
|
|
48
|
+
'aria-hidden': 'true',
|
|
49
|
+
}, h('path', { d: 'M2 6 6 10 10 6' })));
|
|
50
|
+
}
|
|
21
51
|
|
|
22
52
|
/**
|
|
23
53
|
* Collapsible account card.
|
|
24
54
|
*
|
|
25
55
|
* `header` renders the always-visible header line; clicking it toggles.
|
|
26
56
|
* Any interactive control inside the header should stop the click event so it
|
|
27
|
-
* does not toggle the section (e.g. the
|
|
57
|
+
* does not toggle the section (e.g. the alias editor).
|
|
58
|
+
* `settings` is the original more-settings action, shown above the editors.
|
|
28
59
|
* `children` is the collapsed details region.
|
|
29
60
|
*/
|
|
30
61
|
export function CollapsibleAccountSection({
|
|
31
62
|
header,
|
|
63
|
+
settings,
|
|
32
64
|
defaultOpen = false,
|
|
33
65
|
open: controlledOpen,
|
|
34
66
|
onToggle,
|
|
@@ -37,44 +69,35 @@ export function CollapsibleAccountSection({
|
|
|
37
69
|
children,
|
|
38
70
|
}) {
|
|
39
71
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
72
|
+
const generatedId = React.useId();
|
|
40
73
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
41
|
-
const contentId = id
|
|
74
|
+
const contentId = `${id ?? generatedId}-content`;
|
|
42
75
|
|
|
43
76
|
const toggle = () => {
|
|
44
77
|
if (controlledOpen === undefined) setUncontrolledOpen((value) => !value);
|
|
45
78
|
onToggle?.(!open);
|
|
46
79
|
};
|
|
47
80
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
event.preventDefault();
|
|
51
|
-
toggle();
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
return h('div', {
|
|
81
|
+
return h(AccountSectionContext.Provider, { value: { open, toggle, contentId } },
|
|
82
|
+
h('div', {
|
|
56
83
|
className: `dim-collapsibleAccount ${open ? 'is-open' : ''} ${className}`.trim(),
|
|
57
84
|
'data-open': open ? 'true' : 'false',
|
|
58
85
|
},
|
|
59
86
|
h('div', {
|
|
60
87
|
className: 'dim-collapsibleHead',
|
|
61
|
-
role: 'button',
|
|
62
|
-
tabIndex: 0,
|
|
63
88
|
onClick: toggle,
|
|
64
|
-
onKeyDown,
|
|
65
|
-
'aria-expanded': open ? 'true' : 'false',
|
|
66
|
-
'aria-controls': contentId,
|
|
67
|
-
'aria-label': open ? '收起该账号的设置' : '展开该账号的设置',
|
|
68
89
|
},
|
|
69
90
|
h('div', { className: 'dim-collapsibleHeaderContent' }, header),
|
|
70
|
-
h('span', { className: 'dim-collapsibleChevron', 'aria-hidden': 'true' }),
|
|
71
91
|
),
|
|
72
92
|
h('div', {
|
|
73
93
|
id: contentId,
|
|
74
94
|
className: 'dim-collapsibleBody',
|
|
75
95
|
role: 'region',
|
|
76
96
|
},
|
|
77
|
-
h('div', { className: 'dim-collapsibleBodyInner' },
|
|
97
|
+
h('div', { className: 'dim-collapsibleBodyInner' },
|
|
98
|
+
settings ? h('div', { className: 'dim-accountSettingsHeader' },
|
|
99
|
+
h('span', null, '常用配置'), settings) : null,
|
|
100
|
+
children),
|
|
78
101
|
),
|
|
79
|
-
);
|
|
102
|
+
));
|
|
80
103
|
}
|
|
@@ -3,7 +3,7 @@ import { BotName } from '../../bot-alias.js';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
import { CredentialActionIcon, CredentialBindingPanel } from '../../credential-binding.js';
|
|
6
|
-
import { CollapsibleAccountSection } from './collapsible-account.js';
|
|
6
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from './collapsible-account.js';
|
|
7
7
|
import { h } from '../../i18n.js';
|
|
8
8
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
9
9
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
@@ -92,6 +92,13 @@ export function createTokenChannelSettings(definition) {
|
|
|
92
92
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
93
93
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
94
94
|
h(CollapsibleAccountSection, {
|
|
95
|
+
settings: h(BotSettingsButton, {
|
|
96
|
+
channel: channel.toLowerCase(),
|
|
97
|
+
botId: account.botId,
|
|
98
|
+
botName: account.bot.name,
|
|
99
|
+
connected: account.connected,
|
|
100
|
+
accessPolicy: account.accessPolicy,
|
|
101
|
+
}),
|
|
95
102
|
id: `tok-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
96
103
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
97
104
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -113,13 +120,7 @@ export function createTokenChannelSettings(definition) {
|
|
|
113
120
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
114
121
|
formatCheckedTime: checkedTime,
|
|
115
122
|
}),
|
|
116
|
-
h(
|
|
117
|
-
channel: channel.toLowerCase(),
|
|
118
|
-
botId: account.botId,
|
|
119
|
-
botName: account.bot.name,
|
|
120
|
-
connected: account.connected,
|
|
121
|
-
accessPolicy: account.accessPolicy,
|
|
122
|
-
}))),
|
|
123
|
+
h(AccountSettingsToggle))),
|
|
123
124
|
},
|
|
124
125
|
h(WorkspaceEditor, {
|
|
125
126
|
workspace: account.workspace,
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { WecomLogoGlyph } from '../../channel-logos.js';
|
|
6
6
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
7
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
8
8
|
import { h } from '../../i18n.js';
|
|
9
9
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
10
10
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -188,6 +188,13 @@ export function AccountCard({
|
|
|
188
188
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
189
189
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
190
190
|
h(CollapsibleAccountSection, {
|
|
191
|
+
settings: h(BotSettingsButton, {
|
|
192
|
+
channel: 'wecom',
|
|
193
|
+
botId: account.botId,
|
|
194
|
+
botName: account.bot.name,
|
|
195
|
+
connected: account.connected,
|
|
196
|
+
accessPolicy: account.accessPolicy,
|
|
197
|
+
}),
|
|
191
198
|
id: `wec-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
192
199
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
193
200
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -208,13 +215,7 @@ export function AccountCard({
|
|
|
208
215
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
209
216
|
formatCheckedTime: checkedTime,
|
|
210
217
|
}),
|
|
211
|
-
h(
|
|
212
|
-
channel: 'wecom',
|
|
213
|
-
botId: account.botId,
|
|
214
|
-
botName: account.bot.name,
|
|
215
|
-
connected: account.connected,
|
|
216
|
-
accessPolicy: account.accessPolicy,
|
|
217
|
-
})))
|
|
218
|
+
h(AccountSettingsToggle)))
|
|
218
219
|
},
|
|
219
220
|
h(WorkspaceEditor, {
|
|
220
221
|
workspace: account.workspace,
|
|
@@ -3,7 +3,7 @@ import { BotName } from '../../bot-alias.js';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
import { WecomLogoGlyph } from '../../channel-logos.js';
|
|
6
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
6
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
7
|
import { h } from '../../i18n.js';
|
|
8
8
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
9
9
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -263,6 +263,13 @@ export function AccountCard({
|
|
|
263
263
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
264
264
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
265
265
|
h(CollapsibleAccountSection, {
|
|
266
|
+
settings: h(BotSettingsButton, {
|
|
267
|
+
channel: 'wecomApp',
|
|
268
|
+
botId: account.botId,
|
|
269
|
+
botName: account.bot.name,
|
|
270
|
+
connected: account.connected,
|
|
271
|
+
accessPolicy: account.accessPolicy,
|
|
272
|
+
}),
|
|
266
273
|
id: elementId,
|
|
267
274
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
268
275
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -283,13 +290,7 @@ export function AccountCard({
|
|
|
283
290
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
284
291
|
formatCheckedTime: checkedTime,
|
|
285
292
|
}),
|
|
286
|
-
h(
|
|
287
|
-
channel: 'wecomApp',
|
|
288
|
-
botId: account.botId,
|
|
289
|
-
botName: account.bot.name,
|
|
290
|
-
connected: account.connected,
|
|
291
|
-
accessPolicy: account.accessPolicy,
|
|
292
|
-
})))
|
|
293
|
+
h(AccountSettingsToggle)))
|
|
293
294
|
},
|
|
294
295
|
h(CallbackUrlBox, {
|
|
295
296
|
url: account.bot.callbackUrl,
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { WeixinLogoGlyph } from '../../channel-logos.js';
|
|
6
6
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
7
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
8
8
|
import { h } from '../../i18n.js';
|
|
9
9
|
import {
|
|
10
10
|
WEIXIN_ENDPOINTS,
|
|
@@ -230,6 +230,13 @@ export function AccountCard({
|
|
|
230
230
|
return h('article', { className: 'dxw-card dim-botCard', tabIndex: -1, 'data-bot-id': account.botId },
|
|
231
231
|
h('div', { className: 'dxw-cardBody dim-botCardBody' },
|
|
232
232
|
h(CollapsibleAccountSection, {
|
|
233
|
+
settings: h(BotSettingsButton, {
|
|
234
|
+
channel: 'weixin',
|
|
235
|
+
botId: account.botId,
|
|
236
|
+
botName: account.bot.name,
|
|
237
|
+
connected: account.connected,
|
|
238
|
+
accessPolicy: account.accessPolicy,
|
|
239
|
+
}),
|
|
233
240
|
id: `dxw-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
234
241
|
header: h('div', { className: 'dxw-accountTop dim-botCardTop' },
|
|
235
242
|
h('div', { className: 'dxw-accountIdentity dim-botIdentity' },
|
|
@@ -249,13 +256,7 @@ export function AccountCard({
|
|
|
249
256
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
250
257
|
formatCheckedTime: checkedTime,
|
|
251
258
|
}),
|
|
252
|
-
h(
|
|
253
|
-
channel: 'weixin',
|
|
254
|
-
botId: account.botId,
|
|
255
|
-
botName: account.bot.name,
|
|
256
|
-
connected: account.connected,
|
|
257
|
-
accessPolicy: account.accessPolicy,
|
|
258
|
-
})))
|
|
259
|
+
h(AccountSettingsToggle)))
|
|
259
260
|
},
|
|
260
261
|
h(WorkspaceEditor, {
|
|
261
262
|
workspace: account.workspace,
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { WhatsappLogoGlyph } from '../../channel-logos.js';
|
|
6
6
|
import { QrActionIcon } from '../../credential-binding.js';
|
|
7
|
-
import { CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
7
|
+
import { AccountSettingsToggle, CollapsibleAccountSection } from '../shared/collapsible-account.js';
|
|
8
8
|
import { h } from '../../i18n.js';
|
|
9
9
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
10
10
|
import { ContextEnhancementEditor } from '../../context-enhancement.js';
|
|
@@ -208,6 +208,13 @@ export function WhatsappAccountCard({
|
|
|
208
208
|
return h('article', { className: 'ddt-card dim-botCard', 'data-bot-id': account.botId },
|
|
209
209
|
h('div', { className: 'ddt-cardBody dim-botCardBody' },
|
|
210
210
|
h(CollapsibleAccountSection, {
|
|
211
|
+
settings: h(BotSettingsButton, {
|
|
212
|
+
channel: 'whatsapp',
|
|
213
|
+
botId: account.botId,
|
|
214
|
+
botName: account.bot.name,
|
|
215
|
+
connected: account.connected,
|
|
216
|
+
accessPolicy: account.accessPolicy,
|
|
217
|
+
}),
|
|
211
218
|
id: `wsp-settings-${account.botId.replace(/[^a-zA-Z0-9_-]/g, '-')}`,
|
|
212
219
|
header: h('div', { className: 'ddt-accountTop dim-botCardTop' },
|
|
213
220
|
h('div', { className: 'ddt-accountIdentity dim-botIdentity' },
|
|
@@ -231,13 +238,7 @@ export function WhatsappAccountCard({
|
|
|
231
238
|
lastCheckedAt: account.health.lastCheckedAt,
|
|
232
239
|
formatCheckedTime: checkedTime,
|
|
233
240
|
}),
|
|
234
|
-
h(
|
|
235
|
-
channel: 'whatsapp',
|
|
236
|
-
botId: account.botId,
|
|
237
|
-
botName: account.bot.name,
|
|
238
|
-
connected: account.connected,
|
|
239
|
-
accessPolicy: account.accessPolicy,
|
|
240
|
-
})))
|
|
241
|
+
h(AccountSettingsToggle)))
|
|
241
242
|
},
|
|
242
243
|
h(WorkspaceEditor, {
|
|
243
244
|
workspace: account.workspace,
|
|
@@ -45,6 +45,8 @@ const EN = Object.freeze({
|
|
|
45
45
|
'IM机器人设置': 'IM bot settings',
|
|
46
46
|
'IM 面板加载失败': 'Could not load the IM panel',
|
|
47
47
|
'更多机器人设置': 'More bot settings',
|
|
48
|
+
'更多设置': 'More settings',
|
|
49
|
+
'常用配置': 'Common settings',
|
|
48
50
|
'机器人设置': 'Bot settings',
|
|
49
51
|
'机器人设置页签': 'Bot settings tabs',
|
|
50
52
|
'投递设置': 'Delivery settings',
|
|
@@ -130,6 +132,8 @@ const EN = Object.freeze({
|
|
|
130
132
|
'已安装版本': 'Installed version',
|
|
131
133
|
'目标 profile': 'Target profile',
|
|
132
134
|
'目标版本': 'Target version',
|
|
135
|
+
'最新版本': 'Latest version',
|
|
136
|
+
'上次更新目标': 'Previous update target',
|
|
133
137
|
'无法确认': 'Unknown',
|
|
134
138
|
'发现新版本': 'Update available',
|
|
135
139
|
'已是最新版本': 'Up to date',
|
|
@@ -143,6 +147,7 @@ const EN = Object.freeze({
|
|
|
143
147
|
'更新已生效': 'Updated version is active',
|
|
144
148
|
'更新失败': 'Update failed',
|
|
145
149
|
'更新请求失败': 'Update request failed',
|
|
150
|
+
'暂时无法安装更新': 'Update installation is unavailable',
|
|
146
151
|
'仅更新 DSH-IM。安装完成后需手动重启后台;本功能不会自动重启或主动刷新页面。': 'Only DSH-IM will be updated. Restart the backend manually after installation. This feature does not automatically restart it or initiate a page refresh.',
|
|
147
152
|
'当前是源码或链接安装,只能检查版本;请手动更新源码,或迁移到 npm 安装。': 'This is a source or linked installation. You can check versions, but must update the source manually or migrate to an npm installation.',
|
|
148
153
|
'无法确认当前 profile,请在对应的 Harness 环境中手动更新。': 'The current profile could not be identified. Update manually in the corresponding Harness environment.',
|
|
@@ -417,10 +417,15 @@ const CSS = String.raw`
|
|
|
417
417
|
.dim-panel .dim-botCardBody { position: relative; min-width: 0; width: 100%; max-width: 100%; padding: 12px 8px; }
|
|
418
418
|
.dim-collapsibleAccount { min-width: 0; display: flex; flex-direction: column; }
|
|
419
419
|
.dim-collapsibleHead { min-width: 0; display: flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; -webkit-user-select: none; }
|
|
420
|
-
.dim-collapsibleHead:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; border-radius: 8px; }
|
|
421
420
|
.dim-collapsibleHeaderContent { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; }
|
|
422
|
-
|
|
423
|
-
.dim-
|
|
421
|
+
/* Keep the original header footprint; center both icons with equal side space. */
|
|
422
|
+
.dim-accountSettingsToggle { flex: none; width: 45px; height: 32px; display: inline-flex; gap: 5px; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 8px; color: var(--dsw-alias-state-business-primary, #3370ff); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 8%, var(--dsw-alias-bg-layer-1, #fff)); cursor: pointer; }
|
|
423
|
+
.dim-accountSettingsToggle > svg { flex: none; display: block; }
|
|
424
|
+
.dim-accountSettingsToggle:hover { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #3370ff) 14%, var(--dsw-alias-bg-layer-1, #fff)); }
|
|
425
|
+
.dim-accountSettingsToggle:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
426
|
+
.dim-collapsibleChevron { width: 12px; height: 16px; transition: transform .22s cubic-bezier(.4, 0, .2, 1); transform-origin: 50% 50%; }
|
|
427
|
+
.dim-accountSettingsToggle[aria-expanded="true"] .dim-collapsibleChevron { transform: rotate(180deg); }
|
|
428
|
+
.dim-accountSettingsHeader { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #e5e6eb); color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; }
|
|
424
429
|
/* Animate height without measuring content; hide collapsed controls from focus and accessibility. */
|
|
425
430
|
.dim-collapsibleBody { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s cubic-bezier(.4, 0, .2, 1); }
|
|
426
431
|
.dim-collapsibleAccount.is-open > .dim-collapsibleBody { grid-template-rows: 1fr; }
|
|
@@ -445,11 +450,10 @@ const CSS = String.raw`
|
|
|
445
450
|
.dim-panel .dim-botCard .dim-healthDot[data-tone="warning"] { background: var(--dsw-alias-state-warn-primary, #d97706); }
|
|
446
451
|
.dim-panel .dim-botCard .dim-healthDot[data-tone="error"] { background: var(--dsw-alias-state-error-primary, #d54941); }
|
|
447
452
|
.dim-botSettingsAction { position: relative; flex: none; display: inline-flex; }
|
|
448
|
-
.dim-botSettingsButton {
|
|
453
|
+
.dim-botSettingsButton { min-height: 32px; display: inline-flex; align-items: center; gap: 6px; padding: 0 6px; border: 0; border-radius: 8px; color: var(--dsw-alias-state-business-primary, #3370ff); background: transparent; font: inherit; font-size: 12px; white-space: nowrap; cursor: pointer; transition: color .15s ease, background .15s ease; }
|
|
449
454
|
.dim-botSettingsButton:hover { color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #eef0f3); }
|
|
450
455
|
.dim-botSettingsButton:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #3370ff); outline-offset: 2px; }
|
|
451
|
-
.dim-
|
|
452
|
-
.dim-botSettingsAction:hover .dim-botSettingsTooltip, .dim-botSettingsAction:focus-within .dim-botSettingsTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
456
|
+
.dim-moreSettingsChevron { width: 6px; height: 6px; margin-right: 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); }
|
|
453
457
|
.dim-deliveryPage { min-width: 0; display: grid; }
|
|
454
458
|
.dim-deliveryHeader { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
|
|
455
459
|
.dim-botSettingsTabsBar { min-width: 0; margin-top: 10px; border-bottom: 1px solid var(--dsw-alias-border-l2, #dfe1e5); }
|
|
@@ -72,14 +72,17 @@ function summary(snapshot, action, error) {
|
|
|
72
72
|
if (snapshot?.job?.state === 'restart-required' || snapshot?.blockedReason === 'pending-restart') {
|
|
73
73
|
return '已安装,待手动重启';
|
|
74
74
|
}
|
|
75
|
-
if (snapshot?.job?.state === 'completed') return '更新已生效';
|
|
76
|
-
if (snapshot?.job?.state === 'failed') return '更新失败';
|
|
77
|
-
if (snapshot?.job?.state === 'interrupted') return '上次更新已中断,请检查安装状态后重试。';
|
|
78
75
|
if (error) return '更新请求失败';
|
|
76
|
+
if (!snapshot?.job?.recoverable) {
|
|
77
|
+
if (snapshot?.job?.state === 'failed') return '更新失败';
|
|
78
|
+
if (snapshot?.job?.state === 'interrupted') return '上次更新已中断,请检查安装状态后重试。';
|
|
79
|
+
}
|
|
80
|
+
if (snapshot?.blockedReason === 'no-update') return '当前版本无需更新';
|
|
81
|
+
if (snapshot?.blockedReason) return '暂时无法安装更新';
|
|
79
82
|
if (snapshot?.canInstall) return '发现新版本';
|
|
80
83
|
if (snapshot?.checkedAt && snapshot.latestVersion === snapshot.runningVersion) return '已是最新版本';
|
|
81
|
-
if (snapshot?.blockedReason === 'no-update') return '当前版本无需更新';
|
|
82
84
|
if (snapshot?.checkedAt) return '已获取 npm 最新版本';
|
|
85
|
+
if (snapshot?.job?.state === 'completed') return '更新已生效';
|
|
83
86
|
return '检查 npm 最新版本,不会自动安装。';
|
|
84
87
|
}
|
|
85
88
|
|
|
@@ -102,7 +105,7 @@ function manualUpdateCommand(snapshot) {
|
|
|
102
105
|
const targets = [
|
|
103
106
|
snapshot.latestVersion,
|
|
104
107
|
pendingRestart ? snapshot.installedVersion : null,
|
|
105
|
-
snapshot.job?.state !== 'completed' ? snapshot.job?.targetVersion : null,
|
|
108
|
+
snapshot.job?.state !== 'completed' && !snapshot.job?.recoverable ? snapshot.job?.targetVersion : null,
|
|
106
109
|
].filter(validVersion);
|
|
107
110
|
// Keep a known target pinned, and never suggest downgrading an installed/running version.
|
|
108
111
|
const version = targets.length
|
|
@@ -394,9 +397,12 @@ export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
|
394
397
|
const blocked = BLOCKED_REASONS[snapshot?.blockedReason] ?? ERROR_MESSAGES[snapshot?.blockedReason];
|
|
395
398
|
const canConfirm = snapshot?.canInstall && snapshot.checkId && !activeJob && !restartRequired;
|
|
396
399
|
const versionsDiffer = snapshot && clientVersion && snapshot.runningVersion !== clientVersion;
|
|
397
|
-
const failedJob = ['failed', 'interrupted'].includes(snapshot?.job?.state);
|
|
400
|
+
const failedJob = ['failed', 'interrupted'].includes(snapshot?.job?.state) && !snapshot.job.recoverable;
|
|
398
401
|
const jobMessage = snapshot?.job?.message;
|
|
399
|
-
const targetVersion = snapshot?.job?.targetVersion;
|
|
402
|
+
const targetVersion = activeJob || restartRequired ? snapshot?.job?.targetVersion : null;
|
|
403
|
+
const historicalTargetVersion = !activeJob && !restartRequired ? snapshot?.job?.targetVersion : null;
|
|
404
|
+
const latestVersion = !activeJob && !restartRequired && !error && snapshot?.checkedAt
|
|
405
|
+
? snapshot.latestVersion : null;
|
|
400
406
|
const manualCommand = manualUpdateCommand(snapshot);
|
|
401
407
|
const buttonLabel = action === 'checking' ? '检查中…'
|
|
402
408
|
: action === 'starting' || activeJob ? '正在更新…'
|
|
@@ -413,7 +419,7 @@ export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
|
413
419
|
onClick: () => {
|
|
414
420
|
setOpen(true);
|
|
415
421
|
if (restartRequired) void refreshStatus();
|
|
416
|
-
else if (!snapshot?.canInstall && !
|
|
422
|
+
else if (!snapshot?.canInstall && !activeJob && !uncertainInstall) void check();
|
|
417
423
|
},
|
|
418
424
|
}, buttonLabel, buttonLabel === '更新至' ? ` v${snapshot.latestVersion}` : null),
|
|
419
425
|
open ? h(UpdateDialog, { onClose: () => setOpen(false) },
|
|
@@ -425,6 +431,10 @@ export function UpdatePanel({ rpcCall, clientVersion, onStatus }) {
|
|
|
425
431
|
h('dt', null, '已安装版本'), h('dd', null, `v${snapshot.installedVersion}`)) : null,
|
|
426
432
|
targetVersion ? h(React.Fragment, null,
|
|
427
433
|
h('dt', null, '目标版本'), h('dd', null, `v${targetVersion}`)) : null,
|
|
434
|
+
latestVersion ? h(React.Fragment, null,
|
|
435
|
+
h('dt', null, '最新版本'), h('dd', null, `v${latestVersion}`)) : null,
|
|
436
|
+
historicalTargetVersion ? h(React.Fragment, null,
|
|
437
|
+
h('dt', null, '上次更新目标'), h('dd', null, `v${historicalTargetVersion}`)) : null,
|
|
428
438
|
h('dt', null, '目标 profile'), h('dd', null, snapshot?.profileName ?? '无法确认')),
|
|
429
439
|
h('div', {
|
|
430
440
|
className: `dim-updateStatus${error || failedJob ? ' dim-updateStatusError' : ''}`,
|