Les plugins peuvent étendre le panneau d’administration avec des pages personnalisées et des widgets de tableau de bord. Ce sont des composants React rendus aux côtés des fonctionnalités d’administration principales.
Point d’entrée admin
Les plugins avec une UI d’administration exportent des composants depuis un point d’entrée admin :
import { SEOSettingsPage } from "./components/SEOSettingsPage";
import { SEODashboardWidget } from "./components/SEODashboardWidget";
// Dashboard widgets
export const widgets = {
"seo-overview": SEODashboardWidget,
};
// Admin pages
export const pages = {
"/settings": SEOSettingsPage,
};
Configurez le point d’entrée dans package.json :
{
"exports": {
".": "./dist/index.js",
"./admin": "./dist/admin.js"
}
}
Référencez-le dans la définition du plugin :
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" }],
},
});
Pages d’administration
Les pages d’administration sont des composants React qui reçoivent le contexte du plugin via des hooks.
Définition de page
Définissez les pages dans admin.pages :
admin: {
pages: [
{
path: "/settings", // URL path (relative to plugin base)
label: "Settings", // Sidebar label
icon: "settings", // Icon name (optional)
},
{
path: "/reports",
label: "Reports",
icon: "chart",
},
];
}
Les pages sont montées sur /_emdash/admin/plugins/<plugin-id>/<path>.
Composant de page
import { useState, useEffect } from "react";
import { usePluginAPI } from "@emdash-cms/admin";
export function SettingsPage() {
const api = usePluginAPI();
const [settings, setSettings] = useState<Record<string, unknown>>({});
const [saving, setSaving] = useState(false);
useEffect(() => {
api.get("settings").then(setSettings);
}, []);
const handleSave = async () => {
setSaving(true);
await api.post("settings/save", settings);
setSaving(false);
};
return (
<div>
<h1>Plugin Settings</h1>
<label>
Site Title
<input
type="text"
value={settings.siteTitle || ""}
onChange={(e) => setSettings({ ...settings, siteTitle: e.target.value })}
/>
</label>
<label>
<input
type="checkbox"
checked={settings.enabled ?? true}
onChange={(e) => setSettings({ ...settings, enabled: e.target.checked })}
/>
Enabled
</label>
<button onClick={handleSave} disabled={saving}>
{saving ? "Saving..." : "Save Settings"}
</button>
</div>
);
}
Hook API du plugin
Utilisez usePluginAPI() pour appeler les routes de votre plugin :
import { usePluginAPI } from "@emdash-cms/admin";
function MyComponent() {
const api = usePluginAPI();
// GET request to plugin route
const data = await api.get("status");
// POST request with body
await api.post("settings/save", { enabled: true });
// With URL parameters
const result = await api.get("history?limit=50");
}
Le hook ajoute automatiquement le préfixe d’ID de plugin aux URL des routes.
Widgets du tableau de bord
Les widgets apparaissent sur le tableau de bord d’administration et fournissent un aperçu rapide.
Définition du widget
Définissez les widgets dans admin.widgets :
admin: {
widgets: [
{
id: "seo-overview", // Unique widget ID
title: "SEO Overview", // Widget title (optional)
size: "half", // "full" | "half" | "third"
},
];
}
Composant widget
import { useState, useEffect } from "react";
import { usePluginAPI } from "@emdash-cms/admin";
export function SEOWidget() {
const api = usePluginAPI();
const [data, setData] = useState({ score: 0, issues: [] });
useEffect(() => {
api.get("analyze").then(setData);
}, []);
return (
<div className="widget-content">
<div className="score">{data.score}%</div>
<ul>
{data.issues.map((issue, i) => (
<li key={i}>{issue.message}</li>
))}
</ul>
</div>
);
}
Tailles des widgets
| Taille | Description |
|---|---|
full | Largeur complète du tableau de bord |
half | Moitié de la largeur |
third | Un tiers de la largeur |
Les widgets se réorganisent automatiquement selon la largeur de l’écran.
Structure d’export
Le point d’entrée admin exporte deux objets :
import { SettingsPage } from "./components/SettingsPage";
import { ReportsPage } from "./components/ReportsPage";
import { StatusWidget } from "./components/StatusWidget";
import { OverviewWidget } from "./components/OverviewWidget";
// Pages keyed by path
export const pages = {
"/settings": SettingsPage,
"/reports": ReportsPage,
};
// Widgets keyed by ID
export const widgets = {
status: StatusWidget,
overview: OverviewWidget,
};
Composants d’administration
EmDash fournit des composants prêts à l’emploi pour les modèles courants :
import {
Card,
Button,
Input,
Select,
Toggle,
Table,
Pagination,
Alert,
Loading
} from "@emdash-cms/admin";
function SettingsPage() {
return (
<Card title="Settings">
<Input label="API Key" type="password" />
<Toggle label="Enabled" defaultChecked />
<Button variant="primary">Save</Button>
</Card>
);
}
Interface de paramètres générée automatiquement
Si votre plugin ne nécessite qu’un formulaire de paramètres, utilisez admin.settingsSchema sans composants personnalisés :
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
enabled: { type: "boolean", label: "Enabled", default: true }
}
}
EmDash génère automatiquement une page de paramètres. N’ajoutez des pages personnalisées que pour des fonctionnalités au-delà des réglages de base.
Navigation
Les pages du plugin apparaissent dans la barre latérale sous le nom du plugin. L’ordre suit le tableau admin.pages.
admin: {
pages: [
{ path: "/settings", label: "Settings", icon: "settings" }, // First
{ path: "/history", label: "History", icon: "history" }, // Second
{ path: "/reports", label: "Reports", icon: "chart" }, // Third
];
}
Configuration de build
Les composants d’administration nécessitent un point d’entrée de build distinct. Configurez votre bundler :
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"]
}; Gardez React et EmDash admin comme dépendances externes pour éviter les doublons dans le bundle.
Activer / désactiver un plugin
Lorsqu’un plugin est désactivé dans l’admin :
- Les liens de la barre latérale sont masqués
- Les widgets du tableau de bord ne sont pas rendus
- Les pages d’administration renvoient 404
- Les hooks backend s’exécutent toujours (pour la sécurité des données)
Les plugins peuvent vérifier leur état d’activation :
const enabled = await ctx.kv.get<boolean>("_emdash:enabled");
Exemple : interface d’administration complète
import { definePlugin } from "emdash";
export default definePlugin({
id: "analytics",
version: "1.0.0",
capabilities: ["network:fetch"],
allowedHosts: ["api.analytics.example.com"],
storage: {
events: { indexes: ["type", "createdAt"] },
},
admin: {
entry: "@my-org/plugin-analytics/admin",
settingsSchema: {
trackingId: { type: "string", label: "Tracking ID" },
enabled: { type: "boolean", label: "Enabled", default: true },
},
pages: [
{ path: "/dashboard", label: "Dashboard", icon: "chart" },
{ path: "/settings", label: "Settings", icon: "settings" },
],
widgets: [{ id: "events-today", title: "Events Today", size: "third" }],
},
routes: {
stats: {
handler: async (ctx) => {
const today = new Date().toISOString().split("T")[0];
const count = await ctx.storage.events!.count({
createdAt: { gte: today },
});
return { today: count };
},
},
},
});
import { EventsWidget } from "./components/EventsWidget";
import { DashboardPage } from "./components/DashboardPage";
import { SettingsPage } from "./components/SettingsPage";
export const widgets = {
"events-today": EventsWidget,
};
export const pages = {
"/dashboard": DashboardPage,
"/settings": SettingsPage,
};