feat(settings): move IM bot to top-level menu

Remove the legacy Plugins-tab registrations, keep the channel-logo navigation, and harden upgrade/package verification.
This commit is contained in:
xmanrui 2026-08-25 22:42:41 +08:00
parent 892e18db77
commit 1ce8126edb
30 changed files with 815 additions and 842 deletions

View file

@ -16,7 +16,6 @@ import {
} from '../../channel-card-meta.js';
import {
DINGTALK_ENDPOINTS,
DINGTALK_RPC_CHANNEL,
connectionTestFeedback,
formatRemaining,
normalizeProvisioning,
@ -29,9 +28,6 @@ import { installDingtalkStyles } from './styles.js';
const ACTIVE_PROVISION_STATES = new Set(['pending', 'scanned', 'authorizing', 'creating', 'connecting']);
export const name = 'dingtalk-settings';
export const inject = ['slots', 'connection'];
function DingtalkIcon({ size = 28 }) {
return h('svg', {
width: size,
@ -864,16 +860,3 @@ export function DingtalkSettingsTab({ rpcCall }) {
})
: null)));
}
export function apply(ctx) {
ctx.effect(() => installDingtalkStyles(), 'dingtalk-settings: install client styles');
const rpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab',
id: 'dingtalk',
order: 40,
label: '钉钉',
inject: () => ({ rpcCall }),
}, DingtalkSettingsTab));
}

View file

@ -1,4 +1,4 @@
export const DINGTALK_STYLE_ID = 'xmanrui-dsh-dingtalk-settings';
export const DINGTALK_STYLE_ID = 'xmanrui-dsh-im-dingtalk-settings';
const CSS = String.raw`
.ddt-page {
@ -126,7 +126,7 @@ export function installDingtalkStyles() {
const existing = document.querySelector(`style[data-plugin-css="${DINGTALK_STYLE_ID}"]`);
if (existing) return () => {};
const style = document.createElement('style');
style.dataset.plugin = '@xmanrui/dsh-dingtalk';
style.dataset.plugin = '@xmanrui/dsh-im';
style.dataset.pluginCss = DINGTALK_STYLE_ID;
style.textContent = CSS;
document.head.appendChild(style);

View file

@ -6,7 +6,6 @@ import { h } from "../../i18n.js";
import {
FEISHU_ENDPOINTS,
FEISHU_REGISTRATION_OPERATIONS,
FEISHU_RPC_CHANNEL,
formatRemaining,
normalizeBotsSnapshot,
normalizeGroupResponseMode,
@ -28,11 +27,6 @@ import {
ChannelListHeading,
LastMessageErrorSummary,
} from "../../channel-card-meta.js";
import { installFeishuStyles } from "./styles.js";
export const name = "feishu-settings";
export const inject = ["slots", "connection"];
const CALLBACK_REPAIR_OPERATION = FEISHU_REGISTRATION_OPERATIONS.CALLBACK_REPAIR;
const GROUP_MESSAGE_PERMISSION_OPERATION = FEISHU_REGISTRATION_OPERATIONS.GROUP_MESSAGE_PERMISSION;
@ -1540,26 +1534,3 @@ export function FeishuSettingsTab({ rpcCall }) {
),
));
}
export function apply(ctx) {
ctx.effect(
() => installFeishuStyles(),
"feishu-settings: install client styles",
);
const rpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(FEISHU_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject("settings.plugins.tab", () =>
ctx.slots.register(
{
name: "settings.plugins.tab",
id: "feishu",
order: 20,
label: "飞书",
inject: () => ({ rpcCall }),
},
FeishuSettingsTab,
),
);
}

View file

@ -1,4 +1,4 @@
export const FEISHU_STYLE_ID = "beihuixinghe-dsh-feishu-settings";
export const FEISHU_STYLE_ID = "xmanrui-dsh-im-feishu-settings";
const CSS = String.raw`
.bxf-page {
@ -562,7 +562,7 @@ export function installFeishuStyles() {
}
const style = document.createElement("style");
style.dataset.plugin = "@xmanrui/dsh-feishu";
style.dataset.plugin = "@xmanrui/dsh-im";
style.dataset.pluginCss = FEISHU_STYLE_ID;
style.textContent = CSS;
document.head.appendChild(style);

View file

@ -18,7 +18,6 @@ import {
import { installDingtalkStyles } from '../dingtalk/styles.js';
import {
QQ_ENDPOINTS,
QQ_RPC_CHANNEL,
connectionTestFeedback,
formatRemaining,
normalizeProvisioning,
@ -514,11 +513,3 @@ export function QqSettingsTab({ rpcCall }) {
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
botList)));
}
export function apply(ctx) {
ctx.effect(() => installQqStyles(), 'qq-settings: install client styles');
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(QQ_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab', id: 'qq', order: 50, label: 'QQ', inject: () => ({ rpcCall }),
}, QqSettingsTab));
}

