mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 00:33:20 +08:00
feat(ui): show plugin version on brand hover
This commit is contained in:
parent
7211534aef
commit
b42fc411c2
5 changed files with 173 additions and 7 deletions
137
lib/client.js
137
lib/client.js
|
|
@ -35,6 +35,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|||
var index_exports = {};
|
||||
__export(index_exports, {
|
||||
IMSettingsTab: () => IMSettingsTab,
|
||||
IM_PLUGIN_VERSION: () => IM_PLUGIN_VERSION,
|
||||
LoopbackRecoveryNotice: () => LoopbackRecoveryNotice,
|
||||
apply: () => apply,
|
||||
inject: () => inject,
|
||||
|
|
@ -43,6 +44,115 @@ __export(index_exports, {
|
|||
module.exports = __toCommonJS(index_exports);
|
||||
var React20 = __toESM(require("react"), 1);
|
||||
|
||||
// package.json
|
||||
var package_default = {
|
||||
name: "@xmanrui/dsh-im",
|
||||
version: "2.4.0",
|
||||
description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
|
||||
keywords: [
|
||||
"deepseek-harness",
|
||||
"dsh",
|
||||
"dsh-plugin",
|
||||
"ai-agent",
|
||||
"im",
|
||||
"instant-messaging",
|
||||
"chatbot",
|
||||
"feishu",
|
||||
"lark",
|
||||
"wechat",
|
||||
"wecom",
|
||||
"dingtalk",
|
||||
"qq",
|
||||
"slack",
|
||||
"telegram",
|
||||
"discord",
|
||||
"whatsapp",
|
||||
"ai-office"
|
||||
],
|
||||
author: {
|
||||
name: "xmanrui",
|
||||
url: "https://github.com/xmanrui"
|
||||
},
|
||||
contributors: [
|
||||
{
|
||||
name: "C3H3-AI",
|
||||
url: "https://github.com/C3H3-AI"
|
||||
}
|
||||
],
|
||||
license: "MIT",
|
||||
type: "module",
|
||||
repository: {
|
||||
type: "git",
|
||||
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",
|
||||
publishConfig: {
|
||||
access: "public"
|
||||
},
|
||||
bin: {
|
||||
"dsh-im": "bin/dsh-im.mjs"
|
||||
},
|
||||
main: "./lib/index.js",
|
||||
exports: {
|
||||
".": "./lib/index.js",
|
||||
"./client": "./lib/client.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
files: [
|
||||
"assets",
|
||||
"bin",
|
||||
"cordis.patch.yml",
|
||||
"lib",
|
||||
"plugin-src",
|
||||
"scripts",
|
||||
"src",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"README.en.md",
|
||||
"THIRD_PARTY_NOTICES.md"
|
||||
],
|
||||
dsh: {
|
||||
bundle: {
|
||||
patch: "./cordis.patch.yml"
|
||||
},
|
||||
client: {
|
||||
inject: [
|
||||
"@deepseek-ai/dsh-client-connection",
|
||||
"@deepseek-ai/dsh-client-runtime",
|
||||
"@deepseek-ai/dsh-client-ui-settings",
|
||||
"@deepseek-ai/dsh-client-ui-slots",
|
||||
"@deepseek-ai/dsh-client-locale"
|
||||
],
|
||||
platform: "web"
|
||||
}
|
||||
},
|
||||
scripts: {
|
||||
build: "node plugin-src/client/build.mjs && node plugin-src/host/build.mjs",
|
||||
test: "node --test test/*.test.mjs test/channels/*/*.test.mjs",
|
||||
check: "npm test && npm run build && node scripts/verify-package.mjs"
|
||||
},
|
||||
engines: {
|
||||
node: ">=22.19"
|
||||
},
|
||||
dependencies: {
|
||||
"@tencent-connect/qqbot-connector": "1.2.0",
|
||||
"@tencent-connect/qqbot-nodejs": "1.0.4",
|
||||
"@wecom/aibot-node-sdk": "1.0.7",
|
||||
"dingtalk-stream": "2.1.4",
|
||||
qrcode: "1.5.4"
|
||||
},
|
||||
devDependencies: {
|
||||
"@larksuiteoapi/node-sdk": "1.73.0",
|
||||
"@whiskeysockets/baileys": "7.0.0-rc14",
|
||||
esbuild: "0.25.9",
|
||||
"https-proxy-agent": "5.0.1",
|
||||
react: "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-test-renderer": "18.3.1"
|
||||
}
|
||||
};
|
||||
|
||||
// plugin-src/client/channel-logos.js
|
||||
var React = __toESM(require("react"), 1);
|
||||
var h = React.createElement;
|
||||
|
|
@ -199,6 +309,7 @@ var EN = Object.freeze({
|
|||
"IM\u673A\u5668\u4EBA\u8BBE\u7F6E": "IM bot settings",
|
||||
"IM \u6E20\u9053": "IM channels",
|
||||
"\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA": "DeepSeek Harness, always within reach",
|
||||
"\u5F53\u524D\u7248\u672C": "Current version",
|
||||
"AI Office": "AI Office",
|
||||
"\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09": "(Experimental)",
|
||||
"AI Office \u8BBE\u7F6E": "AI Office settings",
|
||||
|
|
@ -10131,9 +10242,13 @@ var CSS11 = String.raw`
|
|||
}
|
||||
.dim-page *, .dim-page *::before, .dim-page *::after { box-sizing: border-box; }
|
||||
.dim-title { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 18px; }
|
||||
.dim-brand { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
|
||||
.dim-brand { position: relative; min-width: 0; width: max-content; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; margin: -2px -6px; padding: 2px 6px; border-radius: 8px; cursor: help; }
|
||||
.dim-brand:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
||||
.dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
|
||||
.dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
|
||||
.dim-versionTooltip { position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 20; width: max-content; max-width: min(220px, 80vw); display: inline-flex; align-items: center; gap: 6px; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
||||
.dim-versionTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font: 600 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||||
.dim-brand:hover .dim-versionTooltip, .dim-brand:focus .dim-versionTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
||||
.dim-githubAction { position: relative; display: inline-flex; flex: none; }
|
||||
.dim-githubLink { min-height: 30px; display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 12px; line-height: normal; font-weight: 560; text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
|
||||
.dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
||||
|
|
@ -10425,6 +10540,7 @@ function installImStyles() {
|
|||
// plugin-src/client/index.js
|
||||
var name = "im-settings";
|
||||
var inject = ["slots", "connection", "locale", "workspaces"];
|
||||
var IM_PLUGIN_VERSION = package_default.version;
|
||||
var CHANNELS = Object.freeze([
|
||||
{ id: "weixin", label: "\u5FAE\u4FE1" },
|
||||
{ id: "feishu", label: "\u98DE\u4E66" },
|
||||
|
|
@ -10549,6 +10665,7 @@ function IMSettingsTab({
|
|||
}) {
|
||||
const [selected, setSelected] = React20.useState("weixin");
|
||||
const [loopbackRecovery, setLoopbackRecovery] = React20.useState(null);
|
||||
const versionTooltipId = React20.useId();
|
||||
const githubTooltipId = React20.useId();
|
||||
const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0];
|
||||
const reportLoopbackRecovery = React20.useCallback((recovery) => {
|
||||
|
|
@ -10593,9 +10710,23 @@ function IMSettingsTab({
|
|||
{ className: "dim-title" },
|
||||
h2(
|
||||
"div",
|
||||
{ className: "dim-brand" },
|
||||
{
|
||||
className: "dim-brand",
|
||||
tabIndex: 0,
|
||||
"aria-describedby": versionTooltipId
|
||||
},
|
||||
h2("strong", { className: "dim-brandName" }, "DSH-IM"),
|
||||
h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA")
|
||||
h2("p", null, "\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA"),
|
||||
h2(
|
||||
"span",
|
||||
{
|
||||
id: versionTooltipId,
|
||||
className: "dim-versionTooltip",
|
||||
role: "tooltip"
|
||||
},
|
||||
h2("span", null, "\u5F53\u524D\u7248\u672C"),
|
||||
h2("strong", null, `v${IM_PLUGIN_VERSION}`)
|
||||
)
|
||||
),
|
||||
h2(
|
||||
"span",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ const EN = Object.freeze({
|
|||
'IM机器人设置': 'IM bot settings',
|
||||
'IM 渠道': 'IM channels',
|
||||
'让 DeepSeek Harness 触手可及': 'DeepSeek Harness, always within reach',
|
||||
'当前版本': 'Current version',
|
||||
'AI Office': 'AI Office',
|
||||
'(实验功能)': '(Experimental)',
|
||||
'AI Office 设置': 'AI Office settings',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import manifest from '../../package.json' with { type: 'json' };
|
||||
|
||||
import {
|
||||
DingtalkLogoGlyph,
|
||||
|
|
@ -51,6 +52,7 @@ import { WorkspaceDirectoryPickerContext } from './workspace-editor.js';
|
|||
|
||||
export const name = 'im-settings';
|
||||
export const inject = ['slots', 'connection', 'locale', 'workspaces'];
|
||||
export const IM_PLUGIN_VERSION = manifest.version;
|
||||
|
||||
const CHANNELS = Object.freeze([
|
||||
{ id: 'weixin', label: '微信' },
|
||||
|
|
@ -159,6 +161,7 @@ export function IMSettingsTab({
|
|||
}) {
|
||||
const [selected, setSelected] = React.useState('weixin');
|
||||
const [loopbackRecovery, setLoopbackRecovery] = React.useState(null);
|
||||
const versionTooltipId = React.useId();
|
||||
const githubTooltipId = React.useId();
|
||||
const active = CHANNELS.find((channel) => channel.id === selected) ?? CHANNELS[0];
|
||||
const reportLoopbackRecovery = React.useCallback((recovery) => {
|
||||
|
|
@ -195,9 +198,20 @@ export function IMSettingsTab({
|
|||
return h(WorkspaceDirectoryPickerContext.Provider, { value: workspaceDirectoryPicker },
|
||||
h('section', { className: 'dim-page', 'aria-label': 'IM机器人设置' },
|
||||
h('header', { className: 'dim-title' },
|
||||
h('div', { className: 'dim-brand' },
|
||||
h('div', {
|
||||
className: 'dim-brand',
|
||||
tabIndex: 0,
|
||||
'aria-describedby': versionTooltipId,
|
||||
},
|
||||
h('strong', { className: 'dim-brandName' }, 'DSH-IM'),
|
||||
h('p', null, '让 DeepSeek Harness 触手可及')),
|
||||
h('p', null, '让 DeepSeek Harness 触手可及'),
|
||||
h('span', {
|
||||
id: versionTooltipId,
|
||||
className: 'dim-versionTooltip',
|
||||
role: 'tooltip',
|
||||
},
|
||||
h('span', null, '当前版本'),
|
||||
h('strong', null, `v${IM_PLUGIN_VERSION}`))),
|
||||
h('span', { className: 'dim-githubAction' },
|
||||
h('a', {
|
||||
className: 'dim-githubLink',
|
||||
|
|
|
|||
|
|
@ -12,9 +12,13 @@ const CSS = String.raw`
|
|||
}
|
||||
.dim-page *, .dim-page *::before, .dim-page *::after { box-sizing: border-box; }
|
||||
.dim-title { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 18px; }
|
||||
.dim-brand { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
|
||||
.dim-brand { position: relative; min-width: 0; width: max-content; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; margin: -2px -6px; padding: 2px 6px; border-radius: 8px; cursor: help; }
|
||||
.dim-brand:focus-visible { outline: 2px solid color-mix(in srgb, var(--dim-blue) 70%, white); outline-offset: 2px; }
|
||||
.dim-brandName { color: var(--dsw-alias-label-primary, #1f2329); font-size: 20px; line-height: 24px; font-weight: 800; letter-spacing: .04em; }
|
||||
.dim-title p { margin: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 500; white-space: nowrap; }
|
||||
.dim-versionTooltip { position: absolute; left: 0; bottom: calc(100% + 8px); z-index: 20; width: max-content; max-width: min(220px, 80vw); display: inline-flex; align-items: center; gap: 6px; padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
||||
.dim-versionTooltip strong { color: var(--dsw-alias-label-primary, #1f2329); font: 600 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||||
.dim-brand:hover .dim-versionTooltip, .dim-brand:focus .dim-versionTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
||||
.dim-githubAction { position: relative; display: inline-flex; flex: none; }
|
||||
.dim-githubLink { min-height: 30px; display: inline-flex; align-items: center; gap: 5px; flex: none; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 12px; line-height: normal; font-weight: 560; text-decoration: none; transition: border-color .15s ease, color .15s ease, background .15s ease; }
|
||||
.dim-githubLink:hover { border-color: #aeb3bb; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-interactive-bg-hover, #f7f8fa); }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { renderToStaticMarkup } from 'react-dom/server';
|
|||
|
||||
import {
|
||||
apply as applyClient,
|
||||
IM_PLUGIN_VERSION,
|
||||
IMSettingsTab,
|
||||
inject as clientInject,
|
||||
} from '../plugin-src/client/index.js';
|
||||
|
|
@ -98,6 +99,10 @@ const QQ_SOURCE_URL = new URL(
|
|||
);
|
||||
|
||||
test('IM settings renders nine IM channels plus the AI Office connector', async () => {
|
||||
const { default: packageMetadata } = await import('../package.json', {
|
||||
with: { type: 'json' },
|
||||
});
|
||||
const { version: packageVersion } = packageMetadata;
|
||||
const styles = await readFile(STYLES_URL, 'utf8');
|
||||
const markup = renderToStaticMarkup(React.createElement(IMSettingsTab, {
|
||||
feishuRpcCall: async () => ({ ok: true, value: {} }),
|
||||
|
|
@ -115,7 +120,12 @@ test('IM settings renders nine IM channels plus the AI Office connector', async
|
|||
assert.match(markup, /IM机器人/);
|
||||
assert.match(markup, /让 DeepSeek Harness 触手可及/);
|
||||
assert.match(markup, /class="dim-brand"/);
|
||||
assert.equal(IM_PLUGIN_VERSION, packageVersion);
|
||||
assert.match(markup, /class="dim-brand" tabindex="0" aria-describedby="[^"]+"/);
|
||||
assert.match(markup, /<strong class="dim-brandName">DSH-IM<\/strong>/);
|
||||
assert.match(markup, new RegExp(
|
||||
`class="dim-versionTooltip" role="tooltip"><span>当前版本<\\/span><strong>v${packageVersion.replaceAll('.', '\\.')}`,
|
||||
));
|
||||
assert.doesNotMatch(markup, /dim-brandLogo|<img/);
|
||||
assert.match(markup, /href="https:\/\/github\.com\/xmanrui\/dsh-im"/);
|
||||
assert.match(markup, /target="_blank"/);
|
||||
|
|
@ -125,8 +135,11 @@ test('IM settings renders nine IM channels plus the AI Office connector', async
|
|||
assert.match(markup, /role="tooltip"[^>]*>帮助与反馈 · 前往 GitHub</);
|
||||
assert.match(styles, /\.dim-title \{[^}]*margin: 0 0 18px;/);
|
||||
assert.match(styles, /\.dim-title p \{[^}]*color: var\(--dsw-alias-label-secondary, #646a73\);[^}]*font-size: 12px;[^}]*font-weight: 500;/);
|
||||
assert.match(styles, /\.dim-brand \{[^}]*display: flex;[^}]*flex-direction: column;[^}]*align-items: flex-start;[^}]*gap: 1px;/);
|
||||
assert.match(styles, /\.dim-brand \{[^}]*position: relative;[^}]*display: flex;[^}]*flex-direction: column;[^}]*align-items: flex-start;[^}]*gap: 1px;[^}]*cursor: help;/);
|
||||
assert.doesNotMatch(styles, /\.dim-brand:hover\s*\{[^}]*background:/);
|
||||
assert.match(styles, /\.dim-brandName \{[^}]*font-size: 20px;[^}]*font-weight: 800;[^}]*letter-spacing: \.04em;/);
|
||||
assert.match(styles, /\.dim-versionTooltip \{[^}]*bottom: calc\(100% \+ 8px\);[^}]*display: inline-flex;[^}]*opacity: 0;[^}]*visibility: hidden;/);
|
||||
assert.match(styles, /\.dim-brand:hover \.dim-versionTooltip, \.dim-brand:focus \.dim-versionTooltip \{[^}]*opacity: 1;[^}]*visibility: visible;/);
|
||||
assert.doesNotMatch(styles, /\.dim-brandLogo/);
|
||||
assert.match(styles, /\.dim-githubLink \{[^}]*border: 1px solid var\(--dsw-alias-border-l2, #dfe1e5\);[^}]*text-decoration: none;/);
|
||||
assert.match(styles, /\.dim-githubTooltip \{[^}]*bottom: calc\(100% \+ 8px\);[^}]*transform: translateY\(3px\);/);
|
||||
|
|
@ -724,6 +737,9 @@ test('client registers a live bilingual locale seat and directory picker for the
|
|||
injected,
|
||||
));
|
||||
assert.match(markup, /DeepSeek Harness, always within reach/);
|
||||
assert.match(markup, new RegExp(
|
||||
`<span>Current version<\\/span><strong>v${IM_PLUGIN_VERSION.replaceAll('.', '\\.')}`,
|
||||
));
|
||||
assert.match(markup, /Help & feedback · Open GitHub/);
|
||||
assert.match(markup, />WeChat<|>Feishu<|>DingTalk<|>WeCom</);
|
||||
assert.match(markup, />QQ<[^]*>Slack<[^]*>Telegram<[^]*>Discord<[^]*>WhatsApp</);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue