причесываем лог

This commit is contained in:
2026-02-28 10:47:19 +03:00
parent 7e43830144
commit daa9f7be3a
5 changed files with 172 additions and 26 deletions

View File

@@ -27,7 +27,7 @@
* @TEST_FIXTURE init_state -> {"taskId": "task-1"}
* @TEST_INVARIANT correct_fetch -> verifies: [init_state]
*/
import { onMount } from "svelte";
import { onDestroy, onMount } from "svelte";
import { page } from "$app/stores";
import { goto } from "$app/navigation";
import { api } from "$lib/api.js";
@@ -41,6 +41,9 @@
let logs = [];
let isLoading = true;
let error = null;
let screenshotBlobUrls = {};
let screenshotLoadErrors = {};
let screenshotLoadToken = 0;
function formatDate(value) {
if (!value) return "-";
@@ -102,10 +105,57 @@
openDrawerForTask(taskId);
}
function cleanupScreenshotBlobUrls() {
Object.values(screenshotBlobUrls).forEach((url) => {
if (url) URL.revokeObjectURL(url);
});
screenshotBlobUrls = {};
}
async function loadScreenshotBlobUrls(paths) {
const currentToken = ++screenshotLoadToken;
cleanupScreenshotBlobUrls();
screenshotLoadErrors = {};
if (!Array.isArray(paths) || paths.length === 0) return;
const nextUrls = {};
const nextErrors = {};
await Promise.all(
paths.map(async (path) => {
try {
const blob = await api.getStorageFileBlob(path);
nextUrls[path] = URL.createObjectURL(blob);
} catch (err) {
nextErrors[path] = err?.message || "Failed to load screenshot";
}
}),
);
if (currentToken !== screenshotLoadToken) {
Object.values(nextUrls).forEach((url) => URL.revokeObjectURL(url));
return;
}
screenshotBlobUrls = nextUrls;
screenshotLoadErrors = nextErrors;
}
function openScreenshot(path) {
const url = screenshotBlobUrls[path];
if (!url) return;
window.open(url, "_blank", "noopener,noreferrer");
}
onMount(async () => {
await loadReport();
});
onDestroy(() => {
cleanupScreenshotBlobUrls();
});
$: result = task?.result || {};
$: checkResult = getDashboardCheckResult(result);
$: timings = result?.timings || {};
@@ -114,6 +164,7 @@
: result?.screenshot_path
? [result.screenshot_path]
: [];
$: void loadScreenshotBlobUrls(screenshotPaths);
$: sentLogs = Array.isArray(result?.logs_sent_to_llm)
? result.logs_sent_to_llm
: [];
@@ -256,19 +307,27 @@
{:else}
<div class="mt-3 grid grid-cols-1 gap-4 lg:grid-cols-2">
{#each screenshotPaths as path}
<a
href={`/api/storage/file?path=${encodeURIComponent(path)}`}
target="_blank"
rel="noreferrer noopener"
class="block"
<button
type="button"
class="block w-full text-left"
on:click={() => openScreenshot(path)}
disabled={!screenshotBlobUrls[path]}
>
<img
src={`/api/storage/file?path=${encodeURIComponent(path)}`}
alt="Validation screenshot"
class="h-64 w-full rounded-lg border border-slate-200 object-cover"
/>
{#if screenshotBlobUrls[path]}
<img
src={screenshotBlobUrls[path]}
alt="Validation screenshot"
class="h-64 w-full rounded-lg border border-slate-200 object-cover"
/>
{:else}
<div
class="flex h-64 w-full items-center justify-center rounded-lg border border-rose-200 bg-rose-50 px-4 text-sm text-rose-700"
>
{screenshotLoadErrors[path] || "Failed to load screenshot"}
</div>
{/if}
<p class="mt-1 truncate text-xs text-slate-500">{path}</p>
</a>
</button>
{/each}
</div>
{/if}