fix client

This commit is contained in:
2026-05-25 09:14:52 +07:00
parent 9e6f57be35
commit a033562c4c
2 changed files with 17 additions and 234 deletions

View File

@@ -20,7 +20,6 @@ import {
Server,
Settings,
ShieldCheck,
TerminalSquare,
Trash2,
WifiOff,
XCircle
@@ -34,8 +33,6 @@ import {
fetchApplicationManifest,
fetchInstalledApps,
fetchPackageApps,
fetchTaskComponents,
fetchTaskLogs,
fetchTaskStatus,
joinUrl,
normalizeUrl,
@@ -67,24 +64,6 @@ function saveSettings(settings) {
window.localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
}
function statusTone(status) {
if (status === 'success' || status === 'installed' || status === 'online') return 'success';
if (status === 'running' || status === 'queued') return 'info';
if (status === 'failed' || status === 'offline') return 'danger';
if (status === 'update') return 'warning';
return 'muted';
}
function formatDate(value) {
if (!value) return '-';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return value;
return new Intl.DateTimeFormat('vi-VN', {
dateStyle: 'short',
timeStyle: 'short'
}).format(date);
}
function getErrorMessage(error) {
return error instanceof Error ? error.message : String(error || 'Có lỗi xảy ra');
}
@@ -107,10 +86,6 @@ function App() {
const [toast, setToast] = useState(null);
const [busyAction, setBusyAction] = useState('');
const [activeTask, setActiveTask] = useState(null);
const [task, setTask] = useState(null);
const [taskLogs, setTaskLogs] = useState([]);
const [taskComponents, setTaskComponents] = useState([]);
const [taskStatus, setTaskStatus] = useState({ state: 'idle', message: '' });
const packageBaseUrl = settings.packageBaseUrl;
const agentBaseUrl = settings.agentBaseUrl;
@@ -235,24 +210,14 @@ function App() {
}, [packageBaseUrl]);
const loadTaskSnapshot = useCallback(async (taskId) => {
setTaskStatus({ state: 'loading', message: 'Đang cập nhật task' });
try {
const [nextTask, nextLogs, nextComponents] = await Promise.all([
fetchTaskStatus(agentBaseUrl, taskId),
fetchTaskLogs(agentBaseUrl, taskId),
fetchTaskComponents(agentBaseUrl, taskId).catch(() => [])
]);
setTask(nextTask);
setTaskLogs(nextLogs);
setTaskComponents(nextComponents);
setTaskStatus({ state: statusTone(nextTask.status), message: nextTask.status });
const nextTask = await fetchTaskStatus(agentBaseUrl, taskId);
if (TERMINAL_TASK_STATUSES.has(nextTask.status)) {
await refreshAgent();
}
return nextTask;
} catch (error) {
setTaskStatus({ state: 'danger', message: getErrorMessage(error) });
} catch {
return null;
}
}, [agentBaseUrl, refreshAgent]);
@@ -265,17 +230,6 @@ function App() {
appName: app.appName,
queuedAt: new Date().toISOString()
});
setTask({
taskId: queuedTask.taskId,
type: action,
appId: app.appId,
appName: app.appName,
status: queuedTask.status || 'queued',
progress: 0,
currentStep: 'queued'
});
setTaskLogs([]);
setTaskComponents([]);
}, []);
const runAppAction = useCallback(async (action, app) => {
@@ -618,14 +572,6 @@ function App() {
status={detailStatus}
packageBaseUrl={packageBaseUrl}
/>
<TaskPanel
activeTask={activeTask}
task={task}
logs={taskLogs}
components={taskComponents}
status={taskStatus}
onRefresh={() => activeTask?.taskId && loadTaskSnapshot(activeTask.taskId)}
/>
</aside>
</div>
</section>
@@ -723,7 +669,7 @@ function AppDetailPanel({ app, detail, manifest, status, packageBaseUrl }) {
const components = manifest?.components || [];
return (
<section className="panel">
<section className="panel app-detail-panel">
<div className="panel-header">
<div>
<h2>{app?.appName || 'App detail'}</h2>
@@ -775,78 +721,6 @@ function AppDetailPanel({ app, detail, manifest, status, packageBaseUrl }) {
);
}
function TaskPanel({ activeTask, task, logs, components, status, onRefresh }) {
const progress = Math.max(0, Math.min(100, Number(task?.progress || 0)));
return (
<section className="panel task-panel">
<div className="panel-header">
<div>
<h2>Task monitor</h2>
<p>{activeTask?.taskId || 'Chưa có task'}</p>
</div>
<button className="icon-button subtle" type="button" onClick={onRefresh} disabled={!activeTask?.taskId} title="Refresh task">
<RefreshCcw size={16} aria-hidden="true" />
</button>
</div>
{task ? (
<>
<div className="task-summary">
<div>
<span className={`badge badge-${statusTone(task.status)}`}>{task.status}</span>
<strong>{task.appName || task.appId}</strong>
<small>{task.currentStep || '-'}</small>
</div>
<span>{progress}%</span>
</div>
<div className="progress-track">
<div style={{ width: `${progress}%` }} />
</div>
{components.length > 0 && (
<div className="component-list task-components">
<div className="component-list-title">
<Activity size={15} aria-hidden="true" />
Component progress
</div>
{components.map((component) => (
<div className="component-item" key={component.componentId}>
<div>
<strong>{component.componentId}</strong>
<span>{component.currentStep || component.type}</span>
</div>
<span className={`badge badge-${statusTone(component.status)}`}>{component.progress || 0}%</span>
</div>
))}
</div>
)}
<div className="logs-box">
<div className="component-list-title">
<TerminalSquare size={15} aria-hidden="true" />
Logs
</div>
<div className="log-lines">
{logs.slice(-8).map((log, index) => (
<div className={`log-line level-${log.level || 'info'}`} key={`${log.time}-${index}`}>
<time>{formatDate(log.time)}</time>
<span>{log.message}</span>
</div>
))}
{logs.length === 0 && (
<div className="table-empty compact-empty">{status.message || 'Đang chờ log.'}</div>
)}
</div>
</div>
</>
) : (
<div className="table-empty compact-empty">Install, update hoặc remove để bắt đầu theo dõi.</div>
)}
</section>
);
}
function Toast({ toast }) {
const tone = toast.type === 'failure' ? 'danger' : toast.type;
const Icon = tone === 'danger' ? AlertCircle : tone === 'success' ? CheckCircle2 : Activity;