mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 10:23:17 +08:00
feat(ui): compact bot connection metadata
This commit is contained in:
parent
59ed364856
commit
2803bbcbab
22 changed files with 632 additions and 556 deletions
|
|
@ -63,16 +63,9 @@ test('the QR card responds to its plugin panel width instead of the browser view
|
|||
assert.match(styles, /\.ddt-qrCopy \{ min-width: 0; overflow-wrap: anywhere; \}/);
|
||||
});
|
||||
|
||||
test('bot metrics stay in one compact two-column row at narrow widths', async () => {
|
||||
test('bot cards do not reserve a row for repeated channel metrics', async () => {
|
||||
const styles = await readFile(STYLES_URL, 'utf8');
|
||||
assert.match(
|
||||
styles,
|
||||
/\.ddt-metrics \{[^\n]*grid-template-columns: repeat\(2, minmax\(0, 1fr\)\)/,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
styles,
|
||||
/\.ddt-metrics \{ grid-template-columns: minmax\(0, 1fr\); \}/,
|
||||
);
|
||||
assert.doesNotMatch(styles, /\.ddt-metrics|\.ddt-metric/);
|
||||
});
|
||||
|
||||
test('the narrow-panel toolbar keeps all three controls on one row', async () => {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ test('Discord account card matches the unified compact card layout', () => {
|
|||
}));
|
||||
assert.match(markup, /data-im-channel-logo="discord"/);
|
||||
assert.match(markup, /@HarnessBot/);
|
||||
assert.match(markup, />Gateway 长连接</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /Gateway 长连接|消息通道|dim-botMetric/);
|
||||
assert.match(markup, />检查连接</);
|
||||
assert.match(markup, />移除接入</);
|
||||
assert.doesNotMatch(markup, /dim-cardSummary/);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ test('QQ settings uses the shared compact channel toolbar', () => {
|
|||
assert.doesNotMatch(markup, /凭据仅保存在本机|role="switch"|type="checkbox"/);
|
||||
});
|
||||
|
||||
test('QQ bot cards match the shared two-metric card treatment', () => {
|
||||
test('QQ bot cards keep check time with status and omit repeated channel details', () => {
|
||||
const markup = renderToStaticMarkup(React.createElement(AccountCard, {
|
||||
account: {
|
||||
botId: 'qq_bot',
|
||||
|
|
@ -38,8 +38,8 @@ test('QQ bot cards match the shared two-metric card treatment', () => {
|
|||
}));
|
||||
assert.match(markup, /class="ddt-card dim-botCard"/);
|
||||
assert.match(markup, /data-im-channel-logo="qq"/);
|
||||
assert.equal((markup.match(/class="ddt-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(markup, />消息通道<[^]*>最近检查</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /消息通道|dim-botMetric/);
|
||||
assert.match(markup, />检查连接<[^]*>移除接入</);
|
||||
assert.match(markup, /class="dim-presetSelect"/);
|
||||
assert.doesNotMatch(markup, /收到\s*\/\s*回复|dim-cardSummary|QQ WebSocket 长连接运行正常/);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ test('Slack account card matches the unified compact layout', () => {
|
|||
}));
|
||||
assert.match(markup, /data-im-channel-logo="slack"/);
|
||||
assert.match(markup, /@deepseek-harness/);
|
||||
assert.match(markup, />Socket Mode 长连接</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /Socket Mode 长连接|消息通道|dim-botMetric/);
|
||||
assert.match(markup, />检查连接</);
|
||||
assert.match(markup, />移除接入</);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ test('Telegram account card matches the unified compact card layout', () => {
|
|||
}));
|
||||
assert.match(markup, /data-im-channel-logo="telegram"/);
|
||||
assert.match(markup, /@harness_bot/);
|
||||
assert.match(markup, />Bot API 长轮询</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /Bot API 长轮询|消息通道|dim-botMetric/);
|
||||
assert.match(markup, />检查连接</);
|
||||
assert.match(markup, />移除接入</);
|
||||
assert.match(markup, />访问设置</);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ test('Enterprise WeChat settings uses the shared compact channel toolbar', () =>
|
|||
assert.doesNotMatch(markup, /凭据仅保存在本机|role="switch"|type="checkbox"/);
|
||||
});
|
||||
|
||||
test('Enterprise WeChat bot cards match the shared two-metric card treatment', () => {
|
||||
test('Enterprise WeChat cards keep check time with status and omit repeated channel details', () => {
|
||||
const markup = renderToStaticMarkup(React.createElement(AccountCard, {
|
||||
account: {
|
||||
botId: 'wecom_bot',
|
||||
|
|
@ -67,8 +67,8 @@ test('Enterprise WeChat bot cards match the shared two-metric card treatment', (
|
|||
}));
|
||||
assert.match(markup, /class="ddt-card dim-botCard"/);
|
||||
assert.match(markup, /data-im-channel-logo="wecom"/);
|
||||
assert.equal((markup.match(/class="ddt-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(markup, />消息通道<[^]*>最近检查</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /消息通道|dim-botMetric/);
|
||||
assert.match(markup, />检查连接<[^]*>移除接入</);
|
||||
assert.match(markup, /class="dim-presetSelect"/);
|
||||
assert.doesNotMatch(markup, /收到\s*\/\s*回复|dim-cardSummary|企业微信 WebSocket 长连接运行正常/);
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@ test('WhatsApp account card uses the unified compact channel layout', () => {
|
|||
testNotice: '测试消息已发送,请到 WhatsApp 自聊会话中确认。',
|
||||
}));
|
||||
assert.match(markup, /data-im-channel-logo="whatsapp"/);
|
||||
assert.match(markup, /WhatsApp Web/);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /WhatsApp Web|消息通道|dim-botMetric/);
|
||||
assert.match(markup, /检查连接/);
|
||||
assert.match(markup, /移除接入/);
|
||||
assert.match(markup, /class="dim-presetSelect"/);
|
||||
assert.match(markup, /role="status"[^>]*>测试消息已发送/);
|
||||
assert.equal((markup.match(/class="ddt-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
});
|
||||
|
||||
test('WhatsApp connection check requests a test message from the existing reconnect endpoint', async () => {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
inject as clientInject,
|
||||
} from '../plugin-src/client/index.js';
|
||||
import { CredentialBindingPanel } from '../plugin-src/client/credential-binding.js';
|
||||
import { ChannelListHeading } from '../plugin-src/client/channel-card-meta.js';
|
||||
import { DINGTALK_ENDPOINTS } from '../plugin-src/client/channels/dingtalk/api.js';
|
||||
import {
|
||||
AccountCard as DingtalkAccountCard,
|
||||
|
|
@ -235,11 +236,11 @@ test('Feishu bot cards place the application identifier under the bot name', asy
|
|||
assert.equal((markup.match(/dim-cardAction(?: |")/g) ?? []).length, 3);
|
||||
assert.doesNotMatch(markup, /连接状态:|bxf-divider/);
|
||||
assert.doesNotMatch(markup, /custom-bot-avatar/);
|
||||
assert.equal((markup.match(/class="bxf-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(markup, />消息通道<[^]*>最近检查</);
|
||||
assert.match(markup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /消息通道|dim-botMetric/);
|
||||
assert.match(markup, /class="dim-presetSelect"/);
|
||||
assert.doesNotMatch(markup, />应用标识<|>飞书机器人</);
|
||||
assert.match(styles, /\.bxf-statusGrid \{[^}]*grid-template-columns: repeat\(2, minmax\(0, 1fr\)\)/);
|
||||
assert.doesNotMatch(styles, /\.bxf-statusGrid|\.bxf-metric/);
|
||||
});
|
||||
|
||||
test('Feishu keeps its heading controls on one row without a plus icon', async () => {
|
||||
|
|
@ -369,9 +370,24 @@ test('bot list headings omit the total already shown by the online badge', async
|
|||
|
||||
for (const source of sources) {
|
||||
assert.doesNotMatch(source, /length} 个/);
|
||||
assert.match(source, /ChannelListHeading/);
|
||||
}
|
||||
});
|
||||
|
||||
test('channel connection details live in an accessible heading tooltip', async () => {
|
||||
const styles = await readFile(STYLES_URL, 'utf8');
|
||||
const markup = renderToStaticMarkup(React.createElement(ChannelListHeading, {
|
||||
className: 'dxw-listHeading',
|
||||
title: '已接入的微信账号',
|
||||
connectionLabel: 'iLink 长轮询',
|
||||
}));
|
||||
|
||||
assert.match(markup, /<h3>已接入的微信账号<\/h3>/);
|
||||
assert.match(markup, /aria-label="查看消息通道说明"/);
|
||||
assert.match(markup, /role="tooltip"><span>消息通道<\/span><strong>iLink 长轮询<\/strong>/);
|
||||
assert.match(styles, /\.dim-panel \.dim-channelHelp:hover \.dim-channelTooltip, \.dim-panel \.dim-channelHelp:focus-within \.dim-channelTooltip \{[^}]*opacity: 1;[^}]*visibility: visible;/);
|
||||
});
|
||||
|
||||
test('all channel settings states use the DingTalk page treatment', async () => {
|
||||
const [styles, feishuSource, weixinSource, dingtalkSource, wecomSource] = await Promise.all([
|
||||
readFile(STYLES_URL, 'utf8'),
|
||||
|
|
@ -398,7 +414,6 @@ test('all channel settings states use the DingTalk page treatment', async () =>
|
|||
'dim-emptyView',
|
||||
'dim-qrLayout',
|
||||
'dim-inlineError',
|
||||
'dim-listHeading',
|
||||
'dim-confirm',
|
||||
]) {
|
||||
assert.match(source, new RegExp(className));
|
||||
|
|
@ -449,7 +464,8 @@ test('bot cards reuse the same channel brand logos as the channel rail', () => {
|
|||
assert.match(accountMarkup, /class="dim-presetSelect"/);
|
||||
assert.doesNotMatch(accountMarkup, /dim-cardSummary|微信消息长轮询运行正常/);
|
||||
assert.equal((accountMarkup.match(/dim-cardAction(?: |")/g) ?? []).length, 2);
|
||||
assert.equal((accountMarkup.match(/class="dxw-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(accountMarkup, /class="dim-botHealthGroup"[^]*class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(accountMarkup, /消息通道|dim-botMetric/);
|
||||
assert.doesNotMatch(accountMarkup, /收到 \/ 回复/);
|
||||
});
|
||||
|
||||
|
|
@ -464,7 +480,8 @@ test('Enterprise WeChat cards reuse the rail logo and compact action treatment',
|
|||
}));
|
||||
assert.match(markup, /data-im-channel-logo="wecom"/);
|
||||
assert.equal((markup.match(/dim-cardAction(?: |")/g) ?? []).length, 2);
|
||||
assert.equal((markup.match(/class="ddt-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(markup, /class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.doesNotMatch(markup, /消息通道|dim-botMetric/);
|
||||
});
|
||||
|
||||
test('DingTalk bot cards omit the redundant received and replied metric', () => {
|
||||
|
|
@ -485,11 +502,11 @@ test('DingTalk bot cards omit the redundant received and replied metric', () =>
|
|||
|
||||
assert.match(markup, /class="ddt-card dim-botCard"/);
|
||||
assert.match(markup, /class="ddt-health dim-botHealth"/);
|
||||
assert.equal((markup.match(/class="ddt-metric dim-botMetric"/g) ?? []).length, 2);
|
||||
assert.match(markup, /class="dim-lastChecked"><span>最近检查<\/span>/);
|
||||
assert.match(markup, /class="ddt-accountFooter dim-cardFooter"/);
|
||||
assert.doesNotMatch(markup, /dim-cardSummary|Stream 长连接运行正常/);
|
||||
assert.equal((markup.match(/dim-cardAction(?: |")/g) ?? []).length, 2);
|
||||
assert.match(markup, />消息通道<[^]*>最近检查</);
|
||||
assert.doesNotMatch(markup, /消息通道|dim-botMetric/);
|
||||
assert.doesNotMatch(markup, /收到 \/ 回复/);
|
||||
});
|
||||
|
||||
|
|
@ -562,10 +579,10 @@ test('all channel bot cards use the DingTalk card treatment', async () => {
|
|||
assert.match(styles, /\.dim-panel \.dim-botCardTop \{[^}]*align-items: flex-start;[^}]*gap: 12px;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botAvatar \{[^}]*width: 38px;[^}]*height: 38px;[^}]*border-radius: 11px;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botName h3 \{[^}]*font-size: 15px;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botHealthGroup \{[^}]*display: grid;[^}]*justify-items: end;[^}]*gap: 5px;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botCard \.dim-botHealth \{[^}]*background: transparent;[^}]*font-size: 12px;[^}]*font-weight: 400;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botMetrics \{[^}]*grid-template-columns: repeat\(2, minmax\(0, 1fr\)\);[^}]*gap: 8px;[^}]*margin: 6px 0;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botMetric \{[^}]*padding: 6px 8px;[^}]*border: 0;[^}]*border-radius: 9px;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-botMetric dd \{[^}]*margin: 3px 0 0;[^}]*font-size: 12px;[^}]*font-weight: 400;/);
|
||||
assert.match(styles, /\.dim-panel \.dim-lastChecked \{[^}]*display: inline-flex;[^}]*font-size: 11px;[^}]*white-space: nowrap;/);
|
||||
assert.doesNotMatch(styles, /\.dim-panel \.dim-botMetrics|\.dim-panel \.dim-botMetric/);
|
||||
});
|
||||
|
||||
test('bot cards keep the full workspace path on its own single line', async () => {
|
||||
|
|
@ -779,7 +796,7 @@ test('all nine channel settings and connected cards render English copy', () =>
|
|||
];
|
||||
const cardMarkup = cards.map(renderToStaticMarkup).join('\n');
|
||||
assert.match(cardMarkup, /Connected/);
|
||||
assert.match(cardMarkup, /Message channel/);
|
||||
assert.doesNotMatch(cardMarkup, /Message channel/);
|
||||
assert.match(cardMarkup, /Last checked/);
|
||||
assert.match(cardMarkup, /Check connection/);
|
||||
assert.match(cardMarkup, /Remove connection/);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue