Feat : Various features
Some checks failed
Build and Push Docker Images / docker (push) Failing after 9s
Some checks failed
Build and Push Docker Images / docker (push) Failing after 9s
This commit is contained in:
110
vps-monitor/frontend/src/components/EditVpsModal.jsx
Normal file
110
vps-monitor/frontend/src/components/EditVpsModal.jsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { X } from 'lucide-react'
|
||||
import TagInput from './TagInput'
|
||||
|
||||
const FIELDS = [
|
||||
{ key: 'name', label: 'Nom affiché', placeholder: 'Mon VPS 1', required: true, type: 'text' },
|
||||
{ key: 'host', label: 'IP ou hostname', placeholder: '192.168.1.10', required: true, type: 'text' },
|
||||
{ key: 'port', label: 'Port agent', placeholder: '8001', required: true, type: 'number' },
|
||||
{ key: 'api_key', label: 'Clé API agent', placeholder: 'Laisser vide pour conserver la clé actuelle', required: false, type: 'password' },
|
||||
{ key: 'description', label: 'Description', placeholder: 'Optionnel', required: false, type: 'text' },
|
||||
]
|
||||
|
||||
export default function EditVpsModal({ vps, onSave, onClose }) {
|
||||
const [form, setForm] = useState({
|
||||
name: vps.name ?? '',
|
||||
host: vps.host ?? '',
|
||||
port: String(vps.port ?? 8001),
|
||||
api_key: '',
|
||||
description: vps.description ?? '',
|
||||
tags: vps.tags ?? [],
|
||||
})
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (e) => { if (e.key === 'Escape') onClose() }
|
||||
window.addEventListener('keydown', handler)
|
||||
return () => window.removeEventListener('keydown', handler)
|
||||
}, [onClose])
|
||||
|
||||
const set = (key) => (e) => setForm(f => ({ ...f, [key]: e.target.value }))
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault()
|
||||
setSaving(true)
|
||||
setError('')
|
||||
try {
|
||||
await onSave(vps.id, { ...form, port: parseInt(form.port, 10) })
|
||||
} catch (err) {
|
||||
setError(err.message)
|
||||
setSaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/75 backdrop-blur-sm"
|
||||
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
||||
>
|
||||
<div className="w-full max-w-md bg-gray-900 border border-gray-700 rounded-xl shadow-2xl">
|
||||
<div className="flex items-center justify-between px-4 py-3 border-b border-gray-700">
|
||||
<div>
|
||||
<h3 className="font-semibold text-sm">Modifier le VPS</h3>
|
||||
<p className="text-xs text-gray-500 mt-0.5 font-mono">{vps.id}</p>
|
||||
</div>
|
||||
<button onClick={onClose} className="p-1.5 rounded-lg hover:bg-gray-800 text-gray-500 hover:text-gray-200 transition-colors">
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="p-4 space-y-3">
|
||||
{FIELDS.map(({ key, label, placeholder, required, type }) => (
|
||||
<div key={key}>
|
||||
<label className="block text-xs text-gray-400 mb-1">
|
||||
{label} {required && <span className="text-red-400">*</span>}
|
||||
</label>
|
||||
<input
|
||||
type={type}
|
||||
value={form[key]}
|
||||
onChange={set(key)}
|
||||
placeholder={placeholder}
|
||||
required={required}
|
||||
className="w-full px-3 py-2 rounded-lg bg-gray-800 border border-gray-700 text-sm placeholder-gray-600 focus:outline-none focus:border-indigo-500 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{error && (
|
||||
<p className="text-xs text-red-400 bg-red-950/30 border border-red-900/40 rounded-lg px-3 py-2">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="block text-xs text-gray-400 mb-1">Tags</label>
|
||||
<TagInput tags={form.tags} onChange={tags => setForm(f => ({ ...f, tags }))} />
|
||||
<p className="text-xs text-gray-600 mt-1">Entrée ou virgule pour valider</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="flex-1 py-2 rounded-lg border border-gray-700 hover:bg-gray-800 text-sm transition-colors"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={saving}
|
||||
className="flex-1 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-sm transition-colors font-medium"
|
||||
>
|
||||
{saving ? 'Enregistrement…' : 'Enregistrer'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user