原生插件可以使用自定义 React 页面、仪表板小部件、字段小部件和内容列表列来扩展管理面板——沙盒插件改为将其 UI 描述为 Block Kit,因为将插件 JavaScript 加载到管理面板会破坏沙盒隔离。
如果您的插件只需要设置表单,自动生成的 admin.settingsSchema 表单(参见您的第一个原生插件)无需编写 React 即可覆盖大多数场景。
管理入口点
import { SEOSettingsPage } from "./components/SEOSettingsPage";
import { SEODashboardWidget } from "./components/SEODashboardWidget";
export const widgets = { "seo-overview": SEODashboardWidget };
export const pages = { "/settings": SEOSettingsPage };
{ "exports": { ".": "./dist/index.js", "./admin": "./dist/admin.js" } }
definePlugin({
id: "seo",
version: "1.0.0",
admin: {
entry: "@my-org/plugin-seo/admin",
pages: [{ path: "/settings", label: "SEO Settings", icon: "settings" }],
widgets: [{ id: "seo-overview", title: "SEO Overview", size: "half" }],
},
});
管理页面
管理页面是挂载在 /_emdash/admin/plugins/<plugin-id>/<路径> 下的 React 组件。标签以英文声明——管理面板在渲染侧边栏和命令面板之前会通过共享的 Lingui 实例处理,因此加载自己消息目录的插件可以免费获得本地化导航。
插件 API Hook
usePluginAPI() 会自动添加插件 ID 前缀和 X-EmDash-Request: 1 CSRF 头来调用插件路由。
仪表板小部件
| 大小 | 描述 |
|---|---|
full | 仪表板全宽 |
half | 仪表板半宽 |
third | 仪表板三分之一宽 |
内容编辑器面板
受信任的 React 插件可以为已保存的内容条目在设置侧边栏中添加宿主框架的区域。
import type { ContentEditorPanelContext } from "@emdash-cms/admin";
function ContentInsights({ entry, locale }: ContentEditorPanelContext) {
return <p>{entry.slug} 的分析({locale ?? "默认区域设置"})</p>;
}
export const contentEditorPanels = [
{ id: "content-insights", title: "内容洞察", component: ContentInsights, collections: ["posts", "pages"], minRole: 40, order: 10 },
];
内容列表列
受信任的 React 插件可以向活跃的内容集合列表添加只读列。
自动生成的设置 UI
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
enabled: { type: "boolean", label: "Enabled", default: true },
},
},
构建配置
tsdown
export default {
entry: { index: "src/index.ts", admin: "src/admin.tsx" },
format: "esm", dts: true,
external: ["react", "react-dom", "emdash", "@emdash-cms/admin"],
}; tsup
export default {
entry: ["src/index.ts", "src/admin.tsx"],
format: "esm", dts: true,
external: ["react", "react-dom", "emdash", "@emdash-cms/admin"],
}; 启用/禁用插件
当插件在管理面板中被禁用时:侧边栏链接被隐藏、仪表板小部件不渲染、内容列表列不渲染、管理页面返回 404、后端钩子继续执行(为了数据安全)。
const enabled = await ctx.kv.get<boolean>("_emdash:enabled");