diff --git a/lib/client.js b/lib/client.js index 443bfae..508c2ed 100644 --- a/lib/client.js +++ b/lib/client.js @@ -2142,24 +2142,28 @@ function AccountCard({ h2( "div", { className: "ddt-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, - feedback ? h2("div", { - className: "ddt-summary dim-cardSummary", - role: "status" - }, feedback) : null, h2( "div", - { className: "ddt-actions dim-cardActions" }, + { className: "dim-cardFooterLayout" }, h2( - Button, - { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, - busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" + "div", + { className: "ddt-actions dim-cardActions" }, + h2( + Button, + { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, + busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" + ), + h2( + Button, + { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, + "\u79FB\u9664\u63A5\u5165" + ) ), - h2( - Button, - { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, - "\u79FB\u9664\u63A5\u5165" - ) + summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, + feedback ? h2("div", { + className: "ddt-summary dim-cardFeedback", + role: "status" + }, feedback) : null ) ) ), @@ -2953,22 +2957,29 @@ function createTokenChannelSettings(definition) { h2( "div", { className: "ddt-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, - testNotice ? h2("div", { className: "ddt-summary dim-cardSummary", role: "status" }, testNotice) : null, h2( "div", - { className: "ddt-actions dim-cardActions" }, - h2(Button3, { - className: "dim-cardAction", - onClick: onReconnect, - disabled: Boolean(busy) - }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h2(Button3, { - className: "dim-cardAction", - kind: "danger", - onClick: onRequestRemove, - disabled: Boolean(busy) - }, "\u79FB\u9664\u63A5\u5165") + { className: "dim-cardFooterLayout" }, + h2( + "div", + { className: "ddt-actions dim-cardActions" }, + h2(Button3, { + className: "dim-cardAction", + onClick: onReconnect, + disabled: Boolean(busy) + }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), + h2(Button3, { + className: "dim-cardAction", + kind: "danger", + onClick: onRequestRemove, + disabled: Boolean(busy) + }, "\u79FB\u9664\u63A5\u5165") + ), + summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, + testNotice ? h2("div", { + className: "ddt-summary dim-cardFeedback", + role: "status" + }, testNotice) : null ) ) ), @@ -4808,40 +4819,44 @@ function BotCard({ h2( "div", { className: "bxf-connectedFooter dim-cardFooter" }, - summary ? h2( - "div", - { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 }, - summary - ) : null, - testNotice ? h2("div", { - className: "bxf-healthSummary dim-cardSummary", - role: "status" - }, testNotice) : null, h2( "div", - { className: "bxf-actions bxf-botActions dim-cardActions" }, - h2(Button5, { - className: "dim-cardAction", - onClick: onReconnect, - disabled: Boolean(busy), - "aria-busy": busy === "reconnect" ? "true" : void 0, - "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}` - }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h2(Button5, { - className: "bxf-repairButton dim-cardAction", - onClick: onRepairCallback, - disabled: Boolean(busy) || repairDisabled, - "aria-busy": busy === "callback-repair" ? "true" : void 0, - "aria-label": `\u4FEE\u590D${bot.name}\u7684\u5361\u7247\u6309\u94AE` - }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u4FEE\u590D\u5361\u7247\u6309\u94AE"), - h2(Button5, { - className: "dim-cardAction", - kind: "danger", - onClick: onRequestRemove, - disabled: Boolean(busy), - ref: removeButtonRef, - "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}` - }, "\u79FB\u9664\u63A5\u5165") + { className: "dim-cardFooterLayout" }, + h2( + "div", + { className: "bxf-actions bxf-botActions dim-cardActions" }, + h2(Button5, { + className: "dim-cardAction", + onClick: onReconnect, + disabled: Boolean(busy), + "aria-busy": busy === "reconnect" ? "true" : void 0, + "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}` + }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), + h2(Button5, { + className: "bxf-repairButton dim-cardAction", + onClick: onRepairCallback, + disabled: Boolean(busy) || repairDisabled, + "aria-busy": busy === "callback-repair" ? "true" : void 0, + "aria-label": `\u4FEE\u590D${bot.name}\u7684\u5361\u7247\u6309\u94AE` + }, busy === "callback-repair" ? "\u7B49\u5F85\u626B\u7801\u2026" : "\u4FEE\u590D\u5361\u7247\u6309\u94AE"), + h2(Button5, { + className: "dim-cardAction", + kind: "danger", + onClick: onRequestRemove, + disabled: Boolean(busy), + ref: removeButtonRef, + "aria-label": `\u4ECE DeepSeek Harness \u79FB\u9664${bot.name}` + }, "\u79FB\u9664\u63A5\u5165") + ), + summary ? h2( + "div", + { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 }, + summary + ) : null, + testNotice ? h2("div", { + className: "bxf-healthSummary dim-cardFeedback", + role: "status" + }, testNotice) : null ) ) ), @@ -6049,17 +6064,21 @@ function AccountCard2({ h2( "div", { className: "ddt-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, - feedback ? h2("div", { - className: "ddt-summary dim-cardSummary", - role: "status", - "aria-live": "polite" - }, feedback) : null, h2( "div", - { className: "ddt-actions dim-cardActions" }, - h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + { className: "dim-cardFooterLayout" }, + h2( + "div", + { className: "ddt-actions dim-cardActions" }, + h2(Button7, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), + h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + ), + summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, + feedback ? h2("div", { + className: "ddt-summary dim-cardFeedback", + role: "status", + "aria-live": "polite" + }, feedback) : null ) ) ), @@ -7588,17 +7607,21 @@ function AccountCard3({ h2( "div", { className: "ddt-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, - feedback ? h2("div", { - className: "ddt-summary dim-cardSummary", - role: "status", - "aria-live": "polite" - }, feedback) : null, h2( "div", - { className: "ddt-actions dim-cardActions" }, - h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + { className: "dim-cardFooterLayout" }, + h2( + "div", + { className: "ddt-actions dim-cardActions" }, + h2(Button10, { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), + h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + ), + summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, + feedback ? h2("div", { + className: "ddt-summary dim-cardFeedback", + role: "status", + "aria-live": "polite" + }, feedback) : null ) ) ), @@ -8543,25 +8566,29 @@ function AccountCard4({ h2( "div", { className: "dxw-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null, - account.lastMessageError ? h2("div", { - className: "dxw-summary dim-cardSummary", - role: "status" - }, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null, - feedback ? h2("div", { - className: "dxw-summary dim-cardSummary", - role: "status", - "aria-live": "polite" - }, feedback) : null, h2( "div", - { className: "dxw-actions dim-cardActions" }, + { className: "dim-cardFooterLayout" }, h2( - Button12, - { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, - busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" + "div", + { className: "dxw-actions dim-cardActions" }, + h2( + Button12, + { className: "dim-cardAction", onClick: onReconnect, disabled: Boolean(busy) }, + busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" + ), + h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") ), - h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null, + account.lastMessageError ? h2("div", { + className: "dxw-summary dim-cardSummary", + role: "status" + }, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null, + feedback ? h2("div", { + className: "dxw-summary dim-cardFeedback", + role: "status", + "aria-live": "polite" + }, feedback) : null ) ) ), @@ -9459,25 +9486,29 @@ function WhatsappAccountCard({ h2( "div", { className: "ddt-accountFooter dim-cardFooter" }, - summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, - testNotice ? h2("div", { - className: "ddt-summary dim-cardSummary", - role: "status" - }, testNotice) : null, h2( "div", - { className: "ddt-actions dim-cardActions" }, - h2(Button14, { - className: "dim-cardAction", - onClick: onReconnect, - disabled: Boolean(busy) - }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h2(Button14, { - className: "dim-cardAction", - kind: "danger", - onClick: onRequestRemove, - disabled: Boolean(busy) - }, "\u79FB\u9664\u63A5\u5165") + { className: "dim-cardFooterLayout" }, + h2( + "div", + { className: "ddt-actions dim-cardActions" }, + h2(Button14, { + className: "dim-cardAction", + onClick: onReconnect, + disabled: Boolean(busy) + }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), + h2(Button14, { + className: "dim-cardAction", + kind: "danger", + onClick: onRequestRemove, + disabled: Boolean(busy) + }, "\u79FB\u9664\u63A5\u5165") + ), + summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null, + testNotice ? h2("div", { + className: "ddt-summary dim-cardFeedback", + role: "status" + }, testNotice) : null ) ) ), @@ -9968,6 +9999,9 @@ var CSS11 = String.raw` .dim-directoryPickerActions button:hover:not(:disabled) { filter: brightness(.97); } .dim-directoryPickerActions button:disabled { cursor: not-allowed; opacity: .52; } .dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; } +.dim-panel .dim-cardFooterLayout { min-width: 0; width: 100%; display: flex; flex-direction: column; align-items: stretch; gap: 9px; } +.dim-panel .dim-cardFooterLayout > .dim-cardActions { align-self: flex-end; } +.dim-panel .dim-cardFeedback { width: 100%; padding: 8px 10px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 12px; font-weight: 400; line-height: 18px; overflow-wrap: anywhere; white-space: normal; } .dim-panel .dim-cardActions { flex: none; display: flex; align-items: center; flex-wrap: nowrap; gap: 8px; margin: 0 0 0 auto; } .dim-panel .dim-cardActions .dim-cardAction { flex: none; min-height: 32px; padding: 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; line-height: normal; white-space: nowrap; } .dim-panel .dim-cardActions .dim-cardAction:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); } diff --git a/plugin-src/client/channels/dingtalk/index.js b/plugin-src/client/channels/dingtalk/index.js index b111e1f..18990f9 100644 --- a/plugin-src/client/channels/dingtalk/index.js +++ b/plugin-src/client/channels/dingtalk/index.js @@ -253,16 +253,17 @@ export function AccountCard({ onSave: onAgentPresetSave, }), h('div', { className: 'ddt-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, - feedback ? h('div', { - className: 'ddt-summary dim-cardSummary', - role: 'status', - }, feedback) : null, - h('div', { className: 'ddt-actions dim-cardActions' }, - h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, - busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, - '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'ddt-actions dim-cardActions' }, + h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, + busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, + '移除接入')), + summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, + feedback ? h('div', { + className: 'ddt-summary dim-cardFeedback', + role: 'status', + }, feedback) : null))), removing ? h(RemoveConfirmation, { account, busy: busy === 'delete', diff --git a/plugin-src/client/channels/feishu/index.js b/plugin-src/client/channels/feishu/index.js index 7a18acb..4e47f72 100644 --- a/plugin-src/client/channels/feishu/index.js +++ b/plugin-src/client/channels/feishu/index.js @@ -629,30 +629,31 @@ export function BotCard({ }, provisionContent) : null, h("div", { className: "bxf-connectedFooter dim-cardFooter" }, - summary ? h("div", { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : undefined }, - summary) : null, - testNotice ? h("div", { - className: "bxf-healthSummary dim-cardSummary", - role: "status", - }, testNotice) : null, - h("div", { className: "bxf-actions bxf-botActions dim-cardActions" }, - h(Button, { - className: "dim-cardAction", onClick: onReconnect, - disabled: Boolean(busy), "aria-busy": busy === "reconnect" ? "true" : undefined, - "aria-label": `${connected ? "检查连接" : "重试连接"}${bot.name}`, - }, busy === "reconnect" ? (connected ? "检查中…" : "正在连接…") : connected ? "检查连接" : "重试连接"), - h(Button, { - className: "bxf-repairButton dim-cardAction", - onClick: onRepairCallback, - disabled: Boolean(busy) || repairDisabled, - "aria-busy": busy === "callback-repair" ? "true" : undefined, - "aria-label": `修复${bot.name}的卡片按钮`, - }, busy === "callback-repair" ? "等待扫码…" : "修复卡片按钮"), - h(Button, { - className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, - disabled: Boolean(busy), ref: removeButtonRef, - "aria-label": `从 DeepSeek Harness 移除${bot.name}`, - }, "移除接入")), + h("div", { className: "dim-cardFooterLayout" }, + h("div", { className: "bxf-actions bxf-botActions dim-cardActions" }, + h(Button, { + className: "dim-cardAction", onClick: onReconnect, + disabled: Boolean(busy), "aria-busy": busy === "reconnect" ? "true" : undefined, + "aria-label": `${connected ? "检查连接" : "重试连接"}${bot.name}`, + }, busy === "reconnect" ? (connected ? "检查中…" : "正在连接…") : connected ? "检查连接" : "重试连接"), + h(Button, { + className: "bxf-repairButton dim-cardAction", + onClick: onRepairCallback, + disabled: Boolean(busy) || repairDisabled, + "aria-busy": busy === "callback-repair" ? "true" : undefined, + "aria-label": `修复${bot.name}的卡片按钮`, + }, busy === "callback-repair" ? "等待扫码…" : "修复卡片按钮"), + h(Button, { + className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, + disabled: Boolean(busy), ref: removeButtonRef, + "aria-label": `从 DeepSeek Harness 移除${bot.name}`, + }, "移除接入")), + summary ? h("div", { className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : undefined }, + summary) : null, + testNotice ? h("div", { + className: "bxf-healthSummary dim-cardFeedback", + role: "status", + }, testNotice) : null), ), ), removing diff --git a/plugin-src/client/channels/qq/index.js b/plugin-src/client/channels/qq/index.js index 119ccae..379fdd4 100644 --- a/plugin-src/client/channels/qq/index.js +++ b/plugin-src/client/channels/qq/index.js @@ -192,15 +192,16 @@ export function AccountCard({ onSave: onAgentPresetSave, }), h('div', { className: 'ddt-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, - feedback ? h('div', { - className: 'ddt-summary dim-cardSummary', - role: 'status', - 'aria-live': 'polite', - }, feedback) : null, - h('div', { className: 'ddt-actions dim-cardActions' }, - h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'ddt-actions dim-cardActions' }, + h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')), + summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, + feedback ? h('div', { + className: 'ddt-summary dim-cardFeedback', + role: 'status', + 'aria-live': 'polite', + }, feedback) : null))), removing ? h(RemoveConfirmation, { account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove, }) : null); diff --git a/plugin-src/client/channels/shared/token-channel.js b/plugin-src/client/channels/shared/token-channel.js index 30aafcd..0842ed8 100644 --- a/plugin-src/client/channels/shared/token-channel.js +++ b/plugin-src/client/channels/shared/token-channel.js @@ -106,20 +106,24 @@ export function createTokenChannelSettings(definition) { onSave: onAccountSettingsSave, }) : null, h('div', { className: 'ddt-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, - testNotice ? h('div', { className: 'ddt-summary dim-cardSummary', role: 'status' }, testNotice) : null, - h('div', { className: 'ddt-actions dim-cardActions' }, - h(Button, { - className: 'dim-cardAction', - onClick: onReconnect, - disabled: Boolean(busy), - }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { - className: 'dim-cardAction', - kind: 'danger', - onClick: onRequestRemove, - disabled: Boolean(busy), - }, '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'ddt-actions dim-cardActions' }, + h(Button, { + className: 'dim-cardAction', + onClick: onReconnect, + disabled: Boolean(busy), + }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { + className: 'dim-cardAction', + kind: 'danger', + onClick: onRequestRemove, + disabled: Boolean(busy), + }, '移除接入')), + summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, + testNotice ? h('div', { + className: 'ddt-summary dim-cardFeedback', + role: 'status', + }, testNotice) : null))), removing ? h('div', { className: 'ddt-confirm dim-confirm', role: 'alertdialog' }, h('strong', null, `从 DeepSeek Harness 移除“${account.bot.name}”?`), h('p', null, `这会停止消息连接,并删除本机保存的 ${credentialNoun}、机器人配置及会话映射。${platformLabel}中的机器人不会被自动删除。`), diff --git a/plugin-src/client/channels/wecom/index.js b/plugin-src/client/channels/wecom/index.js index ed61c5e..2459eaa 100644 --- a/plugin-src/client/channels/wecom/index.js +++ b/plugin-src/client/channels/wecom/index.js @@ -191,15 +191,16 @@ export function AccountCard({ onSave: onAgentPresetSave, }), h('div', { className: 'ddt-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, - feedback ? h('div', { - className: 'ddt-summary dim-cardSummary', - role: 'status', - 'aria-live': 'polite', - }, feedback) : null, - h('div', { className: 'ddt-actions dim-cardActions' }, - h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'ddt-actions dim-cardActions' }, + h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')), + summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, + feedback ? h('div', { + className: 'ddt-summary dim-cardFeedback', + role: 'status', + 'aria-live': 'polite', + }, feedback) : null))), removing ? h(RemoveConfirmation, { account, busy: busy === 'delete', onConfirm: onConfirmRemove, onCancel: onCancelRemove, }) : null); diff --git a/plugin-src/client/channels/weixin/index.js b/plugin-src/client/channels/weixin/index.js index da5c93d..5b556ba 100644 --- a/plugin-src/client/channels/weixin/index.js +++ b/plugin-src/client/channels/weixin/index.js @@ -240,20 +240,21 @@ export function AccountCard({ onSave: onAgentPresetSave, }), h('div', { className: 'dxw-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'dxw-summary dim-cardSummary' }, summary) : null, - account.lastMessageError ? h('div', { - className: 'dxw-summary dim-cardSummary', - role: 'status', - }, `最近一条消息处理失败:${account.lastMessageError.message}`) : null, - feedback ? h('div', { - className: 'dxw-summary dim-cardSummary', - role: 'status', - 'aria-live': 'polite', - }, feedback) : null, - h('div', { className: 'dxw-actions dim-cardActions' }, - h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, - busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'dxw-actions dim-cardActions' }, + h(Button, { className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy) }, + busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy) }, '移除接入')), + summary ? h('div', { className: 'dxw-summary dim-cardSummary' }, summary) : null, + account.lastMessageError ? h('div', { + className: 'dxw-summary dim-cardSummary', + role: 'status', + }, `最近一条消息处理失败:${account.lastMessageError.message}`) : null, + feedback ? h('div', { + className: 'dxw-summary dim-cardFeedback', + role: 'status', + 'aria-live': 'polite', + }, feedback) : null))), removing ? h('div', { className: 'dxw-confirm dim-confirm', role: 'alertdialog' }, h('strong', null, '从此 Harness 移除这个微信账号?'), h('p', null, '这会停止消息连接,并删除本机保存的 bot_token、账号配置和会话映射。其他微信账号不受影响。'), diff --git a/plugin-src/client/channels/whatsapp/index.js b/plugin-src/client/channels/whatsapp/index.js index 8508e65..243af0d 100644 --- a/plugin-src/client/channels/whatsapp/index.js +++ b/plugin-src/client/channels/whatsapp/index.js @@ -217,18 +217,19 @@ export function WhatsappAccountCard({ onSave: onAgentPresetSave, }), h('div', { className: 'ddt-accountFooter dim-cardFooter' }, - summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, - testNotice ? h('div', { - className: 'ddt-summary dim-cardSummary', - role: 'status', - }, testNotice) : null, - h('div', { className: 'ddt-actions dim-cardActions' }, - h(Button, { - className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy), - }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), - h(Button, { - className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy), - }, '移除接入')))), + h('div', { className: 'dim-cardFooterLayout' }, + h('div', { className: 'ddt-actions dim-cardActions' }, + h(Button, { + className: 'dim-cardAction', onClick: onReconnect, disabled: Boolean(busy), + }, busy === 'reconnect' ? '检查中…' : account.connected ? '检查连接' : '重试连接'), + h(Button, { + className: 'dim-cardAction', kind: 'danger', onClick: onRequestRemove, disabled: Boolean(busy), + }, '移除接入')), + summary ? h('div', { className: 'ddt-summary dim-cardSummary' }, summary) : null, + testNotice ? h('div', { + className: 'ddt-summary dim-cardFeedback', + role: 'status', + }, testNotice) : null))), removing ? h(RemoveConfirmation, { account, busy: busy === 'delete', diff --git a/plugin-src/client/styles.js b/plugin-src/client/styles.js index d4be2bc..00bd747 100644 --- a/plugin-src/client/styles.js +++ b/plugin-src/client/styles.js @@ -192,6 +192,9 @@ const CSS = String.raw` .dim-directoryPickerActions button:hover:not(:disabled) { filter: brightness(.97); } .dim-directoryPickerActions button:disabled { cursor: not-allowed; opacity: .52; } .dim-panel .dim-cardSummary { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font: inherit; font-size: 12px; font-weight: 400; line-height: normal; } +.dim-panel .dim-cardFooterLayout { min-width: 0; width: 100%; display: flex; flex-direction: column; align-items: stretch; gap: 9px; } +.dim-panel .dim-cardFooterLayout > .dim-cardActions { align-self: flex-end; } +.dim-panel .dim-cardFeedback { width: 100%; padding: 8px 10px; border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-module-platform, #f7f8fa); font: inherit; font-size: 12px; font-weight: 400; line-height: 18px; overflow-wrap: anywhere; white-space: normal; } .dim-panel .dim-cardActions { flex: none; display: flex; align-items: center; flex-wrap: nowrap; gap: 8px; margin: 0 0 0 auto; } .dim-panel .dim-cardActions .dim-cardAction { flex: none; min-height: 32px; padding: 0 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 13px; font-weight: 560; line-height: normal; white-space: nowrap; } .dim-panel .dim-cardActions .dim-cardAction:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); } diff --git a/test/channels/dingtalk/client-lifecycle.test.mjs b/test/channels/dingtalk/client-lifecycle.test.mjs index 10973e4..0eb13de 100644 --- a/test/channels/dingtalk/client-lifecycle.test.mjs +++ b/test/channels/dingtalk/client-lifecycle.test.mjs @@ -235,7 +235,11 @@ test('connection-check failure stays on the matching card with locale-safe wordi assert.match(nodeText(targetCard), /现有连接错误/); assert.equal( targetCard.findAll((node) => node.props.className?.includes('dim-cardSummary')).length, - 2, + 1, + ); + assert.equal( + targetCard.findAll((node) => node.props.className?.includes('dim-cardFeedback')).length, + 1, ); assert.doesNotMatch(nodeText(targetCard), /provider-specific failure/); const announcement = [...clock.frames.entries()].at(-1); diff --git a/test/channels/feishu/connection-test-client.test.mjs b/test/channels/feishu/connection-test-client.test.mjs index 1cf2861..63ca4f3 100644 --- a/test/channels/feishu/connection-test-client.test.mjs +++ b/test/channels/feishu/connection-test-client.test.mjs @@ -34,7 +34,7 @@ test('Feishu connection check requests and displays test-message feedback', asyn assert.match(source, /机器人尚未收到可用于测试的私聊消息/); assert.doesNotMatch(source, /请先私聊机器人发送 \/status/); - const markup = renderToStaticMarkup(React.createElement(BotCard, { + const cardProps = { connection: { botId: 'bot-feishu-test', state: 'connected', @@ -47,8 +47,21 @@ test('Feishu connection check requests and displays test-message feedback', asyn onRequestRemove() {}, onConfirmRemove() {}, onCancelRemove() {}, - })); + }; + const markup = renderToStaticMarkup(React.createElement(BotCard, cardProps)); assert.match(markup, /role="status"[^>]*>测试消息已发送/); + assert.match(markup, /class="dim-cardFooterLayout"[^]*class="bxf-actions bxf-botActions dim-cardActions"[^]*class="bxf-healthSummary dim-cardFeedback"/); + + let renderer; + await act(async () => { + renderer = create(React.createElement(BotCard, cardProps)); + }); + const footerChildren = renderer.root.findByProps({ className: 'dim-cardFooterLayout' }).children; + assert.match(footerChildren[0].props.className, /\bbxf-botActions\b/); + assert.equal(footerChildren[1].props.role, 'status'); + assert.match(footerChildren[1].props.className, /\bdim-cardFeedback\b/); + await act(async () => renderer.unmount()); + assert.match(markup, /修复卡片按钮/); assert.match(markup, /aria-label="修复飞书测试机器人的卡片按钮"/); assert.match(markup, /]*aria-label="群聊响应方式"/); diff --git a/test/client-ui.test.mjs b/test/client-ui.test.mjs index 42be42c..454bed8 100644 --- a/test/client-ui.test.mjs +++ b/test/client-ui.test.mjs @@ -493,7 +493,7 @@ test('DingTalk bot cards omit the redundant received and replied metric', () => assert.doesNotMatch(markup, /收到 \/ 回复/); }); -test('all channel card action buttons stay on one row', async () => { +test('all IM channel cards place one-row actions above full-width feedback', async () => { const [imStyles, feishuStyles, weixinStyles, dingtalkStyles] = await Promise.all([ readFile(STYLES_URL, 'utf8'), readFile(FEISHU_STYLES_URL, 'utf8'), @@ -505,11 +505,53 @@ test('all channel card action buttons stay on one row', async () => { assert.match(weixinStyles, /\.dxw-accountFooter \.dxw-actions \{[^}]*flex-wrap: nowrap;/); assert.match(dingtalkStyles, /\.ddt-accountFooter \.ddt-actions \{[^}]*flex-wrap: nowrap;/); assert.match(imStyles, /\.dim-panel \.dim-cardFooter \{[^}]*gap: 12px;[^}]*padding-top: 6px;[^}]*border-top: 1px solid/); + assert.match(imStyles, /\.dim-panel \.dim-cardFooterLayout \{[^}]*width: 100%;[^}]*flex-direction: column;[^}]*align-items: stretch;/); + assert.match(imStyles, /\.dim-panel \.dim-cardFooterLayout > \.dim-cardActions \{[^}]*align-self: flex-end;/); + assert.match(imStyles, /\.dim-panel \.dim-cardFeedback \{[^}]*width: 100%;[^}]*overflow-wrap: anywhere;[^}]*white-space: normal;/); assert.match(imStyles, /\.dim-panel \.dim-cardActions \.dim-cardAction \{[^}]*min-height: 32px;[^}]*border-radius: 8px;[^}]*font-size: 13px;/); assert.match(imStyles, /\.dim-panel \.dim-cardActions \.dim-cardAction\[data-kind="danger"\] \{[^}]*#d54941/); - assert.doesNotMatch(feishuStyles, /\.bxf-connectedFooter \{[^}]*flex-direction: column/); - assert.doesNotMatch(weixinStyles, /\.dxw-accountFooter \{[^}]*flex-direction: column/); - assert.doesNotMatch(dingtalkStyles, /\.ddt-accountFooter \{[^}]*flex-direction: column/); + + const account = { + botId: 'footer-layout-bot', + connected: true, + configured: true, + state: 'connected', + groupResponseMode: 'mention', + bot: { + name: '布局测试机器人', + username: 'layout_bot', + appIdMasked: 'cli_test••••1234', + accountIdMasked: 'wx_test••••1234', + clientIdMasked: 'ding_test••••1234', + idMasked: 'bot_test••••1234', + }, + health: { summary: '连接运行正常', lastCheckedAt: Date.now() }, + error: null, + }; + const callbacks = { + onReconnect() {}, + onRequestRemove() {}, + onConfirmRemove() {}, + onCancelRemove() {}, + }; + const notice = '测试消息已发送,请到对应机器人会话中确认。'; + const cards = [ + ['飞书', FeishuBotCard, { connection: account, testNotice: notice }], + ['微信', WeixinAccountCard, { account, feedback: notice }], + ['钉钉', DingtalkAccountCard, { account, feedback: notice }], + ['企业微信', WecomAccountCard, { account, feedback: notice }], + ['QQ', QqAccountCard, { account, feedback: notice }], + ['Slack', SlackAccountCard, { account, testNotice: notice }], + ['Telegram', TelegramAccountCard, { account, testNotice: notice }], + ['Discord', DiscordAccountCard, { account, testNotice: notice }], + ['WhatsApp', WhatsappAccountCard, { account, testNotice: notice }], + ]; + + for (const [channel, Card, props] of cards) { + const markup = renderToStaticMarkup(React.createElement(Card, { ...callbacks, ...props })); + assert.match(markup, /class="dim-cardFooterLayout">
[^]*?<\/div>
{