@xmanrui/dsh-im 0.17.1 → 0.19.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 +3 -2
- package/README.md +3 -2
- package/lib/client.js +1297 -600
- package/lib/index.js +190 -145
- package/package.json +1 -1
- package/plugin-src/client/agent-preset.js +110 -0
- package/plugin-src/client/channels/dingtalk/api.js +5 -0
- package/plugin-src/client/channels/dingtalk/index.js +48 -2
- package/plugin-src/client/channels/feishu/api.js +28 -5
- package/plugin-src/client/channels/feishu/index.js +330 -41
- package/plugin-src/client/channels/feishu/styles.js +46 -0
- package/plugin-src/client/channels/qq/api.js +5 -0
- package/plugin-src/client/channels/qq/index.js +37 -6
- package/plugin-src/client/channels/shared/token-api.js +5 -0
- package/plugin-src/client/channels/shared/token-channel.js +34 -6
- package/plugin-src/client/channels/wecom/api.js +5 -0
- package/plugin-src/client/channels/wecom/index.js +37 -6
- package/plugin-src/client/channels/weixin/api.js +5 -0
- package/plugin-src/client/channels/weixin/index.js +50 -4
- package/plugin-src/client/channels/whatsapp/api.js +5 -0
- package/plugin-src/client/channels/whatsapp/index.js +30 -4
- package/plugin-src/client/i18n.js +59 -0
- package/plugin-src/client/styles.js +8 -0
- package/plugin-src/host/channels/dingtalk/production.mjs +10 -4
- package/plugin-src/host/channels/dingtalk/rpc.mjs +12 -0
- package/plugin-src/host/channels/feishu/connection-supervisor.mjs +1 -1
- package/plugin-src/host/channels/feishu/production.mjs +8 -3
- package/plugin-src/host/channels/feishu/rpc.mjs +78 -7
- package/plugin-src/host/channels/qq/production.mjs +10 -4
- package/plugin-src/host/channels/qq/rpc.mjs +12 -0
- package/plugin-src/host/channels/shared/agent-preset-rpc.mjs +25 -0
- package/plugin-src/host/channels/shared/production.mjs +10 -4
- package/plugin-src/host/channels/shared/rpc.mjs +12 -0
- package/plugin-src/host/channels/shared/workspace-rpc.mjs +2 -0
- package/plugin-src/host/channels/slack/production.mjs +10 -4
- package/plugin-src/host/channels/slack/rpc.mjs +13 -0
- package/plugin-src/host/channels/wecom/production.mjs +10 -4
- package/plugin-src/host/channels/wecom/rpc.mjs +12 -0
- package/plugin-src/host/channels/weixin/production.mjs +10 -4
- package/plugin-src/host/channels/weixin/rpc.mjs +15 -0
- package/plugin-src/host/channels/whatsapp/production.mjs +10 -4
- package/plugin-src/host/channels/whatsapp/rpc.mjs +12 -0
- package/src/channels/discord/discord-api.mjs +1 -1
- package/src/channels/feishu/bridge.mjs +29 -4
- package/src/channels/feishu/feishu-runtime.mjs +14 -0
- package/src/channels/feishu/group-message-permission-manager.mjs +71 -0
- package/src/channels/feishu/group-response-mode.mjs +15 -0
- package/src/channels/feishu/multi-bot-controller.mjs +258 -9
- package/src/channels/feishu/plugin-config-store.mjs +3 -0
- package/src/channels/feishu/repair-manager.mjs +17 -3
- package/src/channels/shared/agent-preset.mjs +74 -0
- package/src/channels/shared/bot-workspace-store.mjs +141 -14
- package/src/channels/shared/harness-client.mjs +6 -4
- package/src/channels/telegram/telegram-api.mjs +31 -0
- package/src/channels/telegram/telegram-runtime.mjs +25 -1
- package/src/channels/weixin/weixin-api.mjs +1 -1
|
@@ -407,6 +407,50 @@ const CSS = String.raw`
|
|
|
407
407
|
.bxf-metric dt { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 17px; }
|
|
408
408
|
.bxf-metric dd { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 18px; font-weight: 550; margin: 3px 0 0; }
|
|
409
409
|
|
|
410
|
+
.bxf-responseMode { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; align-items: center; column-gap: 10px; row-gap: 5px; margin-top: 6px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
411
|
+
.bxf-responseModeHeader { display: contents; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
|
|
412
|
+
.bxf-responseModeHeader > span:first-child { grid-column: 1; grid-row: 1; white-space: nowrap; }
|
|
413
|
+
.bxf-responseModeStatus { grid-column: 2; grid-row: 1; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; white-space: nowrap; }
|
|
414
|
+
.bxf-responseModeSelect { min-width: 0; width: 100%; grid-column: 1 / -1; grid-row: 2; height: 32px; padding: 0 30px 0 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background-color: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; cursor: pointer; transition: border-color .16s ease, box-shadow .16s ease, background-color .16s ease; }
|
|
415
|
+
.bxf-responseModeSelect:hover:not(:disabled) { border-color: color-mix(in srgb, var(--bxf-accent) 45%, var(--dsw-alias-border-l2, #dfe1e5)); }
|
|
416
|
+
.bxf-responseModeSelect:focus-visible { outline: none; border-color: var(--bxf-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--bxf-accent) 16%, transparent); }
|
|
417
|
+
.bxf-responseModeSelect:disabled { cursor: not-allowed; opacity: .55; }
|
|
418
|
+
.bxf-responseModeHelp { grid-column: 1 / -1; grid-row: 3; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.45; }
|
|
419
|
+
.bxf-responseModePermissionAction { grid-column: 1 / -1; grid-row: 4; display: flex; justify-content: flex-start; margin-top: 2px; }
|
|
420
|
+
.bxf-responseModePermissionButton { min-height: 28px; padding: 3px 9px; color: var(--bxf-accent); border-color: color-mix(in srgb, var(--bxf-accent) 30%, var(--dsw-alias-border-l2, #dfe1e5)); background: var(--dsw-alias-bg-layer-1, #fff); }
|
|
421
|
+
.bxf-responseModePermissionButton:hover:not(:disabled) { background: color-mix(in srgb, var(--bxf-accent) 7%, transparent); }
|
|
422
|
+
.bxf-responseModeError { grid-column: 1 / -1; grid-row: 5; color: var(--bxf-error); font-size: 12px; line-height: 1.4; margin: 0; }
|
|
423
|
+
|
|
424
|
+
.bxf-botProvision {
|
|
425
|
+
position: relative;
|
|
426
|
+
margin-top: 14px;
|
|
427
|
+
scroll-margin-block: 20px;
|
|
428
|
+
animation: bxf-revealProvision .2s var(--ds-ease-out, ease-out) both;
|
|
429
|
+
}
|
|
430
|
+
.bxf-botProvision:focus { outline: none; }
|
|
431
|
+
.bxf-botProvision:focus-visible {
|
|
432
|
+
outline: 2px solid color-mix(in srgb, var(--bxf-accent) 75%, transparent);
|
|
433
|
+
outline-offset: 3px;
|
|
434
|
+
border-radius: 12px;
|
|
435
|
+
}
|
|
436
|
+
.bxf-botProvision > .bxf-provisionCard {
|
|
437
|
+
border-radius: 11px;
|
|
438
|
+
box-shadow: none;
|
|
439
|
+
background: color-mix(in srgb, var(--bxf-accent) 2.5%, var(--dsw-alias-bg-layer-3, #fff));
|
|
440
|
+
}
|
|
441
|
+
.bxf-botProvision .bxf-cardBody { padding: 18px; }
|
|
442
|
+
.bxf-botProvision .bxf-qrLayout {
|
|
443
|
+
grid-template-columns: 184px minmax(0, 1fr);
|
|
444
|
+
align-items: start;
|
|
445
|
+
gap: 24px;
|
|
446
|
+
}
|
|
447
|
+
.bxf-botProvision .bxf-qrFrame { width: 176px; height: 176px; padding: 10px; border-radius: 11px; }
|
|
448
|
+
.bxf-botProvision .bxf-countdown { width: 176px; }
|
|
449
|
+
.bxf-botProvision .bxf-qrCopy h3 { font-size: 18px; line-height: 26px; }
|
|
450
|
+
.bxf-botProvision .bxf-steps { gap: 8px; margin-top: 14px; }
|
|
451
|
+
.bxf-botProvision .bxf-actions { margin-top: 16px; }
|
|
452
|
+
.bxf-botProvision .bxf-inlineError { min-height: 160px; padding: 22px; }
|
|
453
|
+
|
|
410
454
|
.bxf-connectedFooter { display: flex; align-items: center; justify-content: space-between; gap: 15px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--dsw-alias-border-l1, #eef0f3); }
|
|
411
455
|
.bxf-healthSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; }
|
|
412
456
|
.bxf-healthSummary[data-error="true"] { color: var(--bxf-error); }
|
|
@@ -459,6 +503,7 @@ const CSS = String.raw`
|
|
|
459
503
|
@keyframes bxf-rotate { to { transform: rotate(360deg); } }
|
|
460
504
|
@keyframes bxf-pulse { 0%, 100% { transform: scale(.9); opacity: .45; } 50% { transform: scale(1.08); opacity: 1; } }
|
|
461
505
|
@keyframes bxf-shimmer { to { background-position: -220% 0; } }
|
|
506
|
+
@keyframes bxf-revealProvision { from { opacity: 0; transform: translateY(-5px); } }
|
|
462
507
|
|
|
463
508
|
@container (max-width: 620px) {
|
|
464
509
|
.bxf-headingTools { gap: 6px; }
|
|
@@ -470,6 +515,7 @@ const CSS = String.raw`
|
|
|
470
515
|
.bxf-intro { grid-template-columns: minmax(0, 1fr); }
|
|
471
516
|
.bxf-markStage { display: none; }
|
|
472
517
|
.bxf-qrLayout { grid-template-columns: minmax(0, 1fr); justify-items: center; }
|
|
518
|
+
.bxf-botProvision .bxf-qrLayout { grid-template-columns: minmax(0, 1fr); }
|
|
473
519
|
.bxf-qrCopy { width: 100%; }
|
|
474
520
|
.bxf-statusGrid { grid-template-columns: minmax(0, 1fr); }
|
|
475
521
|
.bxf-connectedTop { align-items: flex-start; flex-direction: column; }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
|
+
|
|
1
3
|
export const QQ_RPC_CHANNEL = '/qq';
|
|
2
4
|
|
|
3
5
|
export const QQ_ENDPOINTS = Object.freeze({
|
|
@@ -9,6 +11,7 @@ export const QQ_ENDPOINTS = Object.freeze({
|
|
|
9
11
|
reconnectBot: 'bot.reconnect',
|
|
10
12
|
deleteBot: 'bot.delete',
|
|
11
13
|
setWorkspace: 'bot.workspace.set',
|
|
14
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
12
15
|
});
|
|
13
16
|
|
|
14
17
|
const PROVISION_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting', 'connected', 'failed', 'cancelled']);
|
|
@@ -82,6 +85,7 @@ function normalizeBot(value) {
|
|
|
82
85
|
connected,
|
|
83
86
|
state: connected ? 'connected' : state,
|
|
84
87
|
workspace: text(value.workspace, '', 4_096),
|
|
88
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
85
89
|
bot: {
|
|
86
90
|
name: text(value.bot?.name, 'QQ机器人', 100),
|
|
87
91
|
appIdMasked: text(value.bot?.appIdMasked, '应用标识已安全保存', 140),
|
|
@@ -117,6 +121,7 @@ export function normalizeSnapshot(value) {
|
|
|
117
121
|
bots,
|
|
118
122
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
119
123
|
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
124
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
120
125
|
...(testMessage ? { testMessage } : {}),
|
|
121
126
|
};
|
|
122
127
|
}
|
|
@@ -4,6 +4,11 @@ import { QqLogoGlyph } from '../../channel-logos.js';
|
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
5
|
import { h } from '../../i18n.js';
|
|
6
6
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
|
+
import {
|
|
8
|
+
AgentPresetCatalogContext,
|
|
9
|
+
AgentPresetEditor,
|
|
10
|
+
EMPTY_AGENT_PRESET_CATALOG,
|
|
11
|
+
} from '../../agent-preset.js';
|
|
7
12
|
import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
|
|
8
13
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
9
14
|
import {
|
|
@@ -156,6 +161,7 @@ export function AccountCard({
|
|
|
156
161
|
removing,
|
|
157
162
|
onReconnect,
|
|
158
163
|
onWorkspaceSave,
|
|
164
|
+
onAgentPresetSave,
|
|
159
165
|
onRequestRemove,
|
|
160
166
|
onConfirmRemove,
|
|
161
167
|
onCancelRemove,
|
|
@@ -180,6 +186,11 @@ export function AccountCard({
|
|
|
180
186
|
disabled: Boolean(busy),
|
|
181
187
|
onSave: onWorkspaceSave,
|
|
182
188
|
}),
|
|
189
|
+
h(AgentPresetEditor, {
|
|
190
|
+
agentPreset: account.agentPreset,
|
|
191
|
+
disabled: Boolean(busy),
|
|
192
|
+
onSave: onAgentPresetSave,
|
|
193
|
+
}),
|
|
183
194
|
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
|
184
195
|
summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null,
|
|
185
196
|
feedback ? h('div', {
|
|
@@ -196,7 +207,10 @@ export function AccountCard({
|
|
|
196
207
|
}
|
|
197
208
|
|
|
198
209
|
export function QqSettingsTab({ rpcCall }) {
|
|
199
|
-
const [model, setModel] = React.useState({
|
|
210
|
+
const [model, setModel] = React.useState({
|
|
211
|
+
phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
|
|
212
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
213
|
+
});
|
|
200
214
|
const [provision, setProvision] = React.useState(null);
|
|
201
215
|
const [busy, setBusy] = React.useState(false);
|
|
202
216
|
const [busyByBot, setBusyByBot] = React.useState({});
|
|
@@ -233,7 +247,10 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
233
247
|
const snapshot = normalizeSnapshot(await invoke(QQ_ENDPOINTS.status, {}, signal));
|
|
234
248
|
if (!mounted.current || signal?.aborted
|
|
235
249
|
|| !workspaceFence.canCommitStatus(workspaceVersion)) return undefined;
|
|
236
|
-
setModel({
|
|
250
|
+
setModel({
|
|
251
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
252
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
253
|
+
});
|
|
237
254
|
if (restore && snapshot.provisioning) setProvision({
|
|
238
255
|
...snapshot.provisioning,
|
|
239
256
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now()),
|
|
@@ -297,7 +314,10 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
297
314
|
));
|
|
298
315
|
if (!mounted.current) return;
|
|
299
316
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
300
|
-
setModel({
|
|
317
|
+
setModel({
|
|
318
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
319
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
320
|
+
});
|
|
301
321
|
}
|
|
302
322
|
setCredentialOpen(false);
|
|
303
323
|
} catch (error) {
|
|
@@ -357,7 +377,10 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
357
377
|
try {
|
|
358
378
|
const snapshot = normalizeSnapshot(await invoke(endpoint, payload));
|
|
359
379
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
360
|
-
setModel({
|
|
380
|
+
setModel({
|
|
381
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
382
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
383
|
+
});
|
|
361
384
|
}
|
|
362
385
|
return snapshot;
|
|
363
386
|
} finally {
|
|
@@ -424,6 +447,12 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
424
447
|
QQ_ENDPOINTS.setWorkspace,
|
|
425
448
|
{ botId: account.botId, workspace },
|
|
426
449
|
),
|
|
450
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
451
|
+
account,
|
|
452
|
+
'preset',
|
|
453
|
+
QQ_ENDPOINTS.setAgentPreset,
|
|
454
|
+
{ botId: account.botId, agentPreset },
|
|
455
|
+
),
|
|
427
456
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
428
457
|
onCancelRemove: () => setRemoveTarget(null),
|
|
429
458
|
onConfirmRemove: async () => {
|
|
@@ -447,7 +476,9 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
447
476
|
})
|
|
448
477
|
: null;
|
|
449
478
|
|
|
450
|
-
return h(
|
|
479
|
+
return h(AgentPresetCatalogContext.Provider, {
|
|
480
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
481
|
+
}, h('section', { className: 'ddt-page dqq-page dim-channelPage', 'aria-label': 'QQ 设置' },
|
|
451
482
|
h(Heading, {
|
|
452
483
|
totals: model.totals,
|
|
453
484
|
adding: Boolean(provision),
|
|
@@ -465,7 +496,7 @@ export function QqSettingsTab({ rpcCall }) {
|
|
|
465
496
|
provisionView,
|
|
466
497
|
model.bots.length === 0 && !provision && !credentialOpen
|
|
467
498
|
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
|
|
468
|
-
botList));
|
|
499
|
+
botList)));
|
|
469
500
|
}
|
|
470
501
|
|
|
471
502
|
export function apply(ctx) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
|
+
|
|
1
3
|
const ACCOUNT_STATES = new Set(['connected', 'connecting', 'offline', 'error']);
|
|
2
4
|
|
|
3
5
|
function isRecord(value) {
|
|
@@ -25,6 +27,7 @@ export const TOKEN_BOT_ENDPOINTS = Object.freeze({
|
|
|
25
27
|
reconnectBot: 'bot.reconnect',
|
|
26
28
|
deleteBot: 'bot.delete',
|
|
27
29
|
setWorkspace: 'bot.workspace.set',
|
|
30
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
28
31
|
});
|
|
29
32
|
|
|
30
33
|
export function createTokenChannelApi(channel, connectionSummary, {
|
|
@@ -52,6 +55,7 @@ export function createTokenChannelApi(channel, connectionSummary, {
|
|
|
52
55
|
connected,
|
|
53
56
|
state: connected ? 'connected' : state,
|
|
54
57
|
workspace: text(value.workspace, '', 4_096),
|
|
58
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
55
59
|
bot: {
|
|
56
60
|
name: text(value.bot?.name, `${channel}机器人`, 100),
|
|
57
61
|
username: text(value.bot?.username, '', 100),
|
|
@@ -82,6 +86,7 @@ export function createTokenChannelApi(channel, connectionSummary, {
|
|
|
82
86
|
revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
|
|
83
87
|
bots,
|
|
84
88
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
89
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
85
90
|
};
|
|
86
91
|
};
|
|
87
92
|
|
|
@@ -4,6 +4,11 @@ import { CredentialActionIcon, CredentialBindingPanel } from '../../credential-b
|
|
|
4
4
|
import { h } from '../../i18n.js';
|
|
5
5
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
6
6
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
|
+
import {
|
|
8
|
+
AgentPresetCatalogContext,
|
|
9
|
+
AgentPresetEditor,
|
|
10
|
+
EMPTY_AGENT_PRESET_CATALOG,
|
|
11
|
+
} from '../../agent-preset.js';
|
|
7
12
|
import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
|
|
8
13
|
|
|
9
14
|
const Button = React.forwardRef(function Button(
|
|
@@ -63,7 +68,7 @@ export function createTokenChannelSettings(definition) {
|
|
|
63
68
|
accountSettingsEndpoint = null,
|
|
64
69
|
} = definition;
|
|
65
70
|
|
|
66
|
-
function AccountCard({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
71
|
+
function AccountCard({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAgentPresetSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
67
72
|
const state = busy === 'reconnect' ? 'connecting' : account.state;
|
|
68
73
|
const tone = account.connected ? 'success' : state === 'error' ? 'error' : 'warning';
|
|
69
74
|
const stateLabel = account.connected ? '运行正常' : state === 'connecting' ? '正在连接' : '连接未就绪';
|
|
@@ -90,6 +95,11 @@ export function createTokenChannelSettings(definition) {
|
|
|
90
95
|
disabled: Boolean(busy),
|
|
91
96
|
onSave: onWorkspaceSave,
|
|
92
97
|
}),
|
|
98
|
+
h(AgentPresetEditor, {
|
|
99
|
+
agentPreset: account.agentPreset,
|
|
100
|
+
disabled: Boolean(busy),
|
|
101
|
+
onSave: onAgentPresetSave,
|
|
102
|
+
}),
|
|
93
103
|
AccountSettings ? h(AccountSettings, {
|
|
94
104
|
account,
|
|
95
105
|
busy: Boolean(busy),
|
|
@@ -122,6 +132,7 @@ export function createTokenChannelSettings(definition) {
|
|
|
122
132
|
function SettingsTab({ rpcCall }) {
|
|
123
133
|
const [model, setModel] = React.useState({
|
|
124
134
|
phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
|
|
135
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
125
136
|
});
|
|
126
137
|
const [credentialOpen, setCredentialOpen] = React.useState(false);
|
|
127
138
|
const [credentialError, setCredentialError] = React.useState(null);
|
|
@@ -156,7 +167,10 @@ export function createTokenChannelSettings(definition) {
|
|
|
156
167
|
const snapshot = api.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
|
|
157
168
|
if (!mounted.current || signal?.aborted
|
|
158
169
|
|| !workspaceFence.canCommitStatus(workspaceVersion)) return;
|
|
159
|
-
setModel({
|
|
170
|
+
setModel({
|
|
171
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
172
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
173
|
+
});
|
|
160
174
|
} catch (error) {
|
|
161
175
|
if (error?.name !== 'AbortError' && mounted.current && !signal?.aborted
|
|
162
176
|
&& workspaceFence.canCommitStatus(workspaceVersion)) {
|
|
@@ -199,7 +213,10 @@ export function createTokenChannelSettings(definition) {
|
|
|
199
213
|
));
|
|
200
214
|
if (!mounted.current) return;
|
|
201
215
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
202
|
-
setModel({
|
|
216
|
+
setModel({
|
|
217
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
218
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
219
|
+
});
|
|
203
220
|
}
|
|
204
221
|
setCredentialOpen(false);
|
|
205
222
|
} catch (error) {
|
|
@@ -218,7 +235,10 @@ export function createTokenChannelSettings(definition) {
|
|
|
218
235
|
const value = await invoke(endpoint, payload);
|
|
219
236
|
const snapshot = api.normalizeSnapshot(value);
|
|
220
237
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
221
|
-
setModel({
|
|
238
|
+
setModel({
|
|
239
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
240
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
241
|
+
});
|
|
222
242
|
}
|
|
223
243
|
if (mounted.current && operation === 'reconnect') {
|
|
224
244
|
setTestNoticeByBot((current) => ({
|
|
@@ -267,6 +287,12 @@ export function createTokenChannelSettings(definition) {
|
|
|
267
287
|
endpoints.setWorkspace,
|
|
268
288
|
{ botId: account.botId, workspace },
|
|
269
289
|
),
|
|
290
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
291
|
+
account,
|
|
292
|
+
'preset',
|
|
293
|
+
endpoints.setAgentPreset,
|
|
294
|
+
{ botId: account.botId, agentPreset },
|
|
295
|
+
),
|
|
270
296
|
onAccountSettingsSave: AccountSettings && accountSettingsEndpoint
|
|
271
297
|
? (payload) => botAction(
|
|
272
298
|
account,
|
|
@@ -287,7 +313,9 @@ export function createTokenChannelSettings(definition) {
|
|
|
287
313
|
})))))
|
|
288
314
|
: null;
|
|
289
315
|
|
|
290
|
-
return h(
|
|
316
|
+
return h(AgentPresetCatalogContext.Provider, {
|
|
317
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
318
|
+
}, h('section', {
|
|
291
319
|
className: `ddt-page ${pageClass} dim-channelPage`,
|
|
292
320
|
'aria-label': `${channel} 设置`,
|
|
293
321
|
},
|
|
@@ -353,7 +381,7 @@ export function createTokenChannelSettings(definition) {
|
|
|
353
381
|
'aria-hidden': 'true',
|
|
354
382
|
}, h(LogoGlyph, { size: 64 }))))
|
|
355
383
|
: null,
|
|
356
|
-
botList));
|
|
384
|
+
botList)));
|
|
357
385
|
}
|
|
358
386
|
|
|
359
387
|
return { SettingsTab, AccountCard };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
|
+
|
|
1
3
|
export const WECOM_RPC_CHANNEL = '/wecom';
|
|
2
4
|
|
|
3
5
|
export const WECOM_ENDPOINTS = Object.freeze({
|
|
@@ -9,6 +11,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|
|
9
11
|
reconnectBot: 'bot.reconnect',
|
|
10
12
|
deleteBot: 'bot.delete',
|
|
11
13
|
setWorkspace: 'bot.workspace.set',
|
|
14
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
12
15
|
});
|
|
13
16
|
|
|
14
17
|
const PROVISION_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting', 'connected', 'failed', 'cancelled']);
|
|
@@ -91,6 +94,7 @@ function normalizeBot(value) {
|
|
|
91
94
|
connected,
|
|
92
95
|
state: connected ? 'connected' : state,
|
|
93
96
|
workspace: text(value.workspace, '', 4_096),
|
|
97
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
94
98
|
bot: {
|
|
95
99
|
name: text(value.bot?.name, '企业微信机器人', 100),
|
|
96
100
|
appIdMasked: text(value.bot?.appIdMasked, '应用标识已安全保存', 140),
|
|
@@ -116,6 +120,7 @@ export function normalizeSnapshot(value) {
|
|
|
116
120
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
117
121
|
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
118
122
|
testMessage: normalizeTestMessage(source.testMessage),
|
|
123
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
119
124
|
};
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -4,6 +4,11 @@ import { WecomLogoGlyph } from '../../channel-logos.js';
|
|
|
4
4
|
import { CredentialActionIcon, CredentialBindingPanel, QrActionIcon } from '../../credential-binding.js';
|
|
5
5
|
import { h } from '../../i18n.js';
|
|
6
6
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
7
|
+
import {
|
|
8
|
+
AgentPresetCatalogContext,
|
|
9
|
+
AgentPresetEditor,
|
|
10
|
+
EMPTY_AGENT_PRESET_CATALOG,
|
|
11
|
+
} from '../../agent-preset.js';
|
|
7
12
|
import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
|
|
8
13
|
import { installDingtalkStyles } from '../dingtalk/styles.js';
|
|
9
14
|
import {
|
|
@@ -155,6 +160,7 @@ export function AccountCard({
|
|
|
155
160
|
removing,
|
|
156
161
|
onReconnect,
|
|
157
162
|
onWorkspaceSave,
|
|
163
|
+
onAgentPresetSave,
|
|
158
164
|
onRequestRemove,
|
|
159
165
|
onConfirmRemove,
|
|
160
166
|
onCancelRemove,
|
|
@@ -179,6 +185,11 @@ export function AccountCard({
|
|
|
179
185
|
disabled: Boolean(busy),
|
|
180
186
|
onSave: onWorkspaceSave,
|
|
181
187
|
}),
|
|
188
|
+
h(AgentPresetEditor, {
|
|
189
|
+
agentPreset: account.agentPreset,
|
|
190
|
+
disabled: Boolean(busy),
|
|
191
|
+
onSave: onAgentPresetSave,
|
|
192
|
+
}),
|
|
182
193
|
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
|
183
194
|
summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null,
|
|
184
195
|
feedback ? h('div', {
|
|
@@ -195,7 +206,10 @@ export function AccountCard({
|
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
export function WecomSettingsTab({ rpcCall }) {
|
|
198
|
-
const [model, setModel] = React.useState({
|
|
209
|
+
const [model, setModel] = React.useState({
|
|
210
|
+
phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
|
|
211
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
212
|
+
});
|
|
199
213
|
const [provision, setProvision] = React.useState(null);
|
|
200
214
|
const [busy, setBusy] = React.useState(false);
|
|
201
215
|
const [busyByBot, setBusyByBot] = React.useState({});
|
|
@@ -253,7 +267,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
253
267
|
const snapshot = normalizeSnapshot(await invoke(WECOM_ENDPOINTS.status, {}, signal));
|
|
254
268
|
if (!mounted.current || signal?.aborted
|
|
255
269
|
|| !workspaceFence.canCommitStatus(workspaceVersion)) return undefined;
|
|
256
|
-
setModel({
|
|
270
|
+
setModel({
|
|
271
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
272
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
273
|
+
});
|
|
257
274
|
if (restore && snapshot.provisioning) setProvision({
|
|
258
275
|
...snapshot.provisioning,
|
|
259
276
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now()),
|
|
@@ -317,7 +334,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
317
334
|
));
|
|
318
335
|
if (!mounted.current) return;
|
|
319
336
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
320
|
-
setModel({
|
|
337
|
+
setModel({
|
|
338
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
339
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
340
|
+
});
|
|
321
341
|
}
|
|
322
342
|
setCredentialOpen(false);
|
|
323
343
|
} catch (error) {
|
|
@@ -377,7 +397,10 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
377
397
|
try {
|
|
378
398
|
const snapshot = normalizeSnapshot(await invoke(endpoint, payload));
|
|
379
399
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
380
|
-
setModel({
|
|
400
|
+
setModel({
|
|
401
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
402
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
403
|
+
});
|
|
381
404
|
}
|
|
382
405
|
return snapshot;
|
|
383
406
|
} finally {
|
|
@@ -455,6 +478,12 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
455
478
|
WECOM_ENDPOINTS.setWorkspace,
|
|
456
479
|
{ botId: account.botId, workspace },
|
|
457
480
|
),
|
|
481
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
482
|
+
account,
|
|
483
|
+
'preset',
|
|
484
|
+
WECOM_ENDPOINTS.setAgentPreset,
|
|
485
|
+
{ botId: account.botId, agentPreset },
|
|
486
|
+
),
|
|
458
487
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
459
488
|
onCancelRemove: () => setRemoveTarget(null),
|
|
460
489
|
onConfirmRemove: async () => {
|
|
@@ -478,7 +507,9 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
478
507
|
})
|
|
479
508
|
: null;
|
|
480
509
|
|
|
481
|
-
return h(
|
|
510
|
+
return h(AgentPresetCatalogContext.Provider, {
|
|
511
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
512
|
+
}, h('section', { className: 'ddt-page dwecom-page dim-channelPage', 'aria-label': '企业微信设置' },
|
|
482
513
|
h(Heading, {
|
|
483
514
|
totals: model.totals,
|
|
484
515
|
adding: Boolean(provision),
|
|
@@ -497,7 +528,7 @@ export function WecomSettingsTab({ rpcCall }) {
|
|
|
497
528
|
provisionView,
|
|
498
529
|
model.bots.length === 0 && !provision && !credentialOpen
|
|
499
530
|
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
|
|
500
|
-
botList));
|
|
531
|
+
botList)));
|
|
501
532
|
}
|
|
502
533
|
|
|
503
534
|
export function apply(ctx) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
|
+
|
|
1
3
|
export const WEIXIN_RPC_CHANNEL = '/weixin';
|
|
2
4
|
export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
3
5
|
status: 'connection.status',
|
|
@@ -8,6 +10,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
8
10
|
reconnectBot: 'bot.reconnect',
|
|
9
11
|
deleteBot: 'bot.delete',
|
|
10
12
|
setWorkspace: 'bot.workspace.set',
|
|
13
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
11
14
|
});
|
|
12
15
|
|
|
13
16
|
const ACCOUNT_STATES = new Set(['connected', 'connecting', 'offline', 'error']);
|
|
@@ -124,6 +127,7 @@ function normalizeBot(value) {
|
|
|
124
127
|
connected,
|
|
125
128
|
configured: value.configured === true,
|
|
126
129
|
workspace: string(value.workspace).slice(0, 4_096),
|
|
130
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
127
131
|
bot: {
|
|
128
132
|
name: string(value.bot.name, '微信机器人'),
|
|
129
133
|
accountIdMasked: string(value.bot.accountIdMasked, '已安全保存'),
|
|
@@ -163,6 +167,7 @@ export function normalizeSnapshot(value) {
|
|
|
163
167
|
},
|
|
164
168
|
provisioning: value.provisioning ? normalizeProvisioning(value.provisioning) : null,
|
|
165
169
|
testMessage: normalizeTestMessage(value.testMessage),
|
|
170
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
|
|
166
171
|
};
|
|
167
172
|
}
|
|
168
173
|
|
|
@@ -16,6 +16,11 @@ import {
|
|
|
16
16
|
} from './api.js';
|
|
17
17
|
import { createPollScheduler, useAnimationFrameScheduler } from '../../lifecycle.js';
|
|
18
18
|
import { WorkspaceEditor } from '../../workspace-editor.js';
|
|
19
|
+
import {
|
|
20
|
+
AgentPresetCatalogContext,
|
|
21
|
+
AgentPresetEditor,
|
|
22
|
+
EMPTY_AGENT_PRESET_CATALOG,
|
|
23
|
+
} from '../../agent-preset.js';
|
|
19
24
|
import { useWorkspaceSnapshotFence } from '../../workspace-snapshot-fence.js';
|
|
20
25
|
import { installWeixinStyles } from './styles.js';
|
|
21
26
|
|
|
@@ -202,6 +207,7 @@ export function AccountCard({
|
|
|
202
207
|
removing,
|
|
203
208
|
onReconnect,
|
|
204
209
|
onWorkspaceSave,
|
|
210
|
+
onAgentPresetSave,
|
|
205
211
|
onRequestRemove,
|
|
206
212
|
onConfirmRemove,
|
|
207
213
|
onCancelRemove,
|
|
@@ -228,6 +234,11 @@ export function AccountCard({
|
|
|
228
234
|
disabled: Boolean(busy),
|
|
229
235
|
onSave: onWorkspaceSave,
|
|
230
236
|
}),
|
|
237
|
+
h(AgentPresetEditor, {
|
|
238
|
+
agentPreset: account.agentPreset,
|
|
239
|
+
disabled: Boolean(busy),
|
|
240
|
+
onSave: onAgentPresetSave,
|
|
241
|
+
}),
|
|
231
242
|
h('div', { className: 'dxw-accountFooter dim-cardFooter' },
|
|
232
243
|
summary ? h('div', { className: 'dxw-summary dim-cardSummary' }, summary) : null,
|
|
233
244
|
account.lastMessageError ? h('div', {
|
|
@@ -264,6 +275,7 @@ function AccountList(props) {
|
|
|
264
275
|
removing: props.removeTarget === account.botId,
|
|
265
276
|
onReconnect: () => props.onReconnect(account),
|
|
266
277
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
278
|
+
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
|
|
267
279
|
onRequestRemove: () => props.onRequestRemove(account),
|
|
268
280
|
onConfirmRemove: () => props.onConfirmRemove(account),
|
|
269
281
|
onCancelRemove: props.onCancelRemove,
|
|
@@ -289,6 +301,7 @@ export function mergeWeixinProvisioningSnapshot(
|
|
|
289
301
|
export function WeixinSettingsTab({ rpcCall }) {
|
|
290
302
|
const [model, setModel] = React.useState({
|
|
291
303
|
phase: 'loading', bots: [], totals: EMPTY_TOTALS, revision: 0, error: null,
|
|
304
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
292
305
|
});
|
|
293
306
|
const [provision, setProvision] = React.useState(null);
|
|
294
307
|
const [busy, setBusy] = React.useState(false);
|
|
@@ -331,6 +344,7 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
331
344
|
setModel({
|
|
332
345
|
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
|
333
346
|
revision: snapshot.revision, error: null,
|
|
347
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
334
348
|
});
|
|
335
349
|
if (snapshot.provisioning) {
|
|
336
350
|
setProvision((current) => mergeWeixinProvisioningSnapshot(
|
|
@@ -519,7 +533,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
519
533
|
{ botId: account.botId, sendTest: true },
|
|
520
534
|
));
|
|
521
535
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
522
|
-
setModel((current) => ({
|
|
536
|
+
setModel((current) => ({
|
|
537
|
+
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
|
538
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
|
539
|
+
}));
|
|
523
540
|
}
|
|
524
541
|
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
|
525
542
|
let feedback;
|
|
@@ -563,6 +580,29 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
563
580
|
setModel({
|
|
564
581
|
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
|
565
582
|
revision: snapshot.revision, error: null,
|
|
583
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
} finally {
|
|
587
|
+
const shouldRefresh = workspaceFence.endMutation();
|
|
588
|
+
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
589
|
+
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
590
|
+
}
|
|
591
|
+
}, [invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
592
|
+
|
|
593
|
+
const saveAgentPreset = React.useCallback(async (account, agentPreset) => {
|
|
594
|
+
const snapshotVersion = workspaceFence.beginMutation();
|
|
595
|
+
setBotBusy(account.botId, 'preset');
|
|
596
|
+
try {
|
|
597
|
+
const snapshot = normalizeSnapshot(await invoke(
|
|
598
|
+
WEIXIN_ENDPOINTS.setAgentPreset,
|
|
599
|
+
{ botId: account.botId, agentPreset },
|
|
600
|
+
));
|
|
601
|
+
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
602
|
+
setModel({
|
|
603
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
|
604
|
+
revision: snapshot.revision, error: null,
|
|
605
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
566
606
|
});
|
|
567
607
|
}
|
|
568
608
|
} finally {
|
|
@@ -581,7 +621,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
581
621
|
confirm: true,
|
|
582
622
|
}));
|
|
583
623
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
584
|
-
setModel((current) => ({
|
|
624
|
+
setModel((current) => ({
|
|
625
|
+
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
|
626
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
|
627
|
+
}));
|
|
585
628
|
}
|
|
586
629
|
setRemoveTarget(null);
|
|
587
630
|
announce('微信账号及本机凭据已移除。');
|
|
@@ -621,7 +664,9 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
621
664
|
});
|
|
622
665
|
}
|
|
623
666
|
|
|
624
|
-
return h(
|
|
667
|
+
return h(AgentPresetCatalogContext.Provider, {
|
|
668
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
669
|
+
}, h('section', { className: 'dxw-page dim-channelPage', 'aria-label': '微信设置' },
|
|
625
670
|
h(Heading, {
|
|
626
671
|
totals: model.totals,
|
|
627
672
|
adding: Boolean(provision),
|
|
@@ -654,12 +699,13 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
654
699
|
removeTarget,
|
|
655
700
|
onReconnect: (account) => void reconnect(account),
|
|
656
701
|
onWorkspaceSave: saveWorkspace,
|
|
702
|
+
onAgentPresetSave: saveAgentPreset,
|
|
657
703
|
onRequestRemove: (account) => setRemoveTarget(account.botId),
|
|
658
704
|
onConfirmRemove: (account) => void remove(account),
|
|
659
705
|
onCancelRemove: () => setRemoveTarget(null),
|
|
660
706
|
})
|
|
661
707
|
: null),
|
|
662
|
-
);
|
|
708
|
+
));
|
|
663
709
|
}
|
|
664
710
|
|
|
665
711
|
export function apply(ctx) {
|