Cartes de tableau de bord
Les plugins peuvent contribuer des cartes self-contained au tableau de bord admin. Les quatre cartes statistiques intégrées (Posts / Pages / Catégories / Tags) sont au-dessus ; les cartes contribuées
Les plugins peuvent contribuer des cartes self-contained au tableau de bord admin. Les quatre cartes statistiques intégrées (Posts / Pages / Catégories / Tags) sont au-dessus ; les cartes contribuées par les plugins apparaissent dans une grille responsive 1 / 2 / 3 colonnes en dessous.
Le must-use flexweg-metrics utilise ceci pour surfacer l'utilisation du stockage Flexweg et les comptages de documents Firestore / SQLite. Les plugins customs peuvent ajouter les leurs — statut backup, indicateurs de sync, dernières lignes de log, n'importe quoi qui rentre dans une carte.
Enregistrer une carte
import { MyCard } from "./MyCard";
export const manifest: PluginManifest = {
// …
register(api) {
api.registerDashboardCard({
id: "my-plugin/my-card",
priority: 50,
component: MyCard,
});
},
};
Manifest de carte
interface DashboardCardManifest {
id: string; // <namespace>/<name>
priority?: number; // défaut 100 — lower runs first
component: React.ComponentType; // pas de props
}
id— préfixé par votre id de plugin, kebab-case. Identifie la carte.priority— drive l'ordre d'affichage. Plus bas = plus à gauche / plus en haut.component— un composant React qui ne prend AUCUNE prop. Il fetche ses propres données et gère son propre loading / error / empty state.
Le composant
Pas de prop. Fetche tout en interne.
import { useEffect, useState } from "react";
import { useCmsData } from "@flexweg/cms-runtime";
export function MyCard() {
const { settings } = useCmsData();
const [data, setData] = useState<MyData | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchMyData().then((d) => {
setData(d);
setLoading(false);
});
}, []);
if (loading) return <div className="card p-4">Loading…</div>;
if (!data) return <div className="card p-4">No data</div>;
return (
<div className="card p-4">
<h3 className="font-semibold">My Stat</h3>
<p className="text-2xl">{data.value}</p>
</div>
);
}
Conventions visuelles :
- Utilisez
card(class admin standard) pour le container - Utilisez
p-4pour le padding - Titre en
font-semibold - Stat principale en
text-2xloutext-3xl
Fetching de données
Depuis useCmsData
Pour des comptages basés sur la live subscription :
const { posts, pages, terms } = useCmsData();
const draftCount = posts.filter(p => p.status === "draft").length;
C'est gratuit en mode global (la subscription est déjà là). En mode paginated, posts / pages ne sont pas dans le ctx — utilisez useAllPosts ou fetchAllPosts.
Depuis le backend (CRUD)
import { fetchAllPosts } from "@flexweg/cms-runtime";
useEffect(() => {
fetchAllPosts({ type: "post" }).then(setData);
}, []);
fetchAllPosts est dispatcher-routed — fonctionne identiquement en Firebase et SQLite.
Depuis Flexweg API
import { getStorageLimits } from "@flexweg/cms-runtime";
useEffect(() => {
getStorageLimits().then(setData);
}, []);
Depuis une API externe
fetch() standard. Pensez aux CORS si l'API externe ne vous autorise pas l'origine de votre admin.
Refresh
Pas de polling automatique côté framework. Vous décidez :
const [refreshKey, setRefreshKey] = useState(0);
useEffect(() => {
fetchMyData().then(setData);
}, [refreshKey]);
return (
<div className="card p-4">
<button onClick={() => setRefreshKey(k => k + 1)}>Refresh</button>
{/* ... */}
</div>
);
Ou utilisez un setInterval si vous voulez polling.
Le flexweg-metrics ne poll pas — le tableau de bord se re-mount à chaque navigation away/back, ce qui re-déclenche les useEffect.
i18n
Utilisez useTranslation('<plugin-id>') pour les labels :
import { useTranslation } from "react-i18next";
export function MyCard() {
const { t } = useTranslation("my-plugin");
return (
<div className="card p-4">
<h3>{t("dashboardCard.title")}</h3>
</div>
);
}
Définissez la clé dans votre bundle i18n :
// i18n.ts
export const en = {
dashboardCard: { title: "My Card" },
};
export const fr = {
dashboardCard: { title: "Ma carte" },
};
Limites
- Pas d'accès à des registries au-delà de ce que le runtime expose
- Pas d'override du layout du tableau de bord (la grille est fixe)
- Pas de drag-and-drop pour réordonner les cartes (la priority décide)
- Pas de bouton « Masquer cette carte » côté utilisateur (à venir éventuellement)