@xmanrui/dsh-im 0.17.0 → 0.18.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 +964 -538
- package/lib/index.js +189 -144
- 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 +5 -0
- package/plugin-src/client/channels/feishu/index.js +39 -2
- 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 +15 -0
- package/plugin-src/client/channels/weixin/index.js +54 -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 +29 -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 +6 -3
- package/plugin-src/host/channels/feishu/rpc.mjs +17 -0
- 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/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/shared/image-prompt.mjs +32 -1
- package/src/channels/weixin/weixin-api.mjs +1 -1
- package/src/channels/weixin/weixin-bridge.mjs +23 -3
- package/src/channels/weixin/weixin-controller.mjs +15 -0
|
@@ -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']);
|
|
@@ -45,6 +48,15 @@ function normalizeTestMessage(value) {
|
|
|
45
48
|
return { sent: false, code };
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
function normalizeMessageError(value) {
|
|
52
|
+
if (!isRecord(value)) return null;
|
|
53
|
+
const code = string(value.code).slice(0, 64);
|
|
54
|
+
const reason = string(value.reason).slice(0, 128);
|
|
55
|
+
const message = string(value.message).slice(0, 500);
|
|
56
|
+
const at = timestamp(value.at);
|
|
57
|
+
return code && reason && message && at !== null ? { code, reason, message, at } : null;
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
export function unwrapRpcResult(result) {
|
|
49
61
|
if (!isRecord(result) || typeof result.ok !== 'boolean') {
|
|
50
62
|
throw new Error('微信服务返回了无法识别的响应');
|
|
@@ -115,6 +127,7 @@ function normalizeBot(value) {
|
|
|
115
127
|
connected,
|
|
116
128
|
configured: value.configured === true,
|
|
117
129
|
workspace: string(value.workspace).slice(0, 4_096),
|
|
130
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
118
131
|
bot: {
|
|
119
132
|
name: string(value.bot.name, '微信机器人'),
|
|
120
133
|
accountIdMasked: string(value.bot.accountIdMasked, '已安全保存'),
|
|
@@ -128,6 +141,7 @@ function normalizeBot(value) {
|
|
|
128
141
|
messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
|
|
129
142
|
messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0),
|
|
130
143
|
},
|
|
144
|
+
lastMessageError: normalizeMessageError(value.lastMessageError),
|
|
131
145
|
error: isRecord(value.error)
|
|
132
146
|
? {
|
|
133
147
|
code: string(value.error.code, 'WEIXIN_ACCOUNT_ERROR'),
|
|
@@ -153,6 +167,7 @@ export function normalizeSnapshot(value) {
|
|
|
153
167
|
},
|
|
154
168
|
provisioning: value.provisioning ? normalizeProvisioning(value.provisioning) : null,
|
|
155
169
|
testMessage: normalizeTestMessage(value.testMessage),
|
|
170
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog),
|
|
156
171
|
};
|
|
157
172
|
}
|
|
158
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,8 +234,17 @@ 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,
|
|
244
|
+
account.lastMessageError ? h('div', {
|
|
245
|
+
className: 'dxw-summary dim-cardSummary',
|
|
246
|
+
role: 'status',
|
|
247
|
+
}, `最近一条消息处理失败:${account.lastMessageError.message}`) : null,
|
|
233
248
|
feedback ? h('div', {
|
|
234
249
|
className: 'dxw-summary dim-cardSummary',
|
|
235
250
|
role: 'status',
|
|
@@ -260,6 +275,7 @@ function AccountList(props) {
|
|
|
260
275
|
removing: props.removeTarget === account.botId,
|
|
261
276
|
onReconnect: () => props.onReconnect(account),
|
|
262
277
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
278
|
+
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
|
|
263
279
|
onRequestRemove: () => props.onRequestRemove(account),
|
|
264
280
|
onConfirmRemove: () => props.onConfirmRemove(account),
|
|
265
281
|
onCancelRemove: props.onCancelRemove,
|
|
@@ -285,6 +301,7 @@ export function mergeWeixinProvisioningSnapshot(
|
|
|
285
301
|
export function WeixinSettingsTab({ rpcCall }) {
|
|
286
302
|
const [model, setModel] = React.useState({
|
|
287
303
|
phase: 'loading', bots: [], totals: EMPTY_TOTALS, revision: 0, error: null,
|
|
304
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
288
305
|
});
|
|
289
306
|
const [provision, setProvision] = React.useState(null);
|
|
290
307
|
const [busy, setBusy] = React.useState(false);
|
|
@@ -327,6 +344,7 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
327
344
|
setModel({
|
|
328
345
|
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
|
329
346
|
revision: snapshot.revision, error: null,
|
|
347
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
330
348
|
});
|
|
331
349
|
if (snapshot.provisioning) {
|
|
332
350
|
setProvision((current) => mergeWeixinProvisioningSnapshot(
|
|
@@ -515,7 +533,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
515
533
|
{ botId: account.botId, sendTest: true },
|
|
516
534
|
));
|
|
517
535
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
518
|
-
setModel((current) => ({
|
|
536
|
+
setModel((current) => ({
|
|
537
|
+
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
|
538
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
|
539
|
+
}));
|
|
519
540
|
}
|
|
520
541
|
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
|
521
542
|
let feedback;
|
|
@@ -559,6 +580,29 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
559
580
|
setModel({
|
|
560
581
|
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals,
|
|
561
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,
|
|
562
606
|
});
|
|
563
607
|
}
|
|
564
608
|
} finally {
|
|
@@ -577,7 +621,10 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
577
621
|
confirm: true,
|
|
578
622
|
}));
|
|
579
623
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
580
|
-
setModel((current) => ({
|
|
624
|
+
setModel((current) => ({
|
|
625
|
+
...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision,
|
|
626
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog,
|
|
627
|
+
}));
|
|
581
628
|
}
|
|
582
629
|
setRemoveTarget(null);
|
|
583
630
|
announce('微信账号及本机凭据已移除。');
|
|
@@ -617,7 +664,9 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
617
664
|
});
|
|
618
665
|
}
|
|
619
666
|
|
|
620
|
-
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': '微信设置' },
|
|
621
670
|
h(Heading, {
|
|
622
671
|
totals: model.totals,
|
|
623
672
|
adding: Boolean(provision),
|
|
@@ -650,12 +699,13 @@ export function WeixinSettingsTab({ rpcCall }) {
|
|
|
650
699
|
removeTarget,
|
|
651
700
|
onReconnect: (account) => void reconnect(account),
|
|
652
701
|
onWorkspaceSave: saveWorkspace,
|
|
702
|
+
onAgentPresetSave: saveAgentPreset,
|
|
653
703
|
onRequestRemove: (account) => setRemoveTarget(account.botId),
|
|
654
704
|
onConfirmRemove: (account) => void remove(account),
|
|
655
705
|
onCancelRemove: () => setRemoveTarget(null),
|
|
656
706
|
})
|
|
657
707
|
: null),
|
|
658
|
-
);
|
|
708
|
+
));
|
|
659
709
|
}
|
|
660
710
|
|
|
661
711
|
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 WHATSAPP_RPC_CHANNEL = '/whatsapp';
|
|
2
4
|
|
|
3
5
|
export const WHATSAPP_ENDPOINTS = Object.freeze({
|
|
@@ -8,6 +10,7 @@ export const WHATSAPP_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 PROVISION_STATES = new Set(['starting', 'pending', '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, 'WhatsApp机器人', 100),
|
|
87
91
|
idMasked: text(value.bot?.idMasked, 'WhatsApp账号', 140),
|
|
@@ -109,6 +113,7 @@ export function normalizeSnapshot(value) {
|
|
|
109
113
|
bots,
|
|
110
114
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
111
115
|
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
116
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
112
117
|
};
|
|
113
118
|
}
|
|
114
119
|
|
|
@@ -4,6 +4,11 @@ import { WhatsappLogoGlyph } from '../../channel-logos.js';
|
|
|
4
4
|
import { 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 {
|
|
@@ -173,6 +178,7 @@ export function WhatsappAccountCard({
|
|
|
173
178
|
removing,
|
|
174
179
|
onReconnect,
|
|
175
180
|
onWorkspaceSave,
|
|
181
|
+
onAgentPresetSave,
|
|
176
182
|
onRequestRemove,
|
|
177
183
|
onConfirmRemove,
|
|
178
184
|
onCancelRemove,
|
|
@@ -205,6 +211,11 @@ export function WhatsappAccountCard({
|
|
|
205
211
|
disabled: Boolean(busy),
|
|
206
212
|
onSave: onWorkspaceSave,
|
|
207
213
|
}),
|
|
214
|
+
h(AgentPresetEditor, {
|
|
215
|
+
agentPreset: account.agentPreset,
|
|
216
|
+
disabled: Boolean(busy),
|
|
217
|
+
onSave: onAgentPresetSave,
|
|
218
|
+
}),
|
|
208
219
|
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
|
209
220
|
summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null,
|
|
210
221
|
testNotice ? h('div', {
|
|
@@ -229,6 +240,7 @@ export function WhatsappAccountCard({
|
|
|
229
240
|
export function WhatsappSettingsTab({ rpcCall }) {
|
|
230
241
|
const [model, setModel] = React.useState({
|
|
231
242
|
phase: 'loading', bots: [], totals: { configured: 0, connected: 0 }, error: null,
|
|
243
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG,
|
|
232
244
|
});
|
|
233
245
|
const [provision, setProvision] = React.useState(null);
|
|
234
246
|
const [busy, setBusy] = React.useState(false);
|
|
@@ -264,7 +276,10 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
264
276
|
const snapshot = normalizeSnapshot(await invoke(WHATSAPP_ENDPOINTS.status, {}, signal));
|
|
265
277
|
if (!mounted.current || signal?.aborted
|
|
266
278
|
|| !workspaceFence.canCommitStatus(workspaceVersion)) return undefined;
|
|
267
|
-
setModel({
|
|
279
|
+
setModel({
|
|
280
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
281
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
282
|
+
});
|
|
268
283
|
if (restore && snapshot.provisioning) setProvision({
|
|
269
284
|
...snapshot.provisioning,
|
|
270
285
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now()),
|
|
@@ -392,7 +407,10 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
392
407
|
const value = await invoke(endpoint, payload);
|
|
393
408
|
const snapshot = normalizeSnapshot(value);
|
|
394
409
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
395
|
-
setModel({
|
|
410
|
+
setModel({
|
|
411
|
+
phase: 'ready', bots: snapshot.bots, totals: snapshot.totals, error: null,
|
|
412
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
413
|
+
});
|
|
396
414
|
if (operation === 'reconnect') {
|
|
397
415
|
setTestNoticeByBot((current) => ({
|
|
398
416
|
...current,
|
|
@@ -441,6 +459,12 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
441
459
|
WHATSAPP_ENDPOINTS.setWorkspace,
|
|
442
460
|
{ botId: account.botId, workspace },
|
|
443
461
|
),
|
|
462
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
463
|
+
account,
|
|
464
|
+
'preset',
|
|
465
|
+
WHATSAPP_ENDPOINTS.setAgentPreset,
|
|
466
|
+
{ botId: account.botId, agentPreset },
|
|
467
|
+
),
|
|
444
468
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
445
469
|
onCancelRemove: () => setRemoveTarget(null),
|
|
446
470
|
onConfirmRemove: async () => {
|
|
@@ -453,7 +477,9 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
453
477
|
})))))
|
|
454
478
|
: null;
|
|
455
479
|
|
|
456
|
-
return h(
|
|
480
|
+
return h(AgentPresetCatalogContext.Provider, {
|
|
481
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG,
|
|
482
|
+
}, h('section', {
|
|
457
483
|
className: 'ddt-page dwa-page dim-channelPage',
|
|
458
484
|
'aria-label': 'WhatsApp 设置',
|
|
459
485
|
},
|
|
@@ -490,5 +516,5 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
490
516
|
: model.bots.length === 0
|
|
491
517
|
? h(EmptyView, { busy, onStart: () => void startProvisioning(false) })
|
|
492
518
|
: null,
|
|
493
|
-
botList));
|
|
519
|
+
botList)));
|
|
494
520
|
}
|
|
@@ -117,6 +117,15 @@ const EN = Object.freeze({
|
|
|
117
117
|
'工作区路径不存在。': 'The workspace path does not exist.',
|
|
118
118
|
'工作区路径必须指向一个目录。': 'The workspace path must point to a directory.',
|
|
119
119
|
'找不到要修改的机器人。': 'The bot could not be found.',
|
|
120
|
+
'Agent Preset': 'Agent Preset',
|
|
121
|
+
'跟随 Host 默认': 'Follow the Host default',
|
|
122
|
+
'(已不可用)': ' (unavailable)',
|
|
123
|
+
'只影响新建会话;若当前聊天已有会话,先发送 /new,再发送普通消息生效。': 'This affects only new sessions. If the current chat already has a session, send /new, then send a regular message to apply it.',
|
|
124
|
+
'当前 Agent Preset 已不可用,请选择其他 Preset 或跟随 Host 默认。': 'The current Agent Preset is unavailable. Choose another preset or follow the Host default.',
|
|
125
|
+
'Agent Preset 修改失败,请重试。': 'Could not update the Agent Preset. Try again.',
|
|
126
|
+
'请选择 Agent Preset。': 'Choose an Agent Preset.',
|
|
127
|
+
'Agent Preset 无效。': 'The Agent Preset is invalid.',
|
|
128
|
+
'Agent Preset 不存在或不可用。': 'The Agent Preset does not exist or is unavailable.',
|
|
120
129
|
'尚未检查': 'Not checked yet',
|
|
121
130
|
'刚刚': 'Just now',
|
|
122
131
|
'检查连接': 'Check connection',
|
|
@@ -449,6 +458,20 @@ const EN = Object.freeze({
|
|
|
449
458
|
'微信绑定没有完成': 'WeChat setup did not complete',
|
|
450
459
|
'微信连接正常': 'WeChat connection is healthy',
|
|
451
460
|
'微信连接未就绪': 'WeChat connection is not ready',
|
|
461
|
+
'当前模型不支持图片,请用 /models 查看可用模型,再用 /model <序号> 切换后重发。': 'The current model does not support images. Use /models to list models, then /model <number> to switch and resend.',
|
|
462
|
+
'图片超过宿主允许的大小,请压缩后重试。': 'The image exceeds the Host size limit. Compress it and try again.',
|
|
463
|
+
'图片分辨率过高,请压缩后重试。': 'The image resolution is too high. Compress it and try again.',
|
|
464
|
+
'图片内容无效或格式不受支持,请重新发送。': 'The image is invalid or unsupported. Send it again.',
|
|
465
|
+
'未能读取图片内容,请重新发送。': 'The image could not be read. Send it again.',
|
|
466
|
+
'图片格式与实际内容不一致,请重新发送。': 'The declared image format does not match its content. Send it again.',
|
|
467
|
+
'一次发送的图片数量超过宿主限制,请减少后重试。': 'The message exceeds the Host image-count limit. Remove some images and try again.',
|
|
468
|
+
'图片总大小超过宿主限制,请减少图片或压缩后重试。': 'The images exceed the Host total-size limit. Remove or compress some images and try again.',
|
|
469
|
+
'图片下载地址发生了重定向,暂时无法读取。': 'The image download redirected and cannot be read.',
|
|
470
|
+
'图片超过 5 MB,请压缩后重试。': 'The image exceeds 5 MB. Compress it and try again.',
|
|
471
|
+
'一次发送的图片总大小过大,请减少图片数量或压缩后重试。': 'The images are too large in total. Remove or compress some images and try again.',
|
|
472
|
+
'图片下载失败,请重新发送后再试。': 'The image download failed. Send it again.',
|
|
473
|
+
'暂不支持该图片格式,请发送 JPEG、PNG、WebP 或 GIF 图片。': 'This image format is unsupported. Send a JPEG, PNG, WebP, or GIF image.',
|
|
474
|
+
'消息处理失败,请稍后重试。': 'Message processing failed. Try again later.',
|
|
452
475
|
'微信服务没有返回有效的账号列表': 'WeChat did not return a valid account list',
|
|
453
476
|
'尚未绑定微信': 'No WeChat account connected yet',
|
|
454
477
|
'用于把微信机器人绑定到 DeepSeek Harness 的一次性二维码': 'One-time QR code for connecting a WeChat bot to DeepSeek Harness',
|
|
@@ -522,6 +545,12 @@ function translateDynamic(text) {
|
|
|
522
545
|
}
|
|
523
546
|
match = /^二维码剩余 (.+)$/.exec(text);
|
|
524
547
|
if (match) return `QR code expires in ${match[1]}`;
|
|
548
|
+
match = /^最近一条消息处理失败:(.+)$/.exec(text);
|
|
549
|
+
if (match) return `Latest message failed: ${localizeText(match[1])}`;
|
|
550
|
+
match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text);
|
|
551
|
+
if (match) return `The image download failed (HTTP ${match[1]}). Send it again.`;
|
|
552
|
+
match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text);
|
|
553
|
+
if (match) return `A message can contain at most ${match[1]} images.`;
|
|
525
554
|
match = /^状态刷新失败:(.+)$/.exec(text);
|
|
526
555
|
if (match) return `Status refresh failed: ${match[1]}`;
|
|
527
556
|
match = /^状态自动刷新失败:(.+)$/.exec(text);
|
|
@@ -142,6 +142,14 @@ const CSS = String.raw`
|
|
|
142
142
|
.dim-panel .dim-workspaceEdit { grid-column: 2; grid-row: 1; padding: 0; border: 0; color: #1677ff; background: transparent; font: inherit; font-weight: 560; white-space: nowrap; cursor: pointer; }
|
|
143
143
|
.dim-panel .dim-workspaceEdit:disabled { cursor: not-allowed; opacity: .55; }
|
|
144
144
|
.dim-panel .dim-workspacePath { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; display: block; overflow-x: auto; overflow-y: hidden; color: var(--dsw-alias-label-primary, #1f2329); font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; }
|
|
145
|
+
.dim-panel .dim-preset { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) max-content; align-items: center; column-gap: 10px; row-gap: 4px; margin-top: 6px; padding: 6px 10px; border: 1px solid var(--dsw-alias-border-l1, #eef0f3); border-radius: 9px; background: var(--dsw-alias-bg-module-platform, #f7f8fa); }
|
|
146
|
+
.dim-panel .dim-presetHeader { display: contents; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
|
|
147
|
+
.dim-panel .dim-presetHeader > span { grid-column: 1; grid-row: 1; white-space: nowrap; }
|
|
148
|
+
.dim-panel .dim-presetStatus { grid-column: 2; grid-row: 1; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; white-space: nowrap; }
|
|
149
|
+
.dim-panel .dim-presetSelect { min-width: 0; max-width: 100%; grid-column: 1 / -1; grid-row: 2; height: 30px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; }
|
|
150
|
+
.dim-panel .dim-presetSelect:disabled { cursor: not-allowed; opacity: .55; }
|
|
151
|
+
.dim-panel .dim-presetHelp { grid-column: 1 / -1; grid-row: 3; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.4; }
|
|
152
|
+
.dim-panel .dim-presetError { grid-column: 1 / -1; grid-row: 4; margin: 0; color: var(--dsw-alias-state-error-primary, #d54941); font-size: 12px; line-height: 1.4; }
|
|
145
153
|
.dim-directoryPickerBackdrop { --dim-blue: var(--dsw-alias-state-business-primary, #3370ff); --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent); position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgb(15 17 21 / 42%); backdrop-filter: blur(3px); }
|
|
146
154
|
.dim-directoryPickerBackdrop, .dim-directoryPickerBackdrop *, .dim-directoryPickerBackdrop *::before, .dim-directoryPickerBackdrop *::after { box-sizing: border-box; }
|
|
147
155
|
.dim-directoryPicker { width: min(720px, 100%); height: min(620px, calc(100vh - 48px)); min-height: 420px; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 18px; outline: none; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 24px 72px rgb(15 17 21 / 24%); }
|