feat(task): add update logic for task intervals for backup/sync

This commit is contained in:
Sam Chau
2025-08-23 10:12:12 +09:30
parent 7f5f44cd77
commit 2e2abb93be
5 changed files with 142 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
import axios from 'axios';
import Alert from '@ui/Alert';
export const getAllTasks = async () => {
try {
@@ -37,3 +38,23 @@ export const triggerTask = async taskId => {
};
}
};
export const updateTaskInterval = async (taskId, intervalMinutes) => {
try {
const response = await axios.put(`/api/tasks/${taskId}`, {
interval_minutes: intervalMinutes
});
Alert.success(response.data.message || 'Task interval updated successfully');
return {
success: true,
data: response.data
};
} catch (error) {
const errorMessage = error.response?.data?.error || 'Failed to update task interval';
Alert.error(errorMessage);
return {
success: false,
error: errorMessage
};
}
};

View File

@@ -1,8 +1,15 @@
// components/settings/TaskCard.jsx
import React from 'react';
import {Play, Loader} from 'lucide-react';
import React, {useState, useEffect} from 'react';
import {Play, Loader, Edit2, Check, X} from 'lucide-react';
import NumberInput from '@ui/NumberInput';
import {updateTaskInterval} from '@/api/task';
const TaskCard = ({task, onTrigger, isTriggering}) => {
const TaskCard = ({task, onTrigger, isTriggering, isLast, onIntervalUpdate}) => {
const [intervalValue, setIntervalValue] = useState(task.interval_minutes);
const [originalValue, setOriginalValue] = useState(task.interval_minutes);
// Only allow editing for Repository Sync and Backup tasks
const isEditable = task.type === 'Sync' || task.type === 'Backup';
const formatDateTime = dateString => {
if (!dateString) return 'Never';
return new Date(dateString).toLocaleString();
@@ -13,8 +20,32 @@ const TaskCard = ({task, onTrigger, isTriggering}) => {
return `${duration}s`;
};
useEffect(() => {
setIntervalValue(task.interval_minutes);
setOriginalValue(task.interval_minutes);
}, [task.interval_minutes]);
useEffect(() => {
if (intervalValue !== originalValue && intervalValue > 0) {
const updateInterval = async () => {
const result = await updateTaskInterval(task.id, intervalValue);
if (result.success) {
setOriginalValue(intervalValue);
// Refresh task data to get new next_run time
if (onIntervalUpdate) {
onIntervalUpdate();
}
} else {
// Reset to original value if update failed
setIntervalValue(originalValue);
}
};
updateInterval();
}
}, [intervalValue]);
return (
<tr className='bg-gray-900 border-b border-gray-700'>
<tr className={`bg-gray-900 ${!isLast ? 'border-b border-gray-700' : ''}`}>
<td className='py-4 px-4'>
<div className='flex items-center space-x-3'>
<span className='font-medium text-gray-100'>
@@ -23,7 +54,21 @@ const TaskCard = ({task, onTrigger, isTriggering}) => {
</div>
</td>
<td className='py-4 px-4 text-gray-300'>
{task.interval_minutes} minutes
{isEditable ? (
<div className='flex items-center space-x-2'>
<NumberInput
value={intervalValue}
onChange={setIntervalValue}
min={1}
max={43200}
step={1}
className='w-24'
/>
<span className='text-gray-400 text-sm'>minutes</span>
</div>
) : (
<span>{task.interval_minutes} minutes</span>
)}
</td>
<td className='py-4 px-4 text-gray-300'>
{formatDateTime(task.last_run)}

View File

@@ -77,12 +77,14 @@ const TaskContainer = () => {
</tr>
</thead>
<tbody>
{tasks.map(task => (
{tasks.map((task, index) => (
<TaskCard
key={task.id}
task={task}
onTrigger={handleTriggerTask}
isTriggering={triggeringTask === task.id}
isLast={index === tasks.length - 1}
onIntervalUpdate={fetchTasks}
/>
))}
</tbody>

View File

@@ -5,6 +5,8 @@ import {ChevronUp, ChevronDown} from 'lucide-react';
const NumberInput = ({
value,
onChange,
onBlur = () => {},
onFocus = () => {},
className = '',
step = 1,
disabled = false,
@@ -24,26 +26,26 @@ const NumberInput = ({
}
};
const handleBlur = () => {
const handleBlur = (e) => {
setIsFocused(false);
const numValue =
localValue === '' || localValue === '-' ? 0 : parseInt(localValue);
if (min !== undefined && numValue < min) {
onChange(min);
return;
}
if (max !== undefined && numValue > max) {
} else if (max !== undefined && numValue > max) {
onChange(max);
return;
} else {
onChange(numValue);
}
onChange(numValue);
onBlur(e);
};
const handleFocus = () => {
const handleFocus = (e) => {
setIsFocused(true);
setLocalValue(value.toString());
onFocus(e);
};
const increment = () => {