12 changed files with 257 additions and 25 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
import { ReactNode } from "react"; |
||||
|
||||
export function Box(props: { children?: ReactNode }) { |
||||
return ( |
||||
<div className="bg-video-scraping-card rounded-xl p-8"> |
||||
{props.children} |
||||
</div> |
||||
); |
||||
} |
@ -1,3 +1,17 @@
@@ -1,3 +1,17 @@
|
||||
export function Paragraph(props: { children: React.ReactNode }) { |
||||
return <p className="text-errors-type-secondary mt-6">{props.children}</p>; |
||||
import classNames from "classnames"; |
||||
|
||||
export function Paragraph(props: { |
||||
children: React.ReactNode; |
||||
marginClass?: string; |
||||
}) { |
||||
return ( |
||||
<p |
||||
className={classNames( |
||||
"text-errors-type-secondary", |
||||
props.marginClass ?? "mt-6" |
||||
)} |
||||
> |
||||
{props.children} |
||||
</p> |
||||
); |
||||
} |
||||
|
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
import { ThinContainer } from "@/components/layout/ThinContainer"; |
||||
import { Heading1, Paragraph } from "@/components/utils/Text"; |
||||
import { SubPageLayout } from "@/pages/layouts/SubPageLayout"; |
||||
import { WorkerTestPart } from "@/pages/parts/admin/WorkerTestPart"; |
||||
|
||||
export function AdminPage() { |
||||
return ( |
||||
<SubPageLayout> |
||||
<ThinContainer> |
||||
<Heading1>Admin tools</Heading1> |
||||
<Paragraph>Useful tools to test out your current deployment</Paragraph> |
||||
|
||||
<WorkerTestPart /> |
||||
</ThinContainer> |
||||
</SubPageLayout> |
||||
); |
||||
} |
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
import classNames from "classnames"; |
||||
import { f } from "ofetch/dist/shared/ofetch.441891d5"; |
||||
import { useCallback, useMemo, useState } from "react"; |
||||
import { useAsyncFn } from "react-use"; |
||||
|
||||
import { mwFetch } from "@/backend/helpers/fetch"; |
||||
import { Button } from "@/components/Button"; |
||||
import { Icon, Icons } from "@/components/Icon"; |
||||
import { Box } from "@/components/layout/Box"; |
||||
import { Divider } from "@/components/player/internals/ContextMenu/Misc"; |
||||
import { Heading2 } from "@/components/utils/Text"; |
||||
import { conf } from "@/setup/config"; |
||||
|
||||
export function WorkerItem(props: { |
||||
name: string; |
||||
errored?: boolean; |
||||
success?: boolean; |
||||
errorText?: string; |
||||
}) { |
||||
return ( |
||||
<div className="flex mb-2"> |
||||
<Icon |
||||
icon={ |
||||
props.errored |
||||
? Icons.WARNING |
||||
: props.success |
||||
? Icons.CIRCLE_CHECK |
||||
: Icons.EYE_SLASH |
||||
} |
||||
className={classNames({ |
||||
"text-xl mr-2 mt-0.5": true, |
||||
"text-video-scraping-error": props.errored, |
||||
"text-video-scraping-noresult": !props.errored && !props.success, |
||||
"text-video-scraping-success": props.success, |
||||
})} |
||||
/> |
||||
<div className="flex-1"> |
||||
<p className="text-white font-bold">{props.name}</p> |
||||
{props.errorText ? <p>{props.errorText}</p> : null} |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
export function WorkerTestPart() { |
||||
const workerList = useMemo(() => { |
||||
return conf().PROXY_URLS.map((v, ind) => ({ |
||||
id: ind.toString(), |
||||
url: v, |
||||
})); |
||||
}, []); |
||||
const [workerState, setWorkerState] = useState< |
||||
{ id: string; status: "error" | "success"; error?: Error }[] |
||||
>([]); |
||||
|
||||
const runTests = useAsyncFn(async () => { |
||||
function updateWorker(id: string, data: (typeof workerState)[number]) { |
||||
setWorkerState((s) => { |
||||
return [...s.filter((v) => v.id !== id), data]; |
||||
}); |
||||
} |
||||
setWorkerState([]); |
||||
for (const worker of workerList) { |
||||
try { |
||||
await mwFetch(worker.url, { |
||||
query: { |
||||
destination: "https://postman-echo.com/get", |
||||
}, |
||||
}); |
||||
updateWorker(worker.id, { |
||||
id: worker.id, |
||||
status: "success", |
||||
}); |
||||
} catch (err) { |
||||
updateWorker(worker.id, { |
||||
id: worker.id, |
||||
status: "error", |
||||
error: err as Error, |
||||
}); |
||||
} |
||||
} |
||||
}, [workerList, setWorkerState]); |
||||
|
||||
return ( |
||||
<> |
||||
<Heading2 className="mb-0 mt-12">Worker tests</Heading2> |
||||
<p className="mb-8 mt-2">15 workers registered</p> |
||||
<Box> |
||||
{workerList.map((v, i) => { |
||||
const s = workerState.find((segment) => segment.id); |
||||
const name = `Worker ${i + 1}`; |
||||
if (!s) return <WorkerItem name={name} key={v.id} />; |
||||
if (s.status === "error") |
||||
return ( |
||||
<WorkerItem |
||||
name={name} |
||||
errored |
||||
key={v.id} |
||||
errorText={s.error?.toString()} |
||||
/> |
||||
); |
||||
if (s.status === "success") |
||||
return <WorkerItem name={name} success key={v.id} />; |
||||
return <WorkerItem name={name} key={v.id} />; |
||||
})} |
||||
<Divider /> |
||||
<div className="flex justify-end"> |
||||
<Button theme="purple">Run tests</Button> |
||||
</div> |
||||
</Box> |
||||
</> |
||||
); |
||||
} |
Loading…
Reference in new issue