View file

@ -18,7 +18,6 @@ import {
import { installDingtalkStyles } from '../dingtalk/styles.js';
import {
WECOM_ENDPOINTS,
WECOM_RPC_CHANNEL,
formatRemaining,
normalizeProvisioning,
normalizeSnapshot,
@ -546,11 +545,3 @@ export function WecomSettingsTab({ rpcCall }) {
? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null,
botList)));
}
export function apply(ctx) {
ctx.effect(() => installWecomStyles(), 'wecom-settings: install client styles');
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WECOM_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab', id: 'wecom', order: 45, label: '企业微信', inject: () => ({ rpcCall }),
}, WecomSettingsTab));
}

View file

@ -5,7 +5,6 @@ import { QrActionIcon } from '../../credential-binding.js';
import { h } from '../../i18n.js';
import {
WEIXIN_ENDPOINTS,
WEIXIN_RPC_CHANNEL,
formatRemaining,
normalizeProvisioning,
normalizeSnapshot,
@ -27,11 +26,6 @@ import {
ChannelListHeading,
LastMessageErrorSummary,
} from '../../channel-card-meta.js';
import { installWeixinStyles } from './styles.js';
export const name = 'weixin-settings';
export const inject = ['slots', 'connection'];
const Button = React.forwardRef(function Button(
{ children, kind = 'secondary', className = '', ...props },
ref,
@ -717,16 +711,3 @@ export function WeixinSettingsTab({ rpcCall }) {
: null),
));
}
export function apply(ctx) {
ctx.effect(() => installWeixinStyles(), 'weixin-settings: install client styles');
const rpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(WEIXIN_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab',
id: 'weixin',
order: 30,
label: '微信',
inject: () => ({ rpcCall }),
}, WeixinSettingsTab));
}

View file

@ -1,4 +1,4 @@
export const WEIXIN_STYLE_ID = 'xmanrui-dsh-weixin-settings';
export const WEIXIN_STYLE_ID = 'xmanrui-dsh-im-weixin-settings';
const CSS = String.raw`
.dxw-page {
@ -107,7 +107,7 @@ export function installWeixinStyles() {
const existing = document.querySelector(`style[data-plugin-css="${WEIXIN_STYLE_ID}"]`);
if (existing) return () => {};
const style = document.createElement('style');
style.dataset.plugin = '@xmanrui/dsh-weixin';
style.dataset.plugin = '@xmanrui/dsh-im';
style.dataset.pluginCss = WEIXIN_STYLE_ID;
style.textContent = CSS;
document.head.appendChild(style);

View file

@ -333,10 +333,10 @@ export function apply(ctx) {
pickDirectory: () => ctx.workspaces.pickDirectory(),
});
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab',
id: 'im',
order: 20,
ctx.slots.inject('settings.section', () => ctx.slots.register({
name: 'settings.section',
id: 'xmanrui-dsh-im',
order: 21,
label: () => t('IM机器人'),
locale: IM_LOCALE_NAMESPACE,
inject: () => ({