taskwatch 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {taskwatch-0.2.0 → taskwatch-0.2.1}/PKG-INFO +1 -1
- {taskwatch-0.2.0 → taskwatch-0.2.1}/pyproject.toml +1 -1
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/logs.html +64 -33
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/PKG-INFO +1 -1
- {taskwatch-0.2.0 → taskwatch-0.2.1}/README.md +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/setup.cfg +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/log.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/main.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/report.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/run.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/cli/task.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/executor.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/models.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/notifier.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/reporter.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/core/scheduler.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/utils/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/utils/config.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/utils/logger.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/utils/process.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/reports.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/runs.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/settings.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/stats.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/api/tasks.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/app.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/__init__.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/dashboard.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/logs.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/reports.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/settings.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/routes/tasks.py +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/static/css/style.css +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/base.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/dashboard.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/reports.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/settings.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/task_detail.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch/web/templates/tasks.html +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/SOURCES.txt +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/dependency_links.txt +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/entry_points.txt +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/requires.txt +0 -0
- {taskwatch-0.2.0 → taskwatch-0.2.1}/taskwatch.egg-info/top_level.txt +0 -0
|
@@ -97,26 +97,32 @@
|
|
|
97
97
|
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
|
98
98
|
<div class="absolute inset-0 bg-gray-500 opacity-75" onclick="closeLogModal()"></div>
|
|
99
99
|
</div>
|
|
100
|
-
<div class="inline-block align-bottom bg-white rounded-lg text-left
|
|
101
|
-
<div class="bg-white px-
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
<div class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-4 sm:align-middle sm:max-w-5xl sm:w-full">
|
|
101
|
+
<div class="bg-white px-6 pt-5 pb-4 sm:p-6 sm:pb-4 flex flex-col max-h-[85vh]">
|
|
102
|
+
<div class="flex justify-between items-center mb-4 shrink-0">
|
|
103
|
+
<h3 class="text-lg font-medium text-gray-900">运行详情</h3>
|
|
104
|
+
<button onclick="closeLogModal()" class="text-gray-400 hover:text-gray-600 p-1">
|
|
105
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
|
|
106
|
+
</button>
|
|
107
|
+
</div>
|
|
108
|
+
<div id="logInfo" class="grid grid-cols-3 gap-x-4 gap-y-1 text-sm mb-4 shrink-0"></div>
|
|
109
|
+
<div class="flex-1 min-h-0 flex flex-col gap-3 overflow-hidden">
|
|
110
|
+
<div class="flex-1 min-h-0 flex flex-col">
|
|
111
|
+
<div class="flex justify-between items-center mb-1 shrink-0">
|
|
112
|
+
<h4 class="text-sm font-medium text-gray-700">STDOUT</h4>
|
|
113
|
+
<button onclick="copyToClipboard('logStdout')" class="text-xs text-indigo-600 hover:text-indigo-800 px-2 py-0.5 rounded hover:bg-indigo-50">复制</button>
|
|
114
|
+
</div>
|
|
115
|
+
<pre id="logStdout" class="bg-gray-900 text-green-400 p-3 rounded text-xs overflow-auto flex-1 min-h-[120px] max-h-[50vh] font-mono whitespace-pre-wrap break-all"></pre>
|
|
108
116
|
</div>
|
|
109
|
-
<div>
|
|
110
|
-
<
|
|
111
|
-
|
|
117
|
+
<div class="shrink-0 flex flex-col">
|
|
118
|
+
<div class="flex justify-between items-center mb-1">
|
|
119
|
+
<h4 class="text-sm font-medium text-gray-700">STDERR</h4>
|
|
120
|
+
<button onclick="copyToClipboard('logStderr')" class="text-xs text-indigo-600 hover:text-indigo-800 px-2 py-0.5 rounded hover:bg-indigo-50">复制</button>
|
|
121
|
+
</div>
|
|
122
|
+
<pre id="logStderr" class="bg-red-950 text-red-300 p-3 rounded text-xs overflow-auto min-h-[60px] max-h-[30vh] font-mono whitespace-pre-wrap break-all"></pre>
|
|
112
123
|
</div>
|
|
113
|
-
<div id="logFilePath" class="text-xs text-gray-500"></div>
|
|
114
124
|
</div>
|
|
115
|
-
|
|
116
|
-
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
|
117
|
-
<button onclick="closeLogModal()" class="w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 sm:mt-0 sm:w-auto sm:text-sm">
|
|
118
|
-
关闭
|
|
119
|
-
</button>
|
|
125
|
+
<div id="logFilePath" class="text-xs text-gray-500 mt-2 shrink-0"></div>
|
|
120
126
|
</div>
|
|
121
127
|
</div>
|
|
122
128
|
</div>
|
|
@@ -288,24 +294,57 @@
|
|
|
288
294
|
}
|
|
289
295
|
}
|
|
290
296
|
|
|
291
|
-
|
|
292
|
-
const run = await apiCall(`/api/runs/${runId}`);
|
|
293
|
-
if (!run) return;
|
|
294
|
-
|
|
297
|
+
function renderLogInfo(run) {
|
|
295
298
|
const triggerLabel = { schedule: '定时调度', manual: '手动触发' }[run.trigger] || run.trigger || '-';
|
|
296
299
|
document.getElementById('logInfo').innerHTML = `
|
|
297
300
|
<div><span class="text-gray-500">任务名:</span>${run.task_name || '-'}</div>
|
|
298
301
|
<div><span class="text-gray-500">触发方式:</span>${triggerLabel}</div>
|
|
302
|
+
<div><span class="text-gray-500">状态:</span>${run.status}</div>
|
|
299
303
|
<div><span class="text-gray-500">开始时间:</span>${run.start_time ? run.start_time.substring(0, 19) : '-'}</div>
|
|
300
304
|
<div><span class="text-gray-500">结束时间:</span>${run.end_time ? run.end_time.substring(0, 19) : '-'}</div>
|
|
301
|
-
<div><span class="text-gray-500">状态:</span>${run.status}</div>
|
|
302
|
-
<div><span class="text-gray-500">退出码:</span>${run.exit_code !== null ? run.exit_code : '-'}</div>
|
|
303
305
|
<div><span class="text-gray-500">耗时:</span>${run.duration ? (run.duration / 1000).toFixed(1) + 's' : '-'}</div>
|
|
306
|
+
<div><span class="text-gray-500">退出码:</span>${run.exit_code !== null ? run.exit_code : '-'}</div>
|
|
304
307
|
`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function scrollLogToBottom() {
|
|
311
|
+
const stdout = document.getElementById('logStdout');
|
|
312
|
+
const stderr = document.getElementById('logStderr');
|
|
313
|
+
stdout.scrollTop = stdout.scrollHeight;
|
|
314
|
+
stderr.scrollTop = stderr.scrollHeight;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function copyToClipboard(elementId) {
|
|
318
|
+
const text = document.getElementById(elementId).textContent;
|
|
319
|
+
if (!text || text === '(无输出)' || text === '(无错误)') {
|
|
320
|
+
showToast('无内容可复制', 'error');
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
324
|
+
showToast('已复制到剪贴板');
|
|
325
|
+
}).catch(() => {
|
|
326
|
+
const textarea = document.createElement('textarea');
|
|
327
|
+
textarea.value = text;
|
|
328
|
+
textarea.style.position = 'fixed';
|
|
329
|
+
textarea.style.opacity = '0';
|
|
330
|
+
document.body.appendChild(textarea);
|
|
331
|
+
textarea.select();
|
|
332
|
+
document.execCommand('copy');
|
|
333
|
+
document.body.removeChild(textarea);
|
|
334
|
+
showToast('已复制到剪贴板');
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function viewLog(runId) {
|
|
339
|
+
const run = await apiCall(`/api/runs/${runId}`);
|
|
340
|
+
if (!run) return;
|
|
341
|
+
|
|
342
|
+
renderLogInfo(run);
|
|
305
343
|
document.getElementById('logStdout').textContent = run.stdout_summary || '(无输出)';
|
|
306
344
|
document.getElementById('logStderr').textContent = run.stderr_summary || '(无错误)';
|
|
307
345
|
document.getElementById('logFilePath').textContent = run.log_file ? `日志文件: ${run.log_file}` : '';
|
|
308
346
|
document.getElementById('logModal').classList.remove('hidden');
|
|
347
|
+
scrollLogToBottom();
|
|
309
348
|
if (run.status === 'running') {
|
|
310
349
|
startLogRefresh(runId);
|
|
311
350
|
}
|
|
@@ -318,18 +357,10 @@
|
|
|
318
357
|
if (!run) return;
|
|
319
358
|
document.getElementById('logStdout').textContent = run.stdout_summary || '(无输出)';
|
|
320
359
|
document.getElementById('logStderr').textContent = run.stderr_summary || '(无错误)';
|
|
360
|
+
scrollLogToBottom();
|
|
321
361
|
if (run.status !== 'running') {
|
|
322
362
|
stopLogRefresh();
|
|
323
|
-
|
|
324
|
-
document.getElementById('logInfo').innerHTML = `
|
|
325
|
-
<div><span class="text-gray-500">任务名:</span>${run.task_name || '-'}</div>
|
|
326
|
-
<div><span class="text-gray-500">触发方式:</span>${triggerLabel}</div>
|
|
327
|
-
<div><span class="text-gray-500">开始时间:</span>${run.start_time ? run.start_time.substring(0, 19) : '-'}</div>
|
|
328
|
-
<div><span class="text-gray-500">结束时间:</span>${run.end_time ? run.end_time.substring(0, 19) : '-'}</div>
|
|
329
|
-
<div><span class="text-gray-500">状态:</span>${run.status}</div>
|
|
330
|
-
<div><span class="text-gray-500">退出码:</span>${run.exit_code !== null ? run.exit_code : '-'}</div>
|
|
331
|
-
<div><span class="text-gray-500">耗时:</span>${run.duration ? (run.duration / 1000).toFixed(1) + 's' : '-'}</div>
|
|
332
|
-
`;
|
|
363
|
+
renderLogInfo(run);
|
|
333
364
|
loadRuns();
|
|
334
365
|
}
|
|
335
366
|
}, 3000);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|