@xmanrui/dsh-im 0.9.0 → 0.11.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 +7 -3
- package/README.md +7 -3
- package/lib/client.js +378 -27
- package/lib/index.js +134 -131
- package/package.json +1 -1
- package/plugin-src/client/channels/dingtalk/api.js +19 -0
- package/plugin-src/client/channels/dingtalk/index.js +67 -10
- package/plugin-src/client/channels/feishu/index.js +35 -5
- package/plugin-src/client/channels/qq/api.js +21 -0
- package/plugin-src/client/channels/qq/index.js +39 -1
- package/plugin-src/client/channels/shared/token-channel.js +29 -3
- package/plugin-src/client/channels/wecom/api.js +11 -0
- package/plugin-src/client/channels/wecom/index.js +71 -1
- package/plugin-src/client/channels/weixin/api.js +11 -0
- package/plugin-src/client/channels/weixin/index.js +40 -4
- package/plugin-src/client/channels/whatsapp/index.js +41 -2
- package/plugin-src/client/i18n.js +13 -0
- package/plugin-src/host/channels/dingtalk/production.mjs +1 -1
- package/plugin-src/host/channels/dingtalk/rpc.mjs +29 -3
- package/plugin-src/host/channels/feishu/production.mjs +1 -1
- package/plugin-src/host/channels/feishu/rpc.mjs +34 -3
- package/plugin-src/host/channels/qq/production.mjs +1 -1
- package/plugin-src/host/channels/qq/rpc.mjs +35 -2
- package/plugin-src/host/channels/shared/production.mjs +1 -1
- package/plugin-src/host/channels/shared/rpc.mjs +25 -1
- package/plugin-src/host/channels/slack/production.mjs +1 -1
- package/plugin-src/host/channels/slack/rpc.mjs +28 -2
- package/plugin-src/host/channels/wecom/production.mjs +1 -1
- package/plugin-src/host/channels/wecom/rpc.mjs +31 -2
- package/plugin-src/host/channels/weixin/production.mjs +1 -1
- package/plugin-src/host/channels/weixin/rpc.mjs +29 -3
- package/plugin-src/host/channels/whatsapp/production.mjs +1 -1
- package/plugin-src/host/channels/whatsapp/rpc.mjs +31 -3
- package/src/channels/dingtalk/dingtalk-api.mjs +82 -1
- package/src/channels/dingtalk/dingtalk-bridge.mjs +160 -20
- package/src/channels/dingtalk/dingtalk-controller.mjs +18 -0
- package/src/channels/dingtalk/dingtalk-runtime.mjs +21 -0
- package/src/channels/discord/discord-api.mjs +1 -1
- package/src/channels/discord/discord-runtime.mjs +54 -1
- package/src/channels/feishu/bridge.mjs +45 -18
- package/src/channels/feishu/feishu-runtime.mjs +45 -0
- package/src/channels/feishu/message-utils.mjs +227 -6
- package/src/channels/feishu/multi-bot-controller.mjs +21 -0
- package/src/channels/feishu/plugin-controller.mjs +1 -0
- package/src/channels/qq/qq-bridge.mjs +107 -20
- package/src/channels/qq/qq-controller.mjs +18 -0
- package/src/channels/qq/qq-runtime.mjs +26 -0
- package/src/channels/shared/bot-workspace-store.mjs +2 -0
- package/src/channels/shared/connection-test.mjs +54 -0
- package/src/channels/shared/harness-client.mjs +14 -8
- package/src/channels/shared/image-prompt.mjs +268 -0
- package/src/channels/shared/text-harness-bridge.mjs +62 -16
- package/src/channels/shared/token-bot-controller.mjs +21 -0
- package/src/channels/shared/workspace-session.mjs +2 -1
- package/src/channels/slack/manifest.mjs +1 -0
- package/src/channels/slack/slack-api.mjs +95 -0
- package/src/channels/slack/slack-controller.mjs +19 -0
- package/src/channels/slack/slack-runtime.mjs +34 -3
- package/src/channels/telegram/telegram-api.mjs +37 -0
- package/src/channels/telegram/telegram-runtime.mjs +81 -9
- package/src/channels/wecom/wecom-bridge.mjs +160 -23
- package/src/channels/wecom/wecom-controller.mjs +18 -0
- package/src/channels/wecom/wecom-runtime.mjs +18 -0
- package/src/channels/weixin/weixin-api.mjs +98 -2
- package/src/channels/weixin/weixin-bridge.mjs +52 -19
- package/src/channels/weixin/weixin-controller.mjs +18 -0
- package/src/channels/weixin/weixin-runtime.mjs +25 -0
- package/src/channels/whatsapp/whatsapp-controller.mjs +20 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +160 -1
package/lib/client.js
CHANGED
|
@@ -246,6 +246,13 @@ function normalizeError(value, fallbackCode, fallbackMessage) {
|
|
|
246
246
|
message: sanitizeMessage(value.message, fallbackMessage)
|
|
247
247
|
};
|
|
248
248
|
}
|
|
249
|
+
function normalizeTestMessage(value) {
|
|
250
|
+
if (!isRecord(value)) return null;
|
|
251
|
+
if (value.sent === true) return { sent: true };
|
|
252
|
+
if (value.sent !== false) return null;
|
|
253
|
+
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
|
|
254
|
+
return { sent: false, code };
|
|
255
|
+
}
|
|
249
256
|
function unwrapRpcResult(result) {
|
|
250
257
|
if (!isRecord(result) || typeof result.ok !== "boolean") {
|
|
251
258
|
throw new Error("\u9489\u9489\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
|
@@ -340,9 +347,17 @@ function normalizeSnapshot(value) {
|
|
|
340
347
|
configured: bots.length,
|
|
341
348
|
connected: bots.filter((bot) => bot.connected).length
|
|
342
349
|
},
|
|
343
|
-
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null
|
|
350
|
+
provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null,
|
|
351
|
+
testMessage: normalizeTestMessage(source.testMessage)
|
|
344
352
|
};
|
|
345
353
|
}
|
|
354
|
+
function connectionTestFeedback(result) {
|
|
355
|
+
if (result?.sent === true) return "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
|
|
356
|
+
if (result?.code === "test-target-unavailable") {
|
|
357
|
+
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";
|
|
358
|
+
}
|
|
359
|
+
return result ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
360
|
+
}
|
|
346
361
|
function presentError(error) {
|
|
347
362
|
return {
|
|
348
363
|
code: safeErrorCode(error?.code, "DINGTALK_ERROR"),
|
|
@@ -436,6 +451,19 @@ var EN = Object.freeze({
|
|
|
436
451
|
"\u521A\u521A": "Just now",
|
|
437
452
|
"\u68C0\u67E5\u8FDE\u63A5": "Check connection",
|
|
438
453
|
"\u68C0\u67E5\u4E2D\u2026": "Checking\u2026",
|
|
454
|
+
"\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "Connection check failed. Try again later.",
|
|
455
|
+
"\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u5BF9\u5E94\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002": "Test message sent. Check the matching bot conversation.",
|
|
456
|
+
"\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": "Connection check completed. The bot has not received a direct message it can use for testing.",
|
|
457
|
+
"\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002": "Connection check completed, but the test message could not be sent.",
|
|
458
|
+
"\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u98DE\u4E66\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002": "Test message sent. Check the Feishu conversation.",
|
|
459
|
+
"\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230 WhatsApp \u81EA\u804A\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002": "Test message sent. Check the WhatsApp self-chat.",
|
|
460
|
+
"\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684 WhatsApp \u81EA\u804A\u76EE\u6807\u3002": "Connection check completed, but no WhatsApp self-chat target is available.",
|
|
461
|
+
"\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002": "DingTalk connection check completed and the test message was sent.",
|
|
462
|
+
"\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002": "DingTalk connection check completed, but the test message could not be sent.",
|
|
463
|
+
"\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002": "WeChat connection check completed and the test message was sent.",
|
|
464
|
+
"\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002": "WeChat connection check completed, but the test message could not be sent.",
|
|
465
|
+
"\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002": "WeCom connection check completed and the test message was sent.",
|
|
466
|
+
"\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002": "WeCom connection check completed, but the test message could not be sent.",
|
|
439
467
|
"\u91CD\u8BD5\u8FDE\u63A5": "Reconnect",
|
|
440
468
|
"\u91CD\u8BD5\u4E2D\u2026": "Retrying\u2026",
|
|
441
469
|
"\u79FB\u9664\u63A5\u5165": "Remove connection",
|
|
@@ -1735,6 +1763,7 @@ function RemoveConfirmation({ account, busy, onConfirm, onCancel }) {
|
|
|
1735
1763
|
function AccountCard({
|
|
1736
1764
|
account,
|
|
1737
1765
|
busy,
|
|
1766
|
+
feedback,
|
|
1738
1767
|
removing,
|
|
1739
1768
|
onReconnect,
|
|
1740
1769
|
onWorkspaceSave,
|
|
@@ -1798,6 +1827,10 @@ function AccountCard({
|
|
|
1798
1827
|
"div",
|
|
1799
1828
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
1800
1829
|
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
|
|
1830
|
+
feedback ? h2("div", {
|
|
1831
|
+
className: "ddt-summary dim-cardSummary",
|
|
1832
|
+
role: "status"
|
|
1833
|
+
}, feedback) : null,
|
|
1801
1834
|
h2(
|
|
1802
1835
|
"div",
|
|
1803
1836
|
{ className: "ddt-actions dim-cardActions" },
|
|
@@ -1837,6 +1870,7 @@ function AccountList(props) {
|
|
|
1837
1870
|
h2(AccountCard, {
|
|
1838
1871
|
account,
|
|
1839
1872
|
busy: props.busyByBot[account.botId],
|
|
1873
|
+
feedback: props.feedbackByBot[account.botId]?.message,
|
|
1840
1874
|
removing: props.removeTarget === account.botId,
|
|
1841
1875
|
onReconnect: () => props.onReconnect(account),
|
|
1842
1876
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
@@ -1859,6 +1893,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
1859
1893
|
const [provision, setProvision] = React7.useState(null);
|
|
1860
1894
|
const [busy, setBusy] = React7.useState(false);
|
|
1861
1895
|
const [busyByBot, setBusyByBot] = React7.useState({});
|
|
1896
|
+
const [feedbackByBot, setFeedbackByBot] = React7.useState({});
|
|
1862
1897
|
const [removeTarget, setRemoveTarget] = React7.useState(null);
|
|
1863
1898
|
const [credentialOpen, setCredentialOpen] = React7.useState(false);
|
|
1864
1899
|
const [credentialError, setCredentialError] = React7.useState(null);
|
|
@@ -1900,6 +1935,21 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
1900
1935
|
});
|
|
1901
1936
|
}
|
|
1902
1937
|
}, []);
|
|
1938
|
+
const discardStaleFeedback = React7.useCallback((snapshot) => {
|
|
1939
|
+
const botsById = new Map(snapshot.bots.map((bot) => [bot.botId, bot]));
|
|
1940
|
+
setFeedbackByBot((current) => {
|
|
1941
|
+
let changed = false;
|
|
1942
|
+
const next = { ...current };
|
|
1943
|
+
for (const [botId, feedback] of Object.entries(next)) {
|
|
1944
|
+
const bot = botsById.get(botId);
|
|
1945
|
+
if (!bot || feedback.clearWhenDisconnected && (!bot.connected || bot.error)) {
|
|
1946
|
+
delete next[botId];
|
|
1947
|
+
changed = true;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
return changed ? next : current;
|
|
1951
|
+
});
|
|
1952
|
+
}, []);
|
|
1903
1953
|
const focusAddButton = React7.useCallback(() => {
|
|
1904
1954
|
if (!mountedRef.current) return;
|
|
1905
1955
|
if (focusFrameRef.current !== null) window.cancelAnimationFrame(focusFrameRef.current);
|
|
@@ -1936,6 +1986,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
1936
1986
|
revision: snapshot.revision,
|
|
1937
1987
|
error: null
|
|
1938
1988
|
});
|
|
1989
|
+
discardStaleFeedback(snapshot);
|
|
1939
1990
|
if (restoreProvisioning && snapshot.provisioning) {
|
|
1940
1991
|
setProvision((current) => !current || current.attemptId === snapshot.provisioning.attemptId ? {
|
|
1941
1992
|
...current,
|
|
@@ -1953,7 +2004,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
1953
2004
|
}));
|
|
1954
2005
|
return void 0;
|
|
1955
2006
|
}
|
|
1956
|
-
}, [invoke, workspaceFence]);
|
|
2007
|
+
}, [discardStaleFeedback, invoke, workspaceFence]);
|
|
1957
2008
|
React7.useEffect(() => {
|
|
1958
2009
|
const controller = new AbortController();
|
|
1959
2010
|
void loadStatus({ signal: controller.signal, restoreProvisioning: true });
|
|
@@ -2042,6 +2093,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2042
2093
|
revision: snapshot.revision,
|
|
2043
2094
|
error: null
|
|
2044
2095
|
});
|
|
2096
|
+
discardStaleFeedback(snapshot);
|
|
2045
2097
|
}
|
|
2046
2098
|
setCredentialOpen(false);
|
|
2047
2099
|
announce("\u9489\u9489\u673A\u5668\u4EBA\u51ED\u636E\u5DF2\u7ED1\u5B9A\u3002");
|
|
@@ -2052,7 +2104,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2052
2104
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
2053
2105
|
if (mountedRef.current) setBusy(false);
|
|
2054
2106
|
}
|
|
2055
|
-
}, [announce, invoke, loadStatus, workspaceFence]);
|
|
2107
|
+
}, [announce, discardStaleFeedback, invoke, loadStatus, workspaceFence]);
|
|
2056
2108
|
const cancelProvisioning = React7.useCallback(async () => {
|
|
2057
2109
|
if (!mountedRef.current) return;
|
|
2058
2110
|
setBusy(true);
|
|
@@ -2143,6 +2195,13 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2143
2195
|
if (!mountedRef.current) return void 0;
|
|
2144
2196
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2145
2197
|
setBotBusy(account.botId, operation);
|
|
2198
|
+
if (operation === "reconnect") {
|
|
2199
|
+
setFeedbackByBot((current) => {
|
|
2200
|
+
const next = { ...current };
|
|
2201
|
+
delete next[account.botId];
|
|
2202
|
+
return next;
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2146
2205
|
try {
|
|
2147
2206
|
const snapshot = normalizeSnapshot(await invoke(endpoint, payload));
|
|
2148
2207
|
if (!mountedRef.current) return void 0;
|
|
@@ -2154,25 +2213,47 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2154
2213
|
revision: snapshot.revision,
|
|
2155
2214
|
error: null
|
|
2156
2215
|
});
|
|
2216
|
+
discardStaleFeedback(snapshot);
|
|
2157
2217
|
}
|
|
2158
|
-
|
|
2218
|
+
const successMessage = typeof success === "function" ? success(snapshot) : success;
|
|
2219
|
+
if (operation === "reconnect") {
|
|
2220
|
+
setFeedbackByBot((current) => ({
|
|
2221
|
+
...current,
|
|
2222
|
+
[account.botId]: {
|
|
2223
|
+
message: successMessage,
|
|
2224
|
+
clearWhenDisconnected: snapshot.testMessage?.sent === true
|
|
2225
|
+
}
|
|
2226
|
+
}));
|
|
2227
|
+
}
|
|
2228
|
+
announce(successMessage);
|
|
2159
2229
|
return snapshot;
|
|
2160
2230
|
} catch (error) {
|
|
2161
2231
|
if (!mountedRef.current) return void 0;
|
|
2162
|
-
|
|
2232
|
+
const failureMessage = operation === "reconnect" ? "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" : `\u64CD\u4F5C\u5931\u8D25\uFF1A${presentError(error).message}`;
|
|
2233
|
+
if (operation === "reconnect") {
|
|
2234
|
+
setFeedbackByBot((current) => ({
|
|
2235
|
+
...current,
|
|
2236
|
+
[account.botId]: { message: failureMessage, clearWhenDisconnected: false }
|
|
2237
|
+
}));
|
|
2238
|
+
}
|
|
2239
|
+
announce(failureMessage);
|
|
2163
2240
|
return void 0;
|
|
2164
2241
|
} finally {
|
|
2165
2242
|
const shouldRefresh = workspaceFence.endMutation();
|
|
2166
2243
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true, restoreProvisioning: false });
|
|
2167
2244
|
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
2168
2245
|
}
|
|
2169
|
-
}, [announce, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2246
|
+
}, [announce, discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2170
2247
|
const reconnect = React7.useCallback((account) => runBotAction({
|
|
2171
2248
|
account,
|
|
2172
2249
|
operation: "reconnect",
|
|
2173
2250
|
endpoint: DINGTALK_ENDPOINTS.reconnectBot,
|
|
2174
|
-
payload: { botId: account.botId },
|
|
2175
|
-
success: (snapshot) =>
|
|
2251
|
+
payload: { botId: account.botId, sendTest: true },
|
|
2252
|
+
success: (snapshot) => {
|
|
2253
|
+
const refreshed = snapshot?.bots.find((bot) => bot.botId === account.botId);
|
|
2254
|
+
if (!refreshed?.connected) return "\u9489\u9489\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002";
|
|
2255
|
+
return connectionTestFeedback(snapshot.testMessage) ?? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
|
|
2256
|
+
}
|
|
2176
2257
|
}), [runBotAction]);
|
|
2177
2258
|
const saveWorkspace = React7.useCallback(async (account, workspace) => {
|
|
2178
2259
|
const workspaceVersion = workspaceFence.beginMutation();
|
|
@@ -2190,13 +2271,14 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2190
2271
|
revision: snapshot.revision,
|
|
2191
2272
|
error: null
|
|
2192
2273
|
});
|
|
2274
|
+
discardStaleFeedback(snapshot);
|
|
2193
2275
|
}
|
|
2194
2276
|
} finally {
|
|
2195
2277
|
const shouldRefresh = workspaceFence.endMutation();
|
|
2196
2278
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
2197
2279
|
if (mountedRef.current) setBotBusy(account.botId, null);
|
|
2198
2280
|
}
|
|
2199
|
-
}, [invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2281
|
+
}, [discardStaleFeedback, invoke, loadStatus, setBotBusy, workspaceFence]);
|
|
2200
2282
|
const remove = React7.useCallback(async (account) => {
|
|
2201
2283
|
const snapshot = await runBotAction({
|
|
2202
2284
|
account,
|
|
@@ -2287,6 +2369,7 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|
|
2287
2369
|
model.bots.length > 0 ? h2(AccountList, {
|
|
2288
2370
|
bots: model.bots,
|
|
2289
2371
|
busyByBot,
|
|
2372
|
+
feedbackByBot,
|
|
2290
2373
|
removeTarget,
|
|
2291
2374
|
onReconnect: (account) => void reconnect(account),
|
|
2292
2375
|
onWorkspaceSave: saveWorkspace,
|
|
@@ -2411,6 +2494,13 @@ function checkedTime2(value) {
|
|
|
2411
2494
|
return "\u521A\u521A";
|
|
2412
2495
|
}
|
|
2413
2496
|
}
|
|
2497
|
+
function connectionTestNotice(value) {
|
|
2498
|
+
if (value?.testMessage?.sent === true) return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u5BF9\u5E94\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
|
|
2499
|
+
if (value?.testMessage?.code === "test-target-unavailable") {
|
|
2500
|
+
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";
|
|
2501
|
+
}
|
|
2502
|
+
return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
2503
|
+
}
|
|
2414
2504
|
function createTokenChannelSettings(definition) {
|
|
2415
2505
|
const {
|
|
2416
2506
|
channel: channel4,
|
|
@@ -2433,7 +2523,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2433
2523
|
credentialNoun = "Bot Token",
|
|
2434
2524
|
emptyActionLabel = "\u586B\u5199 Bot Token"
|
|
2435
2525
|
} = definition;
|
|
2436
|
-
function AccountCard5({ account, busy, removing, onReconnect, onWorkspaceSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
2526
|
+
function AccountCard5({ account, busy, testNotice, removing, onReconnect, onWorkspaceSave, onRequestRemove, onConfirmRemove, onCancelRemove }) {
|
|
2437
2527
|
const state = busy === "reconnect" ? "connecting" : account.state;
|
|
2438
2528
|
const tone = account.connected ? "success" : state === "error" ? "error" : "warning";
|
|
2439
2529
|
const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA";
|
|
@@ -2495,6 +2585,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2495
2585
|
"div",
|
|
2496
2586
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
2497
2587
|
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
|
|
2588
|
+
testNotice ? h2("div", { className: "ddt-summary dim-cardSummary", role: "status" }, testNotice) : null,
|
|
2498
2589
|
h2(
|
|
2499
2590
|
"div",
|
|
2500
2591
|
{ className: "ddt-actions dim-cardActions" },
|
|
@@ -2541,6 +2632,7 @@ function createTokenChannelSettings(definition) {
|
|
|
2541
2632
|
const [credentialError, setCredentialError] = React8.useState(null);
|
|
2542
2633
|
const [busy, setBusy] = React8.useState(false);
|
|
2543
2634
|
const [busyByBot, setBusyByBot] = React8.useState({});
|
|
2635
|
+
const [testNoticeByBot, setTestNoticeByBot] = React8.useState({});
|
|
2544
2636
|
const [removeTarget, setRemoveTarget] = React8.useState(null);
|
|
2545
2637
|
const mounted = React8.useRef(true);
|
|
2546
2638
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
@@ -2619,10 +2711,25 @@ function createTokenChannelSettings(definition) {
|
|
|
2619
2711
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
2620
2712
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
2621
2713
|
try {
|
|
2622
|
-
const
|
|
2714
|
+
const value = await invoke(endpoint, payload);
|
|
2715
|
+
const snapshot = api4.normalizeSnapshot(value);
|
|
2623
2716
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
2624
2717
|
setModel({ phase: "ready", bots: snapshot.bots, totals: snapshot.totals, error: null });
|
|
2625
2718
|
}
|
|
2719
|
+
if (mounted.current && operation === "reconnect") {
|
|
2720
|
+
setTestNoticeByBot((current) => ({
|
|
2721
|
+
...current,
|
|
2722
|
+
[account.botId]: connectionTestNotice(value)
|
|
2723
|
+
}));
|
|
2724
|
+
}
|
|
2725
|
+
} catch (error) {
|
|
2726
|
+
if (operation !== "reconnect") throw error;
|
|
2727
|
+
if (mounted.current) {
|
|
2728
|
+
setTestNoticeByBot((current) => ({
|
|
2729
|
+
...current,
|
|
2730
|
+
[account.botId]: "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
|
|
2731
|
+
}));
|
|
2732
|
+
}
|
|
2626
2733
|
} finally {
|
|
2627
2734
|
const shouldRefresh = workspaceFence.endMutation();
|
|
2628
2735
|
if (shouldRefresh && mounted.current) void loadStatus({ silent: true });
|
|
@@ -2644,12 +2751,13 @@ function createTokenChannelSettings(definition) {
|
|
|
2644
2751
|
h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard5, {
|
|
2645
2752
|
account,
|
|
2646
2753
|
busy: busyByBot[account.botId],
|
|
2754
|
+
testNotice: testNoticeByBot[account.botId],
|
|
2647
2755
|
removing: removeTarget === account.botId,
|
|
2648
2756
|
onReconnect: () => void botAction(
|
|
2649
2757
|
account,
|
|
2650
2758
|
"reconnect",
|
|
2651
2759
|
endpoints.reconnectBot,
|
|
2652
|
-
{ botId: account.botId }
|
|
2760
|
+
{ botId: account.botId, sendTest: true }
|
|
2653
2761
|
),
|
|
2654
2762
|
onWorkspaceSave: (workspace) => botAction(
|
|
2655
2763
|
account,
|
|
@@ -3946,6 +4054,15 @@ function formatCheckedTime(timestamp7) {
|
|
|
3946
4054
|
return "\u521A\u521A";
|
|
3947
4055
|
}
|
|
3948
4056
|
}
|
|
4057
|
+
function connectionTestNotice2(value) {
|
|
4058
|
+
if (value?.testMessage?.sent === true) {
|
|
4059
|
+
return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u98DE\u4E66\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
|
|
4060
|
+
}
|
|
4061
|
+
if (value?.testMessage?.code === "test-target-unavailable") {
|
|
4062
|
+
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";
|
|
4063
|
+
}
|
|
4064
|
+
return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
4065
|
+
}
|
|
3949
4066
|
function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) {
|
|
3950
4067
|
const cancelRef = React10.useRef(null);
|
|
3951
4068
|
const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
@@ -3988,6 +4105,7 @@ function BotCard({
|
|
|
3988
4105
|
connection,
|
|
3989
4106
|
busy,
|
|
3990
4107
|
actionError,
|
|
4108
|
+
testNotice,
|
|
3991
4109
|
removing,
|
|
3992
4110
|
onReconnect,
|
|
3993
4111
|
onWorkspaceSave,
|
|
@@ -4068,6 +4186,10 @@ function BotCard({
|
|
|
4068
4186
|
{ className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
|
|
4069
4187
|
summary
|
|
4070
4188
|
) : null,
|
|
4189
|
+
testNotice ? h2("div", {
|
|
4190
|
+
className: "bxf-healthSummary dim-cardSummary",
|
|
4191
|
+
role: "status"
|
|
4192
|
+
}, testNotice) : null,
|
|
4071
4193
|
h2(
|
|
4072
4194
|
"div",
|
|
4073
4195
|
{ className: "bxf-actions bxf-botActions dim-cardActions" },
|
|
@@ -4116,6 +4238,7 @@ function BotList(props) {
|
|
|
4116
4238
|
connection: bot,
|
|
4117
4239
|
busy: props.busyByBot[bot.botId],
|
|
4118
4240
|
actionError: props.errorsByBot[bot.botId],
|
|
4241
|
+
testNotice: props.testNoticesByBot[bot.botId],
|
|
4119
4242
|
removing: props.removeTargetId === bot.botId,
|
|
4120
4243
|
onReconnect: () => props.onReconnect(bot),
|
|
4121
4244
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(bot, workspace),
|
|
@@ -4195,6 +4318,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4195
4318
|
const [credentialError, setCredentialError] = React10.useState(null);
|
|
4196
4319
|
const [busyByBot, setBusyByBot] = React10.useState({});
|
|
4197
4320
|
const [errorsByBot, setErrorsByBot] = React10.useState({});
|
|
4321
|
+
const [testNoticesByBot, setTestNoticesByBot] = React10.useState({});
|
|
4198
4322
|
const [removeTargetId, setRemoveTargetId] = React10.useState(null);
|
|
4199
4323
|
const [announcement, setAnnouncement] = React10.useState("");
|
|
4200
4324
|
const [now, setNow] = React10.useState(() => Date.now());
|
|
@@ -4460,8 +4584,14 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4460
4584
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
4461
4585
|
setBotBusy(botId, "reconnect");
|
|
4462
4586
|
setBotError(botId, null);
|
|
4587
|
+
setTestNoticesByBot((current) => {
|
|
4588
|
+
const next = { ...current };
|
|
4589
|
+
delete next[botId];
|
|
4590
|
+
return next;
|
|
4591
|
+
});
|
|
4463
4592
|
try {
|
|
4464
|
-
const
|
|
4593
|
+
const value = await invoke(FEISHU_ENDPOINTS.reconnectBot, { botId, sendTest: true });
|
|
4594
|
+
const snapshot = normalizeBotsSnapshot(value);
|
|
4465
4595
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
4466
4596
|
mergeSnapshot(snapshot);
|
|
4467
4597
|
}
|
|
@@ -4473,10 +4603,16 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4473
4603
|
error.code = refreshed?.error?.code ?? "FEISHU_BOT_OFFLINE";
|
|
4474
4604
|
throw error;
|
|
4475
4605
|
}
|
|
4476
|
-
|
|
4606
|
+
const testNotice = connectionTestNotice2(value);
|
|
4607
|
+
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
4608
|
+
setTestNoticesByBot((current) => ({ ...current, [botId]: testNotice }));
|
|
4609
|
+
}
|
|
4610
|
+
announce(testNotice ?? (connection.connected ? `${bot.name}\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002` : `${bot.name}\u5DF2\u91CD\u65B0\u8FDE\u63A5\u3002`));
|
|
4477
4611
|
} catch (error) {
|
|
4478
|
-
|
|
4479
|
-
|
|
4612
|
+
const failure = new Error("\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
|
|
4613
|
+
failure.code = error?.code;
|
|
4614
|
+
setBotError(botId, failure);
|
|
4615
|
+
announce(failure.message);
|
|
4480
4616
|
} finally {
|
|
4481
4617
|
const shouldRefresh = workspaceFence.endMutation();
|
|
4482
4618
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
@@ -4625,6 +4761,7 @@ function FeishuSettingsTab({ rpcCall }) {
|
|
|
4625
4761
|
bots: model.bots,
|
|
4626
4762
|
busyByBot,
|
|
4627
4763
|
errorsByBot,
|
|
4764
|
+
testNoticesByBot,
|
|
4628
4765
|
removeTargetId,
|
|
4629
4766
|
onReconnect: (bot) => void reconnectOneBot(bot),
|
|
4630
4767
|
onWorkspaceSave: saveWorkspace,
|
|
@@ -4652,6 +4789,7 @@ var QQ_ENDPOINTS = Object.freeze({
|
|
|
4652
4789
|
});
|
|
4653
4790
|
var PROVISION_STATES2 = /* @__PURE__ */ new Set(["starting", "pending", "refreshing", "connecting", "connected", "failed", "cancelled"]);
|
|
4654
4791
|
var ACCOUNT_STATES3 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]);
|
|
4792
|
+
var TEST_MESSAGE_CODES = /* @__PURE__ */ new Set(["test-target-unavailable", "test-message-failed"]);
|
|
4655
4793
|
var QR_DATA_URL2 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
|
|
4656
4794
|
function isRecord4(value) {
|
|
4657
4795
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -4725,17 +4863,35 @@ function normalizeBot3(value) {
|
|
|
4725
4863
|
} : null
|
|
4726
4864
|
};
|
|
4727
4865
|
}
|
|
4866
|
+
function normalizeTestMessage2(value) {
|
|
4867
|
+
if (!isRecord4(value) || typeof value.sent !== "boolean") return void 0;
|
|
4868
|
+
if (value.sent) return { sent: true };
|
|
4869
|
+
const code = text2(value.code, "test-message-failed", 80);
|
|
4870
|
+
return {
|
|
4871
|
+
sent: false,
|
|
4872
|
+
code: TEST_MESSAGE_CODES.has(code) ? code : "test-message-failed"
|
|
4873
|
+
};
|
|
4874
|
+
}
|
|
4728
4875
|
function normalizeSnapshot3(value) {
|
|
4729
4876
|
const source = isRecord4(value?.snapshot) ? value.snapshot : value;
|
|
4730
4877
|
if (!isRecord4(source) || !Array.isArray(source.bots)) throw new Error("QQ \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868");
|
|
4731
4878
|
const bots = source.bots.map(normalizeBot3).filter(Boolean);
|
|
4879
|
+
const testMessage = normalizeTestMessage2(source.testMessage);
|
|
4732
4880
|
return {
|
|
4733
4881
|
revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
|
|
4734
4882
|
bots,
|
|
4735
4883
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
4736
|
-
provisioning: source.provisioning ? normalizeProvisioning3(source.provisioning) : null
|
|
4884
|
+
provisioning: source.provisioning ? normalizeProvisioning3(source.provisioning) : null,
|
|
4885
|
+
...testMessage ? { testMessage } : {}
|
|
4737
4886
|
};
|
|
4738
4887
|
}
|
|
4888
|
+
function connectionTestFeedback2(result) {
|
|
4889
|
+
if (result?.sent === true) return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u5BF9\u5E94\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
|
|
4890
|
+
if (result?.code === "test-target-unavailable") {
|
|
4891
|
+
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";
|
|
4892
|
+
}
|
|
4893
|
+
return result ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
4894
|
+
}
|
|
4739
4895
|
function presentError4(error) {
|
|
4740
4896
|
return {
|
|
4741
4897
|
code: text2(error?.code, "QQ_ERROR", 80),
|
|
@@ -4983,6 +5139,7 @@ function RemoveConfirmation3({ account, busy, onConfirm, onCancel }) {
|
|
|
4983
5139
|
function AccountCard2({
|
|
4984
5140
|
account,
|
|
4985
5141
|
busy,
|
|
5142
|
+
feedback,
|
|
4986
5143
|
removing,
|
|
4987
5144
|
onReconnect,
|
|
4988
5145
|
onWorkspaceSave,
|
|
@@ -5035,6 +5192,11 @@ function AccountCard2({
|
|
|
5035
5192
|
"div",
|
|
5036
5193
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
5037
5194
|
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
|
|
5195
|
+
feedback ? h2("div", {
|
|
5196
|
+
className: "ddt-summary dim-cardSummary",
|
|
5197
|
+
role: "status",
|
|
5198
|
+
"aria-live": "polite"
|
|
5199
|
+
}, feedback) : null,
|
|
5038
5200
|
h2(
|
|
5039
5201
|
"div",
|
|
5040
5202
|
{ className: "ddt-actions dim-cardActions" },
|
|
@@ -5056,6 +5218,7 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5056
5218
|
const [provision, setProvision] = React11.useState(null);
|
|
5057
5219
|
const [busy, setBusy] = React11.useState(false);
|
|
5058
5220
|
const [busyByBot, setBusyByBot] = React11.useState({});
|
|
5221
|
+
const [feedbackByBot, setFeedbackByBot] = React11.useState({});
|
|
5059
5222
|
const [removeTarget, setRemoveTarget] = React11.useState(null);
|
|
5060
5223
|
const [credentialOpen, setCredentialOpen] = React11.useState(false);
|
|
5061
5224
|
const [credentialError, setCredentialError] = React11.useState(null);
|
|
@@ -5216,6 +5379,34 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5216
5379
|
});
|
|
5217
5380
|
}
|
|
5218
5381
|
}, [invoke, loadStatus, workspaceFence]);
|
|
5382
|
+
const reconnect = React11.useCallback(async (account) => {
|
|
5383
|
+
setFeedbackByBot((current) => {
|
|
5384
|
+
const next = { ...current };
|
|
5385
|
+
delete next[account.botId];
|
|
5386
|
+
return next;
|
|
5387
|
+
});
|
|
5388
|
+
try {
|
|
5389
|
+
const snapshot = await botAction(
|
|
5390
|
+
account,
|
|
5391
|
+
"reconnect",
|
|
5392
|
+
QQ_ENDPOINTS.reconnectBot,
|
|
5393
|
+
{ botId: account.botId, sendTest: true }
|
|
5394
|
+
);
|
|
5395
|
+
if (mounted.current) {
|
|
5396
|
+
setFeedbackByBot((current) => ({
|
|
5397
|
+
...current,
|
|
5398
|
+
[account.botId]: connectionTestFeedback2(snapshot?.testMessage)
|
|
5399
|
+
}));
|
|
5400
|
+
}
|
|
5401
|
+
} catch {
|
|
5402
|
+
if (mounted.current) {
|
|
5403
|
+
setFeedbackByBot((current) => ({
|
|
5404
|
+
...current,
|
|
5405
|
+
[account.botId]: "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
|
|
5406
|
+
}));
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
}, [botAction]);
|
|
5219
5410
|
let provisionView = null;
|
|
5220
5411
|
if (provision?.status === "starting") provisionView = h2("div", { className: "ddt-card ddt-loading dim-surfaceCard" }, h2("div", { className: "ddt-spinner" }), "\u6B63\u5728\u7533\u8BF7 QQ \u4E8C\u7EF4\u7801\u2026");
|
|
5221
5412
|
else if (["pending", "refreshing"].includes(provision?.status)) provisionView = h2(QrPanel2, {
|
|
@@ -5242,8 +5433,9 @@ function QqSettingsTab({ rpcCall }) {
|
|
|
5242
5433
|
h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard2, {
|
|
5243
5434
|
account,
|
|
5244
5435
|
busy: busyByBot[account.botId],
|
|
5436
|
+
feedback: feedbackByBot[account.botId],
|
|
5245
5437
|
removing: removeTarget === account.botId,
|
|
5246
|
-
onReconnect: () => void
|
|
5438
|
+
onReconnect: () => void reconnect(account),
|
|
5247
5439
|
onWorkspaceSave: (workspace) => botAction(
|
|
5248
5440
|
account,
|
|
5249
5441
|
"workspace",
|
|
@@ -5329,6 +5521,7 @@ oauth_config:
|
|
|
5329
5521
|
bot:
|
|
5330
5522
|
- app_mentions:read
|
|
5331
5523
|
- chat:write
|
|
5524
|
+
- files:read
|
|
5332
5525
|
- im:history
|
|
5333
5526
|
settings:
|
|
5334
5527
|
event_subscriptions:
|
|
@@ -5596,6 +5789,13 @@ function timestamp4(value) {
|
|
|
5596
5789
|
const parsed = typeof value === "string" ? Date.parse(value) : Number.NaN;
|
|
5597
5790
|
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
5598
5791
|
}
|
|
5792
|
+
function normalizeTestMessage3(value) {
|
|
5793
|
+
if (!isRecord5(value)) return null;
|
|
5794
|
+
if (value.sent === true) return { sent: true };
|
|
5795
|
+
if (value.sent !== false) return null;
|
|
5796
|
+
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
|
|
5797
|
+
return { sent: false, code };
|
|
5798
|
+
}
|
|
5599
5799
|
function unwrapRpcResult7(result) {
|
|
5600
5800
|
if (!isRecord5(result) || typeof result.ok !== "boolean") throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
|
5601
5801
|
if (!result.ok) {
|
|
@@ -5661,7 +5861,8 @@ function normalizeSnapshot6(value) {
|
|
|
5661
5861
|
revision: Number.isSafeInteger(source.revision) ? source.revision : 0,
|
|
5662
5862
|
bots,
|
|
5663
5863
|
totals: { configured: bots.length, connected: bots.filter((bot) => bot.connected).length },
|
|
5664
|
-
provisioning: source.provisioning ? normalizeProvisioning4(source.provisioning) : null
|
|
5864
|
+
provisioning: source.provisioning ? normalizeProvisioning4(source.provisioning) : null,
|
|
5865
|
+
testMessage: normalizeTestMessage3(source.testMessage)
|
|
5665
5866
|
};
|
|
5666
5867
|
}
|
|
5667
5868
|
function presentError7(error) {
|
|
@@ -5911,6 +6112,7 @@ function RemoveConfirmation4({ account, busy, onConfirm, onCancel }) {
|
|
|
5911
6112
|
function AccountCard3({
|
|
5912
6113
|
account,
|
|
5913
6114
|
busy,
|
|
6115
|
+
feedback,
|
|
5914
6116
|
removing,
|
|
5915
6117
|
onReconnect,
|
|
5916
6118
|
onWorkspaceSave,
|
|
@@ -5963,6 +6165,11 @@ function AccountCard3({
|
|
|
5963
6165
|
"div",
|
|
5964
6166
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
5965
6167
|
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
|
|
6168
|
+
feedback ? h2("div", {
|
|
6169
|
+
className: "ddt-summary dim-cardSummary",
|
|
6170
|
+
role: "status",
|
|
6171
|
+
"aria-live": "polite"
|
|
6172
|
+
}, feedback) : null,
|
|
5966
6173
|
h2(
|
|
5967
6174
|
"div",
|
|
5968
6175
|
{ className: "ddt-actions dim-cardActions" },
|
|
@@ -5984,19 +6191,40 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
5984
6191
|
const [provision, setProvision] = React13.useState(null);
|
|
5985
6192
|
const [busy, setBusy] = React13.useState(false);
|
|
5986
6193
|
const [busyByBot, setBusyByBot] = React13.useState({});
|
|
6194
|
+
const [feedbackByBot, setFeedbackByBot] = React13.useState({});
|
|
5987
6195
|
const [removeTarget, setRemoveTarget] = React13.useState(null);
|
|
5988
6196
|
const [credentialOpen, setCredentialOpen] = React13.useState(false);
|
|
5989
6197
|
const [credentialError, setCredentialError] = React13.useState(null);
|
|
6198
|
+
const [notice, setNotice] = React13.useState("");
|
|
5990
6199
|
const [now, setNow] = React13.useState(Date.now());
|
|
5991
6200
|
const mounted = React13.useRef(true);
|
|
5992
6201
|
const workspaceFence = useWorkspaceSnapshotFence();
|
|
5993
6202
|
const addButtonRef = React13.useRef(null);
|
|
6203
|
+
const noticeFrameRef = React13.useRef(null);
|
|
6204
|
+
const announce = React13.useCallback((message) => {
|
|
6205
|
+
if (!mounted.current) return;
|
|
6206
|
+
if (noticeFrameRef.current !== null) {
|
|
6207
|
+
window.cancelAnimationFrame(noticeFrameRef.current);
|
|
6208
|
+
noticeFrameRef.current = null;
|
|
6209
|
+
}
|
|
6210
|
+
setNotice("");
|
|
6211
|
+
if (message) {
|
|
6212
|
+
noticeFrameRef.current = window.requestAnimationFrame(() => {
|
|
6213
|
+
noticeFrameRef.current = null;
|
|
6214
|
+
if (mounted.current) setNotice(message);
|
|
6215
|
+
});
|
|
6216
|
+
}
|
|
6217
|
+
}, []);
|
|
5994
6218
|
React13.useEffect(() => {
|
|
5995
6219
|
const disposeDingtalk = installDingtalkStyles();
|
|
5996
6220
|
const disposeWecom = installWecomStyles();
|
|
5997
6221
|
mounted.current = true;
|
|
5998
6222
|
return () => {
|
|
5999
6223
|
mounted.current = false;
|
|
6224
|
+
if (noticeFrameRef.current !== null) {
|
|
6225
|
+
window.cancelAnimationFrame(noticeFrameRef.current);
|
|
6226
|
+
noticeFrameRef.current = null;
|
|
6227
|
+
}
|
|
6000
6228
|
disposeWecom();
|
|
6001
6229
|
disposeDingtalk();
|
|
6002
6230
|
};
|
|
@@ -6144,6 +6372,45 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
6144
6372
|
});
|
|
6145
6373
|
}
|
|
6146
6374
|
}, [invoke, loadStatus, workspaceFence]);
|
|
6375
|
+
const reconnect = React13.useCallback(async (account) => {
|
|
6376
|
+
setFeedbackByBot((current) => {
|
|
6377
|
+
const next = { ...current };
|
|
6378
|
+
delete next[account.botId];
|
|
6379
|
+
return next;
|
|
6380
|
+
});
|
|
6381
|
+
try {
|
|
6382
|
+
const snapshot = await botAction(
|
|
6383
|
+
account,
|
|
6384
|
+
"reconnect",
|
|
6385
|
+
WECOM_ENDPOINTS.reconnectBot,
|
|
6386
|
+
{ botId: account.botId, sendTest: true }
|
|
6387
|
+
);
|
|
6388
|
+
if (!snapshot) return;
|
|
6389
|
+
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
|
6390
|
+
let feedback;
|
|
6391
|
+
if (!refreshed?.connected) {
|
|
6392
|
+
feedback = "\u4F01\u4E1A\u5FAE\u4FE1\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002";
|
|
6393
|
+
} else if (snapshot.testMessage?.sent) {
|
|
6394
|
+
feedback = "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
|
|
6395
|
+
} else if (snapshot.testMessage?.code === "test-target-unavailable") {
|
|
6396
|
+
feedback = "\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";
|
|
6397
|
+
} else if (snapshot.testMessage) {
|
|
6398
|
+
feedback = "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002";
|
|
6399
|
+
} else {
|
|
6400
|
+
feedback = "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
|
|
6401
|
+
}
|
|
6402
|
+
if (mounted.current) {
|
|
6403
|
+
setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
|
|
6404
|
+
}
|
|
6405
|
+
announce(feedback);
|
|
6406
|
+
} catch {
|
|
6407
|
+
const feedback = "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
|
|
6408
|
+
if (mounted.current) {
|
|
6409
|
+
setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
|
|
6410
|
+
}
|
|
6411
|
+
announce(feedback);
|
|
6412
|
+
}
|
|
6413
|
+
}, [announce, botAction]);
|
|
6147
6414
|
let provisionView = null;
|
|
6148
6415
|
if (provision?.status === "starting") provisionView = h2("div", { className: "ddt-card ddt-loading dim-surfaceCard" }, h2("div", { className: "ddt-spinner" }), "\u6B63\u5728\u7533\u8BF7\u4F01\u4E1A\u5FAE\u4FE1\u4E8C\u7EF4\u7801\u2026");
|
|
6149
6416
|
else if (["pending", "refreshing"].includes(provision?.status)) provisionView = h2(QrPanel3, {
|
|
@@ -6170,8 +6437,9 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
6170
6437
|
h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(AccountCard3, {
|
|
6171
6438
|
account,
|
|
6172
6439
|
busy: busyByBot[account.botId],
|
|
6440
|
+
feedback: feedbackByBot[account.botId],
|
|
6173
6441
|
removing: removeTarget === account.botId,
|
|
6174
|
-
onReconnect: () => void
|
|
6442
|
+
onReconnect: () => void reconnect(account),
|
|
6175
6443
|
onWorkspaceSave: (workspace) => botAction(
|
|
6176
6444
|
account,
|
|
6177
6445
|
"workspace",
|
|
@@ -6215,6 +6483,7 @@ function WecomSettingsTab({ rpcCall }) {
|
|
|
6215
6483
|
credentialOpen,
|
|
6216
6484
|
addButtonRef
|
|
6217
6485
|
}),
|
|
6486
|
+
h2("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice),
|
|
6218
6487
|
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(Button9, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6"))) : h2(
|
|
6219
6488
|
React13.Fragment,
|
|
6220
6489
|
null,
|
|
@@ -6262,6 +6531,13 @@ function string(value, fallback = "") {
|
|
|
6262
6531
|
function timestamp5(value) {
|
|
6263
6532
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
6264
6533
|
}
|
|
6534
|
+
function normalizeTestMessage4(value) {
|
|
6535
|
+
if (!isRecord6(value)) return null;
|
|
6536
|
+
if (value.sent === true) return { sent: true };
|
|
6537
|
+
if (value.sent !== false) return null;
|
|
6538
|
+
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
|
|
6539
|
+
return { sent: false, code };
|
|
6540
|
+
}
|
|
6265
6541
|
function unwrapRpcResult8(result) {
|
|
6266
6542
|
if (!isRecord6(result) || typeof result.ok !== "boolean") {
|
|
6267
6543
|
throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
|
@@ -6355,7 +6631,8 @@ function normalizeSnapshot7(value) {
|
|
|
6355
6631
|
configured: bots.length,
|
|
6356
6632
|
connected: bots.filter((bot) => bot.connected).length
|
|
6357
6633
|
},
|
|
6358
|
-
provisioning: value.provisioning ? normalizeProvisioning5(value.provisioning) : null
|
|
6634
|
+
provisioning: value.provisioning ? normalizeProvisioning5(value.provisioning) : null,
|
|
6635
|
+
testMessage: normalizeTestMessage4(value.testMessage)
|
|
6359
6636
|
};
|
|
6360
6637
|
}
|
|
6361
6638
|
function presentError8(error) {
|
|
@@ -6735,6 +7012,7 @@ function checkedTime5(timestamp7) {
|
|
|
6735
7012
|
function AccountCard4({
|
|
6736
7013
|
account,
|
|
6737
7014
|
busy,
|
|
7015
|
+
feedback,
|
|
6738
7016
|
removing,
|
|
6739
7017
|
onReconnect,
|
|
6740
7018
|
onWorkspaceSave,
|
|
@@ -6792,6 +7070,11 @@ function AccountCard4({
|
|
|
6792
7070
|
"div",
|
|
6793
7071
|
{ className: "dxw-accountFooter dim-cardFooter" },
|
|
6794
7072
|
summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
|
|
7073
|
+
feedback ? h2("div", {
|
|
7074
|
+
className: "dxw-summary dim-cardSummary",
|
|
7075
|
+
role: "status",
|
|
7076
|
+
"aria-live": "polite"
|
|
7077
|
+
}, feedback) : null,
|
|
6795
7078
|
h2(
|
|
6796
7079
|
"div",
|
|
6797
7080
|
{ className: "dxw-actions dim-cardActions" },
|
|
@@ -6833,6 +7116,7 @@ function AccountList2(props) {
|
|
|
6833
7116
|
h2(AccountCard4, {
|
|
6834
7117
|
account,
|
|
6835
7118
|
busy: props.busyByBot[account.botId],
|
|
7119
|
+
feedback: props.feedbackByBot[account.botId],
|
|
6836
7120
|
removing: props.removeTarget === account.botId,
|
|
6837
7121
|
onReconnect: () => props.onReconnect(account),
|
|
6838
7122
|
onWorkspaceSave: (workspace) => props.onWorkspaceSave(account, workspace),
|
|
@@ -6864,6 +7148,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
6864
7148
|
const [provision, setProvision] = React14.useState(null);
|
|
6865
7149
|
const [busy, setBusy] = React14.useState(false);
|
|
6866
7150
|
const [busyByBot, setBusyByBot] = React14.useState({});
|
|
7151
|
+
const [feedbackByBot, setFeedbackByBot] = React14.useState({});
|
|
6867
7152
|
const [removeTarget, setRemoveTarget] = React14.useState(null);
|
|
6868
7153
|
const [notice, setNotice] = React14.useState("");
|
|
6869
7154
|
const [now, setNow] = React14.useState(() => Date.now());
|
|
@@ -7062,15 +7347,42 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
7062
7347
|
const reconnect = React14.useCallback(async (account) => {
|
|
7063
7348
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
7064
7349
|
setBotBusy(account.botId, "reconnect");
|
|
7350
|
+
setFeedbackByBot((current) => {
|
|
7351
|
+
const next = { ...current };
|
|
7352
|
+
delete next[account.botId];
|
|
7353
|
+
return next;
|
|
7354
|
+
});
|
|
7065
7355
|
try {
|
|
7066
|
-
const snapshot = normalizeSnapshot7(await invoke(
|
|
7356
|
+
const snapshot = normalizeSnapshot7(await invoke(
|
|
7357
|
+
WEIXIN_ENDPOINTS.reconnectBot,
|
|
7358
|
+
{ botId: account.botId, sendTest: true }
|
|
7359
|
+
));
|
|
7067
7360
|
if (mountedRef.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
7068
7361
|
setModel((current) => ({ ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision }));
|
|
7069
7362
|
}
|
|
7070
7363
|
const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId);
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7364
|
+
let feedback;
|
|
7365
|
+
if (!refreshed?.connected) {
|
|
7366
|
+
feedback = "\u5FAE\u4FE1\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002";
|
|
7367
|
+
} else if (snapshot.testMessage?.sent) {
|
|
7368
|
+
feedback = "\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002";
|
|
7369
|
+
} else if (snapshot.testMessage?.code === "test-target-unavailable") {
|
|
7370
|
+
feedback = "\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";
|
|
7371
|
+
} else if (snapshot.testMessage) {
|
|
7372
|
+
feedback = "\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002";
|
|
7373
|
+
} else {
|
|
7374
|
+
feedback = "\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002";
|
|
7375
|
+
}
|
|
7376
|
+
if (mountedRef.current) {
|
|
7377
|
+
setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
|
|
7378
|
+
}
|
|
7379
|
+
announce(feedback);
|
|
7380
|
+
} catch {
|
|
7381
|
+
const feedback = "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
|
|
7382
|
+
if (mountedRef.current) {
|
|
7383
|
+
setFeedbackByBot((current) => ({ ...current, [account.botId]: feedback }));
|
|
7384
|
+
}
|
|
7385
|
+
announce(feedback);
|
|
7074
7386
|
} finally {
|
|
7075
7387
|
const shouldRefresh = workspaceFence.endMutation();
|
|
7076
7388
|
if (shouldRefresh && mountedRef.current) void loadStatus({ silent: true });
|
|
@@ -7183,6 +7495,7 @@ function WeixinSettingsTab({ rpcCall }) {
|
|
|
7183
7495
|
model.bots.length > 0 ? h2(AccountList2, {
|
|
7184
7496
|
bots: model.bots,
|
|
7185
7497
|
busyByBot,
|
|
7498
|
+
feedbackByBot,
|
|
7186
7499
|
removeTarget,
|
|
7187
7500
|
onReconnect: (account) => void reconnect(account),
|
|
7188
7501
|
onWorkspaceSave: saveWorkspace,
|
|
@@ -7353,6 +7666,15 @@ function checkedTime6(value) {
|
|
|
7353
7666
|
return "\u521A\u521A";
|
|
7354
7667
|
}
|
|
7355
7668
|
}
|
|
7669
|
+
function connectionTestNotice3(value) {
|
|
7670
|
+
if (value?.testMessage?.sent === true) {
|
|
7671
|
+
return "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230 WhatsApp \u81EA\u804A\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002";
|
|
7672
|
+
}
|
|
7673
|
+
if (value?.testMessage?.code === "test-target-unavailable") {
|
|
7674
|
+
return "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684 WhatsApp \u81EA\u804A\u76EE\u6807\u3002";
|
|
7675
|
+
}
|
|
7676
|
+
return value?.testMessage ? "\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
|
7677
|
+
}
|
|
7356
7678
|
function Heading6({ totals, busy, onAdd, addButtonRef }) {
|
|
7357
7679
|
return h2(
|
|
7358
7680
|
"div",
|
|
@@ -7541,6 +7863,7 @@ function RemoveConfirmation5({ account, busy, onConfirm, onCancel }) {
|
|
|
7541
7863
|
function WhatsappAccountCard({
|
|
7542
7864
|
account,
|
|
7543
7865
|
busy,
|
|
7866
|
+
testNotice,
|
|
7544
7867
|
removing,
|
|
7545
7868
|
onReconnect,
|
|
7546
7869
|
onWorkspaceSave,
|
|
@@ -7607,6 +7930,10 @@ function WhatsappAccountCard({
|
|
|
7607
7930
|
"div",
|
|
7608
7931
|
{ className: "ddt-accountFooter dim-cardFooter" },
|
|
7609
7932
|
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
|
|
7933
|
+
testNotice ? h2("div", {
|
|
7934
|
+
className: "ddt-summary dim-cardSummary",
|
|
7935
|
+
role: "status"
|
|
7936
|
+
}, testNotice) : null,
|
|
7610
7937
|
h2(
|
|
7611
7938
|
"div",
|
|
7612
7939
|
{ className: "ddt-actions dim-cardActions" },
|
|
@@ -7642,6 +7969,7 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
7642
7969
|
const [provision, setProvision] = React15.useState(null);
|
|
7643
7970
|
const [busy, setBusy] = React15.useState(false);
|
|
7644
7971
|
const [busyByBot, setBusyByBot] = React15.useState({});
|
|
7972
|
+
const [testNoticeByBot, setTestNoticeByBot] = React15.useState({});
|
|
7645
7973
|
const [removeTarget, setRemoveTarget] = React15.useState(null);
|
|
7646
7974
|
const [now, setNow] = React15.useState(Date.now());
|
|
7647
7975
|
const mounted = React15.useRef(true);
|
|
@@ -7780,10 +8108,32 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
7780
8108
|
const botAction = React15.useCallback(async (account, operation, endpoint, payload) => {
|
|
7781
8109
|
const snapshotVersion = workspaceFence.beginMutation();
|
|
7782
8110
|
setBusyByBot((current) => ({ ...current, [account.botId]: operation }));
|
|
8111
|
+
if (operation === "reconnect") {
|
|
8112
|
+
setTestNoticeByBot((current) => {
|
|
8113
|
+
const next = { ...current };
|
|
8114
|
+
delete next[account.botId];
|
|
8115
|
+
return next;
|
|
8116
|
+
});
|
|
8117
|
+
}
|
|
7783
8118
|
try {
|
|
7784
|
-
const
|
|
8119
|
+
const value = await invoke(endpoint, payload);
|
|
8120
|
+
const snapshot = normalizeSnapshot8(value);
|
|
7785
8121
|
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
7786
8122
|
setModel({ phase: "ready", bots: snapshot.bots, totals: snapshot.totals, error: null });
|
|
8123
|
+
if (operation === "reconnect") {
|
|
8124
|
+
setTestNoticeByBot((current) => ({
|
|
8125
|
+
...current,
|
|
8126
|
+
[account.botId]: connectionTestNotice3(value)
|
|
8127
|
+
}));
|
|
8128
|
+
}
|
|
8129
|
+
}
|
|
8130
|
+
} catch (error) {
|
|
8131
|
+
if (operation !== "reconnect") throw error;
|
|
8132
|
+
if (mounted.current && workspaceFence.canCommitMutation(snapshotVersion)) {
|
|
8133
|
+
setTestNoticeByBot((current) => ({
|
|
8134
|
+
...current,
|
|
8135
|
+
[account.botId]: "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
|
|
8136
|
+
}));
|
|
7787
8137
|
}
|
|
7788
8138
|
} finally {
|
|
7789
8139
|
const shouldRefresh = workspaceFence.endMutation();
|
|
@@ -7806,12 +8156,13 @@ function WhatsappSettingsTab({ rpcCall }) {
|
|
|
7806
8156
|
h2("ul", { className: "ddt-list dim-botList" }, model.bots.map((account) => h2("li", { key: account.botId }, h2(WhatsappAccountCard, {
|
|
7807
8157
|
account,
|
|
7808
8158
|
busy: busyByBot[account.botId],
|
|
8159
|
+
testNotice: testNoticeByBot[account.botId],
|
|
7809
8160
|
removing: removeTarget === account.botId,
|
|
7810
8161
|
onReconnect: () => void botAction(
|
|
7811
8162
|
account,
|
|
7812
8163
|
"reconnect",
|
|
7813
8164
|
WHATSAPP_ENDPOINTS.reconnectBot,
|
|
7814
|
-
{ botId: account.botId }
|
|
8165
|
+
{ botId: account.botId, sendTest: true }
|
|
7815
8166
|
),
|
|
7816
8167
|
onWorkspaceSave: (workspace) => botAction(
|
|
7817
8168
|
account,
|