mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 04:13:17 +08:00
fix: add actionable DingTalk connection diagnostics
This commit is contained in:
parent
3010535409
commit
1b05fa8d32
18 changed files with 1038 additions and 299 deletions
|
|
@ -593,10 +593,7 @@ var package_default = {
|
|||
"whatsapp",
|
||||
"ai-office"
|
||||
],
|
||||
author: {
|
||||
name: "xmanrui",
|
||||
url: "https://github.com/xmanrui"
|
||||
},
|
||||
author: "xmanrui (https://github.com/xmanrui)",
|
||||
contributors: [
|
||||
{
|
||||
name: "C3H3-AI",
|
||||
|
|
@ -618,7 +615,9 @@ var package_default = {
|
|||
url: "git+https://github.com/xmanrui/dsh-im.git"
|
||||
},
|
||||
homepage: "https://github.com/xmanrui/dsh-im#readme",
|
||||
bugs: "https://github.com/xmanrui/dsh-im/issues",
|
||||
bugs: {
|
||||
url: "https://github.com/xmanrui/dsh-im/issues"
|
||||
},
|
||||
publishConfig: {
|
||||
access: "public"
|
||||
},
|
||||
|
|
@ -687,6 +686,11 @@ var package_default = {
|
|||
"react-dom": "18.3.1",
|
||||
"react-test-renderer": "18.3.1",
|
||||
semver: "7.8.5"
|
||||
},
|
||||
directories: {
|
||||
doc: "docs",
|
||||
lib: "lib",
|
||||
test: "test"
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1189,6 +1193,8 @@ var EN = Object.freeze({
|
|||
"\u68C0\u67E5\u8FDE\u63A5": "Check connection",
|
||||
"\u68C0\u67E5\u4E2D\u2026": "Checking\u2026",
|
||||
"\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002": "Connection check failed. Try again later.",
|
||||
"\u673A\u5668\u4EBA\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u8FDE\u63A5\u672A\u5C31\u7EEA": "The bot was saved, but the connection is not ready",
|
||||
"\u67E5\u770B\u5DF2\u4FDD\u5B58\u7684\u673A\u5668\u4EBA": "View saved bot",
|
||||
"\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.",
|
||||
"\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.",
|
||||
"\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.",
|
||||
|
|
@ -1753,6 +1759,8 @@ function translateDynamic(text6) {
|
|||
if (match) return `Automatic status refresh failed: ${match[1]}`;
|
||||
match = /^操作失败:(.+)$/.exec(text6);
|
||||
if (match) return `Operation failed: ${match[1]}`;
|
||||
match = /^连接检查失败:(.+)(参考号:(.+))$/.exec(text6);
|
||||
if (match) return `Connection check failed: ${localizeText(match[1])} (reference: ${match[2]})`;
|
||||
match = /^连接检查失败:(.+)$/.exec(text6);
|
||||
if (match) return `Connection check failed: ${match[1]}`;
|
||||
match = /^移除失败:(.+)$/.exec(text6);
|
||||
|
|
@ -2252,11 +2260,19 @@ function sanitizeMessage(value, fallback) {
|
|||
if (FORBIDDEN_ERROR_FIELDS.test(message)) return fallback;
|
||||
return message.replace(/([=:]\s*)[^\s,;,。]+/g, "$1\u2022\u2022\u2022\u2022\u2022\u2022").slice(0, 240);
|
||||
}
|
||||
function safeReferenceId(value) {
|
||||
const referenceId = optionalString(value, 40);
|
||||
return referenceId && /^DT-CONN-[A-F0-9]{8}$/.test(referenceId) ? referenceId : void 0;
|
||||
}
|
||||
function normalizeError(value, fallbackCode, fallbackMessage) {
|
||||
if (!isRecord(value)) return void 0;
|
||||
const hint = sanitizeMessage(value.hint, "");
|
||||
const referenceId = safeReferenceId(value.referenceId);
|
||||
return {
|
||||
code: safeErrorCode(value.code, fallbackCode),
|
||||
message: sanitizeMessage(value.message, fallbackMessage)
|
||||
message: sanitizeMessage(value.message, fallbackMessage),
|
||||
...hint ? { hint } : {},
|
||||
...referenceId ? { referenceId } : {}
|
||||
};
|
||||
}
|
||||
function normalizeTestMessage(value) {
|
||||
|
|
@ -2271,8 +2287,15 @@ function unwrapRpcResult(result) {
|
|||
throw new Error("\u9489\u9489\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
|
||||
}
|
||||
if (!result.ok) {
|
||||
const error = new Error(sanitizeMessage(result.error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25"));
|
||||
error.code = safeErrorCode(result.error?.code, "DINGTALK_RPC_ERROR");
|
||||
const visible = normalizeError(
|
||||
result.error,
|
||||
"DINGTALK_RPC_ERROR",
|
||||
"\u9489\u9489\u64CD\u4F5C\u5931\u8D25"
|
||||
) ?? { code: "DINGTALK_RPC_ERROR", message: "\u9489\u9489\u64CD\u4F5C\u5931\u8D25" };
|
||||
const error = new Error(visible.message);
|
||||
error.code = visible.code;
|
||||
if (visible.hint) error.hint = visible.hint;
|
||||
if (visible.referenceId) error.referenceId = visible.referenceId;
|
||||
throw error;
|
||||
}
|
||||
return result.value;
|
||||
|
|
@ -2377,10 +2400,11 @@ function connectionTestFeedback(result) {
|
|||
return result ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002" : null;
|
||||
}
|
||||
function presentError(error) {
|
||||
return {
|
||||
code: safeErrorCode(error?.code, "DINGTALK_ERROR"),
|
||||
message: sanitizeMessage(error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
|
||||
};
|
||||
return normalizeError(
|
||||
error,
|
||||
"DINGTALK_ERROR",
|
||||
"\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"
|
||||
) ?? { code: "DINGTALK_ERROR", message: "\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" };
|
||||
}
|
||||
function formatRemaining(milliseconds) {
|
||||
const seconds = Math.max(0, Math.ceil(Number(milliseconds) / 1e3) || 0);
|
||||
|
|
@ -3680,6 +3704,8 @@ var CSS = String.raw`
|
|||
.ddt-inlineError h3 { font-size: 17px; }
|
||||
.ddt-inlineError p { line-height: 1.55; }
|
||||
.ddt-errorCode { font: 11px ui-monospace, SFMono-Regular, monospace; opacity: .8; }
|
||||
.ddt-errorDiagnostic { display: grid; gap: 5px; color: var(--ddt-error); }
|
||||
.ddt-errorHint { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.55; }
|
||||
.ddt-listHeading { display: flex; align-items: center; justify-content: space-between; margin: 2px 0 9px; }
|
||||
.ddt-listHeading h3 { margin: 0; font-size: 14px; }
|
||||
.ddt-list { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; }
|
||||
|
|
@ -3936,25 +3962,45 @@ function ProgressPanel({ status, busy, onCancel }) {
|
|||
)
|
||||
);
|
||||
}
|
||||
function ConnectionErrorDiagnostic({ error }) {
|
||||
if (!error) return null;
|
||||
return h2(
|
||||
"div",
|
||||
{ className: "ddt-errorDiagnostic" },
|
||||
error.hint ? h2("p", { className: "ddt-errorHint" }, error.hint) : null,
|
||||
h2(
|
||||
"span",
|
||||
{ className: "ddt-errorCode" },
|
||||
h2("span", null, "\u9519\u8BEF\u7801"),
|
||||
`: ${error.code}`,
|
||||
error.referenceId ? h2(React10.Fragment, null, " \xB7 ", h2("span", null, "\u53C2\u8003\u53F7"), `: ${error.referenceId}`) : null
|
||||
)
|
||||
);
|
||||
}
|
||||
function ProvisionError({ provision, busy, onRetry, onClose }) {
|
||||
const error = provision.error ?? {
|
||||
code: "DINGTALK_PROVISION_FAILED",
|
||||
message: "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"
|
||||
};
|
||||
const connectionFailed = Boolean(error.referenceId);
|
||||
return h2(
|
||||
"div",
|
||||
{ className: "ddt-card dim-surfaceCard" },
|
||||
h2(
|
||||
"div",
|
||||
{ className: "ddt-inlineError dim-inlineError", role: "alert" },
|
||||
h2("h3", null, provision.status === "expired" ? "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F" : "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"),
|
||||
h2("h3", null, provision.status === "expired" ? "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F" : connectionFailed ? "\u673A\u5668\u4EBA\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u8FDE\u63A5\u672A\u5C31\u7EEA" : "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"),
|
||||
h2("p", null, error.message),
|
||||
h2("span", { className: "ddt-errorCode" }, error.code),
|
||||
h2(ConnectionErrorDiagnostic, { error }),
|
||||
h2(
|
||||
"div",
|
||||
{ className: "ddt-actions dim-viewActions" },
|
||||
h2(Button, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
|
||||
h2(Button, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
|
||||
connectionFailed ? h2(Button, { kind: "primary", onClick: onClose, disabled: busy }, "\u67E5\u770B\u5DF2\u4FDD\u5B58\u7684\u673A\u5668\u4EBA") : h2(
|
||||
React10.Fragment,
|
||||
null,
|
||||
h2(Button, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"),
|
||||
h2(Button, { onClick: onClose, disabled: busy }, "\u5173\u95ED")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
@ -4091,6 +4137,7 @@ function AccountCard({
|
|||
)
|
||||
),
|
||||
summary2 ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary2) : null,
|
||||
account.error ? h2(ConnectionErrorDiagnostic, { error: account.error }) : null,
|
||||
account.lastMessageError ? h2(LastMessageErrorSummary, {
|
||||
className: "ddt-summary",
|
||||
error: account.lastMessageError
|
||||
|
|
@ -4416,6 +4463,10 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|||
if (!canCommit()) return;
|
||||
const account = result.botId ? snapshot?.bots.find((bot) => bot.botId === result.botId) : snapshot?.bots.find((bot) => bot.connected);
|
||||
if (!account?.connected) {
|
||||
if (account?.error) {
|
||||
setProvision((current) => current?.attemptId === attemptId ? { ...current, ...result, status: "failed", error: account.error } : current);
|
||||
return;
|
||||
}
|
||||
setProvision((current) => current?.attemptId === attemptId ? { ...current, ...result, status: "connecting" } : current);
|
||||
schedule(result.pollIntervalMs);
|
||||
return;
|
||||
|
|
@ -4490,7 +4541,8 @@ function DingtalkSettingsTab({ rpcCall }) {
|
|||
return snapshot;
|
||||
} catch (error) {
|
||||
if (!mountedRef.current) return void 0;
|
||||
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}`;
|
||||
const visibleError = presentError(error);
|
||||
const failureMessage = operation === "reconnect" ? visibleError.referenceId ? `\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF1A${visibleError.message}\uFF08\u53C2\u8003\u53F7\uFF1A${visibleError.referenceId}\uFF09` : "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" : `\u64CD\u4F5C\u5931\u8D25\uFF1A${visibleError.message}`;
|
||||
if (operation === "reconnect") {
|
||||
setFeedbackByBot((current) => ({
|
||||
...current,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue