This commit is contained in:
Gilles Soulier
2025-12-24 14:47:39 +01:00
parent 4590c120fb
commit 383ad292d3
52 changed files with 4694 additions and 1 deletions

108
frontend/src/utils/api.ts Normal file
View File

@@ -0,0 +1,108 @@
import { MQTTMessage, TopicNode } from '../types';
export async function getTopics(): Promise<TopicNode> {
const res = await fetch('/api/topics');
if (!res.ok) throw new Error('Impossible de charger les topics');
return res.json();
}
export async function getHistory(topic: string, limit = 50): Promise<MQTTMessage[]> {
const res = await fetch(`/api/topic/${encodeURIComponent(topic)}/history?limit=${limit}`);
if (!res.ok) throw new Error('Impossible de charger l\'historique');
return res.json();
}
export async function getStats(): Promise<{ count: number; size: string }> {
const res = await fetch('/api/stats');
if (!res.ok) throw new Error('Impossible de charger les stats');
return res.json();
}
export async function getMetrics(): Promise<{
cpuPercent: number;
memBytes: number;
memLimit: number;
dbBytes: number;
dbSize: string;
}> {
const res = await fetch('/api/metrics');
if (!res.ok) throw new Error('Impossible de charger les métriques');
return res.json();
}
export async function getSysinfo(): Promise<{
version: string;
clients: string;
msgReceived: string;
msgSent: string;
msgStored: string;
subscriptions: string;
}> {
const res = await fetch('/api/sysinfo');
if (!res.ok) throw new Error('Impossible de charger SYS');
return res.json();
}
export async function setFilters(rules: { topic: string; save: boolean; view: boolean }[]): Promise<void> {
const res = await fetch('/api/filters', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(rules)
});
if (!res.ok) throw new Error('Impossible de mettre à jour les filtres');
}
export async function getSettings(): Promise<any> {
const res = await fetch('/api/settings');
if (!res.ok) throw new Error('Impossible de charger les paramètres');
return res.json();
}
export async function saveSettings(payload: any): Promise<void> {
const res = await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error('Impossible de sauvegarder les paramètres');
}
export async function clearHistory(topic: string): Promise<{ deleted: number }> {
const res = await fetch(`/api/topic/${encodeURIComponent(topic)}/clear-history`, {
method: 'POST'
});
if (!res.ok) throw new Error('Impossible de supprimer l\'historique');
return res.json();
}
export async function clearAllHistory(): Promise<{ deleted: number }> {
const res = await fetch('/api/history/clear', {
method: 'POST'
});
if (!res.ok) throw new Error('Impossible de supprimer la base');
return res.json();
}
export async function publishMessage(payload: {
topic: string;
payload: string;
qos: number;
retained: boolean;
}): Promise<void> {
const res = await fetch('/api/publish', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error('Publication impossible');
}
export async function testConnection(broker: string): Promise<{ ok: boolean; latency?: number; error?: string }> {
const res = await fetch('/api/test-connection', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ broker })
});
if (!res.ok) throw new Error('Test impossible');
return res.json();
}

View File

@@ -0,0 +1,10 @@
export const formatBytes = (bytes: number) => {
if (!bytes || bytes < 0) return '0 B';
if (bytes < 1024) return `${bytes} B`;
const kb = bytes / 1024;
if (kb < 1024) return `${kb.toFixed(1)} KB`;
const mb = kb / 1024;
if (mb < 1024) return `${mb.toFixed(1)} MB`;
const gb = mb / 1024;
return `${gb.toFixed(2)} GB`;
};

View File

@@ -0,0 +1,16 @@
export type ThemeName = 'dark-monokai' | 'light';
export function setTheme(theme: ThemeName) {
const link = document.getElementById('theme-css') as HTMLLinkElement | null;
if (link) {
link.href = theme === 'dark-monokai' ? '/themes/theme-dark-monokai.css' : '/themes/theme-light.css';
}
document.documentElement.dataset.theme = theme;
}
export function initTheme() {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const fallback: ThemeName = prefersDark ? 'dark-monokai' : 'light';
setTheme(fallback);
return fallback;
}