@xmanrui/dsh-im 0.17.1 → 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 +931 -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 +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 +9 -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/weixin/weixin-api.mjs +1 -1
package/lib/client.js
CHANGED
|
@@ -40,7 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
name: () => name
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(index_exports);
|
|
43
|
-
var
|
|
43
|
+
var React19 = __toESM(require("react"), 1);
|
|
44
44
|
|
|
45
45
|
// plugin-src/client/channel-logos.js
|
|
46
46
|
var React = __toESM(require("react"), 1);
|
|
@@ -186,207 +186,7 @@ function OfficeLogoGlyph({ size } = {}) {
|
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
// plugin-src/client/
|
|
190
|
-
var DINGTALK_RPC_CHANNEL = "/dingtalk";
|
|
191
|
-
var DINGTALK_ENDPOINTS = Object.freeze({
|
|
192
|
-
status: "connection.status",
|
|
193
|
-
beginProvisioning: "provision.begin",
|
|
194
|
-
pollProvisioning: "provision.poll",
|
|
195
|
-
cancelProvisioning: "provision.cancel",
|
|
196
|
-
bindCredentials: "bot.bind-credentials",
|
|
197
|
-
reconnectBot: "bot.reconnect",
|
|
198
|
-
deleteBot: "bot.delete",
|
|
199
|
-
setWorkspace: "bot.workspace.set"
|
|
200
|
-
});
|
|
201
|
-
var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
202
|
-
var SNAPSHOT_STATES = /* @__PURE__ */ new Set(["disconnected", "offline", "provisioning", "connected", "degraded"]);
|
|
203
|
-
var PROVISION_STATES = /* @__PURE__ */ new Set([
|
|
204
|
-
"starting",
|
|
205
|
-
"pending",
|
|
206
|
-
"scanned",
|
|
207
|
-
"authorizing",
|
|
208
|
-
"creating",
|
|
209
|
-
"connecting",
|
|
210
|
-
"connected",
|
|
211
|
-
"expired",
|
|
212
|
-
"failed",
|
|
213
|
-
"cancelled"
|
|
214
|
-
]);
|
|
215
|
-
var HEALTH_STATES = /* @__PURE__ */ new Set(["healthy", "checking", "degraded", "offline"]);
|
|
216
|
-
var FORBIDDEN_ERROR_FIELDS = /(client[_-]?secret|secret[_-]?ref|device[_-]?code|app[_-]?secret|access[_-]?token|token)/i;
|
|
217
|
-
var QR_DATA_URL = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
|
|
218
|
-
var MAX_QR_SOURCE_LENGTH = 2 * 1024 * 1024;
|
|
219
|
-
function isRecord(value) {
|
|
220
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
221
|
-
}
|
|
222
|
-
function optionalString(value, maxLength = 240) {
|
|
223
|
-
if (typeof value !== "string") return void 0;
|
|
224
|
-
const trimmed = value.trim();
|
|
225
|
-
return trimmed ? trimmed.slice(0, maxLength) : void 0;
|
|
226
|
-
}
|
|
227
|
-
function opaqueId(value) {
|
|
228
|
-
const id5 = optionalString(value, 128);
|
|
229
|
-
return id5 && /^[a-z\d_-]+$/i.test(id5) ? id5 : void 0;
|
|
230
|
-
}
|
|
231
|
-
function timestamp(value) {
|
|
232
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
233
|
-
if (typeof value === "string" && value.trim()) {
|
|
234
|
-
const parsed = Date.parse(value);
|
|
235
|
-
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
236
|
-
}
|
|
237
|
-
return void 0;
|
|
238
|
-
}
|
|
239
|
-
function nonNegativeInteger(value) {
|
|
240
|
-
const number = Number(value);
|
|
241
|
-
return Number.isSafeInteger(number) && number >= 0 ? number : 0;
|
|
242
|
-
}
|
|
243
|
-
function clamp(value, min, max, fallback) {
|
|
244
|
-
const number = Number(value);
|
|
245
|
-
return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback;
|
|
246
|
-
}
|
|
247
|
-
function safeErrorCode(value, fallback) {
|
|
248
|
-
const code = optionalString(value, 80);
|
|
249
|
-
return code && /^[a-z][a-z\d_.:-]*$/i.test(code) && !FORBIDDEN_ERROR_FIELDS.test(code) ? code : fallback;
|
|
250
|
-
}
|
|
251
|
-
function sanitizeMessage(value, fallback) {
|
|
252
|
-
const message = optionalString(value, 480) ?? fallback;
|
|
253
|
-
if (FORBIDDEN_ERROR_FIELDS.test(message)) return fallback;
|
|
254
|
-
return message.replace(/([=:]\s*)[^\s,;,。]+/g, "$1\u2022\u2022\u2022\u2022\u2022\u2022").slice(0, 240);
|
|
255
|
-
}
|
|
256
|
-
function normalizeError(value, fallbackCode, fallbackMessage) {
|
|
257
|
-
if (!isRecord(value)) return void 0;
|
|
258
|
-
return {
|
|
259
|
-
code: safeErrorCode(value.code, fallbackCode),
|
|
260
|
-
message: sanitizeMessage(value.message, fallbackMessage)
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function normalizeTestMessage(value) {
|
|
264
|
-
if (!isRecord(value)) return null;
|
|
265
|
-
if (value.sent === true) return { sent: true };
|
|
266
|
-
if (value.sent !== false) return null;
|
|
267
|
-
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
|
|
268
|
-
return { sent: false, code };
|
|
269
|
-
}
|
|
270
|
-
function unwrapRpcResult(result) {
|
|
271
|
-
if (!isRecord(result) || typeof result.ok !== "boolean") {
|
|
272
|
-
throw new Error("\u9489\u9489\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
|
273
|
-
}
|
|
274
|
-
if (!result.ok) {
|
|
275
|
-
const error = new Error(sanitizeMessage(result.error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25"));
|
|
276
|
-
error.code = safeErrorCode(result.error?.code, "DINGTALK_RPC_ERROR");
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
return result.value;
|
|
280
|
-
}
|
|
281
|
-
function safeQrSource(value) {
|
|
282
|
-
if (typeof value !== "string" || value.length > MAX_QR_SOURCE_LENGTH) return void 0;
|
|
283
|
-
return QR_DATA_URL.test(value) ? value : void 0;
|
|
284
|
-
}
|
|
285
|
-
function normalizeProvisioning(value, now = Date.now()) {
|
|
286
|
-
const source = isRecord(value?.provisioning) ? value.provisioning : value;
|
|
287
|
-
if (!isRecord(source)) throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
|
|
288
|
-
const attemptId = opaqueId(source.attemptId);
|
|
289
|
-
if (!attemptId) throw new Error("\u9489\u9489\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
|
|
290
|
-
const reportedStatus = optionalString(source.status, 32) ?? optionalString(source.state, 32);
|
|
291
|
-
const status = PROVISION_STATES.has(reportedStatus) ? reportedStatus : "failed";
|
|
292
|
-
const expiresAt = timestamp(source.expiresAt) ?? now + clamp(source.expiresIn, 1, 2 * 60 * 60, 10 * 60) * 1e3;
|
|
293
|
-
const result = {
|
|
294
|
-
attemptId,
|
|
295
|
-
status,
|
|
296
|
-
expiresAt,
|
|
297
|
-
pollIntervalMs: clamp(source.pollIntervalMs, 1e3, 1e4, 3e3)
|
|
298
|
-
};
|
|
299
|
-
const qrCodeDataUrl = safeQrSource(source.qrCodeDataUrl);
|
|
300
|
-
if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
|
|
301
|
-
if (opaqueId(source.botId)) result.botId = opaqueId(source.botId);
|
|
302
|
-
if (source.alreadyConnected === true) result.alreadyConnected = true;
|
|
303
|
-
const error = normalizeError(
|
|
304
|
-
source.error,
|
|
305
|
-
"DINGTALK_PROVISION_FAILED",
|
|
306
|
-
"\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"
|
|
307
|
-
);
|
|
308
|
-
if (error) result.error = error;
|
|
309
|
-
return result;
|
|
310
|
-
}
|
|
311
|
-
function normalizeBot(value) {
|
|
312
|
-
if (!isRecord(value)) return void 0;
|
|
313
|
-
const botId = opaqueId(value.botId);
|
|
314
|
-
if (!botId) return void 0;
|
|
315
|
-
const bot = isRecord(value.bot) ? value.bot : {};
|
|
316
|
-
const connected = value.connected === true;
|
|
317
|
-
const reportedState = ACCOUNT_STATES.has(value.state) ? value.state : "offline";
|
|
318
|
-
const state = connected ? "connected" : reportedState === "connected" ? "connecting" : reportedState;
|
|
319
|
-
const health = isRecord(value.health) ? value.health : {};
|
|
320
|
-
const stats = isRecord(value.stats) ? value.stats : {};
|
|
321
|
-
return {
|
|
322
|
-
botId,
|
|
323
|
-
state,
|
|
324
|
-
connected,
|
|
325
|
-
configured: value.configured !== false,
|
|
326
|
-
workspace: optionalString(value.workspace, 4096) ?? "",
|
|
327
|
-
bot: {
|
|
328
|
-
name: optionalString(bot.name, 100) ?? "\u9489\u9489\u673A\u5668\u4EBA",
|
|
329
|
-
clientIdMasked: optionalString(bot.clientIdMasked, 140) ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58"
|
|
330
|
-
},
|
|
331
|
-
health: {
|
|
332
|
-
status: HEALTH_STATES.has(health.status) ? health.status : connected ? "healthy" : "offline",
|
|
333
|
-
summary: optionalString(health.summary, 200) ?? (connected ? "\u9489\u9489 Stream \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
|
|
334
|
-
lastCheckedAt: timestamp(health.lastCheckedAt),
|
|
335
|
-
lastConnectedAt: timestamp(health.lastConnectedAt)
|
|
336
|
-
},
|
|
337
|
-
stats: {
|
|
338
|
-
messagesReceived: nonNegativeInteger(stats.messagesReceived),
|
|
339
|
-
messagesReplied: nonNegativeInteger(stats.messagesReplied)
|
|
340
|
-
},
|
|
341
|
-
error: normalizeError(value.error, "DINGTALK_ACCOUNT_ERROR", "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA") ?? null
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
function normalizeSnapshot(value) {
|
|
345
|
-
const source = isRecord(value?.snapshot) ? value.snapshot : value;
|
|
346
|
-
if (!isRecord(source) || !Array.isArray(source.bots)) {
|
|
347
|
-
throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868");
|
|
348
|
-
}
|
|
349
|
-
const seen = /* @__PURE__ */ new Set();
|
|
350
|
-
const bots = source.bots.map(normalizeBot).filter((bot) => {
|
|
351
|
-
if (!bot || seen.has(bot.botId)) return false;
|
|
352
|
-
seen.add(bot.botId);
|
|
353
|
-
return true;
|
|
354
|
-
});
|
|
355
|
-
return {
|
|
356
|
-
schemaVersion: Number.isSafeInteger(source.schemaVersion) ? source.schemaVersion : 1,
|
|
357
|
-
revision: nonNegativeInteger(source.revision),
|
|
358
|
-
state: SNAPSHOT_STATES.has(source.state) ? source.state : "offline",
|
|
359
|
-
bots,
|
|
360
|
-
totals: {
|
|
361
|
-
configured: bots.length,
|
|
362
|
-
connected: bots.filter((bot) => bot.connected).length
|
|
363
|
-
},
|
|
364
|
-
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
365
|
-
testMessage: normalizeTestMessage(source.testMessage)
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
function connectionTestFeedback(result) {
|
|
369
|
-
if (result?.sent === true) return "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
|
|
370
|
-
if (result?.code === "test-target-unavailable") {
|
|
371
|
-
return "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002\u673A\u5668\u4EBA\u5C1A\u672A\u6536\u5230\u53EF\u7528\u4E8E\u6D4B\u8BD5\u7684\u79C1\u804A\u6D88\u606F\u3002";
|
|
372
|
-
}
|
|
373
|
-
return result ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
374
|
-
}
|
|
375
|
-
function presentError(error) {
|
|
376
|
-
return {
|
|
377
|
-
code: safeErrorCode(error?.code, "DINGTALK_ERROR"),
|
|
378
|
-
message: sanitizeMessage(error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
function formatRemaining(milliseconds) {
|
|
382
|
-
const seconds = Math.max(0, Math.ceil(Number(milliseconds) / 1e3) || 0);
|
|
383
|
-
return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// plugin-src/client/channels/dingtalk/index.js
|
|
387
|
-
var React7 = __toESM(require("react"), 1);
|
|
388
|
-
|
|
389
|
-
// plugin-src/client/credential-binding.js
|
|
189
|
+
// plugin-src/client/agent-preset.js
|
|
390
190
|
var React3 = __toESM(require("react"), 1);
|
|
391
191
|
|
|
392
192
|
// plugin-src/client/i18n.js
|
|
@@ -507,6 +307,15 @@ var EN = Object.freeze({
|
|
|
507
307
|
"\u5DE5\u4F5C\u533A\u8DEF\u5F84\u4E0D\u5B58\u5728\u3002": "The workspace path does not exist.",
|
|
508
308
|
"\u5DE5\u4F5C\u533A\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u76EE\u5F55\u3002": "The workspace path must point to a directory.",
|
|
509
309
|
"\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002": "The bot could not be found.",
|
|
310
|
+
"Agent Preset": "Agent Preset",
|
|
311
|
+
"\u8DDF\u968F Host \u9ED8\u8BA4": "Follow the Host default",
|
|
312
|
+
"\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09": " (unavailable)",
|
|
313
|
+
"\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002": "This affects only new sessions. If the current chat already has a session, send /new, then send a regular message to apply it.",
|
|
314
|
+
"\u5F53\u524D Agent Preset \u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6 Preset \u6216\u8DDF\u968F Host \u9ED8\u8BA4\u3002": "The current Agent Preset is unavailable. Choose another preset or follow the Host default.",
|
|
315
|
+
"Agent Preset \u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002": "Could not update the Agent Preset. Try again.",
|
|
316
|
+
"\u8BF7\u9009\u62E9 Agent Preset\u3002": "Choose an Agent Preset.",
|
|
317
|
+
"Agent Preset \u65E0\u6548\u3002": "The Agent Preset is invalid.",
|
|
318
|
+
"Agent Preset \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\u3002": "The Agent Preset does not exist or is unavailable.",
|
|
510
319
|
"\u5C1A\u672A\u68C0\u67E5": "Not checked yet",
|
|
511
320
|
"\u521A\u521A": "Just now",
|
|
512
321
|
"\u68C0\u67E5\u8FDE\u63A5": "Check connection",
|
|
@@ -1005,7 +814,310 @@ function h2(type, props, ...children) {
|
|
|
1005
814
|
return React2.createElement(type, localizedProps, ...children.map(localizeChild));
|
|
1006
815
|
}
|
|
1007
816
|
|
|
817
|
+
// plugin-src/client/agent-preset.js
|
|
818
|
+
var SET_AGENT_PRESET_ENDPOINT = "bot.preset.set";
|
|
819
|
+
var PRESET_ID = /^[a-z0-9][a-z0-9-]*$/;
|
|
820
|
+
var EMPTY_AGENT_PRESET_CATALOG = Object.freeze({
|
|
821
|
+
defaultId: "",
|
|
822
|
+
items: Object.freeze([])
|
|
823
|
+
});
|
|
824
|
+
var AgentPresetCatalogContext = React3.createContext(EMPTY_AGENT_PRESET_CATALOG);
|
|
825
|
+
function normalizeAgentPresetId(value) {
|
|
826
|
+
if (typeof value !== "string") return "";
|
|
827
|
+
const id5 = value.trim();
|
|
828
|
+
return PRESET_ID.test(id5) ? id5 : "";
|
|
829
|
+
}
|
|
830
|
+
function normalizeAgentPresetCatalog(value) {
|
|
831
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
832
|
+
return { defaultId: "", items: [] };
|
|
833
|
+
}
|
|
834
|
+
const items = [];
|
|
835
|
+
const seen = /* @__PURE__ */ new Set();
|
|
836
|
+
for (const entry of Array.isArray(value.items) ? value.items : []) {
|
|
837
|
+
const id5 = typeof entry === "string" ? normalizeAgentPresetId(entry) : normalizeAgentPresetId(entry?.id);
|
|
838
|
+
if (!id5 || seen.has(id5)) continue;
|
|
839
|
+
seen.add(id5);
|
|
840
|
+
const label = typeof entry?.label === "string" && entry.label.trim() ? entry.label.trim().slice(0, 128) : typeof entry?.name === "string" && entry.name.trim() ? entry.name.trim().slice(0, 128) : id5;
|
|
841
|
+
items.push({ id: id5, label });
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
defaultId: normalizeAgentPresetId(value.defaultId),
|
|
845
|
+
items
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
|
|
849
|
+
const catalog = React3.useContext(AgentPresetCatalogContext) ?? EMPTY_AGENT_PRESET_CATALOG;
|
|
850
|
+
const current = normalizeAgentPresetId(agentPreset);
|
|
851
|
+
const [saving, setSaving] = React3.useState(false);
|
|
852
|
+
const [error, setError] = React3.useState(null);
|
|
853
|
+
const items = [];
|
|
854
|
+
const seen = /* @__PURE__ */ new Set();
|
|
855
|
+
for (const item of Array.isArray(catalog.items) ? catalog.items : []) {
|
|
856
|
+
if (!item?.id || seen.has(item.id)) continue;
|
|
857
|
+
seen.add(item.id);
|
|
858
|
+
items.push(item);
|
|
859
|
+
}
|
|
860
|
+
const currentUnavailable = Boolean(current && !seen.has(current));
|
|
861
|
+
if (currentUnavailable) items.push({ id: current, label: current, unavailable: true });
|
|
862
|
+
const inheritLabel = "\u8DDF\u968F Host \u9ED8\u8BA4";
|
|
863
|
+
const change = async (event) => {
|
|
864
|
+
const next = event.target.value;
|
|
865
|
+
if (next === current || saving || disabled) return;
|
|
866
|
+
setSaving(true);
|
|
867
|
+
setError(null);
|
|
868
|
+
try {
|
|
869
|
+
await onSave?.(next || null);
|
|
870
|
+
} catch (cause) {
|
|
871
|
+
setError(cause?.message ?? "Agent Preset \u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
872
|
+
} finally {
|
|
873
|
+
setSaving(false);
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
return h2(
|
|
877
|
+
"div",
|
|
878
|
+
{ className: "dim-preset" },
|
|
879
|
+
h2(
|
|
880
|
+
"div",
|
|
881
|
+
{ className: "dim-presetHeader" },
|
|
882
|
+
h2("span", null, "Agent Preset"),
|
|
883
|
+
saving ? h2("span", { className: "dim-presetStatus" }, "\u4FDD\u5B58\u4E2D\u2026") : null
|
|
884
|
+
),
|
|
885
|
+
React3.createElement(
|
|
886
|
+
"select",
|
|
887
|
+
{
|
|
888
|
+
className: "dim-presetSelect",
|
|
889
|
+
value: current,
|
|
890
|
+
disabled: disabled || saving,
|
|
891
|
+
"aria-label": "Agent Preset",
|
|
892
|
+
onChange: (event) => {
|
|
893
|
+
void change(event);
|
|
894
|
+
}
|
|
895
|
+
},
|
|
896
|
+
h2("option", { value: "" }, inheritLabel),
|
|
897
|
+
...items.map((item) => h2(
|
|
898
|
+
"option",
|
|
899
|
+
{ key: item.id, value: item.id },
|
|
900
|
+
item.unavailable ? [item.id, "\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09"] : item.label && item.label !== item.id ? `${item.label}\uFF08${item.id}\uFF09` : item.id
|
|
901
|
+
))
|
|
902
|
+
),
|
|
903
|
+
h2(
|
|
904
|
+
"small",
|
|
905
|
+
{ className: "dim-presetHelp" },
|
|
906
|
+
"\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002"
|
|
907
|
+
),
|
|
908
|
+
error || currentUnavailable ? h2(
|
|
909
|
+
"p",
|
|
910
|
+
{ className: "dim-presetError", role: error ? "alert" : "status" },
|
|
911
|
+
error ?? "\u5F53\u524D Agent Preset \u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6 Preset \u6216\u8DDF\u968F Host \u9ED8\u8BA4\u3002"
|
|
912
|
+
) : null
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// plugin-src/client/channels/dingtalk/api.js
|
|
917
|
+
var DINGTALK_RPC_CHANNEL = "/dingtalk";
|
|
918
|
+
var DINGTALK_ENDPOINTS = Object.freeze({
|
|
919
|
+
status: "connection.status",
|
|
920
|
+
beginProvisioning: "provision.begin",
|
|
921
|
+
pollProvisioning: "provision.poll",
|
|
922
|
+
cancelProvisioning: "provision.cancel",
|
|
923
|
+
bindCredentials: "bot.bind-credentials",
|
|
924
|
+
reconnectBot: "bot.reconnect",
|
|
925
|
+
deleteBot: "bot.delete",
|
|
926
|
+
setWorkspace: "bot.workspace.set",
|
|
927
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
928
|
+
});
|
|
929
|
+
var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
930
|
+
var SNAPSHOT_STATES = /* @__PURE__ */ new Set(["disconnected", "offline", "provisioning", "connected", "degraded"]);
|
|
931
|
+
var PROVISION_STATES = /* @__PURE__ */ new Set([
|
|
932
|
+
"starting",
|
|
933
|
+
"pending",
|
|
934
|
+
"scanned",
|
|
935
|
+
"authorizing",
|
|
936
|
+
"creating",
|
|
937
|
+
"connecting",
|
|
938
|
+
"connected",
|
|
939
|
+
"expired",
|
|
940
|
+
"failed",
|
|
941
|
+
"cancelled"
|
|
942
|
+
]);
|
|
943
|
+
var HEALTH_STATES = /* @__PURE__ */ new Set(["healthy", "checking", "degraded", "offline"]);
|
|
944
|
+
var FORBIDDEN_ERROR_FIELDS = /(client[_-]?secret|secret[_-]?ref|device[_-]?code|app[_-]?secret|access[_-]?token|token)/i;
|
|
945
|
+
var QR_DATA_URL = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
|
|
946
|
+
var MAX_QR_SOURCE_LENGTH = 2 * 1024 * 1024;
|
|
947
|
+
function isRecord(value) {
|
|
948
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
949
|
+
}
|
|
950
|
+
function optionalString(value, maxLength = 240) {
|
|
951
|
+
if (typeof value !== "string") return void 0;
|
|
952
|
+
const trimmed = value.trim();
|
|
953
|
+
return trimmed ? trimmed.slice(0, maxLength) : void 0;
|
|
954
|
+
}
|
|
955
|
+
function opaqueId(value) {
|
|
956
|
+
const id5 = optionalString(value, 128);
|
|
957
|
+
return id5 && /^[a-z\d_-]+$/i.test(id5) ? id5 : void 0;
|
|
958
|
+
}
|
|
959
|
+
function timestamp(value) {
|
|
960
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
961
|
+
if (typeof value === "string" && value.trim()) {
|
|
962
|
+
const parsed = Date.parse(value);
|
|
963
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
964
|
+
}
|
|
965
|
+
return void 0;
|
|
966
|
+
}
|
|
967
|
+
function nonNegativeInteger(value) {
|
|
968
|
+
const number = Number(value);
|
|
969
|
+
return Number.isSafeInteger(number) && number >= 0 ? number : 0;
|
|
970
|
+
}
|
|
971
|
+
function clamp(value, min, max, fallback) {
|
|
972
|
+
const number = Number(value);
|
|
973
|
+
return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback;
|
|
974
|
+
}
|
|
975
|
+
function safeErrorCode(value, fallback) {
|
|
976
|
+
const code = optionalString(value, 80);
|
|
977
|
+
return code && /^[a-z][a-z\d_.:-]*$/i.test(code) && !FORBIDDEN_ERROR_FIELDS.test(code) ? code : fallback;
|
|
978
|
+
}
|
|
979
|
+
function sanitizeMessage(value, fallback) {
|
|
980
|
+
const message = optionalString(value, 480) ?? fallback;
|
|
981
|
+
if (FORBIDDEN_ERROR_FIELDS.test(message)) return fallback;
|
|
982
|
+
return message.replace(/([=:]\s*)[^\s,;,。]+/g, "$1\u2022\u2022\u2022\u2022\u2022\u2022").slice(0, 240);
|
|
983
|
+
}
|
|
984
|
+
function normalizeError(value, fallbackCode, fallbackMessage) {
|
|
985
|
+
if (!isRecord(value)) return void 0;
|
|
986
|
+
return {
|
|
987
|
+
code: safeErrorCode(value.code, fallbackCode),
|
|
988
|
+
message: sanitizeMessage(value.message, fallbackMessage)
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
function normalizeTestMessage(value) {
|
|
992
|
+
if (!isRecord(value)) return null;
|
|
993
|
+
if (value.sent === true) return { sent: true };
|
|
994
|
+
if (value.sent !== false) return null;
|
|
995
|
+
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
|
|
996
|
+
return { sent: false, code };
|
|
997
|
+
}
|
|
998
|
+
function unwrapRpcResult(result) {
|
|
999
|
+
if (!isRecord(result) || typeof result.ok !== "boolean") {
|
|
1000
|
+
throw new Error("\u9489\u9489\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
|
1001
|
+
}
|
|
1002
|
+
if (!result.ok) {
|
|
1003
|
+
const error = new Error(sanitizeMessage(result.error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25"));
|
|
1004
|
+
error.code = safeErrorCode(result.error?.code, "DINGTALK_RPC_ERROR");
|
|
1005
|
+
throw error;
|
|
1006
|
+
}
|
|
1007
|
+
return result.value;
|
|
1008
|
+
}
|
|
1009
|
+
function safeQrSource(value) {
|
|
1010
|
+
if (typeof value !== "string" || value.length > MAX_QR_SOURCE_LENGTH) return void 0;
|
|
1011
|
+
return QR_DATA_URL.test(value) ? value : void 0;
|
|
1012
|
+
}
|
|
1013
|
+
function normalizeProvisioning(value, now = Date.now()) {
|
|
1014
|
+
const source = isRecord(value?.provisioning) ? value.provisioning : value;
|
|
1015
|
+
if (!isRecord(source)) throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
|
|
1016
|
+
const attemptId = opaqueId(source.attemptId);
|
|
1017
|
+
if (!attemptId) throw new Error("\u9489\u9489\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
|
|
1018
|
+
const reportedStatus = optionalString(source.status, 32) ?? optionalString(source.state, 32);
|
|
1019
|
+
const status = PROVISION_STATES.has(reportedStatus) ? reportedStatus : "failed";
|
|
1020
|
+
const expiresAt = timestamp(source.expiresAt) ?? now + clamp(source.expiresIn, 1, 2 * 60 * 60, 10 * 60) * 1e3;
|
|
1021
|
+
const result = {
|
|
1022
|
+
attemptId,
|
|
1023
|
+
status,
|
|
1024
|
+
expiresAt,
|
|
1025
|
+
pollIntervalMs: clamp(source.pollIntervalMs, 1e3, 1e4, 3e3)
|
|
1026
|
+
};
|
|
1027
|
+
const qrCodeDataUrl = safeQrSource(source.qrCodeDataUrl);
|
|
1028
|
+
if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
|
|
1029
|
+
if (opaqueId(source.botId)) result.botId = opaqueId(source.botId);
|
|
1030
|
+
if (source.alreadyConnected === true) result.alreadyConnected = true;
|
|
1031
|
+
const error = normalizeError(
|
|
1032
|
+
source.error,
|
|
1033
|
+
"DINGTALK_PROVISION_FAILED",
|
|
1034
|
+
"\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"
|
|
1035
|
+
);
|
|
1036
|
+
if (error) result.error = error;
|
|
1037
|
+
return result;
|
|
1038
|
+
}
|
|
1039
|
+
function normalizeBot(value) {
|
|
1040
|
+
if (!isRecord(value)) return void 0;
|
|
1041
|
+
const botId = opaqueId(value.botId);
|
|
1042
|
+
if (!botId) return void 0;
|
|
1043
|
+
const bot = isRecord(value.bot) ? value.bot : {};
|
|
1044
|
+
const connected = value.connected === true;
|
|
1045
|
+
const reportedState = ACCOUNT_STATES.has(value.state) ? value.state : "offline";
|
|
1046
|
+
const state = connected ? "connected" : reportedState === "connected" ? "connecting" : reportedState;
|
|
1047
|
+
const health = isRecord(value.health) ? value.health : {};
|
|
1048
|
+
const stats = isRecord(value.stats) ? value.stats : {};
|
|
1049
|
+
return {
|
|
1050
|
+
botId,
|
|
1051
|
+
state,
|
|
1052
|
+
connected,
|
|
1053
|
+
configured: value.configured !== false,
|
|
1054
|
+
workspace: optionalString(value.workspace, 4096) ?? "",
|
|
1055
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
1056
|
+
bot: {
|
|
1057
|
+
name: optionalString(bot.name, 100) ?? "\u9489\u9489\u673A\u5668\u4EBA",
|
|
1058
|
+
clientIdMasked: optionalString(bot.clientIdMasked, 140) ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58"
|
|
1059
|
+
},
|
|
1060
|
+
health: {
|
|
1061
|
+
status: HEALTH_STATES.has(health.status) ? health.status : connected ? "healthy" : "offline",
|
|
1062
|
+
summary: optionalString(health.summary, 200) ?? (connected ? "\u9489\u9489 Stream \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
|
|
1063
|
+
lastCheckedAt: timestamp(health.lastCheckedAt),
|
|
1064
|
+
lastConnectedAt: timestamp(health.lastConnectedAt)
|
|
1065
|
+
},
|
|
1066
|
+
stats: {
|
|
1067
|
+
messagesReceived: nonNegativeInteger(stats.messagesReceived),
|
|
1068
|
+
messagesReplied: nonNegativeInteger(stats.messagesReplied)
|
|
1069
|
+
},
|
|
1070
|
+
error: normalizeError(value.error, "DINGTALK_ACCOUNT_ERROR", "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA") ?? null
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
function normalizeSnapshot(value) {
|
|
1074
|
+
const source = isRecord(value?.snapshot) ? value.snapshot : value;
|
|
1075
|
+
if (!isRecord(source) || !Array.isArray(source.bots)) {
|
|
1076
|
+
throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868");
|
|
1077
|
+
}
|
|
1078
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1079
|
+
const bots = source.bots.map(normalizeBot).filter((bot) => {
|
|
1080
|
+
if (!bot || seen.has(bot.botId)) return false;
|
|
1081
|
+
seen.add(bot.botId);
|
|
1082
|
+
return true;
|
|
1083
|
+
});
|
|
1084
|
+
return {
|
|
1085
|
+
schemaVersion: Number.isSafeInteger(source.schemaVersion) ? source.schemaVersion : 1,
|
|
1086
|
+
revision: nonNegativeInteger(source.revision),
|
|
1087
|
+
state: SNAPSHOT_STATES.has(source.state) ? source.state : "offline",
|
|
1088
|
+
bots,
|
|
1089
|
+
totals: {
|
|
1090
|
+
configured: bots.length,
|
|
1091
|
+
connected: bots.filter((bot) => bot.connected).length
|
|
1092
|
+
},
|
|
1093
|
+
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
1094
|
+
testMessage: normalizeTestMessage(source.testMessage),
|
|
1095
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog)
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
function connectionTestFeedback(result) {
|
|
1099
|
+
if (result?.sent === true) return "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
|
|
1100
|
+
if (result?.code === "test-target-unavailable") {
|
|
1101
|
+
return "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002\u673A\u5668\u4EBA\u5C1A\u672A\u6536\u5230\u53EF\u7528\u4E8E\u6D4B\u8BD5\u7684\u79C1\u804A\u6D88\u606F\u3002";
|
|
1102
|
+
}
|
|
1103
|
+
return result ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
1104
|
+
}
|
|
1105
|
+
function presentError(error) {
|
|
1106
|
+
return {
|
|
1107
|
+
code: safeErrorCode(error?.code, "DINGTALK_ERROR"),
|
|
1108
|
+
message: sanitizeMessage(error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function formatRemaining(milliseconds) {
|
|
1112
|
+
const seconds = Math.max(0, Math.ceil(Number(milliseconds) / 1e3) || 0);
|
|
1113
|
+
return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// plugin-src/client/channels/dingtalk/index.js
|
|
1117
|
+
var React8 = __toESM(require("react"), 1);
|
|
1118
|
+
|
|
1008
1119
|
// plugin-src/client/credential-binding.js
|
|
1120
|
+
var React4 = __toESM(require("react"), 1);
|
|
1009
1121
|
function ActionIcon({ children }) {
|
|
1010
1122
|
return h2("svg", {
|
|
1011
1123
|
className: "dim-actionIcon",
|
|
@@ -1065,9 +1177,9 @@ function CredentialBindingPanel({
|
|
|
1065
1177
|
onSubmit,
|
|
1066
1178
|
onCancel
|
|
1067
1179
|
}) {
|
|
1068
|
-
const [identity, setIdentity] =
|
|
1069
|
-
const [secret, setSecret] =
|
|
1070
|
-
const headingId =
|
|
1180
|
+
const [identity, setIdentity] = React4.useState("");
|
|
1181
|
+
const [secret, setSecret] = React4.useState("");
|
|
1182
|
+
const headingId = React4.useId();
|
|
1071
1183
|
const hasIdentity = Boolean(identityLabel);
|
|
1072
1184
|
const submit = (event) => {
|
|
1073
1185
|
event.preventDefault();
|
|
@@ -1146,10 +1258,10 @@ function CredentialBindingPanel({
|
|
|
1146
1258
|
}
|
|
1147
1259
|
|
|
1148
1260
|
// plugin-src/client/workspace-editor.js
|
|
1149
|
-
var
|
|
1261
|
+
var React6 = __toESM(require("react"), 1);
|
|
1150
1262
|
|
|
1151
1263
|
// plugin-src/client/workspace-directory-picker.js
|
|
1152
|
-
var
|
|
1264
|
+
var React5 = __toESM(require("react"), 1);
|
|
1153
1265
|
var import_react_dom = require("react-dom");
|
|
1154
1266
|
function pickerErrorCode(error) {
|
|
1155
1267
|
return error?.rpcError?.code ?? error?.code;
|
|
@@ -1161,7 +1273,7 @@ function pickerErrorMessage(error) {
|
|
|
1161
1273
|
return error?.rpcError?.message ?? error?.message ?? "\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002";
|
|
1162
1274
|
}
|
|
1163
1275
|
function FolderIcon() {
|
|
1164
|
-
return
|
|
1276
|
+
return React5.createElement(
|
|
1165
1277
|
"svg",
|
|
1166
1278
|
{
|
|
1167
1279
|
viewBox: "0 0 24 24",
|
|
@@ -1172,11 +1284,11 @@ function FolderIcon() {
|
|
|
1172
1284
|
strokeLinejoin: "round",
|
|
1173
1285
|
"aria-hidden": "true"
|
|
1174
1286
|
},
|
|
1175
|
-
|
|
1287
|
+
React5.createElement("path", { d: "M3.5 7.25A2.25 2.25 0 0 1 5.75 5h4.1l1.8 2h6.6a2.25 2.25 0 0 1 2.25 2.25v7A2.75 2.75 0 0 1 17.75 19h-12A2.25 2.25 0 0 1 3.5 16.75v-9.5Z" })
|
|
1176
1288
|
);
|
|
1177
1289
|
}
|
|
1178
1290
|
function ChevronIcon() {
|
|
1179
|
-
return
|
|
1291
|
+
return React5.createElement("svg", {
|
|
1180
1292
|
viewBox: "0 0 20 20",
|
|
1181
1293
|
fill: "none",
|
|
1182
1294
|
stroke: "currentColor",
|
|
@@ -1184,7 +1296,7 @@ function ChevronIcon() {
|
|
|
1184
1296
|
strokeLinecap: "round",
|
|
1185
1297
|
strokeLinejoin: "round",
|
|
1186
1298
|
"aria-hidden": "true"
|
|
1187
|
-
},
|
|
1299
|
+
}, React5.createElement("path", { d: "m7.5 4.5 5 5.5-5 5.5" }));
|
|
1188
1300
|
}
|
|
1189
1301
|
function displayCrumbs(listing) {
|
|
1190
1302
|
const homeIndex = listing.crumbs.findIndex((crumb) => crumb.path === listing.home);
|
|
@@ -1200,25 +1312,25 @@ function WorkspaceDirectoryPicker({
|
|
|
1200
1312
|
onPicked,
|
|
1201
1313
|
onCancel
|
|
1202
1314
|
}) {
|
|
1203
|
-
const [listing, setListing] =
|
|
1204
|
-
const [loading, setLoading] =
|
|
1205
|
-
const [error, setError] =
|
|
1206
|
-
const [showHidden, setShowHidden] =
|
|
1207
|
-
const [retryKey, setRetryKey] =
|
|
1208
|
-
const requestRef =
|
|
1209
|
-
const controllerRef =
|
|
1210
|
-
const dialogRef =
|
|
1211
|
-
const bodyRef =
|
|
1212
|
-
const titleId =
|
|
1213
|
-
const noticeId =
|
|
1214
|
-
const initialPathRef =
|
|
1215
|
-
const onPickedRef =
|
|
1216
|
-
const onCancelRef =
|
|
1217
|
-
const busyRef =
|
|
1315
|
+
const [listing, setListing] = React5.useState(null);
|
|
1316
|
+
const [loading, setLoading] = React5.useState(false);
|
|
1317
|
+
const [error, setError] = React5.useState(null);
|
|
1318
|
+
const [showHidden, setShowHidden] = React5.useState(false);
|
|
1319
|
+
const [retryKey, setRetryKey] = React5.useState(0);
|
|
1320
|
+
const requestRef = React5.useRef(0);
|
|
1321
|
+
const controllerRef = React5.useRef(null);
|
|
1322
|
+
const dialogRef = React5.useRef(null);
|
|
1323
|
+
const bodyRef = React5.useRef(null);
|
|
1324
|
+
const titleId = React5.useId();
|
|
1325
|
+
const noticeId = React5.useId();
|
|
1326
|
+
const initialPathRef = React5.useRef(startPath);
|
|
1327
|
+
const onPickedRef = React5.useRef(onPicked);
|
|
1328
|
+
const onCancelRef = React5.useRef(onCancel);
|
|
1329
|
+
const busyRef = React5.useRef(busy);
|
|
1218
1330
|
onPickedRef.current = onPicked;
|
|
1219
1331
|
onCancelRef.current = onCancel;
|
|
1220
1332
|
busyRef.current = busy;
|
|
1221
|
-
const loadDirectory =
|
|
1333
|
+
const loadDirectory = React5.useCallback(async (path, { reportError = true } = {}) => {
|
|
1222
1334
|
const request = requestRef.current + 1;
|
|
1223
1335
|
requestRef.current = request;
|
|
1224
1336
|
controllerRef.current?.abort();
|
|
@@ -1241,7 +1353,7 @@ function WorkspaceDirectoryPicker({
|
|
|
1241
1353
|
if (request === requestRef.current) setLoading(false);
|
|
1242
1354
|
}
|
|
1243
1355
|
}, [picker]);
|
|
1244
|
-
|
|
1356
|
+
React5.useEffect(() => {
|
|
1245
1357
|
if (!open) return void 0;
|
|
1246
1358
|
let active = true;
|
|
1247
1359
|
setListing(null);
|
|
@@ -1319,10 +1431,10 @@ function WorkspaceDirectoryPicker({
|
|
|
1319
1431
|
"nav",
|
|
1320
1432
|
{ className: "dim-directoryCrumbs", "aria-label": "\u5F53\u524D\u76EE\u5F55" },
|
|
1321
1433
|
crumbs.map((crumb, index) => h2(
|
|
1322
|
-
|
|
1434
|
+
React5.Fragment,
|
|
1323
1435
|
{ key: crumb.path },
|
|
1324
1436
|
index > 0 ? h2("span", { className: "dim-directoryCrumbSeparator", "aria-hidden": "true" }, "\u203A") : null,
|
|
1325
|
-
|
|
1437
|
+
React5.createElement("button", {
|
|
1326
1438
|
type: "button",
|
|
1327
1439
|
title: crumb.path,
|
|
1328
1440
|
disabled: loading || busy,
|
|
@@ -1343,7 +1455,7 @@ function WorkspaceDirectoryPicker({
|
|
|
1343
1455
|
) : listing ? entries.length > 0 ? h2("ul", { className: "dim-directoryList" }, entries.map((entry) => h2(
|
|
1344
1456
|
"li",
|
|
1345
1457
|
{ key: entry.path },
|
|
1346
|
-
|
|
1458
|
+
React5.createElement(
|
|
1347
1459
|
"button",
|
|
1348
1460
|
{
|
|
1349
1461
|
type: "button",
|
|
@@ -1352,7 +1464,7 @@ function WorkspaceDirectoryPicker({
|
|
|
1352
1464
|
onClick: () => void loadDirectory(entry.path)
|
|
1353
1465
|
},
|
|
1354
1466
|
h2("span", { className: "dim-directoryFolder" }, h2(FolderIcon)),
|
|
1355
|
-
|
|
1467
|
+
React5.createElement("span", { className: "dim-directoryName" }, entry.name),
|
|
1356
1468
|
h2("span", { className: "dim-directoryChevron" }, h2(ChevronIcon))
|
|
1357
1469
|
)
|
|
1358
1470
|
))) : h2(
|
|
@@ -1405,21 +1517,21 @@ function WorkspaceDirectoryPicker({
|
|
|
1405
1517
|
}
|
|
1406
1518
|
|
|
1407
1519
|
// plugin-src/client/workspace-editor.js
|
|
1408
|
-
var WorkspaceDirectoryPickerContext =
|
|
1520
|
+
var WorkspaceDirectoryPickerContext = React6.createContext(null);
|
|
1409
1521
|
function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave }) {
|
|
1410
|
-
const sharedDirectoryPicker =
|
|
1522
|
+
const sharedDirectoryPicker = React6.useContext(WorkspaceDirectoryPickerContext);
|
|
1411
1523
|
const activeDirectoryPicker = directoryPicker ?? sharedDirectoryPicker;
|
|
1412
|
-
const [open, setOpen] =
|
|
1413
|
-
const [saving, setSaving] =
|
|
1414
|
-
const [error, setError] =
|
|
1415
|
-
const editButtonRef =
|
|
1416
|
-
const savingRef =
|
|
1417
|
-
const close =
|
|
1524
|
+
const [open, setOpen] = React6.useState(false);
|
|
1525
|
+
const [saving, setSaving] = React6.useState(false);
|
|
1526
|
+
const [error, setError] = React6.useState(null);
|
|
1527
|
+
const editButtonRef = React6.useRef(null);
|
|
1528
|
+
const savingRef = React6.useRef(false);
|
|
1529
|
+
const close = React6.useCallback(() => {
|
|
1418
1530
|
setOpen(false);
|
|
1419
1531
|
setError(null);
|
|
1420
1532
|
queueMicrotask(() => editButtonRef.current?.focus?.());
|
|
1421
1533
|
}, []);
|
|
1422
|
-
const pick =
|
|
1534
|
+
const pick = React6.useCallback(async (value) => {
|
|
1423
1535
|
if (!value || savingRef.current || disabled) return;
|
|
1424
1536
|
if (value === workspace) {
|
|
1425
1537
|
close();
|
|
@@ -1456,7 +1568,7 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
|
|
|
1456
1568
|
disabled: disabled || !activeDirectoryPicker
|
|
1457
1569
|
}, "\u9009\u62E9\u76EE\u5F55")
|
|
1458
1570
|
),
|
|
1459
|
-
workspace ?
|
|
1571
|
+
workspace ? React6.createElement("code", {
|
|
1460
1572
|
className: "dim-workspacePath",
|
|
1461
1573
|
title: workspace
|
|
1462
1574
|
}, workspace) : h2("code", { className: "dim-workspacePath" }, "\u672A\u8BBE\u7F6E"),
|
|
@@ -1473,10 +1585,10 @@ function WorkspaceEditor({ workspace, directoryPicker, disabled = false, onSave
|
|
|
1473
1585
|
}
|
|
1474
1586
|
|
|
1475
1587
|
// plugin-src/client/workspace-snapshot-fence.js
|
|
1476
|
-
var
|
|
1588
|
+
var React7 = __toESM(require("react"), 1);
|
|
1477
1589
|
function useWorkspaceSnapshotFence() {
|
|
1478
|
-
const state =
|
|
1479
|
-
return
|
|
1590
|
+
const state = React7.useRef({ version: 0, pendingMutations: 0 });
|
|
1591
|
+
return React7.useMemo(() => Object.freeze({
|
|
1480
1592
|
beginStatus() {
|
|
1481
1593
|
return state.current.pendingMutations === 0 ? state.current.version : null;
|
|
1482
1594
|
},
|
|
@@ -1656,7 +1768,7 @@ function DingtalkIcon({ size = 28 }) {
|
|
|
1656
1768
|
d: "M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498"
|
|
1657
1769
|
}));
|
|
1658
1770
|
}
|
|
1659
|
-
var Button =
|
|
1771
|
+
var Button = React8.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
1660
1772
|
return h2("button", {
|
|
1661
1773
|
...props,
|
|
1662
1774
|
ref,
|
|
@@ -1752,13 +1864,13 @@ function EmptyView({ busy, onStart }) {
|
|
|
1752
1864
|
);
|
|
1753
1865
|
}
|
|
1754
1866
|
function QrPanel({ provision, now, busy, onRefresh, onCancel }) {
|
|
1755
|
-
const [imageFailed, setImageFailed] =
|
|
1867
|
+
const [imageFailed, setImageFailed] = React8.useState(false);
|
|
1756
1868
|
const source = safeQrSource(provision.qrCodeDataUrl);
|
|
1757
1869
|
const remaining = Math.max(0, provision.expiresAt - now);
|
|
1758
1870
|
const expired = remaining === 0 || provision.status === "expired";
|
|
1759
1871
|
const duration = Math.max(1, provision.durationMs ?? 10 * 6e4);
|
|
1760
1872
|
const progress = Math.round(Math.min(1, remaining / duration) * 100);
|
|
1761
|
-
|
|
1873
|
+
React8.useEffect(() => setImageFailed(false), [source]);
|
|
1762
1874
|
return h2(
|
|
1763
1875
|
"div",
|
|
1764
1876
|
{ className: "ddt-card dim-surfaceCard" },
|
|
@@ -1875,8 +1987,8 @@ function checkedTime(value) {
|
|
|
1875
1987
|
}
|
|
1876
1988
|
}
|
|
1877
1989
|
function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
|
|
1878
|
-
const cancelRef =
|
|
1879
|
-
|
|
1990
|
+
const cancelRef = React8.useRef(null);
|
|
1991
|
+
React8.useEffect(() => cancelRef.current?.focus(), []);
|
|
1880
1992
|
return h2(
|
|
1881
1993
|
"div",
|
|
1882
1994
|
{
|
|
@@ -1908,6 +2020,7 @@ function AccountCard({
|
|
|
1908
2020
|
removing,
|
|
1909
2021
|
onReconnect,
|
|
1910
2022
|
onWorkspaceSave,
|
|
2023
|
+
onAgentPresetSave,
|
|
1911
2024
|
onRequestRemove,
|
|
1912
2025
|
onConfirmRemove,
|
|
1913
2026
|
onCancelRemove
|
|
@@ -1964,6 +2077,11 @@ function AccountCard({
|
|
|
1964
2077
|
disabled: Boolean(busy),
|
|
1965
2078
|
onSave: onWorkspaceSave
|
|
1966
2079
|
}),
|
|
2080
|
+
h2(AgentPresetEditor, {
|
|
2081
|
+
agentPreset: account.agentPreset,
|
|
2082
|
+
disabled: Boolean(busy),
|
|
2083
|
+
onSave: onAgentPresetSave
|
|
2084
|
+
}),
|
|
1967
2085
|
h2(
|
|
1968
2086
|
"div",
|
|
1969
2087
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
@@ -2015,6 +2133,7 @@ function AccountList(props) {
|
|
|
2015
2133
|
removing: props.removeTarget === account.botId,
|
|
2016
2134
|
onReconnect: () => props.onReconnect(account),
|
|
2017
2135
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
2136
|
+
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
|
|
2018
2137
|
onRequestRemove: () => props.onRequestRemove(account),
|
|
2019
2138
|
onConfirmRemove: () => props.onConfirmRemove(account),
|
|
2020
2139
|
onCancelRemove: props.onCancelRemove
|
|
@@ -2024,29 +2143,30 @@ function AccountList(props) {
|
|
|
2024
2143
|
}
|
|
2025
2144
|
var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 });
|
|
2026
2145
|
function DingtalkSettingsTab({ rpcCall }) {
|
|
2027
|
-
const [model, setModel] =
|
|
2146
|
+
const [model, setModel] = React8.useState({
|
|
2028
2147
|
phase: "loading",
|
|
2029
2148
|
bots: [],
|
|
2030
2149
|
totals: EMPTY_TOTALS,
|
|
2031
2150
|
revision: 0,
|
|
2032
|
-
error: null
|
|
2151
|
+
error: null,
|
|
2152
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
2033
2153
|
});
|
|
2034
|
-
const [provision, setProvision] =
|
|
2035
|
-
const [busy, setBusy] =
|
|
2036
|
-
const [busyByBot, setBusyByBot] =
|
|
2037
|
-
const [feedbackByBot, setFeedbackByBot] =
|
|
2038
|
-
const [removeTarget, setRemoveTarget] =
|
|
2039
|
-
const [credentialOpen, setCredentialOpen] =
|
|
2040
|
-
const [credentialError, setCredentialError] =
|
|
2041
|
-
const [notice, setNotice] =
|
|
2042
|
-
const [now, setNow] =
|
|
2043
|
-
const addButtonRef =
|
|
2044
|
-
const mountedRef =
|
|
2045
|
-
const statusRequestRef =
|
|
2154
|
+
const [provision, setProvision] = React8.useState(null);
|
|
2155
|
+
const [busy, setBusy] = React8.useState(false);
|
|
2156
|
+
const [busyByBot, setBusyByBot] = React8.useState({});
|
|
2157
|
+
const [feedbackByBot, setFeedbackByBot] = React8.useState({});
|
|
2158
|
+
const [removeTarget, setRemoveTarget] = React8.useState(null);
|
|
2159
|
+
const [credentialOpen, setCredentialOpen] = React8.useState(false);
|
|
2160
|
+
const [credentialError, setCredentialError] = React8.useState(null);
|
|
2161
|
+
const [notice, setNotice] = React8.useState("");
|
|
2162
|
+
const [now, setNow] = React8.useState(() => Date.now());
|
|
2163
|
+
const addButtonRef = React8.useRef(null);
|
|
2164
|
+
const mountedRef = React8.useRef(true);
|
|
2165
|
+
const statusRequestRef = React8.useRef(0);
|
|
2046
2166
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
2047
|
-
const noticeFrameRef =
|
|
2048
|
-
const focusFrameRef =
|
|
2049
|
-
|
|
2167
|
+
const noticeFrameRef = React8.useRef(null);
|
|
2168
|
+
const focusFrameRef = React8.useRef(null);
|
|
2169
|
+
React8.useEffect(() => {
|
|
2050
2170
|
mountedRef.current = true;
|
|
2051
2171
|
return () => {
|
|
2052
2172
|
mountedRef.current = false;
|
|
@@ -2061,8 +2181,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2061
2181
|
}
|
|
2062
2182
|
};
|
|
2063
2183
|
}, []);
|
|
2064
|
-
|
|
2065
|
-
const announce =
|
|
2184
|
+
React8.useEffect(() => installDingtalkStyles(), []);
|
|
2185
|
+
const announce = React8.useCallback((message) => {
|
|
2066
2186
|
if (!mountedRef.current) return;
|
|
2067
2187
|
if (noticeFrameRef.current !== null) {
|
|
2068
2188
|
window.cancelAnimationFrame(noticeFrameRef.current);
|
|
@@ -2076,7 +2196,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2076
2196
|
});
|
|
2077
2197
|
}
|
|
2078
2198
|
}, []);
|
|
2079
|
-
const discardStaleFeedback =
|
|
2199
|
+
const discardStaleFeedback = React8.useCallback((snapshot) => {
|
|
2080
2200
|
const botsById = new Map(snapshot.bots.map((bot) => [bot.botId, bot]));
|
|
2081
2201
|
setFeedbackByBot((current) => {
|
|
2082
2202
|
let changed = false;
|
|
@@ -2091,7 +2211,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2091
2211
|
return changed ? next : current;
|
|
2092
2212
|
});
|
|
2093
2213
|
}, []);
|
|
2094
|
-
const focusAddButton =
|
|
2214
|
+
const focusAddButton = React8.useCallback(() => {
|
|
2095
2215
|
if (!mountedRef.current) return;
|
|
2096
2216
|
if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
|
|
2097
2217
|
focusFrameRef.current = window.requestAnimationFrame(() => {
|
|
@@ -2099,11 +2219,11 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2099
2219
|
if (mountedRef.current) addButtonRef.current?.focus();
|
|
2100
2220
|
});
|
|
2101
2221
|
}, []);
|
|
2102
|
-
const invoke =
|
|
2222
|
+
const invoke = React8.useCallback(async (endpoint, payload = {}, signal) => {
|
|
2103
2223
|
if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
|
|
2104
2224
|
return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
|
|
2105
2225
|
}, [rpcCall]);
|
|
2106
|
-
const loadStatus =
|
|
2226
|
+
const loadStatus = React8.useCallback(async ({
|
|
2107
2227
|
signal,
|
|
2108
2228
|
silent = false,
|
|
2109
2229
|
restoreProvisioning = false
|
|
@@ -2125,7 +2245,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2125
2245
|
bots: snapshot.bots,
|
|
2126
2246
|
totals: snapshot.totals,
|
|
2127
2247
|
revision: snapshot.revision,
|
|
2128
|
-
error: null
|
|
2248
|
+
error: null,
|
|
2249
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2129
2250
|
});
|
|
2130
2251
|
discardStaleFeedback(snapshot);
|
|
2131
2252
|
if (restoreProvisioning && snapshot.provisioning) {
|
|
@@ -2146,12 +2267,12 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2146
2267
|
return void 0;
|
|
2147
2268
|
}
|
|
2148
2269
|
}, [discardStaleFeedback, invoke, workspaceFence]);
|
|
2149
|
-
|
|
2270
|
+
React8.useEffect(() => {
|
|
2150
2271
|
const controller = new AbortController();
|
|
2151
2272
|
void loadStatus({ signal: controller.signal, restoreProvisioning: true });
|
|
2152
2273
|
return () => controller.abort();
|
|
2153
2274
|
}, [loadStatus]);
|
|
2154
|
-
|
|
2275
|
+
React8.useEffect(() => {
|
|
2155
2276
|
if (model.phase !== "ready") return void 0;
|
|
2156
2277
|
const controller = new AbortController();
|
|
2157
2278
|
let running = false;
|
|
@@ -2170,14 +2291,14 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2170
2291
|
window.clearInterval(timer);
|
|
2171
2292
|
};
|
|
2172
2293
|
}, [loadStatus, model.phase]);
|
|
2173
|
-
|
|
2294
|
+
React8.useEffect(() => {
|
|
2174
2295
|
if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
|
|
2175
2296
|
const timer = window.setInterval(() => {
|
|
2176
2297
|
if (mountedRef.current) setNow(Date.now());
|
|
2177
2298
|
}, 1e3);
|
|
2178
2299
|
return () => window.clearInterval(timer);
|
|
2179
2300
|
}, [provision?.attemptId, provision?.status]);
|
|
2180
|
-
const startProvisioning =
|
|
2301
|
+
const startProvisioning = React8.useCallback(async ({ replace = false } = {}) => {
|
|
2181
2302
|
if (!mountedRef.current) return;
|
|
2182
2303
|
setCredentialOpen(false);
|
|
2183
2304
|
setCredentialError(null);
|
|
@@ -2215,7 +2336,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2215
2336
|
if (mountedRef.current) setBusy(false);
|
|
2216
2337
|
}
|
|
2217
2338
|
}, [announce, invoke, provision?.attemptId]);
|
|
2218
|
-
const bindCredentials =
|
|
2339
|
+
const bindCredentials = React8.useCallback(async ({ identity, secret }) => {
|
|
2219
2340
|
if (!mountedRef.current) return;
|
|
2220
2341
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2221
2342
|
setBusy(true);
|
|
@@ -2232,7 +2353,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2232
2353
|
bots: snapshot.bots,
|
|
2233
2354
|
totals: snapshot.totals,
|
|
2234
2355
|
revision: snapshot.revision,
|
|
2235
|
-
error: null
|
|
2356
|
+
error: null,
|
|
2357
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2236
2358
|
});
|
|
2237
2359
|
discardStaleFeedback(snapshot);
|
|
2238
2360
|
}
|
|
@@ -2246,7 +2368,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2246
2368
|
if (mountedRef.current) setBusy(false);
|
|
2247
2369
|
}
|
|
2248
2370
|
}, [announce, discardStaleFeedback, invoke, loadStatus, workspaceFence]);
|
|
2249
|
-
const cancelProvisioning =
|
|
2371
|
+
const cancelProvisioning = React8.useCallback(async () => {
|
|
2250
2372
|
if (!mountedRef.current) return;
|
|
2251
2373
|
setBusy(true);
|
|
2252
2374
|
try {
|
|
@@ -2264,7 +2386,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2264
2386
|
if (mountedRef.current) setBusy(false);
|
|
2265
2387
|
}
|
|
2266
2388
|
}, [announce, focusAddButton, invoke, provision?.attemptId, provision?.status]);
|
|
2267
|
-
|
|
2389
|
+
React8.useEffect(() => {
|
|
2268
2390
|
const attemptId = provision?.attemptId;
|
|
2269
2391
|
if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0;
|
|
2270
2392
|
const controller = new AbortController();
|
|
@@ -2323,7 +2445,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2323
2445
|
timer = null;
|
|
2324
2446
|
};
|
|
2325
2447
|
}, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
|
|
2326
|
-
const setBotBusy =
|
|
2448
|
+
const setBotBusy = React8.useCallback((botId, operation) => {
|
|
2327
2449
|
if (!mountedRef.current) return;
|
|
2328
2450
|
setBusyByBot((current) => {
|
|
2329
2451
|
const next = { ...current };
|
|
@@ -2332,7 +2454,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2332
2454
|
return next;
|
|
2333
2455
|
});
|
|
2334
2456
|
}, []);
|
|
2335
|
-
const runBotAction =
|
|
2457
|
+
const runBotAction = React8.useCallback(async ({ account, operation, endpoint, payload, success }) => {
|
|
2336
2458
|
if (!mountedRef.current) return void 0;
|
|
2337
2459
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2338
2460
|
setBotBusy(account.botId, operation);
|
|
@@ -2352,7 +2474,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2352
2474
|
bots: snapshot.bots,
|
|
2353
2475
|
totals: snapshot.totals,
|
|
2354
2476
|
revision: snapshot.revision,
|
|
2355
|
-
error: null
|
|
2477
|
+
error: null,
|
|
2478
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2356
2479
|
});
|
|
2357
2480
|
discardStaleFeedback(snapshot);
|
|
2358
2481
|
}
|
|
@@ -2385,7 +2508,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2385
2508
|
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
2386
2509
|
}
|
|
2387
2510
|
}, [announce, discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2388
|
-
const reconnect =
|
|
2511
|
+
const reconnect = React8.useCallback((account) => runBotAction({
|
|
2389
2512
|
account,
|
|
2390
2513
|
operation: "reconnect",
|
|
2391
2514
|
endpoint: DINGTALK_ENDPOINTS.reconnectBot,
|
|
@@ -2396,7 +2519,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2396
2519
|
return connectionTestFeedback(snapshot.testMessage) ?? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
|
|
2397
2520
|
}
|
|
2398
2521
|
}), [runBotAction]);
|
|
2399
|
-
const saveWorkspace =
|
|
2522
|
+
const saveWorkspace = React8.useCallback(async (account, workspace) => {
|
|
2400
2523
|
const workspaceVersion = workspaceFence.beginMutation();
|
|
2401
2524
|
setBotBusy(account.botId, "workspace");
|
|
2402
2525
|
try {
|
|
@@ -2410,7 +2533,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2410
2533
|
bots: snapshot.bots,
|
|
2411
2534
|
totals: snapshot.totals,
|
|
2412
2535
|
revision: snapshot.revision,
|
|
2413
|
-
error: null
|
|
2536
|
+
error: null,
|
|
2537
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2414
2538
|
});
|
|
2415
2539
|
discardStaleFeedback(snapshot);
|
|
2416
2540
|
}
|
|
@@ -2420,7 +2544,32 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2420
2544
|
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
2421
2545
|
}
|
|
2422
2546
|
}, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2423
|
-
const
|
|
2547
|
+
const saveAgentPreset = React8.useCallback(async (account, agentPreset) => {
|
|
2548
|
+
const snapshotVersion = workspaceFence.beginMutation();
|
|
2549
|
+
setBotBusy(account.botId, "preset");
|
|
2550
|
+
try {
|
|
2551
|
+
const snapshot = normalizeSnapshot(await invoke(
|
|
2552
|
+
DINGTALK_ENDPOINTS.setAgentPreset,
|
|
2553
|
+
{ botId: account.botId, agentPreset }
|
|
2554
|
+
));
|
|
2555
|
+
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
2556
|
+
setModel({
|
|
2557
|
+
phase: "ready",
|
|
2558
|
+
bots: snapshot.bots,
|
|
2559
|
+
totals: snapshot.totals,
|
|
2560
|
+
revision: snapshot.revision,
|
|
2561
|
+
error: null,
|
|
2562
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2563
|
+
});
|
|
2564
|
+
discardStaleFeedback(snapshot);
|
|
2565
|
+
}
|
|
2566
|
+
} finally {
|
|
2567
|
+
const shouldRefresh = workspaceFence.endMutation();
|
|
2568
|
+
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
2569
|
+
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
2570
|
+
}
|
|
2571
|
+
}, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2572
|
+
const remove = React8.useCallback(async (account) => {
|
|
2424
2573
|
const snapshot = await runBotAction({
|
|
2425
2574
|
account,
|
|
2426
2575
|
operation: "delete",
|
|
@@ -2474,7 +2623,9 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2474
2623
|
setCredentialError(null);
|
|
2475
2624
|
}
|
|
2476
2625
|
}) : null;
|
|
2477
|
-
return h2(
|
|
2626
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
2627
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2628
|
+
}, h2(
|
|
2478
2629
|
"section",
|
|
2479
2630
|
{ className: "ddt-page dim-channelPage", "aria-label": "\u9489\u9489\u8BBE\u7F6E" },
|
|
2480
2631
|
h2(Heading, {
|
|
@@ -2502,7 +2653,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2502
2653
|
h2(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
|
|
2503
2654
|
)
|
|
2504
2655
|
) : h2(
|
|
2505
|
-
|
|
2656
|
+
React8.Fragment,
|
|
2506
2657
|
null,
|
|
2507
2658
|
credentialView,
|
|
2508
2659
|
provisionView,
|
|
@@ -2514,12 +2665,13 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2514
2665
|
removeTarget,
|
|
2515
2666
|
onReconnect: (account) => void reconnect(account),
|
|
2516
2667
|
onWorkspaceSave: saveWorkspace,
|
|
2668
|
+
onAgentPresetSave: saveAgentPreset,
|
|
2517
2669
|
onRequestRemove: (account) => setRemoveTarget(account.botId),
|
|
2518
2670
|
onConfirmRemove: (account) => void remove(account),
|
|
2519
2671
|
onCancelRemove: () => setRemoveTarget(null)
|
|
2520
2672
|
}) : null
|
|
2521
2673
|
)
|
|
2522
|
-
);
|
|
2674
|
+
));
|
|
2523
2675
|
}
|
|
2524
2676
|
|
|
2525
2677
|
// plugin-src/client/channels/shared/token-api.js
|
|
@@ -2544,7 +2696,8 @@ var TOKEN_BOT_ENDPOINTS = Object.freeze({
|
|
|
2544
2696
|
bindCredentials: "bot.bind-credentials",
|
|
2545
2697
|
reconnectBot: "bot.reconnect",
|
|
2546
2698
|
deleteBot: "bot.delete",
|
|
2547
|
-
setWorkspace: "bot.workspace.set"
|
|
2699
|
+
setWorkspace: "bot.workspace.set",
|
|
2700
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
2548
2701
|
});
|
|
2549
2702
|
function createTokenChannelApi(channel4, connectionSummary, {
|
|
2550
2703
|
normalizeBotExtension = () => ({})
|
|
@@ -2570,6 +2723,7 @@ function createTokenChannelApi(channel4, connectionSummary, {
|
|
|
2570
2723
|
connected,
|
|
2571
2724
|
state: connected ? "connected" : state,
|
|
2572
2725
|
workspace: text(value.workspace, "", 4096),
|
|
2726
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
2573
2727
|
bot: {
|
|
2574
2728
|
name: text(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
|
|
2575
2729
|
username: text(value.bot?.username, "", 100),
|
|
@@ -2598,7 +2752,8 @@ function createTokenChannelApi(channel4, connectionSummary, {
|
|
|
2598
2752
|
return {
|
|
2599
2753
|
revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
|
|
2600
2754
|
bots,
|
|
2601
|
-
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length }
|
|
2755
|
+
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
2756
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog)
|
|
2602
2757
|
};
|
|
2603
2758
|
};
|
|
2604
2759
|
const presentError10 = (error) => ({
|
|
@@ -2617,8 +2772,8 @@ var normalizeSnapshot2 = api.normalizeSnapshot;
|
|
|
2617
2772
|
var presentError2 = api.presentError;
|
|
2618
2773
|
|
|
2619
2774
|
// plugin-src/client/channels/shared/token-channel.js
|
|
2620
|
-
var
|
|
2621
|
-
var Button3 =
|
|
2775
|
+
var React9 = __toESM(require("react"), 1);
|
|
2776
|
+
var Button3 = React9.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
2622
2777
|
return h2("button", {
|
|
2623
2778
|
...props,
|
|
2624
2779
|
ref,
|
|
@@ -2670,7 +2825,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2670
2825
|
AccountSettings = null,
|
|
2671
2826
|
accountSettingsEndpoint = null
|
|
2672
2827
|
} = definition;
|
|
2673
|
-
function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
2828
|
+
function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onAgentPresetSave, onAccountSettingsSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
2674
2829
|
const state = busy === "reconnect" ? "connecting" : account.state;
|
|
2675
2830
|
const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
|
|
2676
2831
|
const stateLabel2 = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
|
|
@@ -2728,6 +2883,11 @@ function createTokenChannelSettings(definition) {
|
|
|
2728
2883
|
disabled: Boolean(busy),
|
|
2729
2884
|
onSave: onWorkspaceSave
|
|
2730
2885
|
}),
|
|
2886
|
+
h2(AgentPresetEditor, {
|
|
2887
|
+
agentPreset: account.agentPreset,
|
|
2888
|
+
disabled: Boolean(busy),
|
|
2889
|
+
onSave: onAgentPresetSave
|
|
2890
|
+
}),
|
|
2731
2891
|
AccountSettings ? h2(AccountSettings, {
|
|
2732
2892
|
account,
|
|
2733
2893
|
busy: Boolean(busy),
|
|
@@ -2774,21 +2934,22 @@ function createTokenChannelSettings(definition) {
|
|
|
2774
2934
|
);
|
|
2775
2935
|
}
|
|
2776
2936
|
function SettingsTab({ rpcCall }) {
|
|
2777
|
-
const [model, setModel] =
|
|
2937
|
+
const [model, setModel] = React9.useState({
|
|
2778
2938
|
phase: "loading",
|
|
2779
2939
|
bots: [],
|
|
2780
2940
|
totals: { configured: 0, connected: 0 },
|
|
2781
|
-
error: null
|
|
2941
|
+
error: null,
|
|
2942
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
2782
2943
|
});
|
|
2783
|
-
const [credentialOpen, setCredentialOpen] =
|
|
2784
|
-
const [credentialError, setCredentialError] =
|
|
2785
|
-
const [busy, setBusy] =
|
|
2786
|
-
const [busyByBot, setBusyByBot] =
|
|
2787
|
-
const [testNoticeByBot, setTestNoticeByBot] =
|
|
2788
|
-
const [removeTarget, setRemoveTarget] =
|
|
2789
|
-
const mounted =
|
|
2944
|
+
const [credentialOpen, setCredentialOpen] = React9.useState(false);
|
|
2945
|
+
const [credentialError, setCredentialError] = React9.useState(null);
|
|
2946
|
+
const [busy, setBusy] = React9.useState(false);
|
|
2947
|
+
const [busyByBot, setBusyByBot] = React9.useState({});
|
|
2948
|
+
const [testNoticeByBot, setTestNoticeByBot] = React9.useState({});
|
|
2949
|
+
const [removeTarget, setRemoveTarget] = React9.useState(null);
|
|
2950
|
+
const mounted = React9.useRef(true);
|
|
2790
2951
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
2791
|
-
|
|
2952
|
+
React9.useEffect(() => {
|
|
2792
2953
|
const disposeDingtalk = installDingtalkStyles();
|
|
2793
2954
|
const disposeChannel = installStyles();
|
|
2794
2955
|
mounted.current = true;
|
|
@@ -2798,18 +2959,24 @@ function createTokenChannelSettings(definition) {
|
|
|
2798
2959
|
disposeDingtalk();
|
|
2799
2960
|
};
|
|
2800
2961
|
}, []);
|
|
2801
|
-
const invoke =
|
|
2962
|
+
const invoke = React9.useCallback(async (endpoint, payload = {}, signal) => {
|
|
2802
2963
|
if (typeof rpcCall !== "function") throw new TypeError(`${channel4} \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5`);
|
|
2803
2964
|
return api4.unwrapRpcResult(await rpcCall(endpoint, payload, signal));
|
|
2804
2965
|
}, [rpcCall]);
|
|
2805
|
-
const loadStatus =
|
|
2966
|
+
const loadStatus = React9.useCallback(async ({ signal, silent = false } = {}) => {
|
|
2806
2967
|
const workspaceVersion = workspaceFence.beginStatus();
|
|
2807
2968
|
if (workspaceVersion === null) return;
|
|
2808
2969
|
if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
|
|
2809
2970
|
try {
|
|
2810
2971
|
const snapshot = api4.normalizeSnapshot(await invoke(endpoints.status, {}, signal));
|
|
2811
2972
|
if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return;
|
|
2812
|
-
setModel({
|
|
2973
|
+
setModel({
|
|
2974
|
+
phase: "ready",
|
|
2975
|
+
bots: snapshot.bots,
|
|
2976
|
+
totals: snapshot.totals,
|
|
2977
|
+
error: null,
|
|
2978
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
2979
|
+
});
|
|
2813
2980
|
} catch (error) {
|
|
2814
2981
|
if (error?.name !== "AbortError" && mounted.current && !signal?.aborted && workspaceFence.canCommitStatus(workspaceVersion)) {
|
|
2815
2982
|
setModel((current) => ({
|
|
@@ -2820,12 +2987,12 @@ function createTokenChannelSettings(definition) {
|
|
|
2820
2987
|
}
|
|
2821
2988
|
}
|
|
2822
2989
|
}, [invoke, workspaceFence]);
|
|
2823
|
-
|
|
2990
|
+
React9.useEffect(() => {
|
|
2824
2991
|
const controller = new AbortController();
|
|
2825
2992
|
void loadStatus({ signal: controller.signal });
|
|
2826
2993
|
return () => controller.abort();
|
|
2827
2994
|
}, [loadStatus]);
|
|
2828
|
-
|
|
2995
|
+
React9.useEffect(() => {
|
|
2829
2996
|
if (model.phase !== "ready") return void 0;
|
|
2830
2997
|
const controller = new AbortController();
|
|
2831
2998
|
const timer = window.setInterval(
|
|
@@ -2837,7 +3004,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2837
3004
|
window.clearInterval(timer);
|
|
2838
3005
|
};
|
|
2839
3006
|
}, [loadStatus, model.phase]);
|
|
2840
|
-
const bindCredentials =
|
|
3007
|
+
const bindCredentials = React9.useCallback(async (values) => {
|
|
2841
3008
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2842
3009
|
setBusy(true);
|
|
2843
3010
|
setCredentialError(null);
|
|
@@ -2848,7 +3015,13 @@ function createTokenChannelSettings(definition) {
|
|
|
2848
3015
|
));
|
|
2849
3016
|
if (!mounted.current) return;
|
|
2850
3017
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
2851
|
-
setModel({
|
|
3018
|
+
setModel({
|
|
3019
|
+
phase: "ready",
|
|
3020
|
+
bots: snapshot.bots,
|
|
3021
|
+
totals: snapshot.totals,
|
|
3022
|
+
error: null,
|
|
3023
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
3024
|
+
});
|
|
2852
3025
|
}
|
|
2853
3026
|
setCredentialOpen(false);
|
|
2854
3027
|
} catch (error) {
|
|
@@ -2859,14 +3032,20 @@ function createTokenChannelSettings(definition) {
|
|
|
2859
3032
|
if (mounted.current) setBusy(false);
|
|
2860
3033
|
}
|
|
2861
3034
|
}, [invoke, loadStatus, workspaceFence]);
|
|
2862
|
-
const botAction =
|
|
3035
|
+
const botAction = React9.useCallback(async (account, operation, endpoint, payload) => {
|
|
2863
3036
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2864
3037
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
2865
3038
|
try {
|
|
2866
3039
|
const value = await invoke(endpoint, payload);
|
|
2867
3040
|
const snapshot = api4.normalizeSnapshot(value);
|
|
2868
3041
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
2869
|
-
setModel({
|
|
3042
|
+
setModel({
|
|
3043
|
+
phase: "ready",
|
|
3044
|
+
bots: snapshot.bots,
|
|
3045
|
+
totals: snapshot.totals,
|
|
3046
|
+
error: null,
|
|
3047
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
3048
|
+
});
|
|
2870
3049
|
}
|
|
2871
3050
|
if (mounted.current && operation === "reconnect") {
|
|
2872
3051
|
setTestNoticeByBot((current) => ({
|
|
@@ -2917,6 +3096,12 @@ function createTokenChannelSettings(definition) {
|
|
|
2917
3096
|
endpoints.setWorkspace,
|
|
2918
3097
|
{ botId: account.botId, workspace }
|
|
2919
3098
|
),
|
|
3099
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
3100
|
+
account,
|
|
3101
|
+
"preset",
|
|
3102
|
+
endpoints.setAgentPreset,
|
|
3103
|
+
{ botId: account.botId, agentPreset }
|
|
3104
|
+
),
|
|
2920
3105
|
onAccountSettingsSave: AccountSettings && accountSettingsEndpoint ? (payload) => botAction(
|
|
2921
3106
|
account,
|
|
2922
3107
|
"settings",
|
|
@@ -2934,7 +3119,9 @@ function createTokenChannelSettings(definition) {
|
|
|
2934
3119
|
}
|
|
2935
3120
|
}))))
|
|
2936
3121
|
) : null;
|
|
2937
|
-
return h2(
|
|
3122
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
3123
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
3124
|
+
}, h2(
|
|
2938
3125
|
"section",
|
|
2939
3126
|
{
|
|
2940
3127
|
className: `ddt-page ${pageClass} dim-channelPage`,
|
|
@@ -2982,7 +3169,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2982
3169
|
h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
|
|
2983
3170
|
)
|
|
2984
3171
|
) : h2(
|
|
2985
|
-
|
|
3172
|
+
React9.Fragment,
|
|
2986
3173
|
null,
|
|
2987
3174
|
credentialOpen ? CredentialPanel ? h2(CredentialPanel, {
|
|
2988
3175
|
busy,
|
|
@@ -3038,7 +3225,7 @@ function createTokenChannelSettings(definition) {
|
|
|
3038
3225
|
) : null,
|
|
3039
3226
|
botList
|
|
3040
3227
|
)
|
|
3041
|
-
);
|
|
3228
|
+
));
|
|
3042
3229
|
}
|
|
3043
3230
|
return { SettingsTab, AccountCard: AccountCard5 };
|
|
3044
3231
|
}
|
|
@@ -3083,7 +3270,7 @@ var DiscordSettingsTab = channel.SettingsTab;
|
|
|
3083
3270
|
var DiscordAccountCard = channel.AccountCard;
|
|
3084
3271
|
|
|
3085
3272
|
// plugin-src/client/channels/feishu/index.js
|
|
3086
|
-
var
|
|
3273
|
+
var React11 = __toESM(require("react"), 1);
|
|
3087
3274
|
|
|
3088
3275
|
// plugin-src/client/channels/feishu/api.js
|
|
3089
3276
|
var FEISHU_RPC_CHANNEL = "/feishu";
|
|
@@ -3098,6 +3285,7 @@ var FEISHU_ENDPOINTS = Object.freeze({
|
|
|
3098
3285
|
disconnectBot: "bot.disconnect",
|
|
3099
3286
|
deleteBot: "bot.delete",
|
|
3100
3287
|
setWorkspace: "bot.workspace.set",
|
|
3288
|
+
setAgentPreset: "bot.preset.set",
|
|
3101
3289
|
// Kept for rolling upgrades. The multi-bot UI never calls these endpoints.
|
|
3102
3290
|
testConnection: "connection.test",
|
|
3103
3291
|
disconnect: "connection.disconnect"
|
|
@@ -3231,6 +3419,7 @@ function normalizeBotConnection(value, fallbackBotId) {
|
|
|
3231
3419
|
connected,
|
|
3232
3420
|
configured: value.configured !== false,
|
|
3233
3421
|
workspace: optionalString2(value.workspace)?.slice(0, 4096) ?? "",
|
|
3422
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
3234
3423
|
bot: normalizeBot2(value.bot),
|
|
3235
3424
|
health: normalizeHealth(value.health, connected),
|
|
3236
3425
|
error: normalizeError2(value.error)
|
|
@@ -3271,7 +3460,8 @@ function normalizeBotsSnapshot(value) {
|
|
|
3271
3460
|
// make the UI claim that an unavailable bot is online.
|
|
3272
3461
|
totals: { configured, connected },
|
|
3273
3462
|
provisioning: value.provisioning ? normalizeProvisioning2(value.provisioning) : void 0,
|
|
3274
|
-
error: normalizeError2(value.error)
|
|
3463
|
+
error: normalizeError2(value.error),
|
|
3464
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog)
|
|
3275
3465
|
};
|
|
3276
3466
|
}
|
|
3277
3467
|
function normalizeConnectionSnapshot(value) {
|
|
@@ -3321,7 +3511,7 @@ function formatRemaining2(milliseconds) {
|
|
|
3321
3511
|
}
|
|
3322
3512
|
|
|
3323
3513
|
// plugin-src/client/lifecycle.js
|
|
3324
|
-
var
|
|
3514
|
+
var React10 = __toESM(require("react"), 1);
|
|
3325
3515
|
function createPollScheduler({ setTimeoutFn, clearTimeoutFn }) {
|
|
3326
3516
|
let disposed = false;
|
|
3327
3517
|
let timer;
|
|
@@ -3383,8 +3573,8 @@ function createAnimationFrameScheduler({ requestFrame, cancelFrame }) {
|
|
|
3383
3573
|
};
|
|
3384
3574
|
}
|
|
3385
3575
|
function useAnimationFrameScheduler() {
|
|
3386
|
-
const schedulerRef =
|
|
3387
|
-
|
|
3576
|
+
const schedulerRef = React10.useRef(null);
|
|
3577
|
+
React10.useEffect(() => {
|
|
3388
3578
|
const scheduler = createAnimationFrameScheduler({
|
|
3389
3579
|
requestFrame: (callback) => window.requestAnimationFrame(callback),
|
|
3390
3580
|
cancelFrame: (frame) => window.cancelAnimationFrame(frame)
|
|
@@ -3395,7 +3585,7 @@ function useAnimationFrameScheduler() {
|
|
|
3395
3585
|
if (schedulerRef.current === scheduler) schedulerRef.current = null;
|
|
3396
3586
|
};
|
|
3397
3587
|
}, []);
|
|
3398
|
-
return
|
|
3588
|
+
return React10.useCallback(
|
|
3399
3589
|
(callback, key) => schedulerRef.current?.schedule(callback, key) ?? false,
|
|
3400
3590
|
[]
|
|
3401
3591
|
);
|
|
@@ -3969,7 +4159,7 @@ function QrIcon({ size = 58 }) {
|
|
|
3969
4159
|
fill: "currentColor"
|
|
3970
4160
|
}));
|
|
3971
4161
|
}
|
|
3972
|
-
var Button5 =
|
|
4162
|
+
var Button5 = React11.forwardRef(function Button6({ children, kind = "secondary", size, icon, className = "", ...props }, ref) {
|
|
3973
4163
|
return h2("button", {
|
|
3974
4164
|
...props,
|
|
3975
4165
|
ref,
|
|
@@ -4086,7 +4276,7 @@ function safeQrSource2(value) {
|
|
|
4086
4276
|
return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0;
|
|
4087
4277
|
}
|
|
4088
4278
|
function QrPane({ provision, now, onRefresh, onCancel, busy }) {
|
|
4089
|
-
const [imageFailed, setImageFailed] =
|
|
4279
|
+
const [imageFailed, setImageFailed] = React11.useState(false);
|
|
4090
4280
|
const qrSource = safeQrSource2(provision.qrCodeDataUrl);
|
|
4091
4281
|
const href = safeVerificationHref(provision.verificationUrl);
|
|
4092
4282
|
const remaining = Math.max(0, provision.expiresAt - now);
|
|
@@ -4094,7 +4284,7 @@ function QrPane({ provision, now, onRefresh, onCancel, busy }) {
|
|
|
4094
4284
|
const progress = Math.min(1, remaining / Math.max(1, provision.durationMs ?? remaining));
|
|
4095
4285
|
const repairing = isCallbackRepair(provision);
|
|
4096
4286
|
const botName = provision.botName ?? "\u6B64\u673A\u5668\u4EBA";
|
|
4097
|
-
|
|
4287
|
+
React11.useEffect(() => setImageFailed(false), [qrSource]);
|
|
4098
4288
|
return h2(
|
|
4099
4289
|
"div",
|
|
4100
4290
|
{ className: "bxf-card bxf-provisionCard dim-surfaceCard" },
|
|
@@ -4255,11 +4445,11 @@ function connectionTestNotice2(value) {
|
|
|
4255
4445
|
return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
4256
4446
|
}
|
|
4257
4447
|
function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
|
|
4258
|
-
const cancelRef =
|
|
4448
|
+
const cancelRef = React11.useRef(null);
|
|
4259
4449
|
const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
4260
4450
|
const titleId = `bxf-remove-title-${idPart}`;
|
|
4261
4451
|
const descriptionId = `bxf-remove-description-${idPart}`;
|
|
4262
|
-
|
|
4452
|
+
React11.useEffect(() => cancelRef.current?.focus(), []);
|
|
4263
4453
|
return h2(
|
|
4264
4454
|
"div",
|
|
4265
4455
|
{
|
|
@@ -4302,6 +4492,7 @@ function BotCard({
|
|
|
4302
4492
|
onReconnect,
|
|
4303
4493
|
onRepairCallback,
|
|
4304
4494
|
onWorkspaceSave,
|
|
4495
|
+
onAgentPresetSave,
|
|
4305
4496
|
onRequestRemove,
|
|
4306
4497
|
onConfirmRemove,
|
|
4307
4498
|
onCancelRemove,
|
|
@@ -4371,6 +4562,11 @@ function BotCard({
|
|
|
4371
4562
|
disabled: Boolean(busy),
|
|
4372
4563
|
onSave: onWorkspaceSave
|
|
4373
4564
|
}),
|
|
4565
|
+
h2(AgentPresetEditor, {
|
|
4566
|
+
agentPreset: connection.agentPreset,
|
|
4567
|
+
disabled: Boolean(busy),
|
|
4568
|
+
onSave: onAgentPresetSave
|
|
4569
|
+
}),
|
|
4374
4570
|
h2(
|
|
4375
4571
|
"div",
|
|
4376
4572
|
{ className: "bxf-connectedFooter dim-cardFooter" },
|
|
@@ -4444,6 +4640,7 @@ function BotList(props) {
|
|
|
4444
4640
|
onReconnect: () => props.onReconnect(bot),
|
|
4445
4641
|
onRepairCallback: () => props.onRepairCallback(bot),
|
|
4446
4642
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(bot, workspace),
|
|
4643
|
+
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(bot, agentPreset),
|
|
4447
4644
|
onRequestRemove: () => props.onRequestRemove(bot),
|
|
4448
4645
|
onConfirmRemove: () => props.onConfirmRemove(bot),
|
|
4449
4646
|
onCancelRemove: props.onCancelRemove,
|
|
@@ -4501,53 +4698,55 @@ function mergeFeishuSnapshotState(current, snapshot, { restoreProvisioning = fal
|
|
|
4501
4698
|
totals: snapshot.totals,
|
|
4502
4699
|
provisioning,
|
|
4503
4700
|
pageError: null,
|
|
4504
|
-
statusError: null
|
|
4701
|
+
statusError: null,
|
|
4702
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog
|
|
4505
4703
|
};
|
|
4506
4704
|
}
|
|
4507
4705
|
function FeishuSettingsTab({ rpcCall }) {
|
|
4508
|
-
const [model, setModel] =
|
|
4706
|
+
const [model, setModel] = React11.useState({
|
|
4509
4707
|
phase: "loading",
|
|
4510
4708
|
revision: 0,
|
|
4511
4709
|
bots: [],
|
|
4512
4710
|
totals: EMPTY_TOTALS2,
|
|
4513
4711
|
provisioning: null,
|
|
4514
4712
|
pageError: null,
|
|
4515
|
-
statusError: null
|
|
4713
|
+
statusError: null,
|
|
4714
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
4516
4715
|
});
|
|
4517
|
-
const [pageBusy, setPageBusy] =
|
|
4518
|
-
const [provisionBusy, setProvisionBusy] =
|
|
4519
|
-
const [credentialOpen, setCredentialOpen] =
|
|
4520
|
-
const [credentialBusy, setCredentialBusy] =
|
|
4521
|
-
const [credentialError, setCredentialError] =
|
|
4522
|
-
const [busyByBot, setBusyByBot] =
|
|
4523
|
-
const [errorsByBot, setErrorsByBot] =
|
|
4524
|
-
const [testNoticesByBot, setTestNoticesByBot] =
|
|
4525
|
-
const [removeTargetId, setRemoveTargetId] =
|
|
4526
|
-
const [announcement, setAnnouncement] =
|
|
4527
|
-
const [now, setNow] =
|
|
4528
|
-
const [focusBotId, setFocusBotId] =
|
|
4529
|
-
const cardRefs =
|
|
4530
|
-
const removeButtonRefs =
|
|
4531
|
-
const addButtonRef =
|
|
4532
|
-
const mountedRef =
|
|
4716
|
+
const [pageBusy, setPageBusy] = React11.useState(false);
|
|
4717
|
+
const [provisionBusy, setProvisionBusy] = React11.useState(false);
|
|
4718
|
+
const [credentialOpen, setCredentialOpen] = React11.useState(false);
|
|
4719
|
+
const [credentialBusy, setCredentialBusy] = React11.useState(false);
|
|
4720
|
+
const [credentialError, setCredentialError] = React11.useState(null);
|
|
4721
|
+
const [busyByBot, setBusyByBot] = React11.useState({});
|
|
4722
|
+
const [errorsByBot, setErrorsByBot] = React11.useState({});
|
|
4723
|
+
const [testNoticesByBot, setTestNoticesByBot] = React11.useState({});
|
|
4724
|
+
const [removeTargetId, setRemoveTargetId] = React11.useState(null);
|
|
4725
|
+
const [announcement, setAnnouncement] = React11.useState("");
|
|
4726
|
+
const [now, setNow] = React11.useState(() => Date.now());
|
|
4727
|
+
const [focusBotId, setFocusBotId] = React11.useState(null);
|
|
4728
|
+
const cardRefs = React11.useRef(/* @__PURE__ */ new Map());
|
|
4729
|
+
const removeButtonRefs = React11.useRef(/* @__PURE__ */ new Map());
|
|
4730
|
+
const addButtonRef = React11.useRef(null);
|
|
4731
|
+
const mountedRef = React11.useRef(true);
|
|
4533
4732
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
4534
4733
|
const scheduleAnimationFrame = useAnimationFrameScheduler();
|
|
4535
|
-
|
|
4734
|
+
React11.useEffect(() => {
|
|
4536
4735
|
mountedRef.current = true;
|
|
4537
4736
|
return () => {
|
|
4538
4737
|
mountedRef.current = false;
|
|
4539
4738
|
};
|
|
4540
4739
|
}, []);
|
|
4541
|
-
const announce =
|
|
4740
|
+
const announce = React11.useCallback((message) => {
|
|
4542
4741
|
setAnnouncement("");
|
|
4543
4742
|
scheduleAnimationFrame(() => {
|
|
4544
4743
|
if (message) setAnnouncement(message);
|
|
4545
4744
|
}, "announcement");
|
|
4546
4745
|
}, [scheduleAnimationFrame]);
|
|
4547
|
-
const invoke =
|
|
4746
|
+
const invoke = React11.useCallback(async (endpoint, payload = {}, signal) => {
|
|
4548
4747
|
return unwrapRpcResult3(await rpcCall(endpoint, payload, signal));
|
|
4549
4748
|
}, [rpcCall]);
|
|
4550
|
-
const mergeSnapshot =
|
|
4749
|
+
const mergeSnapshot = React11.useCallback((snapshot, { restoreProvisioning = false } = {}) => {
|
|
4551
4750
|
const now2 = Date.now();
|
|
4552
4751
|
setModel((current) => mergeFeishuSnapshotState(
|
|
4553
4752
|
current,
|
|
@@ -4555,7 +4754,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4555
4754
|
{ restoreProvisioning, now: now2 }
|
|
4556
4755
|
));
|
|
4557
4756
|
}, []);
|
|
4558
|
-
const loadStatus =
|
|
4757
|
+
const loadStatus = React11.useCallback(async ({ signal, silent = false, restoreProvisioning = false } = {}) => {
|
|
4559
4758
|
const workspaceVersion = workspaceFence.beginStatus();
|
|
4560
4759
|
if (workspaceVersion === null || !mountedRef.current) return void 0;
|
|
4561
4760
|
if (!silent) setPageBusy(true);
|
|
@@ -4573,12 +4772,12 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4573
4772
|
if (!silent && !signal?.aborted && mountedRef.current) setPageBusy(false);
|
|
4574
4773
|
}
|
|
4575
4774
|
}, [invoke, mergeSnapshot, workspaceFence]);
|
|
4576
|
-
|
|
4775
|
+
React11.useEffect(() => {
|
|
4577
4776
|
const controller = new AbortController();
|
|
4578
4777
|
void loadStatus({ signal: controller.signal, restoreProvisioning: true });
|
|
4579
4778
|
return () => controller.abort();
|
|
4580
4779
|
}, [loadStatus]);
|
|
4581
|
-
|
|
4780
|
+
React11.useEffect(() => {
|
|
4582
4781
|
if (model.phase !== "ready") return void 0;
|
|
4583
4782
|
const controller = new AbortController();
|
|
4584
4783
|
let inFlight = false;
|
|
@@ -4597,7 +4796,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4597
4796
|
window.clearInterval(timer);
|
|
4598
4797
|
};
|
|
4599
4798
|
}, [loadStatus, model.phase]);
|
|
4600
|
-
|
|
4799
|
+
React11.useEffect(() => {
|
|
4601
4800
|
if (!focusBotId) return;
|
|
4602
4801
|
const node = cardRefs.current.get(focusBotId);
|
|
4603
4802
|
if (!node) return;
|
|
@@ -4605,7 +4804,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4605
4804
|
node.focus({ preventScroll: true });
|
|
4606
4805
|
setFocusBotId(null);
|
|
4607
4806
|
}, [focusBotId, model.bots]);
|
|
4608
|
-
const startProvisioning =
|
|
4807
|
+
const startProvisioning = React11.useCallback(async ({
|
|
4609
4808
|
replace = false,
|
|
4610
4809
|
operation = FEISHU_REGISTRATION_OPERATIONS.PROVISION,
|
|
4611
4810
|
bot
|
|
@@ -4678,7 +4877,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4678
4877
|
model.provisioning?.botId,
|
|
4679
4878
|
model.provisioning?.botName
|
|
4680
4879
|
]);
|
|
4681
|
-
const bindCredentials =
|
|
4880
|
+
const bindCredentials = React11.useCallback(async ({ identity, secret }) => {
|
|
4682
4881
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
4683
4882
|
setCredentialBusy(true);
|
|
4684
4883
|
setCredentialError(null);
|
|
@@ -4700,7 +4899,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4700
4899
|
setCredentialBusy(false);
|
|
4701
4900
|
}
|
|
4702
4901
|
}, [announce, invoke, loadStatus, mergeSnapshot, workspaceFence]);
|
|
4703
|
-
const cancelProvisioning =
|
|
4902
|
+
const cancelProvisioning = React11.useCallback(async () => {
|
|
4704
4903
|
const activeProvision = model.provisioning;
|
|
4705
4904
|
const attemptId = activeProvision?.attemptId;
|
|
4706
4905
|
const repairing = isCallbackRepair(activeProvision);
|
|
@@ -4763,7 +4962,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4763
4962
|
const countdownPhase = model.provisioning?.phase;
|
|
4764
4963
|
const countdownExpiresAt = model.provisioning?.expiresAt;
|
|
4765
4964
|
const countdownExpired = model.provisioning?.expired;
|
|
4766
|
-
|
|
4965
|
+
React11.useEffect(() => {
|
|
4767
4966
|
if (!countdownAttemptId || countdownPhase !== "qr" || countdownExpired) return void 0;
|
|
4768
4967
|
const tick = () => {
|
|
4769
4968
|
const timestamp7 = Date.now();
|
|
@@ -4776,7 +4975,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4776
4975
|
const timer = window.setInterval(tick, 1e3);
|
|
4777
4976
|
return () => window.clearInterval(timer);
|
|
4778
4977
|
}, [countdownAttemptId, countdownPhase, countdownExpiresAt, countdownExpired]);
|
|
4779
|
-
|
|
4978
|
+
React11.useEffect(() => {
|
|
4780
4979
|
const provision2 = model.provisioning;
|
|
4781
4980
|
if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0;
|
|
4782
4981
|
const controller = new AbortController();
|
|
@@ -4844,7 +5043,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4844
5043
|
window.clearTimeout(timer);
|
|
4845
5044
|
};
|
|
4846
5045
|
}, [announce, invoke, loadStatus, model.provisioning]);
|
|
4847
|
-
const setBotBusy =
|
|
5046
|
+
const setBotBusy = React11.useCallback((botId, value) => {
|
|
4848
5047
|
setBusyByBot((current) => {
|
|
4849
5048
|
const next = { ...current };
|
|
4850
5049
|
if (value) next[botId] = value;
|
|
@@ -4852,7 +5051,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4852
5051
|
return next;
|
|
4853
5052
|
});
|
|
4854
5053
|
}, []);
|
|
4855
|
-
const setBotError =
|
|
5054
|
+
const setBotError = React11.useCallback((botId, error) => {
|
|
4856
5055
|
setErrorsByBot((current) => {
|
|
4857
5056
|
const next = { ...current };
|
|
4858
5057
|
if (error) next[botId] = presentError3(error);
|
|
@@ -4860,7 +5059,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4860
5059
|
return next;
|
|
4861
5060
|
});
|
|
4862
5061
|
}, []);
|
|
4863
|
-
const repairCallback =
|
|
5062
|
+
const repairCallback = React11.useCallback((connection) => {
|
|
4864
5063
|
if (model.provisioning) return;
|
|
4865
5064
|
setRemoveTargetId(null);
|
|
4866
5065
|
setBotError(connection.botId, null);
|
|
@@ -4874,7 +5073,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4874
5073
|
bot: connection
|
|
4875
5074
|
});
|
|
4876
5075
|
}, [model.provisioning, setBotError, startProvisioning]);
|
|
4877
|
-
const reconnectOneBot =
|
|
5076
|
+
const reconnectOneBot = React11.useCallback(async (connection) => {
|
|
4878
5077
|
const { botId, bot } = connection;
|
|
4879
5078
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
4880
5079
|
setBotBusy(botId, "reconnect");
|
|
@@ -4914,7 +5113,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4914
5113
|
setBotBusy(botId, null);
|
|
4915
5114
|
}
|
|
4916
5115
|
}, [announce, invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
|
|
4917
|
-
const saveWorkspace =
|
|
5116
|
+
const saveWorkspace = React11.useCallback(async (connection, workspace) => {
|
|
4918
5117
|
const { botId } = connection;
|
|
4919
5118
|
const workspaceVersion = workspaceFence.beginMutation();
|
|
4920
5119
|
setBotBusy(botId, "workspace");
|
|
@@ -4933,15 +5132,34 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4933
5132
|
if (mountedRef.current) setBotBusy(botId, null);
|
|
4934
5133
|
}
|
|
4935
5134
|
}, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
|
|
4936
|
-
const
|
|
5135
|
+
const saveAgentPreset = React11.useCallback(async (connection, agentPreset) => {
|
|
5136
|
+
const { botId } = connection;
|
|
5137
|
+
const snapshotVersion = workspaceFence.beginMutation();
|
|
5138
|
+
setBotBusy(botId, "preset");
|
|
5139
|
+
setBotError(botId, null);
|
|
5140
|
+
try {
|
|
5141
|
+
const snapshot = normalizeBotsSnapshot(await invoke(
|
|
5142
|
+
FEISHU_ENDPOINTS.setAgentPreset,
|
|
5143
|
+
{ botId, agentPreset }
|
|
5144
|
+
));
|
|
5145
|
+
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
5146
|
+
mergeSnapshot(snapshot);
|
|
5147
|
+
}
|
|
5148
|
+
} finally {
|
|
5149
|
+
const shouldRefresh = workspaceFence.endMutation();
|
|
5150
|
+
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
5151
|
+
if (mountedRef.current) setBotBusy(botId, null);
|
|
5152
|
+
}
|
|
5153
|
+
}, [invoke, loadStatus, mergeSnapshot, setBotBusy, setBotError, workspaceFence]);
|
|
5154
|
+
const requestRemove = React11.useCallback((connection) => {
|
|
4937
5155
|
setRemoveTargetId(connection.botId);
|
|
4938
5156
|
}, []);
|
|
4939
|
-
const cancelRemove =
|
|
5157
|
+
const cancelRemove = React11.useCallback(() => {
|
|
4940
5158
|
const botId = removeTargetId;
|
|
4941
5159
|
setRemoveTargetId(null);
|
|
4942
5160
|
scheduleAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus(), "focus");
|
|
4943
5161
|
}, [removeTargetId, scheduleAnimationFrame]);
|
|
4944
|
-
const confirmRemove =
|
|
5162
|
+
const confirmRemove = React11.useCallback(async (connection) => {
|
|
4945
5163
|
const { botId, bot } = connection;
|
|
4946
5164
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
4947
5165
|
setBotBusy(botId, "delete");
|
|
@@ -5026,15 +5244,17 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
5026
5244
|
setCredentialError(null);
|
|
5027
5245
|
}
|
|
5028
5246
|
}) : null;
|
|
5029
|
-
const setCardRef =
|
|
5247
|
+
const setCardRef = React11.useCallback((botId, node) => {
|
|
5030
5248
|
if (node) cardRefs.current.set(botId, node);
|
|
5031
5249
|
else cardRefs.current.delete(botId);
|
|
5032
5250
|
}, []);
|
|
5033
|
-
const setRemoveButtonRef =
|
|
5251
|
+
const setRemoveButtonRef = React11.useCallback((botId, node) => {
|
|
5034
5252
|
if (node) removeButtonRefs.current.set(botId, node);
|
|
5035
5253
|
else removeButtonRefs.current.delete(botId);
|
|
5036
5254
|
}, []);
|
|
5037
|
-
return h2(
|
|
5255
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
5256
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
5257
|
+
}, h2(
|
|
5038
5258
|
"section",
|
|
5039
5259
|
{ className: "bxf-page dim-channelPage", "aria-label": "\u98DE\u4E66\u673A\u5668\u4EBA\u8BBE\u7F6E" },
|
|
5040
5260
|
h2(Heading2, {
|
|
@@ -5067,7 +5287,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
5067
5287
|
onRetry: () => void loadStatus(),
|
|
5068
5288
|
busy: pageBusy
|
|
5069
5289
|
}) : h2(
|
|
5070
|
-
|
|
5290
|
+
React11.Fragment,
|
|
5071
5291
|
null,
|
|
5072
5292
|
credentialContent,
|
|
5073
5293
|
provisionContent,
|
|
@@ -5082,6 +5302,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
5082
5302
|
onReconnect: (bot) => void reconnectOneBot(bot),
|
|
5083
5303
|
onRepairCallback: repairCallback,
|
|
5084
5304
|
onWorkspaceSave: saveWorkspace,
|
|
5305
|
+
onAgentPresetSave: saveAgentPreset,
|
|
5085
5306
|
onRequestRemove: requestRemove,
|
|
5086
5307
|
onConfirmRemove: (bot) => void confirmRemove(bot),
|
|
5087
5308
|
onCancelRemove: cancelRemove,
|
|
@@ -5089,7 +5310,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
5089
5310
|
setRemoveButtonRef
|
|
5090
5311
|
}) : null
|
|
5091
5312
|
)
|
|
5092
|
-
);
|
|
5313
|
+
));
|
|
5093
5314
|
}
|
|
5094
5315
|
|
|
5095
5316
|
// plugin-src/client/channels/qq/api.js
|
|
@@ -5102,7 +5323,8 @@ var QQ_ENDPOINTS = Object.freeze({
|
|
|
5102
5323
|
bindCredentials: "bot.bind-credentials",
|
|
5103
5324
|
reconnectBot: "bot.reconnect",
|
|
5104
5325
|
deleteBot: "bot.delete",
|
|
5105
|
-
setWorkspace: "bot.workspace.set"
|
|
5326
|
+
setWorkspace: "bot.workspace.set",
|
|
5327
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
5106
5328
|
});
|
|
5107
5329
|
var PROVISION_STATES2 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
|
|
5108
5330
|
var ACCOUNT_STATES3 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
@@ -5166,6 +5388,7 @@ function normalizeBot3(value) {
|
|
|
5166
5388
|
connected,
|
|
5167
5389
|
state: connected ? "connected" : state,
|
|
5168
5390
|
workspace: text2(value.workspace, "", 4096),
|
|
5391
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
5169
5392
|
bot: {
|
|
5170
5393
|
name: text2(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
|
|
5171
5394
|
appIdMasked: text2(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
|
|
@@ -5199,6 +5422,7 @@ function normalizeSnapshot3(value) {
|
|
|
5199
5422
|
bots,
|
|
5200
5423
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
5201
5424
|
provisioning: source.provisioning ? normalizeProvisioning3(source.provisioning) : null,
|
|
5425
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog),
|
|
5202
5426
|
...testMessage ? { testMessage } : {}
|
|
5203
5427
|
};
|
|
5204
5428
|
}
|
|
@@ -5221,7 +5445,7 @@ function formatRemaining3(milliseconds) {
|
|
|
5221
5445
|
}
|
|
5222
5446
|
|
|
5223
5447
|
// plugin-src/client/channels/qq/index.js
|
|
5224
|
-
var
|
|
5448
|
+
var React12 = __toESM(require("react"), 1);
|
|
5225
5449
|
|
|
5226
5450
|
// plugin-src/client/channels/qq/styles.js
|
|
5227
5451
|
var QQ_STYLE_ID = "xmanrui-dsh-im-qq-settings";
|
|
@@ -5246,7 +5470,7 @@ function installQqStyles() {
|
|
|
5246
5470
|
|
|
5247
5471
|
// plugin-src/client/channels/qq/index.js
|
|
5248
5472
|
var ACTIVE_STATES = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
|
|
5249
|
-
var Button7 =
|
|
5473
|
+
var Button7 = React12.forwardRef(function Button8({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
5250
5474
|
return h2("button", {
|
|
5251
5475
|
...props,
|
|
5252
5476
|
ref,
|
|
@@ -5460,6 +5684,7 @@ function AccountCard2({
|
|
|
5460
5684
|
removing,
|
|
5461
5685
|
onReconnect,
|
|
5462
5686
|
onWorkspaceSave,
|
|
5687
|
+
onAgentPresetSave,
|
|
5463
5688
|
onRequestRemove,
|
|
5464
5689
|
onConfirmRemove,
|
|
5465
5690
|
onCancelRemove
|
|
@@ -5505,6 +5730,11 @@ function AccountCard2({
|
|
|
5505
5730
|
disabled: Boolean(busy),
|
|
5506
5731
|
onSave: onWorkspaceSave
|
|
5507
5732
|
}),
|
|
5733
|
+
h2(AgentPresetEditor, {
|
|
5734
|
+
agentPreset: account.agentPreset,
|
|
5735
|
+
disabled: Boolean(busy),
|
|
5736
|
+
onSave: onAgentPresetSave
|
|
5737
|
+
}),
|
|
5508
5738
|
h2(
|
|
5509
5739
|
"div",
|
|
5510
5740
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
@@ -5531,19 +5761,25 @@ function AccountCard2({
|
|
|
5531
5761
|
);
|
|
5532
5762
|
}
|
|
5533
5763
|
function QqSettingsTab({ rpcCall }) {
|
|
5534
|
-
const [model, setModel] =
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
const [
|
|
5542
|
-
const [
|
|
5543
|
-
const
|
|
5764
|
+
const [model, setModel] = React12.useState({
|
|
5765
|
+
phase: "loading",
|
|
5766
|
+
bots: [],
|
|
5767
|
+
totals: { configured: 0, connected: 0 },
|
|
5768
|
+
error: null,
|
|
5769
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
5770
|
+
});
|
|
5771
|
+
const [provision, setProvision] = React12.useState(null);
|
|
5772
|
+
const [busy, setBusy] = React12.useState(false);
|
|
5773
|
+
const [busyByBot, setBusyByBot] = React12.useState({});
|
|
5774
|
+
const [feedbackByBot, setFeedbackByBot] = React12.useState({});
|
|
5775
|
+
const [removeTarget, setRemoveTarget] = React12.useState(null);
|
|
5776
|
+
const [credentialOpen, setCredentialOpen] = React12.useState(false);
|
|
5777
|
+
const [credentialError, setCredentialError] = React12.useState(null);
|
|
5778
|
+
const [now, setNow] = React12.useState(Date.now());
|
|
5779
|
+
const mounted = React12.useRef(true);
|
|
5544
5780
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
5545
|
-
const addButtonRef =
|
|
5546
|
-
|
|
5781
|
+
const addButtonRef = React12.useRef(null);
|
|
5782
|
+
React12.useEffect(() => {
|
|
5547
5783
|
const disposeDingtalk = installDingtalkStyles();
|
|
5548
5784
|
const disposeQq = installQqStyles();
|
|
5549
5785
|
mounted.current = true;
|
|
@@ -5553,18 +5789,24 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5553
5789
|
disposeDingtalk();
|
|
5554
5790
|
};
|
|
5555
5791
|
}, []);
|
|
5556
|
-
const invoke =
|
|
5792
|
+
const invoke = React12.useCallback(async (endpoint, payload = {}, signal) => {
|
|
5557
5793
|
if (typeof rpcCall !== "function") throw new TypeError("QQ \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
|
|
5558
5794
|
return unwrapRpcResult4(await rpcCall(endpoint, payload, signal));
|
|
5559
5795
|
}, [rpcCall]);
|
|
5560
|
-
const loadStatus =
|
|
5796
|
+
const loadStatus = React12.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
|
|
5561
5797
|
const workspaceVersion = workspaceFence.beginStatus();
|
|
5562
5798
|
if (workspaceVersion === null) return void 0;
|
|
5563
5799
|
if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
|
|
5564
5800
|
try {
|
|
5565
5801
|
const snapshot = normalizeSnapshot3(await invoke(QQ_ENDPOINTS.status, {}, signal));
|
|
5566
5802
|
if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
|
|
5567
|
-
setModel({
|
|
5803
|
+
setModel({
|
|
5804
|
+
phase: "ready",
|
|
5805
|
+
bots: snapshot.bots,
|
|
5806
|
+
totals: snapshot.totals,
|
|
5807
|
+
error: null,
|
|
5808
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
5809
|
+
});
|
|
5568
5810
|
if (restore && snapshot.provisioning) setProvision({
|
|
5569
5811
|
...snapshot.provisioning,
|
|
5570
5812
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now())
|
|
@@ -5577,12 +5819,12 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5577
5819
|
return void 0;
|
|
5578
5820
|
}
|
|
5579
5821
|
}, [invoke, workspaceFence]);
|
|
5580
|
-
|
|
5822
|
+
React12.useEffect(() => {
|
|
5581
5823
|
const controller = new AbortController();
|
|
5582
5824
|
void loadStatus({ signal: controller.signal, restore: true });
|
|
5583
5825
|
return () => controller.abort();
|
|
5584
5826
|
}, [loadStatus]);
|
|
5585
|
-
|
|
5827
|
+
React12.useEffect(() => {
|
|
5586
5828
|
if (model.phase !== "ready") return void 0;
|
|
5587
5829
|
const controller = new AbortController();
|
|
5588
5830
|
const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
|
|
@@ -5591,12 +5833,12 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5591
5833
|
window.clearInterval(timer);
|
|
5592
5834
|
};
|
|
5593
5835
|
}, [loadStatus, model.phase]);
|
|
5594
|
-
|
|
5836
|
+
React12.useEffect(() => {
|
|
5595
5837
|
if (!provision || !ACTIVE_STATES.has(provision.status)) return void 0;
|
|
5596
5838
|
const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
|
|
5597
5839
|
return () => window.clearInterval(timer);
|
|
5598
5840
|
}, [provision?.attemptId, provision?.status]);
|
|
5599
|
-
const startProvisioning =
|
|
5841
|
+
const startProvisioning = React12.useCallback(async (replace = false) => {
|
|
5600
5842
|
setCredentialOpen(false);
|
|
5601
5843
|
setCredentialError(null);
|
|
5602
5844
|
setBusy(true);
|
|
@@ -5614,7 +5856,7 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5614
5856
|
if (mounted.current) setBusy(false);
|
|
5615
5857
|
}
|
|
5616
5858
|
}, [invoke, provision?.attemptId]);
|
|
5617
|
-
const bindCredentials =
|
|
5859
|
+
const bindCredentials = React12.useCallback(async ({ identity, secret }) => {
|
|
5618
5860
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
5619
5861
|
setBusy(true);
|
|
5620
5862
|
setCredentialError(null);
|
|
@@ -5625,7 +5867,13 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5625
5867
|
));
|
|
5626
5868
|
if (!mounted.current) return;
|
|
5627
5869
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
5628
|
-
setModel({
|
|
5870
|
+
setModel({
|
|
5871
|
+
phase: "ready",
|
|
5872
|
+
bots: snapshot.bots,
|
|
5873
|
+
totals: snapshot.totals,
|
|
5874
|
+
error: null,
|
|
5875
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
5876
|
+
});
|
|
5629
5877
|
}
|
|
5630
5878
|
setCredentialOpen(false);
|
|
5631
5879
|
} catch (error) {
|
|
@@ -5636,7 +5884,7 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5636
5884
|
if (mounted.current) setBusy(false);
|
|
5637
5885
|
}
|
|
5638
5886
|
}, [invoke, loadStatus, workspaceFence]);
|
|
5639
|
-
const closeProvision =
|
|
5887
|
+
const closeProvision = React12.useCallback(async () => {
|
|
5640
5888
|
setBusy(true);
|
|
5641
5889
|
try {
|
|
5642
5890
|
if (provision?.attemptId && ACTIVE_STATES.has(provision.status)) {
|
|
@@ -5647,7 +5895,7 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5647
5895
|
if (mounted.current) setBusy(false);
|
|
5648
5896
|
}
|
|
5649
5897
|
}, [invoke, provision?.attemptId, provision?.status]);
|
|
5650
|
-
|
|
5898
|
+
React12.useEffect(() => {
|
|
5651
5899
|
const attemptId = provision?.attemptId;
|
|
5652
5900
|
if (!attemptId || !ACTIVE_STATES.has(provision.status)) return void 0;
|
|
5653
5901
|
const controller = new AbortController();
|
|
@@ -5677,13 +5925,19 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5677
5925
|
window.clearTimeout(timer);
|
|
5678
5926
|
};
|
|
5679
5927
|
}, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
|
|
5680
|
-
const botAction =
|
|
5928
|
+
const botAction = React12.useCallback(async (account, operation, endpoint, payload) => {
|
|
5681
5929
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
5682
5930
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
5683
5931
|
try {
|
|
5684
5932
|
const snapshot = normalizeSnapshot3(await invoke(endpoint, payload));
|
|
5685
5933
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
5686
|
-
setModel({
|
|
5934
|
+
setModel({
|
|
5935
|
+
phase: "ready",
|
|
5936
|
+
bots: snapshot.bots,
|
|
5937
|
+
totals: snapshot.totals,
|
|
5938
|
+
error: null,
|
|
5939
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
5940
|
+
});
|
|
5687
5941
|
}
|
|
5688
5942
|
return snapshot;
|
|
5689
5943
|
} finally {
|
|
@@ -5696,7 +5950,7 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5696
5950
|
});
|
|
5697
5951
|
}
|
|
5698
5952
|
}, [invoke, loadStatus, workspaceFence]);
|
|
5699
|
-
const reconnect =
|
|
5953
|
+
const reconnect = React12.useCallback(async (account) => {
|
|
5700
5954
|
setFeedbackByBot((current) => {
|
|
5701
5955
|
const next = { ...current };
|
|
5702
5956
|
delete next[account.botId];
|
|
@@ -5759,6 +6013,12 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5759
6013
|
QQ_ENDPOINTS.setWorkspace,
|
|
5760
6014
|
{ botId: account.botId, workspace }
|
|
5761
6015
|
),
|
|
6016
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
6017
|
+
account,
|
|
6018
|
+
"preset",
|
|
6019
|
+
QQ_ENDPOINTS.setAgentPreset,
|
|
6020
|
+
{ botId: account.botId, agentPreset }
|
|
6021
|
+
),
|
|
5762
6022
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
5763
6023
|
onCancelRemove: () => setRemoveTarget(null),
|
|
5764
6024
|
onConfirmRemove: async () => {
|
|
@@ -5781,7 +6041,9 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5781
6041
|
setCredentialError(null);
|
|
5782
6042
|
}
|
|
5783
6043
|
}) : null;
|
|
5784
|
-
return h2(
|
|
6044
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
6045
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
6046
|
+
}, h2(
|
|
5785
6047
|
"section",
|
|
5786
6048
|
{ className: "ddt-page dqq-page dim-channelPage", "aria-label": "QQ \u8BBE\u7F6E" },
|
|
5787
6049
|
h2(Heading3, {
|
|
@@ -5797,14 +6059,14 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5797
6059
|
addButtonRef
|
|
5798
6060
|
}),
|
|
5799
6061
|
model.phase === "loading" ? h2(LoadingView3) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6 QQ \u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button7, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
|
|
5800
|
-
|
|
6062
|
+
React12.Fragment,
|
|
5801
6063
|
null,
|
|
5802
6064
|
credentialView,
|
|
5803
6065
|
provisionView,
|
|
5804
6066
|
model.bots.length === 0 && !provision && !credentialOpen ? h2(EmptyView3, { busy, onStart: () => void startProvisioning() }) : null,
|
|
5805
6067
|
botList
|
|
5806
6068
|
)
|
|
5807
|
-
);
|
|
6069
|
+
));
|
|
5808
6070
|
}
|
|
5809
6071
|
|
|
5810
6072
|
// src/channels/office/protocol.mjs
|
|
@@ -5886,7 +6148,7 @@ function normalizeOfficeStatus(value) {
|
|
|
5886
6148
|
}
|
|
5887
6149
|
|
|
5888
6150
|
// plugin-src/client/channels/office/index.js
|
|
5889
|
-
var
|
|
6151
|
+
var React13 = __toESM(require("react"), 1);
|
|
5890
6152
|
function Button9({ children, kind = "secondary", ...props }) {
|
|
5891
6153
|
return h2("button", { ...props, type: "button", className: "ddt-button", "data-kind": kind }, children);
|
|
5892
6154
|
}
|
|
@@ -5915,12 +6177,12 @@ function stateLabel(model) {
|
|
|
5915
6177
|
return "\u5DF2\u914D\u7F6E";
|
|
5916
6178
|
}
|
|
5917
6179
|
function OfficeSettingsTab({ rpcCall, initialStatus }) {
|
|
5918
|
-
const [model, setModel] =
|
|
5919
|
-
const [phase, setPhase] =
|
|
5920
|
-
const [busy, setBusy] =
|
|
5921
|
-
const [error, setError] =
|
|
5922
|
-
const [notice, setNotice] =
|
|
5923
|
-
const [form, setForm] =
|
|
6180
|
+
const [model, setModel] = React13.useState(normalizeOfficeStatus(initialStatus));
|
|
6181
|
+
const [phase, setPhase] = React13.useState(initialStatus === void 0 ? "loading" : "ready");
|
|
6182
|
+
const [busy, setBusy] = React13.useState("");
|
|
6183
|
+
const [error, setError] = React13.useState("");
|
|
6184
|
+
const [notice, setNotice] = React13.useState("");
|
|
6185
|
+
const [form, setForm] = React13.useState({
|
|
5924
6186
|
baseUrl: "",
|
|
5925
6187
|
deviceId: "local-harness",
|
|
5926
6188
|
deviceToken: "",
|
|
@@ -5929,11 +6191,11 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
|
|
|
5929
6191
|
workspaces: "",
|
|
5930
6192
|
instructionPresets: ""
|
|
5931
6193
|
});
|
|
5932
|
-
const invoke =
|
|
6194
|
+
const invoke = React13.useCallback(async (endpoint, payload = {}) => {
|
|
5933
6195
|
if (typeof rpcCall !== "function") throw new Error("AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
|
|
5934
6196
|
return unwrapOfficeRpc(await rpcCall(endpoint, payload));
|
|
5935
6197
|
}, [rpcCall]);
|
|
5936
|
-
const adopt =
|
|
6198
|
+
const adopt = React13.useCallback((value) => {
|
|
5937
6199
|
const next = normalizeOfficeStatus(value?.snapshot ?? value);
|
|
5938
6200
|
setModel(next);
|
|
5939
6201
|
if (next.config) setForm((current) => ({
|
|
@@ -5948,7 +6210,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
|
|
|
5948
6210
|
}));
|
|
5949
6211
|
return next;
|
|
5950
6212
|
}, []);
|
|
5951
|
-
const load =
|
|
6213
|
+
const load = React13.useCallback(async () => {
|
|
5952
6214
|
try {
|
|
5953
6215
|
adopt(await invoke(OFFICE_RPC_ENDPOINTS.status));
|
|
5954
6216
|
setPhase("ready");
|
|
@@ -5958,7 +6220,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
|
|
|
5958
6220
|
setError(caught.message);
|
|
5959
6221
|
}
|
|
5960
6222
|
}, [adopt, invoke]);
|
|
5961
|
-
|
|
6223
|
+
React13.useEffect(() => {
|
|
5962
6224
|
void load();
|
|
5963
6225
|
}, [load]);
|
|
5964
6226
|
const run = async (name2, operation) => {
|
|
@@ -5975,7 +6237,7 @@ function OfficeSettingsTab({ rpcCall, initialStatus }) {
|
|
|
5975
6237
|
setBusy("");
|
|
5976
6238
|
}
|
|
5977
6239
|
};
|
|
5978
|
-
const hooks =
|
|
6240
|
+
const hooks = React13.useMemo(() => {
|
|
5979
6241
|
try {
|
|
5980
6242
|
return officeHookUrls(form.baseUrl);
|
|
5981
6243
|
} catch {
|
|
@@ -6160,7 +6422,7 @@ var normalizeSnapshot4 = api2.normalizeSnapshot;
|
|
|
6160
6422
|
var presentError5 = api2.presentError;
|
|
6161
6423
|
|
|
6162
6424
|
// plugin-src/client/channels/slack/index.js
|
|
6163
|
-
var
|
|
6425
|
+
var React14 = __toESM(require("react"), 1);
|
|
6164
6426
|
|
|
6165
6427
|
// src/channels/slack/manifest.mjs
|
|
6166
6428
|
var SLACK_APP_MANIFEST_YAML = `_metadata:
|
|
@@ -6233,10 +6495,10 @@ function installSlackStyles() {
|
|
|
6233
6495
|
|
|
6234
6496
|
// plugin-src/client/channels/slack/index.js
|
|
6235
6497
|
function SlackCredentialPanel({ busy, error, onSubmit, onCancel }) {
|
|
6236
|
-
const [botToken, setBotToken] =
|
|
6237
|
-
const [appToken, setAppToken] =
|
|
6238
|
-
const [copied, setCopied] =
|
|
6239
|
-
const headingId =
|
|
6498
|
+
const [botToken, setBotToken] = React14.useState("");
|
|
6499
|
+
const [appToken, setAppToken] = React14.useState("");
|
|
6500
|
+
const [copied, setCopied] = React14.useState(false);
|
|
6501
|
+
const headingId = React14.useId();
|
|
6240
6502
|
const copyManifest = async () => {
|
|
6241
6503
|
try {
|
|
6242
6504
|
await navigator.clipboard.writeText(SLACK_APP_MANIFEST_YAML);
|
|
@@ -6392,7 +6654,7 @@ var normalizeSnapshot5 = api3.normalizeSnapshot;
|
|
|
6392
6654
|
var presentError6 = api3.presentError;
|
|
6393
6655
|
|
|
6394
6656
|
// plugin-src/client/channels/telegram/index.js
|
|
6395
|
-
var
|
|
6657
|
+
var React15 = __toESM(require("react"), 1);
|
|
6396
6658
|
|
|
6397
6659
|
// plugin-src/client/channels/telegram/styles.js
|
|
6398
6660
|
var TELEGRAM_STYLE_ID = "xmanrui-dsh-im-telegram-settings";
|
|
@@ -6458,11 +6720,11 @@ function allowedUsersFromText(value) {
|
|
|
6458
6720
|
function TelegramAccessSettings({ account, busy = false, onSave }) {
|
|
6459
6721
|
const policy = policyFor(account);
|
|
6460
6722
|
const sourceUsers = policy.allowedUsers.join("\n");
|
|
6461
|
-
const accessHelpId =
|
|
6462
|
-
const [accessMode, setAccessMode] =
|
|
6463
|
-
const [allowedUsers, setAllowedUsers] =
|
|
6464
|
-
const [error, setError] =
|
|
6465
|
-
|
|
6723
|
+
const accessHelpId = React15.useId();
|
|
6724
|
+
const [accessMode, setAccessMode] = React15.useState(policy.accessMode);
|
|
6725
|
+
const [allowedUsers, setAllowedUsers] = React15.useState(sourceUsers);
|
|
6726
|
+
const [error, setError] = React15.useState(null);
|
|
6727
|
+
React15.useEffect(() => {
|
|
6466
6728
|
setAccessMode(policy.accessMode);
|
|
6467
6729
|
setAllowedUsers(sourceUsers);
|
|
6468
6730
|
setError(null);
|
|
@@ -6611,7 +6873,8 @@ var WECOM_ENDPOINTS = Object.freeze({
|
|
|
6611
6873
|
bindCredentials: "bot.bind-credentials",
|
|
6612
6874
|
reconnectBot: "bot.reconnect",
|
|
6613
6875
|
deleteBot: "bot.delete",
|
|
6614
|
-
setWorkspace: "bot.workspace.set"
|
|
6876
|
+
setWorkspace: "bot.workspace.set",
|
|
6877
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
6615
6878
|
});
|
|
6616
6879
|
var PROVISION_STATES3 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
|
|
6617
6880
|
var ACCOUNT_STATES4 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
@@ -6681,6 +6944,7 @@ function normalizeBot4(value) {
|
|
|
6681
6944
|
connected,
|
|
6682
6945
|
state: connected ? "connected" : state,
|
|
6683
6946
|
workspace: text3(value.workspace, "", 4096),
|
|
6947
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
6684
6948
|
bot: {
|
|
6685
6949
|
name: text3(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
|
|
6686
6950
|
appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
|
|
@@ -6704,7 +6968,8 @@ function normalizeSnapshot6(value) {
|
|
|
6704
6968
|
bots,
|
|
6705
6969
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
6706
6970
|
provisioning: source.provisioning ? normalizeProvisioning4(source.provisioning) : null,
|
|
6707
|
-
testMessage: normalizeTestMessage3(source.testMessage)
|
|
6971
|
+
testMessage: normalizeTestMessage3(source.testMessage),
|
|
6972
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog)
|
|
6708
6973
|
};
|
|
6709
6974
|
}
|
|
6710
6975
|
function presentError7(error) {
|
|
@@ -6719,7 +6984,7 @@ function formatRemaining4(milliseconds) {
|
|
|
6719
6984
|
}
|
|
6720
6985
|
|
|
6721
6986
|
// plugin-src/client/channels/wecom/index.js
|
|
6722
|
-
var
|
|
6987
|
+
var React16 = __toESM(require("react"), 1);
|
|
6723
6988
|
|
|
6724
6989
|
// plugin-src/client/channels/wecom/styles.js
|
|
6725
6990
|
var WECOM_STYLE_ID = "xmanrui-dsh-im-wecom-settings";
|
|
@@ -6744,7 +7009,7 @@ function installWecomStyles() {
|
|
|
6744
7009
|
|
|
6745
7010
|
// plugin-src/client/channels/wecom/index.js
|
|
6746
7011
|
var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["pending", "refreshing", "connecting"]);
|
|
6747
|
-
var Button10 =
|
|
7012
|
+
var Button10 = React16.forwardRef(function Button11({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
6748
7013
|
return h2("button", {
|
|
6749
7014
|
...props,
|
|
6750
7015
|
ref,
|
|
@@ -6958,6 +7223,7 @@ function AccountCard3({
|
|
|
6958
7223
|
removing,
|
|
6959
7224
|
onReconnect,
|
|
6960
7225
|
onWorkspaceSave,
|
|
7226
|
+
onAgentPresetSave,
|
|
6961
7227
|
onRequestRemove,
|
|
6962
7228
|
onConfirmRemove,
|
|
6963
7229
|
onCancelRemove
|
|
@@ -7003,6 +7269,11 @@ function AccountCard3({
|
|
|
7003
7269
|
disabled: Boolean(busy),
|
|
7004
7270
|
onSave: onWorkspaceSave
|
|
7005
7271
|
}),
|
|
7272
|
+
h2(AgentPresetEditor, {
|
|
7273
|
+
agentPreset: account.agentPreset,
|
|
7274
|
+
disabled: Boolean(busy),
|
|
7275
|
+
onSave: onAgentPresetSave
|
|
7276
|
+
}),
|
|
7006
7277
|
h2(
|
|
7007
7278
|
"div",
|
|
7008
7279
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
@@ -7029,21 +7300,27 @@ function AccountCard3({
|
|
|
7029
7300
|
);
|
|
7030
7301
|
}
|
|
7031
7302
|
function WecomSettingsTab({ rpcCall }) {
|
|
7032
|
-
const [model, setModel] =
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
const [
|
|
7040
|
-
const [
|
|
7041
|
-
const [
|
|
7042
|
-
const
|
|
7303
|
+
const [model, setModel] = React16.useState({
|
|
7304
|
+
phase: "loading",
|
|
7305
|
+
bots: [],
|
|
7306
|
+
totals: { configured: 0, connected: 0 },
|
|
7307
|
+
error: null,
|
|
7308
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
7309
|
+
});
|
|
7310
|
+
const [provision, setProvision] = React16.useState(null);
|
|
7311
|
+
const [busy, setBusy] = React16.useState(false);
|
|
7312
|
+
const [busyByBot, setBusyByBot] = React16.useState({});
|
|
7313
|
+
const [feedbackByBot, setFeedbackByBot] = React16.useState({});
|
|
7314
|
+
const [removeTarget, setRemoveTarget] = React16.useState(null);
|
|
7315
|
+
const [credentialOpen, setCredentialOpen] = React16.useState(false);
|
|
7316
|
+
const [credentialError, setCredentialError] = React16.useState(null);
|
|
7317
|
+
const [notice, setNotice] = React16.useState("");
|
|
7318
|
+
const [now, setNow] = React16.useState(Date.now());
|
|
7319
|
+
const mounted = React16.useRef(true);
|
|
7043
7320
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
7044
|
-
const addButtonRef =
|
|
7045
|
-
const noticeFrameRef =
|
|
7046
|
-
const announce =
|
|
7321
|
+
const addButtonRef = React16.useRef(null);
|
|
7322
|
+
const noticeFrameRef = React16.useRef(null);
|
|
7323
|
+
const announce = React16.useCallback((message) => {
|
|
7047
7324
|
if (!mounted.current) return;
|
|
7048
7325
|
if (noticeFrameRef.current !== null) {
|
|
7049
7326
|
window.cancelAnimationFrame(noticeFrameRef.current);
|
|
@@ -7057,7 +7334,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7057
7334
|
});
|
|
7058
7335
|
}
|
|
7059
7336
|
}, []);
|
|
7060
|
-
|
|
7337
|
+
React16.useEffect(() => {
|
|
7061
7338
|
const disposeDingtalk = installDingtalkStyles();
|
|
7062
7339
|
const disposeWecom = installWecomStyles();
|
|
7063
7340
|
mounted.current = true;
|
|
@@ -7071,18 +7348,24 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7071
7348
|
disposeDingtalk();
|
|
7072
7349
|
};
|
|
7073
7350
|
}, []);
|
|
7074
|
-
const invoke =
|
|
7351
|
+
const invoke = React16.useCallback(async (endpoint, payload = {}, signal) => {
|
|
7075
7352
|
if (typeof rpcCall !== "function") throw new TypeError("\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
|
|
7076
7353
|
return unwrapRpcResult7(await rpcCall(endpoint, payload, signal));
|
|
7077
7354
|
}, [rpcCall]);
|
|
7078
|
-
const loadStatus =
|
|
7355
|
+
const loadStatus = React16.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
|
|
7079
7356
|
const workspaceVersion = workspaceFence.beginStatus();
|
|
7080
7357
|
if (workspaceVersion === null) return void 0;
|
|
7081
7358
|
if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
|
|
7082
7359
|
try {
|
|
7083
7360
|
const snapshot = normalizeSnapshot6(await invoke(WECOM_ENDPOINTS.status, {}, signal));
|
|
7084
7361
|
if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
|
|
7085
|
-
setModel({
|
|
7362
|
+
setModel({
|
|
7363
|
+
phase: "ready",
|
|
7364
|
+
bots: snapshot.bots,
|
|
7365
|
+
totals: snapshot.totals,
|
|
7366
|
+
error: null,
|
|
7367
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
7368
|
+
});
|
|
7086
7369
|
if (restore && snapshot.provisioning) setProvision({
|
|
7087
7370
|
...snapshot.provisioning,
|
|
7088
7371
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now())
|
|
@@ -7095,12 +7378,12 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7095
7378
|
return void 0;
|
|
7096
7379
|
}
|
|
7097
7380
|
}, [invoke, workspaceFence]);
|
|
7098
|
-
|
|
7381
|
+
React16.useEffect(() => {
|
|
7099
7382
|
const controller = new AbortController();
|
|
7100
7383
|
void loadStatus({ signal: controller.signal, restore: true });
|
|
7101
7384
|
return () => controller.abort();
|
|
7102
7385
|
}, [loadStatus]);
|
|
7103
|
-
|
|
7386
|
+
React16.useEffect(() => {
|
|
7104
7387
|
if (model.phase !== "ready") return void 0;
|
|
7105
7388
|
const controller = new AbortController();
|
|
7106
7389
|
const timer = window.setInterval(() => void loadStatus({ signal: controller.signal, silent: true }), 15e3);
|
|
@@ -7109,12 +7392,12 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7109
7392
|
window.clearInterval(timer);
|
|
7110
7393
|
};
|
|
7111
7394
|
}, [loadStatus, model.phase]);
|
|
7112
|
-
|
|
7395
|
+
React16.useEffect(() => {
|
|
7113
7396
|
if (!provision || !ACTIVE_STATES2.has(provision.status)) return void 0;
|
|
7114
7397
|
const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
|
|
7115
7398
|
return () => window.clearInterval(timer);
|
|
7116
7399
|
}, [provision?.attemptId, provision?.status]);
|
|
7117
|
-
const startProvisioning =
|
|
7400
|
+
const startProvisioning = React16.useCallback(async (replace = false) => {
|
|
7118
7401
|
setCredentialOpen(false);
|
|
7119
7402
|
setCredentialError(null);
|
|
7120
7403
|
setBusy(true);
|
|
@@ -7132,7 +7415,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7132
7415
|
if (mounted.current) setBusy(false);
|
|
7133
7416
|
}
|
|
7134
7417
|
}, [invoke, provision?.attemptId]);
|
|
7135
|
-
const bindCredentials =
|
|
7418
|
+
const bindCredentials = React16.useCallback(async ({ identity, secret }) => {
|
|
7136
7419
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
7137
7420
|
setBusy(true);
|
|
7138
7421
|
setCredentialError(null);
|
|
@@ -7143,7 +7426,13 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7143
7426
|
));
|
|
7144
7427
|
if (!mounted.current) return;
|
|
7145
7428
|
if (workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
7146
|
-
setModel({
|
|
7429
|
+
setModel({
|
|
7430
|
+
phase: "ready",
|
|
7431
|
+
bots: snapshot.bots,
|
|
7432
|
+
totals: snapshot.totals,
|
|
7433
|
+
error: null,
|
|
7434
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
7435
|
+
});
|
|
7147
7436
|
}
|
|
7148
7437
|
setCredentialOpen(false);
|
|
7149
7438
|
} catch (error) {
|
|
@@ -7154,7 +7443,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7154
7443
|
if (mounted.current) setBusy(false);
|
|
7155
7444
|
}
|
|
7156
7445
|
}, [invoke, loadStatus, workspaceFence]);
|
|
7157
|
-
const closeProvision =
|
|
7446
|
+
const closeProvision = React16.useCallback(async () => {
|
|
7158
7447
|
setBusy(true);
|
|
7159
7448
|
try {
|
|
7160
7449
|
if (provision?.attemptId && ACTIVE_STATES2.has(provision.status)) {
|
|
@@ -7165,7 +7454,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7165
7454
|
if (mounted.current) setBusy(false);
|
|
7166
7455
|
}
|
|
7167
7456
|
}, [invoke, provision?.attemptId, provision?.status]);
|
|
7168
|
-
|
|
7457
|
+
React16.useEffect(() => {
|
|
7169
7458
|
const attemptId = provision?.attemptId;
|
|
7170
7459
|
if (!attemptId || !ACTIVE_STATES2.has(provision.status)) return void 0;
|
|
7171
7460
|
const controller = new AbortController();
|
|
@@ -7195,13 +7484,19 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7195
7484
|
window.clearTimeout(timer);
|
|
7196
7485
|
};
|
|
7197
7486
|
}, [invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]);
|
|
7198
|
-
const botAction =
|
|
7487
|
+
const botAction = React16.useCallback(async (account, operation, endpoint, payload) => {
|
|
7199
7488
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
7200
7489
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
7201
7490
|
try {
|
|
7202
7491
|
const snapshot = normalizeSnapshot6(await invoke(endpoint, payload));
|
|
7203
7492
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
7204
|
-
setModel({
|
|
7493
|
+
setModel({
|
|
7494
|
+
phase: "ready",
|
|
7495
|
+
bots: snapshot.bots,
|
|
7496
|
+
totals: snapshot.totals,
|
|
7497
|
+
error: null,
|
|
7498
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
7499
|
+
});
|
|
7205
7500
|
}
|
|
7206
7501
|
return snapshot;
|
|
7207
7502
|
} finally {
|
|
@@ -7214,7 +7509,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7214
7509
|
});
|
|
7215
7510
|
}
|
|
7216
7511
|
}, [invoke, loadStatus, workspaceFence]);
|
|
7217
|
-
const reconnect =
|
|
7512
|
+
const reconnect = React16.useCallback(async (account) => {
|
|
7218
7513
|
setFeedbackByBot((current) => {
|
|
7219
7514
|
const next = { ...current };
|
|
7220
7515
|
delete next[account.botId];
|
|
@@ -7288,6 +7583,12 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7288
7583
|
WECOM_ENDPOINTS.setWorkspace,
|
|
7289
7584
|
{ botId: account.botId, workspace }
|
|
7290
7585
|
),
|
|
7586
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
7587
|
+
account,
|
|
7588
|
+
"preset",
|
|
7589
|
+
WECOM_ENDPOINTS.setAgentPreset,
|
|
7590
|
+
{ botId: account.botId, agentPreset }
|
|
7591
|
+
),
|
|
7291
7592
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
7292
7593
|
onCancelRemove: () => setRemoveTarget(null),
|
|
7293
7594
|
onConfirmRemove: async () => {
|
|
@@ -7310,7 +7611,9 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7310
7611
|
setCredentialError(null);
|
|
7311
7612
|
}
|
|
7312
7613
|
}) : null;
|
|
7313
|
-
return h2(
|
|
7614
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
7615
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
7616
|
+
}, h2(
|
|
7314
7617
|
"section",
|
|
7315
7618
|
{ className: "ddt-page dwecom-page dim-channelPage", "aria-label": "\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E" },
|
|
7316
7619
|
h2(Heading4, {
|
|
@@ -7327,18 +7630,18 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
7327
7630
|
}),
|
|
7328
7631
|
h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
|
|
7329
7632
|
model.phase === "loading" ? h2(LoadingView4) : model.phase === "error" ? h2("div", { className: "ddt-card dim-surfaceCard" }, h2("div", { className: "ddt-inlineError dim-inlineError" }, h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u72B6\u6001"), h2("p", null, model.error?.message), h2(Button10, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
|
|
7330
|
-
|
|
7633
|
+
React16.Fragment,
|
|
7331
7634
|
null,
|
|
7332
7635
|
credentialView,
|
|
7333
7636
|
provisionView,
|
|
7334
7637
|
model.bots.length === 0 && !provision && !credentialOpen ? h2(EmptyView4, { busy, onStart: () => void startProvisioning() }) : null,
|
|
7335
7638
|
botList
|
|
7336
7639
|
)
|
|
7337
|
-
);
|
|
7640
|
+
));
|
|
7338
7641
|
}
|
|
7339
7642
|
|
|
7340
7643
|
// plugin-src/client/channels/weixin/index.js
|
|
7341
|
-
var
|
|
7644
|
+
var React17 = __toESM(require("react"), 1);
|
|
7342
7645
|
|
|
7343
7646
|
// plugin-src/client/channels/weixin/api.js
|
|
7344
7647
|
var WEIXIN_RPC_CHANNEL = "/weixin";
|
|
@@ -7350,7 +7653,8 @@ var WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
7350
7653
|
cancelProvisioning: "provision.cancel",
|
|
7351
7654
|
reconnectBot: "bot.reconnect",
|
|
7352
7655
|
deleteBot: "bot.delete",
|
|
7353
|
-
setWorkspace: "bot.workspace.set"
|
|
7656
|
+
setWorkspace: "bot.workspace.set",
|
|
7657
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
7354
7658
|
});
|
|
7355
7659
|
var ACCOUNT_STATES5 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
7356
7660
|
var PROVISION_STATES4 = /* @__PURE__ */ new Set([
|
|
@@ -7448,6 +7752,7 @@ function normalizeBot5(value) {
|
|
|
7448
7752
|
connected,
|
|
7449
7753
|
configured: value.configured === true,
|
|
7450
7754
|
workspace: string(value.workspace).slice(0, 4096),
|
|
7755
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
7451
7756
|
bot: {
|
|
7452
7757
|
name: string(value.bot.name, "\u5FAE\u4FE1\u673A\u5668\u4EBA"),
|
|
7453
7758
|
accountIdMasked: string(value.bot.accountIdMasked, "\u5DF2\u5B89\u5168\u4FDD\u5B58")
|
|
@@ -7483,7 +7788,8 @@ function normalizeSnapshot7(value) {
|
|
|
7483
7788
|
connected: bots.filter((bot) => bot.connected).length
|
|
7484
7789
|
},
|
|
7485
7790
|
provisioning: value.provisioning ? normalizeProvisioning5(value.provisioning) : null,
|
|
7486
|
-
testMessage: normalizeTestMessage4(value.testMessage)
|
|
7791
|
+
testMessage: normalizeTestMessage4(value.testMessage),
|
|
7792
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(value.agentPresetCatalog)
|
|
7487
7793
|
};
|
|
7488
7794
|
}
|
|
7489
7795
|
function presentError8(error) {
|
|
@@ -7620,7 +7926,7 @@ function installWeixinStyles() {
|
|
|
7620
7926
|
}
|
|
7621
7927
|
|
|
7622
7928
|
// plugin-src/client/channels/weixin/index.js
|
|
7623
|
-
var Button12 =
|
|
7929
|
+
var Button12 = React17.forwardRef(function Button13({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
7624
7930
|
return h2("button", {
|
|
7625
7931
|
...props,
|
|
7626
7932
|
ref,
|
|
@@ -7693,14 +7999,14 @@ function EmptyView5({ onStart, busy }) {
|
|
|
7693
7999
|
);
|
|
7694
8000
|
}
|
|
7695
8001
|
function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
|
|
7696
|
-
const [imageFailed, setImageFailed] =
|
|
8002
|
+
const [imageFailed, setImageFailed] = React17.useState(false);
|
|
7697
8003
|
const source = safeQrSource5(provision.qrCodeDataUrl);
|
|
7698
8004
|
const href = safeVerificationUrl(provision.verificationUrl);
|
|
7699
8005
|
const remaining = Math.max(0, provision.expiresAt - now);
|
|
7700
8006
|
const expired = remaining === 0 || provision.status === "expired";
|
|
7701
8007
|
const duration = Math.max(1, provision.durationMs ?? 5 * 6e4);
|
|
7702
8008
|
const progress = Math.round(Math.min(1, remaining / duration) * 100);
|
|
7703
|
-
|
|
8009
|
+
React17.useEffect(() => setImageFailed(false), [source]);
|
|
7704
8010
|
return h2(
|
|
7705
8011
|
"div",
|
|
7706
8012
|
{ className: "dxw-card dim-surfaceCard" },
|
|
@@ -7767,9 +8073,9 @@ function QrPanel4({ provision, now, busy, onRefresh, onCancel }) {
|
|
|
7767
8073
|
);
|
|
7768
8074
|
}
|
|
7769
8075
|
function VerificationPanel({ provision, busy, onSubmit, onCancel }) {
|
|
7770
|
-
const [code, setCode] =
|
|
8076
|
+
const [code, setCode] = React17.useState("");
|
|
7771
8077
|
const valid = /^\d{4,8}$/.test(code);
|
|
7772
|
-
|
|
8078
|
+
React17.useEffect(() => setCode(""), [provision.attemptId]);
|
|
7773
8079
|
return h2(
|
|
7774
8080
|
"div",
|
|
7775
8081
|
{ className: "dxw-card dim-surfaceCard" },
|
|
@@ -7867,6 +8173,7 @@ function AccountCard4({
|
|
|
7867
8173
|
removing,
|
|
7868
8174
|
onReconnect,
|
|
7869
8175
|
onWorkspaceSave,
|
|
8176
|
+
onAgentPresetSave,
|
|
7870
8177
|
onRequestRemove,
|
|
7871
8178
|
onConfirmRemove,
|
|
7872
8179
|
onCancelRemove
|
|
@@ -7917,6 +8224,11 @@ function AccountCard4({
|
|
|
7917
8224
|
disabled: Boolean(busy),
|
|
7918
8225
|
onSave: onWorkspaceSave
|
|
7919
8226
|
}),
|
|
8227
|
+
h2(AgentPresetEditor, {
|
|
8228
|
+
agentPreset: account.agentPreset,
|
|
8229
|
+
disabled: Boolean(busy),
|
|
8230
|
+
onSave: onAgentPresetSave
|
|
8231
|
+
}),
|
|
7920
8232
|
h2(
|
|
7921
8233
|
"div",
|
|
7922
8234
|
{ className: "dxw-accountFooter dim-cardFooter" },
|
|
@@ -7975,6 +8287,7 @@ function AccountList2(props) {
|
|
|
7975
8287
|
removing: props.removeTarget === account.botId,
|
|
7976
8288
|
onReconnect: () => props.onReconnect(account),
|
|
7977
8289
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
8290
|
+
onAgentPresetSave: (agentPreset) => props.onAgentPresetSave(account, agentPreset),
|
|
7978
8291
|
onRequestRemove: () => props.onRequestRemove(account),
|
|
7979
8292
|
onConfirmRemove: () => props.onConfirmRemove(account),
|
|
7980
8293
|
onCancelRemove: props.onCancelRemove
|
|
@@ -7993,40 +8306,41 @@ function mergeWeixinProvisioningSnapshot(current, incoming, { restoreProvisionin
|
|
|
7993
8306
|
};
|
|
7994
8307
|
}
|
|
7995
8308
|
function WeixinSettingsTab({ rpcCall }) {
|
|
7996
|
-
const [model, setModel] =
|
|
8309
|
+
const [model, setModel] = React17.useState({
|
|
7997
8310
|
phase: "loading",
|
|
7998
8311
|
bots: [],
|
|
7999
8312
|
totals: EMPTY_TOTALS3,
|
|
8000
8313
|
revision: 0,
|
|
8001
|
-
error: null
|
|
8314
|
+
error: null,
|
|
8315
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
8002
8316
|
});
|
|
8003
|
-
const [provision, setProvision] =
|
|
8004
|
-
const [busy, setBusy] =
|
|
8005
|
-
const [busyByBot, setBusyByBot] =
|
|
8006
|
-
const [feedbackByBot, setFeedbackByBot] =
|
|
8007
|
-
const [removeTarget, setRemoveTarget] =
|
|
8008
|
-
const [notice, setNotice] =
|
|
8009
|
-
const [now, setNow] =
|
|
8010
|
-
const addButtonRef =
|
|
8011
|
-
const mountedRef =
|
|
8317
|
+
const [provision, setProvision] = React17.useState(null);
|
|
8318
|
+
const [busy, setBusy] = React17.useState(false);
|
|
8319
|
+
const [busyByBot, setBusyByBot] = React17.useState({});
|
|
8320
|
+
const [feedbackByBot, setFeedbackByBot] = React17.useState({});
|
|
8321
|
+
const [removeTarget, setRemoveTarget] = React17.useState(null);
|
|
8322
|
+
const [notice, setNotice] = React17.useState("");
|
|
8323
|
+
const [now, setNow] = React17.useState(() => Date.now());
|
|
8324
|
+
const addButtonRef = React17.useRef(null);
|
|
8325
|
+
const mountedRef = React17.useRef(true);
|
|
8012
8326
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
8013
8327
|
const scheduleAnimationFrame = useAnimationFrameScheduler();
|
|
8014
|
-
|
|
8328
|
+
React17.useEffect(() => {
|
|
8015
8329
|
mountedRef.current = true;
|
|
8016
8330
|
return () => {
|
|
8017
8331
|
mountedRef.current = false;
|
|
8018
8332
|
};
|
|
8019
8333
|
}, []);
|
|
8020
|
-
const announce =
|
|
8334
|
+
const announce = React17.useCallback((value) => {
|
|
8021
8335
|
setNotice("");
|
|
8022
8336
|
scheduleAnimationFrame(() => {
|
|
8023
8337
|
if (value) setNotice(value);
|
|
8024
8338
|
}, "announcement");
|
|
8025
8339
|
}, [scheduleAnimationFrame]);
|
|
8026
|
-
const invoke =
|
|
8340
|
+
const invoke = React17.useCallback(async (endpoint, payload = {}, signal) => {
|
|
8027
8341
|
return unwrapRpcResult8(await rpcCall(endpoint, payload, signal));
|
|
8028
8342
|
}, [rpcCall]);
|
|
8029
|
-
const loadStatus =
|
|
8343
|
+
const loadStatus = React17.useCallback(async ({
|
|
8030
8344
|
signal,
|
|
8031
8345
|
silent = false,
|
|
8032
8346
|
restoreProvisioning = false
|
|
@@ -8042,7 +8356,8 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8042
8356
|
bots: snapshot.bots,
|
|
8043
8357
|
totals: snapshot.totals,
|
|
8044
8358
|
revision: snapshot.revision,
|
|
8045
|
-
error: null
|
|
8359
|
+
error: null,
|
|
8360
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
8046
8361
|
});
|
|
8047
8362
|
if (snapshot.provisioning) {
|
|
8048
8363
|
setProvision((current) => mergeWeixinProvisioningSnapshot(
|
|
@@ -8062,12 +8377,12 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8062
8377
|
return void 0;
|
|
8063
8378
|
}
|
|
8064
8379
|
}, [invoke, workspaceFence]);
|
|
8065
|
-
|
|
8380
|
+
React17.useEffect(() => {
|
|
8066
8381
|
const controller = new AbortController();
|
|
8067
8382
|
void loadStatus({ signal: controller.signal, restoreProvisioning: true });
|
|
8068
8383
|
return () => controller.abort();
|
|
8069
8384
|
}, [loadStatus]);
|
|
8070
|
-
|
|
8385
|
+
React17.useEffect(() => {
|
|
8071
8386
|
if (model.phase !== "ready") return void 0;
|
|
8072
8387
|
const controller = new AbortController();
|
|
8073
8388
|
let running = false;
|
|
@@ -8086,12 +8401,12 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8086
8401
|
window.clearInterval(timer);
|
|
8087
8402
|
};
|
|
8088
8403
|
}, [loadStatus, model.phase]);
|
|
8089
|
-
|
|
8404
|
+
React17.useEffect(() => {
|
|
8090
8405
|
if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0;
|
|
8091
8406
|
const timer = window.setInterval(() => setNow(Date.now()), 1e3);
|
|
8092
8407
|
return () => window.clearInterval(timer);
|
|
8093
8408
|
}, [provision?.attemptId, provision?.status]);
|
|
8094
|
-
const startProvisioning =
|
|
8409
|
+
const startProvisioning = React17.useCallback(async ({ replace = false } = {}) => {
|
|
8095
8410
|
setBusy(true);
|
|
8096
8411
|
try {
|
|
8097
8412
|
if (replace && provision?.attemptId) {
|
|
@@ -8112,7 +8427,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8112
8427
|
setBusy(false);
|
|
8113
8428
|
}
|
|
8114
8429
|
}, [announce, invoke, provision?.attemptId]);
|
|
8115
|
-
const cancelProvisioning =
|
|
8430
|
+
const cancelProvisioning = React17.useCallback(async () => {
|
|
8116
8431
|
setBusy(true);
|
|
8117
8432
|
try {
|
|
8118
8433
|
if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) {
|
|
@@ -8127,7 +8442,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8127
8442
|
setBusy(false);
|
|
8128
8443
|
}
|
|
8129
8444
|
}, [announce, invoke, provision?.attemptId, provision?.status, scheduleAnimationFrame]);
|
|
8130
|
-
const submitVerification =
|
|
8445
|
+
const submitVerification = React17.useCallback(async (verifyCode) => {
|
|
8131
8446
|
if (!provision?.attemptId) return;
|
|
8132
8447
|
setBusy(true);
|
|
8133
8448
|
try {
|
|
@@ -8143,7 +8458,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8143
8458
|
setBusy(false);
|
|
8144
8459
|
}
|
|
8145
8460
|
}, [announce, invoke, provision?.attemptId]);
|
|
8146
|
-
|
|
8461
|
+
React17.useEffect(() => {
|
|
8147
8462
|
const attemptId = provision?.attemptId;
|
|
8148
8463
|
if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0;
|
|
8149
8464
|
const controller = new AbortController();
|
|
@@ -8191,7 +8506,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8191
8506
|
controller.abort();
|
|
8192
8507
|
};
|
|
8193
8508
|
}, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]);
|
|
8194
|
-
const setBotBusy =
|
|
8509
|
+
const setBotBusy = React17.useCallback((botId, value) => {
|
|
8195
8510
|
setBusyByBot((current) => {
|
|
8196
8511
|
const next = { ...current };
|
|
8197
8512
|
if (value) next[botId] = value;
|
|
@@ -8199,7 +8514,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8199
8514
|
return next;
|
|
8200
8515
|
});
|
|
8201
8516
|
}, []);
|
|
8202
|
-
const reconnect =
|
|
8517
|
+
const reconnect = React17.useCallback(async (account) => {
|
|
8203
8518
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
8204
8519
|
setBotBusy(account.botId, "reconnect");
|
|
8205
8520
|
setFeedbackByBot((current) => {
|
|
@@ -8213,7 +8528,13 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8213
8528
|
{ botId: account.botId, sendTest: true }
|
|
8214
8529
|
));
|
|
8215
8530
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
8216
|
-
setModel((current) => ({
|
|
8531
|
+
setModel((current) => ({
|
|
8532
|
+
...current,
|
|
8533
|
+
bots: snapshot.bots,
|
|
8534
|
+
totals: snapshot.totals,
|
|
8535
|
+
revision: snapshot.revision,
|
|
8536
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog
|
|
8537
|
+
}));
|
|
8217
8538
|
}
|
|
8218
8539
|
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
|
8219
8540
|
let feedback;
|
|
@@ -8244,7 +8565,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8244
8565
|
setBotBusy(account.botId, null);
|
|
8245
8566
|
}
|
|
8246
8567
|
}, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
8247
|
-
const saveWorkspace =
|
|
8568
|
+
const saveWorkspace = React17.useCallback(async (account, workspace) => {
|
|
8248
8569
|
const workspaceVersion = workspaceFence.beginMutation();
|
|
8249
8570
|
setBotBusy(account.botId, "workspace");
|
|
8250
8571
|
try {
|
|
@@ -8258,7 +8579,32 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8258
8579
|
bots: snapshot.bots,
|
|
8259
8580
|
totals: snapshot.totals,
|
|
8260
8581
|
revision: snapshot.revision,
|
|
8261
|
-
error: null
|
|
8582
|
+
error: null,
|
|
8583
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
8584
|
+
});
|
|
8585
|
+
}
|
|
8586
|
+
} finally {
|
|
8587
|
+
const shouldRefresh = workspaceFence.endMutation();
|
|
8588
|
+
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
8589
|
+
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
8590
|
+
}
|
|
8591
|
+
}, [invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
8592
|
+
const saveAgentPreset = React17.useCallback(async (account, agentPreset) => {
|
|
8593
|
+
const snapshotVersion = workspaceFence.beginMutation();
|
|
8594
|
+
setBotBusy(account.botId, "preset");
|
|
8595
|
+
try {
|
|
8596
|
+
const snapshot = normalizeSnapshot7(await invoke(
|
|
8597
|
+
WEIXIN_ENDPOINTS.setAgentPreset,
|
|
8598
|
+
{ botId: account.botId, agentPreset }
|
|
8599
|
+
));
|
|
8600
|
+
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
8601
|
+
setModel({
|
|
8602
|
+
phase: "ready",
|
|
8603
|
+
bots: snapshot.bots,
|
|
8604
|
+
totals: snapshot.totals,
|
|
8605
|
+
revision: snapshot.revision,
|
|
8606
|
+
error: null,
|
|
8607
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
8262
8608
|
});
|
|
8263
8609
|
}
|
|
8264
8610
|
} finally {
|
|
@@ -8267,7 +8613,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8267
8613
|
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
8268
8614
|
}
|
|
8269
8615
|
}, [invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
8270
|
-
const remove =
|
|
8616
|
+
const remove = React17.useCallback(async (account) => {
|
|
8271
8617
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
8272
8618
|
setBotBusy(account.botId, "delete");
|
|
8273
8619
|
try {
|
|
@@ -8276,7 +8622,13 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8276
8622
|
confirm: true
|
|
8277
8623
|
}));
|
|
8278
8624
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
8279
|
-
setModel((current) => ({
|
|
8625
|
+
setModel((current) => ({
|
|
8626
|
+
...current,
|
|
8627
|
+
bots: snapshot.bots,
|
|
8628
|
+
totals: snapshot.totals,
|
|
8629
|
+
revision: snapshot.revision,
|
|
8630
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? current.agentPresetCatalog
|
|
8631
|
+
}));
|
|
8280
8632
|
}
|
|
8281
8633
|
setRemoveTarget(null);
|
|
8282
8634
|
announce("\u5FAE\u4FE1\u8D26\u53F7\u53CA\u672C\u673A\u51ED\u636E\u5DF2\u79FB\u9664\u3002");
|
|
@@ -8320,7 +8672,9 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8320
8672
|
onClose: () => void cancelProvisioning()
|
|
8321
8673
|
});
|
|
8322
8674
|
}
|
|
8323
|
-
return h2(
|
|
8675
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
8676
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
8677
|
+
}, h2(
|
|
8324
8678
|
"section",
|
|
8325
8679
|
{ className: "dxw-page dim-channelPage", "aria-label": "\u5FAE\u4FE1\u8BBE\u7F6E" },
|
|
8326
8680
|
h2(Heading5, {
|
|
@@ -8343,7 +8697,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8343
8697
|
h2(Button12, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
|
|
8344
8698
|
)
|
|
8345
8699
|
) : h2(
|
|
8346
|
-
|
|
8700
|
+
React17.Fragment,
|
|
8347
8701
|
null,
|
|
8348
8702
|
provisionView,
|
|
8349
8703
|
model.bots.length === 0 && !provision ? h2(EmptyView5, { onStart: () => void startProvisioning(), busy }) : null,
|
|
@@ -8354,12 +8708,13 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
8354
8708
|
removeTarget,
|
|
8355
8709
|
onReconnect: (account) => void reconnect(account),
|
|
8356
8710
|
onWorkspaceSave: saveWorkspace,
|
|
8711
|
+
onAgentPresetSave: saveAgentPreset,
|
|
8357
8712
|
onRequestRemove: (account) => setRemoveTarget(account.botId),
|
|
8358
8713
|
onConfirmRemove: (account) => void remove(account),
|
|
8359
8714
|
onCancelRemove: () => setRemoveTarget(null)
|
|
8360
8715
|
}) : null
|
|
8361
8716
|
)
|
|
8362
|
-
);
|
|
8717
|
+
));
|
|
8363
8718
|
}
|
|
8364
8719
|
|
|
8365
8720
|
// plugin-src/client/channels/whatsapp/api.js
|
|
@@ -8371,7 +8726,8 @@ var WHATSAPP_ENDPOINTS = Object.freeze({
|
|
|
8371
8726
|
cancelProvisioning: "provision.cancel",
|
|
8372
8727
|
reconnectBot: "bot.reconnect",
|
|
8373
8728
|
deleteBot: "bot.delete",
|
|
8374
|
-
setWorkspace: "bot.workspace.set"
|
|
8729
|
+
setWorkspace: "bot.workspace.set",
|
|
8730
|
+
setAgentPreset: SET_AGENT_PRESET_ENDPOINT
|
|
8375
8731
|
});
|
|
8376
8732
|
var PROVISION_STATES5 = /* @__PURE__ */ new Set(["starting", "pending", "connecting", "connected", "failed", "cancelled"]);
|
|
8377
8733
|
var BOT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
@@ -8436,6 +8792,7 @@ function normalizeBot6(value) {
|
|
|
8436
8792
|
connected,
|
|
8437
8793
|
state: connected ? "connected" : state,
|
|
8438
8794
|
workspace: text4(value.workspace, "", 4096),
|
|
8795
|
+
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
8439
8796
|
bot: {
|
|
8440
8797
|
name: text4(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
|
|
8441
8798
|
idMasked: text4(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
|
|
@@ -8460,7 +8817,8 @@ function normalizeSnapshot8(value) {
|
|
|
8460
8817
|
revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
|
|
8461
8818
|
bots,
|
|
8462
8819
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
8463
|
-
provisioning: source.provisioning ? normalizeProvisioning6(source.provisioning) : null
|
|
8820
|
+
provisioning: source.provisioning ? normalizeProvisioning6(source.provisioning) : null,
|
|
8821
|
+
agentPresetCatalog: normalizeAgentPresetCatalog(source.agentPresetCatalog)
|
|
8464
8822
|
};
|
|
8465
8823
|
}
|
|
8466
8824
|
function presentError9(error) {
|
|
@@ -8475,7 +8833,7 @@ function formatRemaining6(milliseconds) {
|
|
|
8475
8833
|
}
|
|
8476
8834
|
|
|
8477
8835
|
// plugin-src/client/channels/whatsapp/index.js
|
|
8478
|
-
var
|
|
8836
|
+
var React18 = __toESM(require("react"), 1);
|
|
8479
8837
|
|
|
8480
8838
|
// plugin-src/client/channels/whatsapp/styles.js
|
|
8481
8839
|
var WHATSAPP_STYLE_ID = "xmanrui-dsh-im-whatsapp-settings";
|
|
@@ -8500,7 +8858,7 @@ function installWhatsappStyles() {
|
|
|
8500
8858
|
|
|
8501
8859
|
// plugin-src/client/channels/whatsapp/index.js
|
|
8502
8860
|
var ACTIVE_STATES3 = /* @__PURE__ */ new Set(["pending", "connecting"]);
|
|
8503
|
-
var Button14 =
|
|
8861
|
+
var Button14 = React18.forwardRef(function Button15({ children, kind = "secondary", className = "", ...props }, ref) {
|
|
8504
8862
|
return h2("button", {
|
|
8505
8863
|
...props,
|
|
8506
8864
|
ref,
|
|
@@ -8722,6 +9080,7 @@ function WhatsappAccountCard({
|
|
|
8722
9080
|
removing,
|
|
8723
9081
|
onReconnect,
|
|
8724
9082
|
onWorkspaceSave,
|
|
9083
|
+
onAgentPresetSave,
|
|
8725
9084
|
onRequestRemove,
|
|
8726
9085
|
onConfirmRemove,
|
|
8727
9086
|
onCancelRemove
|
|
@@ -8781,6 +9140,11 @@ function WhatsappAccountCard({
|
|
|
8781
9140
|
disabled: Boolean(busy),
|
|
8782
9141
|
onSave: onWorkspaceSave
|
|
8783
9142
|
}),
|
|
9143
|
+
h2(AgentPresetEditor, {
|
|
9144
|
+
agentPreset: account.agentPreset,
|
|
9145
|
+
disabled: Boolean(busy),
|
|
9146
|
+
onSave: onAgentPresetSave
|
|
9147
|
+
}),
|
|
8784
9148
|
h2(
|
|
8785
9149
|
"div",
|
|
8786
9150
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
@@ -8815,22 +9179,23 @@ function WhatsappAccountCard({
|
|
|
8815
9179
|
);
|
|
8816
9180
|
}
|
|
8817
9181
|
function WhatsappSettingsTab({ rpcCall }) {
|
|
8818
|
-
const [model, setModel] =
|
|
9182
|
+
const [model, setModel] = React18.useState({
|
|
8819
9183
|
phase: "loading",
|
|
8820
9184
|
bots: [],
|
|
8821
9185
|
totals: { configured: 0, connected: 0 },
|
|
8822
|
-
error: null
|
|
9186
|
+
error: null,
|
|
9187
|
+
agentPresetCatalog: EMPTY_AGENT_PRESET_CATALOG
|
|
8823
9188
|
});
|
|
8824
|
-
const [provision, setProvision] =
|
|
8825
|
-
const [busy, setBusy] =
|
|
8826
|
-
const [busyByBot, setBusyByBot] =
|
|
8827
|
-
const [testNoticeByBot, setTestNoticeByBot] =
|
|
8828
|
-
const [removeTarget, setRemoveTarget] =
|
|
8829
|
-
const [now, setNow] =
|
|
8830
|
-
const mounted =
|
|
9189
|
+
const [provision, setProvision] = React18.useState(null);
|
|
9190
|
+
const [busy, setBusy] = React18.useState(false);
|
|
9191
|
+
const [busyByBot, setBusyByBot] = React18.useState({});
|
|
9192
|
+
const [testNoticeByBot, setTestNoticeByBot] = React18.useState({});
|
|
9193
|
+
const [removeTarget, setRemoveTarget] = React18.useState(null);
|
|
9194
|
+
const [now, setNow] = React18.useState(Date.now());
|
|
9195
|
+
const mounted = React18.useRef(true);
|
|
8831
9196
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
8832
|
-
const addButtonRef =
|
|
8833
|
-
|
|
9197
|
+
const addButtonRef = React18.useRef(null);
|
|
9198
|
+
React18.useEffect(() => {
|
|
8834
9199
|
const disposeDingtalk = installDingtalkStyles();
|
|
8835
9200
|
const disposeWhatsapp = installWhatsappStyles();
|
|
8836
9201
|
mounted.current = true;
|
|
@@ -8840,18 +9205,24 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8840
9205
|
disposeDingtalk();
|
|
8841
9206
|
};
|
|
8842
9207
|
}, []);
|
|
8843
|
-
const invoke =
|
|
9208
|
+
const invoke = React18.useCallback(async (endpoint, payload = {}, signal) => {
|
|
8844
9209
|
if (typeof rpcCall !== "function") throw new TypeError("WhatsApp \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5");
|
|
8845
9210
|
return unwrapRpcResult9(await rpcCall(endpoint, payload, signal));
|
|
8846
9211
|
}, [rpcCall]);
|
|
8847
|
-
const loadStatus =
|
|
9212
|
+
const loadStatus = React18.useCallback(async ({ signal, silent = false, restore = false } = {}) => {
|
|
8848
9213
|
const workspaceVersion = workspaceFence.beginStatus();
|
|
8849
9214
|
if (workspaceVersion === null) return void 0;
|
|
8850
9215
|
if (!silent && mounted.current) setModel((current) => ({ ...current, phase: "loading", error: null }));
|
|
8851
9216
|
try {
|
|
8852
9217
|
const snapshot = normalizeSnapshot8(await invoke(WHATSAPP_ENDPOINTS.status, {}, signal));
|
|
8853
9218
|
if (!mounted.current || signal?.aborted || !workspaceFence.canCommitStatus(workspaceVersion)) return void 0;
|
|
8854
|
-
setModel({
|
|
9219
|
+
setModel({
|
|
9220
|
+
phase: "ready",
|
|
9221
|
+
bots: snapshot.bots,
|
|
9222
|
+
totals: snapshot.totals,
|
|
9223
|
+
error: null,
|
|
9224
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
9225
|
+
});
|
|
8855
9226
|
if (restore && snapshot.provisioning) setProvision({
|
|
8856
9227
|
...snapshot.provisioning,
|
|
8857
9228
|
durationMs: Math.max(1, snapshot.provisioning.expiresAt - Date.now())
|
|
@@ -8868,12 +9239,12 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8868
9239
|
return void 0;
|
|
8869
9240
|
}
|
|
8870
9241
|
}, [invoke, workspaceFence]);
|
|
8871
|
-
|
|
9242
|
+
React18.useEffect(() => {
|
|
8872
9243
|
const controller = new AbortController();
|
|
8873
9244
|
void loadStatus({ signal: controller.signal, restore: true });
|
|
8874
9245
|
return () => controller.abort();
|
|
8875
9246
|
}, [loadStatus]);
|
|
8876
|
-
|
|
9247
|
+
React18.useEffect(() => {
|
|
8877
9248
|
if (model.phase !== "ready") return void 0;
|
|
8878
9249
|
const controller = new AbortController();
|
|
8879
9250
|
const timer = window.setInterval(
|
|
@@ -8885,12 +9256,12 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8885
9256
|
window.clearInterval(timer);
|
|
8886
9257
|
};
|
|
8887
9258
|
}, [loadStatus, model.phase]);
|
|
8888
|
-
|
|
9259
|
+
React18.useEffect(() => {
|
|
8889
9260
|
if (!provision || !ACTIVE_STATES3.has(provision.status)) return void 0;
|
|
8890
9261
|
const timer = window.setInterval(() => mounted.current && setNow(Date.now()), 1e3);
|
|
8891
9262
|
return () => window.clearInterval(timer);
|
|
8892
9263
|
}, [provision?.attemptId, provision?.status]);
|
|
8893
|
-
const startProvisioning =
|
|
9264
|
+
const startProvisioning = React18.useCallback(async (replace = false) => {
|
|
8894
9265
|
setBusy(true);
|
|
8895
9266
|
try {
|
|
8896
9267
|
if (replace && provision?.attemptId) {
|
|
@@ -8908,7 +9279,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8908
9279
|
if (mounted.current) setBusy(false);
|
|
8909
9280
|
}
|
|
8910
9281
|
}, [invoke, provision?.attemptId]);
|
|
8911
|
-
const closeProvision =
|
|
9282
|
+
const closeProvision = React18.useCallback(async () => {
|
|
8912
9283
|
setBusy(true);
|
|
8913
9284
|
try {
|
|
8914
9285
|
if (provision?.attemptId && ACTIVE_STATES3.has(provision.status)) {
|
|
@@ -8919,7 +9290,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8919
9290
|
if (mounted.current) setBusy(false);
|
|
8920
9291
|
}
|
|
8921
9292
|
}, [invoke, provision?.attemptId, provision?.status]);
|
|
8922
|
-
|
|
9293
|
+
React18.useEffect(() => {
|
|
8923
9294
|
const attemptId = provision?.attemptId;
|
|
8924
9295
|
if (!attemptId || !ACTIVE_STATES3.has(provision.status)) return void 0;
|
|
8925
9296
|
const controller = new AbortController();
|
|
@@ -8960,7 +9331,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8960
9331
|
if (timer) window.clearTimeout(timer);
|
|
8961
9332
|
};
|
|
8962
9333
|
}, [invoke, loadStatus, provision?.attemptId, provision?.status]);
|
|
8963
|
-
const botAction =
|
|
9334
|
+
const botAction = React18.useCallback(async (account, operation, endpoint, payload) => {
|
|
8964
9335
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
8965
9336
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
8966
9337
|
if (operation === "reconnect") {
|
|
@@ -8974,7 +9345,13 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
8974
9345
|
const value = await invoke(endpoint, payload);
|
|
8975
9346
|
const snapshot = normalizeSnapshot8(value);
|
|
8976
9347
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
8977
|
-
setModel({
|
|
9348
|
+
setModel({
|
|
9349
|
+
phase: "ready",
|
|
9350
|
+
bots: snapshot.bots,
|
|
9351
|
+
totals: snapshot.totals,
|
|
9352
|
+
error: null,
|
|
9353
|
+
agentPresetCatalog: snapshot.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
9354
|
+
});
|
|
8978
9355
|
if (operation === "reconnect") {
|
|
8979
9356
|
setTestNoticeByBot((current) => ({
|
|
8980
9357
|
...current,
|
|
@@ -9025,6 +9402,12 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
9025
9402
|
WHATSAPP_ENDPOINTS.setWorkspace,
|
|
9026
9403
|
{ botId: account.botId, workspace }
|
|
9027
9404
|
),
|
|
9405
|
+
onAgentPresetSave: (agentPreset) => botAction(
|
|
9406
|
+
account,
|
|
9407
|
+
"preset",
|
|
9408
|
+
WHATSAPP_ENDPOINTS.setAgentPreset,
|
|
9409
|
+
{ botId: account.botId, agentPreset }
|
|
9410
|
+
),
|
|
9028
9411
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
9029
9412
|
onCancelRemove: () => setRemoveTarget(null),
|
|
9030
9413
|
onConfirmRemove: async () => {
|
|
@@ -9036,7 +9419,9 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
9036
9419
|
}
|
|
9037
9420
|
}))))
|
|
9038
9421
|
) : null;
|
|
9039
|
-
return h2(
|
|
9422
|
+
return h2(AgentPresetCatalogContext.Provider, {
|
|
9423
|
+
value: model.agentPresetCatalog ?? EMPTY_AGENT_PRESET_CATALOG
|
|
9424
|
+
}, h2(
|
|
9040
9425
|
"section",
|
|
9041
9426
|
{
|
|
9042
9427
|
className: "ddt-page dwa-page dim-channelPage",
|
|
@@ -9059,7 +9444,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
9059
9444
|
h2(Button14, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6")
|
|
9060
9445
|
)
|
|
9061
9446
|
) : h2(
|
|
9062
|
-
|
|
9447
|
+
React18.Fragment,
|
|
9063
9448
|
null,
|
|
9064
9449
|
provision?.status === "pending" ? h2(QrPanel5, {
|
|
9065
9450
|
provision,
|
|
@@ -9075,7 +9460,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
9075
9460
|
}) : model.bots.length === 0 ? h2(EmptyView6, { busy, onStart: () => void startProvisioning(false) }) : null,
|
|
9076
9461
|
botList
|
|
9077
9462
|
)
|
|
9078
|
-
);
|
|
9463
|
+
));
|
|
9079
9464
|
}
|
|
9080
9465
|
|
|
9081
9466
|
// plugin-src/client/styles.js
|
|
@@ -9222,6 +9607,14 @@ var CSS11 = String.raw`
|
|
|
9222
9607
|
.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; }
|
|
9223
9608
|
.dim-panel .dim-workspaceEdit:disabled { cursor: not-allowed; opacity: .55; }
|
|
9224
9609
|
.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; }
|
|
9610
|
+
.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); }
|
|
9611
|
+
.dim-panel .dim-presetHeader { display: contents; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: normal; }
|
|
9612
|
+
.dim-panel .dim-presetHeader > span { grid-column: 1; grid-row: 1; white-space: nowrap; }
|
|
9613
|
+
.dim-panel .dim-presetStatus { grid-column: 2; grid-row: 1; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; white-space: nowrap; }
|
|
9614
|
+
.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; }
|
|
9615
|
+
.dim-panel .dim-presetSelect:disabled { cursor: not-allowed; opacity: .55; }
|
|
9616
|
+
.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; }
|
|
9617
|
+
.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; }
|
|
9225
9618
|
.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); }
|
|
9226
9619
|
.dim-directoryPickerBackdrop, .dim-directoryPickerBackdrop *, .dim-directoryPickerBackdrop *::before, .dim-directoryPickerBackdrop *::after { box-sizing: border-box; }
|
|
9227
9620
|
.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%); }
|
|
@@ -9452,8 +9845,8 @@ function IMSettingsTab({
|
|
|
9452
9845
|
officeRpcCall,
|
|
9453
9846
|
workspaceDirectoryPicker
|
|
9454
9847
|
}) {
|
|
9455
|
-
const [selected, setSelected] =
|
|
9456
|
-
const githubTooltipId =
|
|
9848
|
+
const [selected, setSelected] = React19.useState("weixin");
|
|
9849
|
+
const githubTooltipId = React19.useId();
|
|
9457
9850
|
const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
|
|
9458
9851
|
return h2(
|
|
9459
9852
|
WorkspaceDirectoryPickerContext.Provider,
|