feat: placer les services infra en tête des listes
This commit is contained in:
@@ -447,8 +447,9 @@ router.get('/public/apps', (req, res) => {
|
|||||||
// getAllStatuses() retourne un tableau vide si aucun check n'a encore été effectué
|
// getAllStatuses() retourne un tableau vide si aucun check n'a encore été effectué
|
||||||
// On ne déclenche PAS checkAllApps() ici pour éviter de bloquer la réponse
|
// On ne déclenche PAS checkAllApps() ici pour éviter de bloquer la réponse
|
||||||
const statuses = getAllStatuses();
|
const statuses = getAllStatuses();
|
||||||
|
// Le portail répartit lui-même les applications par onglet, y compris INFRA.
|
||||||
|
// L’API expose donc toutes les applications du registre local, sans en masquer.
|
||||||
const publicApps = config.apps
|
const publicApps = config.apps
|
||||||
.filter((a) => a.category !== 'INFRA') // Exclure les apps infra (portail, dashboard)
|
|
||||||
.map((a) => {
|
.map((a) => {
|
||||||
const status = statuses.find((s) => s.id === a.id);
|
const status = statuses.find((s) => s.id === a.id);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Box, RefreshCw, Plus } from 'lucide-react';
|
|||||||
import AppCard from '../components/AppCard';
|
import AppCard from '../components/AppCard';
|
||||||
import AddAppModal from '../components/AddAppModal';
|
import AddAppModal from '../components/AddAppModal';
|
||||||
import { getApps, getGiteaCommits } from '../utils/api';
|
import { getApps, getGiteaCommits } from '../utils/api';
|
||||||
|
import { sortAppsWithInfraFirst } from '../utils/appSorting';
|
||||||
|
|
||||||
export default function AppsPage({ apps, onRefresh }) {
|
export default function AppsPage({ apps, onRefresh }) {
|
||||||
const [commitsMap, setCommitsMap] = useState({});
|
const [commitsMap, setCommitsMap] = useState({});
|
||||||
@@ -26,6 +27,9 @@ export default function AppsPage({ apps, onRefresh }) {
|
|||||||
});
|
});
|
||||||
}, [apps]);
|
}, [apps]);
|
||||||
|
|
||||||
|
// Les services d’infrastructure restent visibles en premier, sans modifier les données API.
|
||||||
|
const sortedApps = sortAppsWithInfraFirst(apps);
|
||||||
|
|
||||||
const handleAddSuccess = () => {
|
const handleAddSuccess = () => {
|
||||||
setShowAddModal(false);
|
setShowAddModal(false);
|
||||||
// Rafraîchir la liste après un délai pour laisser le temps au health check
|
// Rafraîchir la liste après un délai pour laisser le temps au health check
|
||||||
@@ -86,7 +90,7 @@ export default function AppsPage({ apps, onRefresh }) {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{apps.map((app) => (
|
{sortedApps.map((app) => (
|
||||||
<AppCard
|
<AppCard
|
||||||
key={app.id}
|
key={app.id}
|
||||||
app={app}
|
app={app}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { getApps, getSystemInfo } from '../utils/api';
|
import { getApps, getSystemInfo } from '../utils/api';
|
||||||
import StatusBadge from '../components/StatusBadge';
|
import StatusBadge from '../components/StatusBadge';
|
||||||
|
import { sortAppsWithInfraFirst } from '../utils/appSorting';
|
||||||
|
|
||||||
function StatCard({ icon: Icon, label, value, color, subtext }) {
|
function StatCard({ icon: Icon, label, value, color, subtext }) {
|
||||||
return (
|
return (
|
||||||
@@ -44,6 +45,7 @@ export default function DashboardPage({ apps }) {
|
|||||||
const onlineApps = apps.filter((a) => a.status === 'online').length;
|
const onlineApps = apps.filter((a) => a.status === 'online').length;
|
||||||
const offlineApps = apps.filter((a) => a.status === 'offline').length;
|
const offlineApps = apps.filter((a) => a.status === 'offline').length;
|
||||||
const errorApps = apps.filter((a) => a.status === 'error').length;
|
const errorApps = apps.filter((a) => a.status === 'error').length;
|
||||||
|
const sortedApps = sortAppsWithInfraFirst(apps);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@@ -147,7 +149,7 @@ export default function DashboardPage({ apps }) {
|
|||||||
<p className="text-gray-500 text-sm">Aucune application détectée</p>
|
<p className="text-gray-500 text-sm">Aucune application détectée</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{apps.map((app) => {
|
{sortedApps.map((app) => {
|
||||||
const isInfra = app.category === "INFRA" || ["portail-santinova", "manus-dashboard"].includes(app.id);
|
const isInfra = app.category === "INFRA" || ["portail-santinova", "manus-dashboard"].includes(app.id);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
15
src/frontend/src/utils/appSorting.js
Normal file
15
src/frontend/src/utils/appSorting.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Retourne une copie triée sans modifier la liste fournie par l'API.
|
||||||
|
* Les services INFRA sont affichés en premier ; l'ordre d'origine est conservé
|
||||||
|
* au sein de chaque groupe afin d'éviter des déplacements visuels inutiles.
|
||||||
|
*/
|
||||||
|
export function sortAppsWithInfraFirst(apps) {
|
||||||
|
return (Array.isArray(apps) ? apps : [])
|
||||||
|
.map((app, index) => ({ app, index }))
|
||||||
|
.sort((left, right) => {
|
||||||
|
const leftPriority = left.app?.category === 'INFRA' ? 0 : 1;
|
||||||
|
const rightPriority = right.app?.category === 'INFRA' ? 0 : 1;
|
||||||
|
return leftPriority - rightPriority || left.index - right.index;
|
||||||
|
})
|
||||||
|
.map(({ app }) => app);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user