kopia lustrzana https://github.com/OpenDroneMap/WebODM
processing time
rodzic
a8ab95131f
commit
ec57a5fc77
|
@ -125,7 +125,8 @@ export default function MainMenu(props) {
|
||||||
...task,
|
...task,
|
||||||
progressPct,
|
progressPct,
|
||||||
status: taskStatus,
|
status: taskStatus,
|
||||||
running_progress: taskDetail.running_progress || 0
|
running_progress: taskDetail.running_progress || 0,
|
||||||
|
processing_time: taskDetail.processing_time || null
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// This catch block handles network errors or JSON parsing errors, but not 404s
|
// This catch block handles network errors or JSON parsing errors, but not 404s
|
||||||
|
@ -366,6 +367,7 @@ export default function MainMenu(props) {
|
||||||
} finally {
|
} finally {
|
||||||
sessionStorage.removeItem('username');
|
sessionStorage.removeItem('username');
|
||||||
props.setIsLogged(false);
|
props.setIsLogged(false);
|
||||||
|
navigate('/');
|
||||||
}
|
}
|
||||||
}} className="logout-dialog-btn">Yes</button>
|
}} className="logout-dialog-btn">Yes</button>
|
||||||
<button onClick={() => setShowLogoutDialog(false)} className="logout-dialog-btn no">No</button>
|
<button onClick={() => setShowLogoutDialog(false)} className="logout-dialog-btn no">No</button>
|
||||||
|
|
|
@ -374,6 +374,15 @@
|
||||||
background: #ddd;
|
background: #ddd;
|
||||||
color: #222;
|
color: #222;
|
||||||
}
|
}
|
||||||
|
.task-processing-time {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.processing-time-text {
|
||||||
|
color: #718096;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
/* ====== THUMBNAILS ====== */
|
/* ====== THUMBNAILS ====== */
|
||||||
.task-thumbnail {
|
.task-thumbnail {
|
||||||
|
|
|
@ -4,11 +4,23 @@ import ProjectViewer from "./ProjectContainer.jsx";
|
||||||
import Export from './Export.jsx';
|
import Export from './Export.jsx';
|
||||||
import { authorizedFetch } from '../utils/api.js';
|
import { authorizedFetch } from '../utils/api.js';
|
||||||
|
|
||||||
// New TaskBox component with thumbnail hover functionality
|
// Helper function from the first code block for processing time format
|
||||||
|
const formatProcessingTime = (milliseconds) => {
|
||||||
|
const totalSeconds = Math.floor(milliseconds / 1000);
|
||||||
|
const hours = Math.floor(totalSeconds / 3600);
|
||||||
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||||
|
const seconds = totalSeconds % 60;
|
||||||
|
|
||||||
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// New TaskBox component with processing time functionality and second block's UI
|
||||||
const TaskBox = ({ task, onAction, onShowDeleteDialog, fetchJSON, isDeleteDialogOpen = false, openExportTaskId, setOpenExportTaskId }) => {
|
const TaskBox = ({ task, onAction, onShowDeleteDialog, fetchJSON, isDeleteDialogOpen = false, openExportTaskId, setOpenExportTaskId }) => {
|
||||||
const [lastError, setLastError] = useState(null);
|
const [lastError, setLastError] = useState(null);
|
||||||
const [isHovering, setIsHovering] = useState(false);
|
const [isHovering, setIsHovering] = useState(false);
|
||||||
const [thumbnailUrl, setThumbnailUrl] = useState(null);
|
const [thumbnailUrl, setThumbnailUrl] = useState(null);
|
||||||
|
// Added state for processing time
|
||||||
|
const [processingTime, setProcessingTime] = useState(null);
|
||||||
|
|
||||||
const fetchLastError = useCallback(async () => {
|
const fetchLastError = useCallback(async () => {
|
||||||
if (task.status === 30) {
|
if (task.status === 30) {
|
||||||
|
@ -30,7 +42,11 @@ const TaskBox = ({ task, onAction, onShowDeleteDialog, fetchJSON, isDeleteDialog
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchLastError();
|
fetchLastError();
|
||||||
}, [fetchLastError]);
|
// Added logic for setting processing time on completion
|
||||||
|
if (task.status === 40 && task.processing_time && !processingTime) {
|
||||||
|
setProcessingTime(task.processing_time);
|
||||||
|
}
|
||||||
|
}, [fetchLastError, task, processingTime]); // Dependency array updated
|
||||||
|
|
||||||
const getStatusText = (statusCode) => {
|
const getStatusText = (statusCode) => {
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
|
@ -71,94 +87,93 @@ const TaskBox = ({ task, onAction, onShowDeleteDialog, fetchJSON, isDeleteDialog
|
||||||
>
|
>
|
||||||
<div className="main-content-area">
|
<div className="main-content-area">
|
||||||
<div className="task-header">
|
<div className="task-header">
|
||||||
<div className="task-info">
|
<div className="task-info">
|
||||||
<h3 className="task-name">{task.taskName}</h3>
|
<h3 className="task-name">{task.taskName}</h3>
|
||||||
<p className="task-project-name">{task.projectName}</p>
|
<p className="task-project-name">{task.projectName}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="task-status-info">
|
<div className="task-status-info">
|
||||||
<div className={`status-indicator ${getStatusClass(effectiveStatus)}`}></div>
|
<div className={`status-indicator ${getStatusClass(effectiveStatus)}`}></div>
|
||||||
<span className={`status-badge ${getStatusClass(effectiveStatus)}`}>
|
<span className={`status-badge ${getStatusClass(effectiveStatus)}`}>
|
||||||
{getStatusText(effectiveStatus)}
|
{getStatusText(effectiveStatus)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="task-id-row">
|
<div className="task-id-row">
|
||||||
<span className="task-id">{task.id}</span>
|
<span className="task-id">ID: {task.id}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="task-content">
|
<div className="task-content">
|
||||||
{effectiveStatus === 30 && lastError && (
|
{effectiveStatus === 30 && lastError && (
|
||||||
<p className="task-error"><strong>Error:</strong> {lastError}</p>
|
<p className="task-error"><strong>Error:</strong> {lastError}</p>
|
||||||
)}
|
)}
|
||||||
{effectiveStatus === 20 && (
|
{effectiveStatus === 20 && (
|
||||||
<div className="task-progress">
|
<div className="task-progress">
|
||||||
<div className="progress-info">
|
<div className="progress-info">
|
||||||
<span>
|
<span>
|
||||||
{task.running_progress === 0 ? 'Uploading and Resizing...' : `Progress: ${task.progressPct}%`}
|
{task.running_progress === 0 ? 'Uploading and Resizing...' : `Progress: ${task.progressPct}%`}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
{task.running_progress > 0 && (
|
|
||||||
<div className="progress-bar">
|
|
||||||
<div
|
|
||||||
className="progress-fill"
|
|
||||||
style={{
|
|
||||||
width: `${task.progressPct}%`,
|
|
||||||
transition: "width 0.5s ease",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
{task.running_progress > 0 && (
|
||||||
|
<div className="progress-bar">
|
||||||
|
<div
|
||||||
|
className="progress-fill"
|
||||||
|
style={{
|
||||||
|
width: `${task.progressPct}%`,
|
||||||
|
transition: "width 0.5s ease",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Processing Time Display added here, as per the first code block's functionality */}
|
||||||
|
{effectiveStatus === 40 && processingTime && (
|
||||||
|
<div className="task-processing-time">
|
||||||
|
<span className="processing-time-text">{formatProcessingTime(processingTime)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="task-actions">
|
<div className="task-actions">
|
||||||
{effectiveStatus === 20 && (
|
{effectiveStatus === 20 && (
|
||||||
<>
|
<>
|
||||||
<button className="btn-cancel" onClick={() => onShowDeleteDialog({ ...task, actionType: 'cancel' })}>Cancel</button>
|
<button className="btn-cancel" onClick={() => onShowDeleteDialog({ ...task, actionType: 'cancel' })}>Cancel</button>
|
||||||
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{effectiveStatus === 40 && (
|
{effectiveStatus === 40 && (
|
||||||
<>
|
<>
|
||||||
<Export
|
<Export
|
||||||
projectId={task.projectId}
|
projectId={task.projectId}
|
||||||
taskId={task.id}
|
taskId={task.id}
|
||||||
openExportTaskId={openExportTaskId}
|
openExportTaskId={openExportTaskId}
|
||||||
setOpenExportTaskId={setOpenExportTaskId}
|
setOpenExportTaskId={setOpenExportTaskId}
|
||||||
/>
|
/>
|
||||||
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{effectiveStatus === 30 && (
|
{effectiveStatus === 30 && (
|
||||||
<>
|
<>
|
||||||
<button className="btn-restart" onClick={() => handleAction('restart')}>Restart</button>
|
<button className="btn-restart" onClick={() => handleAction('restart')}>Restart</button>
|
||||||
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{effectiveStatus === 50 && (
|
{effectiveStatus === 50 && (
|
||||||
<>
|
<>
|
||||||
<button className="btn-restart" onClick={() => handleAction('restart')}>Restart</button>
|
<button className="btn-restart" onClick={() => handleAction('restart')}>Restart</button>
|
||||||
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{effectiveStatus === 10 && (
|
{effectiveStatus === 10 && (
|
||||||
<>
|
<>
|
||||||
<button className="btn-cancel" onClick={() => onShowDeleteDialog({ ...task, actionType: 'cancel' })}>Cancel</button>
|
<button className="btn-cancel" onClick={() => onShowDeleteDialog({ ...task, actionType: 'cancel' })}>Cancel</button>
|
||||||
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
<button className="btn-delete" onClick={() => onShowDeleteDialog({ ...task, actionType: 'delete' })}>Delete</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Thumbnail container outside the main content but inside the task-box */}
|
{/* Thumbnail container exactly as in the second code block (no click handler) */}
|
||||||
{isHovering && effectiveStatus === 40 && thumbnailUrl && (
|
{isHovering && effectiveStatus === 40 && thumbnailUrl && (
|
||||||
<div className="task-thumbnail-wrapper">
|
<div className="task-thumbnail-wrapper">
|
||||||
<button
|
<img src={thumbnailUrl} alt={`Thumbnail for task ${task.id}`} className="task-thumbnail" />
|
||||||
type="button"
|
|
||||||
className="thumbnail-button"
|
|
||||||
onClick={() => handleAction('view')}
|
|
||||||
title="View"
|
|
||||||
>
|
|
||||||
<img src={thumbnailUrl} alt={`Thumbnail for task ${task.id}`} className="task-thumbnail" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,9 +184,7 @@ const TaskBox = ({ task, onAction, onShowDeleteDialog, fetchJSON, isDeleteDialog
|
||||||
const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitView,selectedTask, filterProjectId, setFilterProjectId, projects }) => {
|
const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitView,selectedTask, filterProjectId, setFilterProjectId, projects }) => {
|
||||||
const [deleteDialogTask, setDeleteDialogTask] = useState(null);
|
const [deleteDialogTask, setDeleteDialogTask] = useState(null);
|
||||||
const [filterProjectName, setFilterProjectName] = useState(null);
|
const [filterProjectName, setFilterProjectName] = useState(null);
|
||||||
// Share delete dialog state with child components
|
|
||||||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
||||||
// Add state to track the currently open Export dropdown
|
|
||||||
const [openExportTaskId, setOpenExportTaskId] = useState(null);
|
const [openExportTaskId, setOpenExportTaskId] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -266,6 +279,7 @@ const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitV
|
||||||
<>
|
<>
|
||||||
{categorizedTasks.running.length > 0 && (
|
{categorizedTasks.running.length > 0 && (
|
||||||
<div className="task-category">
|
<div className="task-category">
|
||||||
|
<h3>Running Tasks ({categorizedTasks.running.length})</h3>
|
||||||
<div className="tasks-grid">
|
<div className="tasks-grid">
|
||||||
{categorizedTasks.running.map((task) => (
|
{categorizedTasks.running.map((task) => (
|
||||||
<TaskBox
|
<TaskBox
|
||||||
|
@ -284,6 +298,7 @@ const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitV
|
||||||
)}
|
)}
|
||||||
{categorizedTasks.completed.length > 0 && (
|
{categorizedTasks.completed.length > 0 && (
|
||||||
<div className="task-category">
|
<div className="task-category">
|
||||||
|
<h3>Completed Tasks ({categorizedTasks.completed.length})</h3>
|
||||||
<div className="tasks-grid">
|
<div className="tasks-grid">
|
||||||
{categorizedTasks.completed.map((task) => (
|
{categorizedTasks.completed.map((task) => (
|
||||||
<TaskBox
|
<TaskBox
|
||||||
|
@ -302,6 +317,7 @@ const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitV
|
||||||
)}
|
)}
|
||||||
{categorizedTasks.failed.length > 0 && (
|
{categorizedTasks.failed.length > 0 && (
|
||||||
<div className="task-category">
|
<div className="task-category">
|
||||||
|
<h3>Failed Tasks ({categorizedTasks.failed.length})</h3>
|
||||||
<div className="tasks-grid">
|
<div className="tasks-grid">
|
||||||
{categorizedTasks.failed.map((task) => (
|
{categorizedTasks.failed.map((task) => (
|
||||||
<TaskBox
|
<TaskBox
|
||||||
|
@ -320,6 +336,7 @@ const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitV
|
||||||
)}
|
)}
|
||||||
{categorizedTasks.canceled.length > 0 && (
|
{categorizedTasks.canceled.length > 0 && (
|
||||||
<div className="task-category">
|
<div className="task-category">
|
||||||
|
<h3>Canceled Tasks ({categorizedTasks.canceled.length})</h3>
|
||||||
<div className="tasks-grid">
|
<div className="tasks-grid">
|
||||||
{categorizedTasks.canceled.map((task) => (
|
{categorizedTasks.canceled.map((task) => (
|
||||||
<TaskBox
|
<TaskBox
|
||||||
|
@ -338,6 +355,7 @@ const Tasks = ({ runningTasks, loading, onRefresh, onTaskAction ,isViewing,exitV
|
||||||
)}
|
)}
|
||||||
{categorizedTasks.queued.length > 0 && (
|
{categorizedTasks.queued.length > 0 && (
|
||||||
<div className="task-category">
|
<div className="task-category">
|
||||||
|
<h3>Queued Tasks ({categorizedTasks.queued.length})</h3>
|
||||||
<div className="tasks-grid">
|
<div className="tasks-grid">
|
||||||
{categorizedTasks.queued.map((task) => (
|
{categorizedTasks.queued.map((task) => (
|
||||||
<TaskBox
|
<TaskBox
|
||||||
|
|
Ładowanie…
Reference in New Issue