feat(admin): add core users widget and reorganize dashboard widget registration
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { getClientWidgets } from '../../dashboard/clientRegistry.js';
|
import { getClientWidgets } from '../../dashboard/clientRegistry.js';
|
||||||
|
import '../../dashboard/widgets/index.client.js';
|
||||||
import '../../../dashboard.client.js';
|
import '../../../dashboard.client.js';
|
||||||
|
|
||||||
// Évalué après tous les imports : les auto-registrations sont complètes
|
// Évalué après tous les imports : les auto-registrations sont complètes
|
||||||
@@ -20,7 +21,7 @@ export default function DashboardPage({ stats }) {
|
|||||||
</div>
|
</div>
|
||||||
</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 }) => (
|
{sortedWidgets.map(({ id, Component }) => (
|
||||||
<Component
|
<Component
|
||||||
key={id}
|
key={id}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
export { collectAllDashboardData } from './registry.js';
|
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 './registry.js';
|
||||||
|
import './widgets/index.server.js';
|
||||||
import '../../dashboard.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';
|
'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
|
* Ce fichier est le SEUL à modifier pour ajouter le widget client
|
||||||
* d'une nouvelle feature au tableau de bord.
|
* d'une nouvelle feature au tableau de bord.
|
||||||
@@ -12,5 +12,3 @@
|
|||||||
* Exemple pour une feature 'blog' :
|
* Exemple pour une feature 'blog' :
|
||||||
* import './blog/dashboard.widget.js';
|
* 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
|
* Ce fichier est le SEUL à modifier pour ajouter la contribution serveur
|
||||||
* d'une nouvelle feature au tableau de bord.
|
* d'une nouvelle feature au tableau de bord.
|
||||||
@@ -10,5 +10,3 @@
|
|||||||
* Exemple pour une feature 'blog' :
|
* Exemple pour une feature 'blog' :
|
||||||
* import './blog/dashboard.server.js';
|
* import './blog/dashboard.server.js';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './auth/dashboard.server.js';
|
|
||||||
|
|||||||
Reference in New Issue
Block a user