feat(admin): add core users widget and reorganize dashboard widget registration
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { getClientWidgets } from '../../dashboard/clientRegistry.js';
|
||||
import '../../dashboard/widgets/index.client.js';
|
||||
import '../../../dashboard.client.js';
|
||||
|
||||
// Évalué après tous les imports : les auto-registrations sont complètes
|
||||
@@ -20,7 +21,7 @@ export default function DashboardPage({ stats }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-4 sm:gap-6">
|
||||
{sortedWidgets.map(({ id, Component }) => (
|
||||
<Component
|
||||
key={id}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
export { collectAllDashboardData } from './registry.js';
|
||||
|
||||
// Side effect : initialise le registre, puis déclenche toutes les auto-registrations
|
||||
// Side effect : initialise le registre, enregistre les widgets core, puis les features
|
||||
import './registry.js';
|
||||
import './widgets/index.server.js';
|
||||
import '../../dashboard.server.js';
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Widgets core — Câblage client
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter un widget core côté client.
|
||||
* Les widgets core sont auto-enregistrés au démarrage de l'admin, sans module externe.
|
||||
*/
|
||||
|
||||
import './users.widget.js';
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Widgets core — Câblage serveur
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter un widget core côté serveur.
|
||||
* Les widgets core sont auto-enregistrés au démarrage de l'admin, sans module externe.
|
||||
*/
|
||||
|
||||
import './users.server.js';
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Widget core — Contribution serveur : nombre d'utilisateurs
|
||||
*
|
||||
* Auto-enregistré via admin/dashboard/widgets/index.server.js.
|
||||
* Pas besoin de modifier features/dashboard.server.js pour ce widget.
|
||||
*/
|
||||
|
||||
import { registerServerWidget } from '../registry.js';
|
||||
import { query } from '@zen/core/database';
|
||||
import { fail } from '@zen/core/shared/logger';
|
||||
|
||||
async function getUsersDashboardData() {
|
||||
try {
|
||||
const result = await query(`
|
||||
SELECT
|
||||
COUNT(*) AS total,
|
||||
COUNT(CASE WHEN created_at >= NOW() - INTERVAL '30 days' THEN 1 END) AS new_this_month
|
||||
FROM zen_auth_users
|
||||
`);
|
||||
return {
|
||||
totalUsers: parseInt(result.rows[0].total) || 0,
|
||||
newThisMonth: parseInt(result.rows[0].new_this_month) || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
fail(`Users dashboard data error: ${error.message}`);
|
||||
return { totalUsers: 0, newThisMonth: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
registerServerWidget('users', getUsersDashboardData);
|
||||
@@ -0,0 +1,36 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Widget core — Composant client : nombre d'utilisateurs
|
||||
*
|
||||
* Auto-enregistré via admin/dashboard/widgets/index.client.js.
|
||||
* Pas besoin de modifier features/dashboard.client.js pour ce widget.
|
||||
*
|
||||
* Props du composant :
|
||||
* data — { totalUsers: number, newThisMonth: number } retourné par getUsersDashboardData(), ou null
|
||||
* loading — true tant que les données serveur ne sont pas disponibles
|
||||
*/
|
||||
|
||||
import { registerClientWidget } from '../clientRegistry.js';
|
||||
import { StatCard } from '@zen/core/shared/components';
|
||||
import { UserMultiple02Icon } from '@zen/core/shared/icons';
|
||||
|
||||
function UsersDashboardWidget({ data, loading }) {
|
||||
const newThisMonth = data?.newThisMonth ?? 0;
|
||||
return (
|
||||
<StatCard
|
||||
title="Nombre d'utilisateurs"
|
||||
value={loading ? '-' : String(data?.totalUsers ?? 0)}
|
||||
change={!loading && newThisMonth > 0 ? `+${newThisMonth} ce mois` : undefined}
|
||||
changeType="increase"
|
||||
icon={UserMultiple02Icon}
|
||||
color="text-purple-400"
|
||||
bgColor="bg-purple-500/10"
|
||||
loading={loading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
registerClientWidget('users', UsersDashboardWidget, 10);
|
||||
|
||||
export default UsersDashboardWidget;
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Auth Feature — Contribution serveur au tableau de bord
|
||||
*
|
||||
* Ce module s'auto-enregistre auprès du registre admin en side effect.
|
||||
* Dépendance correcte : auth → admin (feature → core).
|
||||
*/
|
||||
|
||||
import { registerServerWidget } from '../admin/dashboard/registry.js';
|
||||
import { query } from '@zen/core/database';
|
||||
import { fail } from '@zen/core/shared/logger';
|
||||
|
||||
async function getDashboardData() {
|
||||
try {
|
||||
const result = await query(`SELECT COUNT(*) as count FROM zen_auth_users`);
|
||||
return { totalUsers: parseInt(result.rows[0].count) || 0 };
|
||||
} catch (error) {
|
||||
fail(`Auth dashboard data error: ${error.message}`);
|
||||
return { totalUsers: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
registerServerWidget('auth', getDashboardData);
|
||||
@@ -1,33 +0,0 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Auth Feature — Widget client pour le tableau de bord
|
||||
*
|
||||
* Ce module s'auto-enregistre auprès du registre admin en side effect.
|
||||
* Dépendance correcte : auth → admin (feature → core).
|
||||
*
|
||||
* Props du composant :
|
||||
* data — { totalUsers: number } retourné par getDashboardData(), ou null
|
||||
* loading — true tant que les données serveur ne sont pas disponibles
|
||||
*/
|
||||
|
||||
import { registerClientWidget } from '../admin/dashboard/clientRegistry.js';
|
||||
import { StatCard } from '@zen/core/shared/components';
|
||||
import { UserMultiple02Icon } from '@zen/core/shared/icons';
|
||||
|
||||
function AuthDashboardWidget({ data, loading }) {
|
||||
return (
|
||||
<StatCard
|
||||
title="Nombre d'utilisateurs"
|
||||
value={loading ? '-' : String(data?.totalUsers ?? 0)}
|
||||
icon={UserMultiple02Icon}
|
||||
color="text-purple-400"
|
||||
bgColor="bg-purple-500/10"
|
||||
loading={loading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
registerClientWidget('auth', AuthDashboardWidget, 10);
|
||||
|
||||
export default AuthDashboardWidget;
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Câblage client des widgets du tableau de bord
|
||||
* Câblage client des widgets du tableau de bord — Features externes
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter le widget client
|
||||
* d'une nouvelle feature au tableau de bord.
|
||||
@@ -12,5 +12,3 @@
|
||||
* Exemple pour une feature 'blog' :
|
||||
* import './blog/dashboard.widget.js';
|
||||
*/
|
||||
|
||||
import './auth/dashboard.widget.js';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Câblage serveur des widgets du tableau de bord
|
||||
* Câblage serveur des widgets du tableau de bord — Features externes
|
||||
*
|
||||
* Ce fichier est le SEUL à modifier pour ajouter la contribution serveur
|
||||
* d'une nouvelle feature au tableau de bord.
|
||||
@@ -10,5 +10,3 @@
|
||||
* Exemple pour une feature 'blog' :
|
||||
* import './blog/dashboard.server.js';
|
||||
*/
|
||||
|
||||
import './auth/dashboard.server.js';
|
||||
|
||||
Reference in New Issue
Block a user