mirror of
https://github.com/LowderPlay/cheburcheck.git
synced 2026-10-05 05:08:09 +03:00
feat: individual tasks (#86)
* feat: hidden nodes and individual tasks * chore: bump version
This commit is contained in:
@@ -113,10 +113,14 @@ export type ProbeStatus = {
|
||||
|
||||
export function startProbeSSE(
|
||||
id: string,
|
||||
token: string,
|
||||
onResult: (result: ProbeResult) => void,
|
||||
onStatus: (status: Partial<ProbeStatus>) => void,
|
||||
) {
|
||||
const eventSource = new EventSource(`/api/v1/probe/${id}`);
|
||||
const params = new URLSearchParams();
|
||||
if (token) params.set("token", token);
|
||||
const query = params.size > 0 ? `?${params.toString()}` : "";
|
||||
const eventSource = new EventSource(`/api/v1/probe/${id}${query}`);
|
||||
|
||||
eventSource.addEventListener("started", (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
@@ -27,11 +27,19 @@ type ResultVerdict = ResolvedProbeVerdict | "blocked";
|
||||
let {
|
||||
result,
|
||||
probeVerdict = null,
|
||||
token = "",
|
||||
}: {
|
||||
result: CheckResult;
|
||||
probeVerdict?: ResolvedProbeVerdict | null;
|
||||
token?: string;
|
||||
} = $props();
|
||||
|
||||
function checkHref(target: string): string {
|
||||
const params = new URLSearchParams({ target });
|
||||
if (token) params.set("token", token);
|
||||
return `/check?${params.toString()}`;
|
||||
}
|
||||
|
||||
const valueClass = "text-right text-sm font-medium text-neutral-200";
|
||||
const alertValueClass = `${valueClass} text-red-500`;
|
||||
const successValueClass = `${valueClass} text-green-500`;
|
||||
@@ -114,7 +122,7 @@ const providerCidrs = (provider: Provider) =>
|
||||
{#each result.reverseLookup as ptr}
|
||||
<span class={valueClass}>
|
||||
<a
|
||||
href={`/check?target=${ptr}`}
|
||||
href={checkHref(ptr)}
|
||||
class="text-neutral-100 underline decoration-neutral-500 transition-all hover:text-white hover:decoration-neutral-100"
|
||||
>
|
||||
{ptr}
|
||||
@@ -135,7 +143,7 @@ const providerCidrs = (provider: Provider) =>
|
||||
<span class={valueClass}>
|
||||
{#if result.geo.asn}
|
||||
<a
|
||||
href={`/check?target=${result.geo.asn}`}
|
||||
href={checkHref(result.geo.asn)}
|
||||
class="text-neutral-100 underline decoration-neutral-500 transition-all hover:text-white hover:decoration-neutral-100"
|
||||
>
|
||||
{result.geo.asn}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { ChevronRight, Search } from "@lucide/svelte";
|
||||
|
||||
let { token = "" }: { token?: string } = $props();
|
||||
</script>
|
||||
|
||||
<form
|
||||
class="group relative flex w-full flex-col gap-3 sm:flex-row sm:gap-0"
|
||||
action="/check"
|
||||
>
|
||||
{#if token}
|
||||
<input type="hidden" name="token" value={token}>
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y_autofocus -->
|
||||
<!-- biome-ignore-start lint/a11y/noAutofocus: using autofocus is acceptable here -->
|
||||
<input
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import SearchForm from "$lib/components/SearchForm.svelte";
|
||||
import StatCard from "$lib/components/StatCard.svelte";
|
||||
import { getStatusContext } from "$lib/context/status";
|
||||
|
||||
const statusQuery = getStatusContext();
|
||||
const status = $derived(statusQuery.data);
|
||||
const token = $derived(page.url.searchParams.get("token")?.trim() ?? "");
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -21,7 +23,7 @@ const status = $derived(statusQuery.data);
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<SearchForm />
|
||||
<SearchForm {token} />
|
||||
|
||||
<div
|
||||
class="mt-8 grid grid-cols-1 gap-4 text-xs text-neutral-500 sm:grid-cols-3"
|
||||
|
||||
@@ -23,6 +23,7 @@ type ProbeQueryData = {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const target = $derived(page.url.searchParams.get("target")?.trim() ?? "");
|
||||
const token = $derived(page.url.searchParams.get("token")?.trim() ?? "");
|
||||
|
||||
const checkQuery = createQuery(() => ({
|
||||
queryKey: ["check", target],
|
||||
@@ -48,7 +49,7 @@ function createInitialProbeData(id: string): ProbeQueryData {
|
||||
}
|
||||
|
||||
const probeQuery = createQuery(() => ({
|
||||
queryKey: ["probes", queryId],
|
||||
queryKey: ["probes", queryId, token],
|
||||
queryFn: () => createInitialProbeData(queryId ?? ""),
|
||||
enabled: shouldProbe,
|
||||
staleTime: Infinity,
|
||||
@@ -59,43 +60,50 @@ $effect(() => {
|
||||
if (!queryId || !shouldProbe) return;
|
||||
|
||||
queryClient.setQueryData<ProbeQueryData>(
|
||||
["probes", queryId],
|
||||
["probes", queryId, token],
|
||||
createInitialProbeData(queryId),
|
||||
);
|
||||
|
||||
const cleanup = startProbeSSE(
|
||||
queryId,
|
||||
token,
|
||||
(result) => {
|
||||
queryClient.setQueryData<ProbeQueryData>(["probes", queryId], (old) => {
|
||||
const current = old ?? createInitialProbeData(queryId);
|
||||
const probes = current.probes.some(
|
||||
(probe) => probe.probe_id === result.probe_id,
|
||||
)
|
||||
? current.probes.map((probe) =>
|
||||
probe.probe_id === result.probe_id ? result : probe,
|
||||
)
|
||||
: [...current.probes, result];
|
||||
queryClient.setQueryData<ProbeQueryData>(
|
||||
["probes", queryId, token],
|
||||
(old) => {
|
||||
const current = old ?? createInitialProbeData(queryId);
|
||||
const probes = current.probes.some(
|
||||
(probe) => probe.probe_id === result.probe_id,
|
||||
)
|
||||
? current.probes.map((probe) =>
|
||||
probe.probe_id === result.probe_id ? result : probe,
|
||||
)
|
||||
: [...current.probes, result];
|
||||
|
||||
return {
|
||||
...current,
|
||||
probes,
|
||||
status: {
|
||||
...current.status,
|
||||
status: "progress",
|
||||
response_count: probes.length,
|
||||
},
|
||||
};
|
||||
});
|
||||
return {
|
||||
...current,
|
||||
probes,
|
||||
status: {
|
||||
...current.status,
|
||||
status: "progress",
|
||||
response_count: probes.length,
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
(statusUpdate) => {
|
||||
queryClient.setQueryData<ProbeQueryData>(["probes", queryId], (old) => {
|
||||
const current = old ?? createInitialProbeData(queryId);
|
||||
queryClient.setQueryData<ProbeQueryData>(
|
||||
["probes", queryId, token],
|
||||
(old) => {
|
||||
const current = old ?? createInitialProbeData(queryId);
|
||||
|
||||
return {
|
||||
...current,
|
||||
status: { ...current.status, ...statusUpdate },
|
||||
};
|
||||
});
|
||||
return {
|
||||
...current,
|
||||
status: { ...current.status, ...statusUpdate },
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -115,7 +123,7 @@ const liveVerdict = $derived(
|
||||
);
|
||||
</script>
|
||||
|
||||
<SearchForm />
|
||||
<SearchForm {token} />
|
||||
|
||||
{#if target.length === 0}
|
||||
<div class="mt-4 border border-neutral-800 p-6 text-sm text-neutral-500">
|
||||
@@ -130,7 +138,7 @@ const liveVerdict = $derived(
|
||||
<ErrorMessage status={error.status} reason={error.message} />
|
||||
</div>
|
||||
{:else if checkQuery.data}
|
||||
<ResultPanel result={checkQuery.data} probeVerdict={liveVerdict} />
|
||||
<ResultPanel result={checkQuery.data} probeVerdict={liveVerdict} {token} />
|
||||
|
||||
{#if shouldProbe && probeQuery.data && probeQuery.data.status.online_probes > 0}
|
||||
<ProbeTable
|
||||
|
||||
Reference in New Issue
Block a user