add process with node API key added

This commit is contained in:
Blomios
2026-01-18 22:22:00 +01:00
parent b69c69e11a
commit e8e2a4a01e
17 changed files with 390 additions and 156 deletions

View File

@ -0,0 +1,92 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Plus, Terminal } from 'lucide-react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter,
} from '@/components/ui/dialog';
interface AddServiceDialogProps {
onAdd: (name: string, command: string) => void;
}
export function AddServiceDialog({ onAdd }: AddServiceDialogProps) {
const [open, setOpen] = useState(false);
const [name, setName] = useState('');
const [command, setCommand] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (name.trim() && command.trim()) {
onAdd(name.trim(), command.trim());
setName('');
setCommand('');
setOpen(false);
}
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button size="sm" className="w-full sm:w-auto">
<Plus className="w-4 h-4 mr-2" />
Ajouter un service
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Terminal className="w-5 h-5" />
Ajouter un service
</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="dialog-service-name">Nom du service</Label>
<Input
id="dialog-service-name"
placeholder="ex: API Gateway"
value={name}
onChange={(e) => setName(e.target.value)}
className="bg-background"
/>
</div>
<div className="space-y-2">
<Label htmlFor="dialog-service-command">Script Bash</Label>
<div className="relative">
<div className="absolute left-0 top-0 p-3 text-muted-foreground font-mono text-xs select-none border-r border-border bg-muted/50 rounded-l-md h-full flex items-start">
<span>$</span>
</div>
<textarea
id="dialog-service-command"
placeholder={`#!/bin/bash\nsystemctl status nginx\nexit $?`}
value={command}
onChange={(e) => setCommand(e.target.value)}
className="w-full min-h-[200px] pl-10 pr-4 py-3 rounded-md border border-input bg-[#1a1a2e] text-green-400 font-mono text-sm resize-y focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background placeholder:text-muted-foreground/50"
spellCheck={false}
/>
</div>
<p className="text-xs text-muted-foreground">
Entrez le script bash qui sera exécuté pour vérifier l'état du service.
</p>
</div>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => setOpen(false)}>
Annuler
</Button>
<Button type="submit" disabled={!name.trim() || !command.trim()}>
<Plus className="w-4 h-4 mr-2" />
Ajouter
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}

View File

@ -1,18 +1,30 @@
import { useState } from 'react';
import { Node, Service } from '@/types/monitoring';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { StatusIndicator } from '@/components/StatusIndicator';
import { AddServiceForm } from './AddServiceForm';
import { Server, Trash2, Terminal } from 'lucide-react';
import { AddServiceDialog } from './AddServiceDialog';
import { Server, Trash2, Terminal, Key } from 'lucide-react';
import { cn } from '@/lib/utils';
interface NodeAdminCardProps {
node: Node;
onAddService: (nodeId: number, name: string, command: string) => void;
onAddService: (nodeId: number, name: string, command: string, apiKey: string) => void;
onRemoveService: (nodeId: number, serviceId: number) => void;
onApiKeyChange?: (nodeId: number, apiKey: string) => void;
apiKey?: string;
}
export function NodeAdminCard({ node, onAddService, onRemoveService }: NodeAdminCardProps) {
export function NodeAdminCard({ node, onAddService, onRemoveService, onApiKeyChange, apiKey = '' }: NodeAdminCardProps) {
const [localApiKey, setLocalApiKey] = useState(apiKey);
const handleApiKeyChange = (value: string) => {
setLocalApiKey(value);
onApiKeyChange?.(node.id, value);
};
return (
<Card className="glass-card animate-fade-in">
<CardHeader className="p-3 sm:p-6">
@ -30,6 +42,22 @@ export function NodeAdminCard({ node, onAddService, onRemoveService }: NodeAdmin
</div>
</CardHeader>
<CardContent className="space-y-4">
{/* API Key Field */}
<div className="space-y-2 p-3 rounded-lg bg-muted/30 border border-border/50">
<Label htmlFor={`api-key-${node.id}`} className="text-sm font-medium flex items-center gap-2">
<Key className="w-4 h-4" />
Clé API du node
</Label>
<Input
id={`api-key-${node.id}`}
type="password"
placeholder="Entrez la clé API pour ce node..."
value={localApiKey}
onChange={(e) => handleApiKeyChange(e.target.value)}
className="bg-background/50 font-mono text-sm"
/>
</div>
{/* Services List */}
<div className="space-y-2">
<h4 className="text-sm font-medium text-muted-foreground">
@ -74,8 +102,8 @@ export function NodeAdminCard({ node, onAddService, onRemoveService }: NodeAdmin
)}
</div>
{/* Add Service Form */}
<AddServiceForm onAdd={(name, command) => onAddService(node.id, name, command)} />
{/* Add Service Dialog */}
<AddServiceDialog onAdd={(name, command) => onAddService(node.id, name, command, localApiKey)} />
</CardContent>
</Card>
);

View File

@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { Layout } from '@/components/Layout';
import { NodeAdminCard } from '@/components/admin/NodeAdminCard';
import { mockNodes, useNodeUpdater } from '@/data/mockData';
import { Node, Service, NodeDeleteRequest } from '@/types/monitoring';
import { Node, Service, NodeDeleteRequest,AddServiceRequest } from '@/types/monitoring';
import { useToast } from '@/hooks/use-toast';
import api from '@/lib/axios';
@ -12,31 +12,48 @@ const Admin = () => {
const { toast } = useToast();
const handleAddService = (nodeId: number, name: string, command: string) => {
const newService: Service = {
id: 0,
name: `svc-${Date.now()}`,
command,
status: 'operational',
history: {
minute: [],
hour: [],
day: [],
},
};
const handleAddService = (nodeId: number, name: string, command: string, apiKey: string) => {
setNodes(prevNodes =>
prevNodes.map(node =>
node.id === nodeId
? { ...node, services: [...node.services, newService] }
: node
)
);
const addService = async () => {
try {
const response = await api.post<void>(`/addProcess`, {
node_id: nodeId,
name: name,
command: command,
node_api_key: apiKey,
});
toast({
title: 'Service ajouté',
description: `Le service "${name}" a été ajouté avec succès.`,
});
const newService: Service = {
id: 0,
name: name,
command: command,
status: 'operational',
history: {
minute: [],
hour: [],
day: [],
},
};
setNodes(prevNodes =>
prevNodes.map(node =>
node.id === nodeId
? { ...node, services: [...node.services, newService] }
: node
)
);
toast({
title: 'Service ajouté',
description: `Le service "${response.status.toString()}" a été ajouté avec succès.`,
});
} catch (err: any) {
console.error("Erreur lors de l'ajout d'un service", err);
}
}
addService();
};
const handleRemoveService = (nodeId: number, serviceId: number) => {

View File

@ -17,6 +17,13 @@ export interface Service {
};
}
export interface AddServiceRequest {
node_id: number;
name: string;
command: string;
node_api_key: string;
}
export interface Node {
id: number;
name: string;