feat: agregar edicion de Trabajos de Backup desde la UI web
This commit is contained in:
@@ -7,7 +7,8 @@ import {
|
|||||||
Folder,
|
Folder,
|
||||||
Filter,
|
Filter,
|
||||||
Calendar,
|
Calendar,
|
||||||
X
|
X,
|
||||||
|
Edit2
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { BackupJobItem, ClientItem, api, SystemSettingsResponse } from '../services/api';
|
import { BackupJobItem, ClientItem, api, SystemSettingsResponse } from '../services/api';
|
||||||
|
|
||||||
@@ -37,8 +38,9 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
skip_readonly: false,
|
skip_readonly: false,
|
||||||
sync_deletions: false,
|
sync_deletions: false,
|
||||||
});
|
});
|
||||||
|
const [editingJobId, setEditingJobId] = useState<number | null>(null);
|
||||||
|
|
||||||
const handleCreateJob = async (e: React.FormEvent) => {
|
const handleSubmitJob = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!formData.client_id) {
|
if (!formData.client_id) {
|
||||||
alert('Por favor selecciona un cliente');
|
alert('Por favor selecciona un cliente');
|
||||||
@@ -46,16 +48,41 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
|
if (editingJobId !== null) {
|
||||||
|
await api.updateJob(editingJobId, formData);
|
||||||
|
} else {
|
||||||
await api.createJob(formData);
|
await api.createJob(formData);
|
||||||
|
}
|
||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
onRefresh();
|
onRefresh();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
alert(`Error creando trabajo: ${err.message}`);
|
alert(`Error guardando trabajo: ${err.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditClick = (job: BackupJobItem) => {
|
||||||
|
setEditingJobId(job.id);
|
||||||
|
setFormData({
|
||||||
|
client_id: job.client_id,
|
||||||
|
name: job.name,
|
||||||
|
source_path: job.source_path,
|
||||||
|
file_patterns: job.file_patterns,
|
||||||
|
schedule_cron: job.schedule_cron,
|
||||||
|
keep_daily: job.keep_daily,
|
||||||
|
keep_weekly: job.keep_weekly,
|
||||||
|
keep_monthly: job.keep_monthly,
|
||||||
|
min_stable_time_seconds: job.min_stable_time_seconds,
|
||||||
|
exclude_patterns: job.exclude_patterns || '',
|
||||||
|
skip_hidden: job.skip_hidden,
|
||||||
|
skip_system: job.skip_system,
|
||||||
|
skip_readonly: job.skip_readonly,
|
||||||
|
sync_deletions: job.sync_deletions,
|
||||||
|
});
|
||||||
|
setShowModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleTrigger = async (job: BackupJobItem) => {
|
const handleTrigger = async (job: BackupJobItem) => {
|
||||||
try {
|
try {
|
||||||
await api.triggerJob(job.id);
|
await api.triggerJob(job.id);
|
||||||
@@ -98,6 +125,7 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
alert('Primero debes registrar al menos un cliente Windows.');
|
alert('Primero debes registrar al menos un cliente Windows.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setEditingJobId(null);
|
||||||
setFormData({
|
setFormData({
|
||||||
client_id: clients[0].id,
|
client_id: clients[0].id,
|
||||||
name: '',
|
name: '',
|
||||||
@@ -195,6 +223,14 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
<Play size={13} />
|
<Play size={13} />
|
||||||
Ejecutar
|
Ejecutar
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{ padding: '6px 10px', fontSize: '0.78rem', color: 'var(--text-muted)' }}
|
||||||
|
onClick={() => handleEditClick(job)}
|
||||||
|
title="Editar parámetros del trabajo"
|
||||||
|
>
|
||||||
|
<Edit2 size={13} />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-danger"
|
className="btn btn-danger"
|
||||||
style={{ padding: '6px 10px', fontSize: '0.78rem' }}
|
style={{ padding: '6px 10px', fontSize: '0.78rem' }}
|
||||||
@@ -222,18 +258,16 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
{/* Create Job Modal */}
|
{/* Create Job Modal */}
|
||||||
{showModal && (
|
{showModal && (
|
||||||
<div className="modal-backdrop">
|
<div className="modal-backdrop">
|
||||||
<div className="modal-card">
|
<div className="modal-content" style={{ maxWidth: '640px' }}>
|
||||||
<div className="modal-header">
|
<div className="modal-header">
|
||||||
<h3 style={{ fontSize: '1.1rem', fontWeight: 700 }}>Nuevo Trabajo de Backup</h3>
|
<h4 style={{ fontSize: '1.1rem', fontWeight: 700 }}>
|
||||||
<button
|
{editingJobId ? 'Editar Trabajo de Backup' : 'Crear Trabajo de Backup'}
|
||||||
style={{ background: 'transparent', border: 'none', color: 'var(--text-muted)', cursor: 'pointer' }}
|
</h4>
|
||||||
onClick={() => setShowModal(false)}
|
<button className="modal-close" onClick={() => setShowModal(false)}>
|
||||||
>
|
<X size={18} />
|
||||||
<X size={20} />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<form onSubmit={handleSubmitJob}>
|
||||||
<form onSubmit={handleCreateJob}>
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Cliente Windows Destino:</label>
|
<label>Cliente Windows Destino:</label>
|
||||||
<select
|
<select
|
||||||
@@ -401,12 +435,12 @@ export const JobsView: React.FC<JobsViewProps> = ({ jobs, clients, onRefresh, se
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '12px', marginTop: '24px' }}>
|
<div className="modal-footer">
|
||||||
<button type="button" className="btn btn-secondary" onClick={() => setShowModal(false)}>
|
<button type="button" className="btn btn-secondary" onClick={() => setShowModal(false)}>
|
||||||
Cancelar
|
Cancelar
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" className="btn btn-primary" disabled={loading}>
|
<button type="submit" className="btn btn-primary" disabled={loading}>
|
||||||
{loading ? 'Guardando...' : 'Crear Trabajo'}
|
{loading ? 'Guardando...' : editingJobId ? 'Actualizar Trabajo' : 'Crear Trabajo'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -210,6 +210,27 @@ export const api = {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(jobData),
|
body: JSON.stringify(jobData),
|
||||||
}),
|
}),
|
||||||
|
updateJob: (jobId: number, jobData: Partial<{
|
||||||
|
client_id: number;
|
||||||
|
name: string;
|
||||||
|
source_path: string;
|
||||||
|
file_patterns: string;
|
||||||
|
exclude_patterns: string;
|
||||||
|
skip_hidden: boolean;
|
||||||
|
skip_system: boolean;
|
||||||
|
skip_readonly: boolean;
|
||||||
|
sync_deletions: boolean;
|
||||||
|
schedule_cron: string;
|
||||||
|
keep_daily: number;
|
||||||
|
keep_weekly: number;
|
||||||
|
keep_monthly: number;
|
||||||
|
min_stable_time_seconds: number;
|
||||||
|
is_active: boolean;
|
||||||
|
}>) =>
|
||||||
|
request<BackupJobItem>(`/jobs/${jobId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(jobData),
|
||||||
|
}),
|
||||||
triggerJob: (jobId: number) =>
|
triggerJob: (jobId: number) =>
|
||||||
request<{ message: string }>(`/jobs/${jobId}/trigger`, { method: 'POST' }),
|
request<{ message: string }>(`/jobs/${jobId}/trigger`, { method: 'POST' }),
|
||||||
deleteJob: (jobId: number) =>
|
deleteJob: (jobId: number) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user