fix: client side refresh for component

This commit is contained in:
bennykok 2024-02-01 17:01:54 +08:00
parent 4c715b815a
commit ea675fcd4c
10 changed files with 106 additions and 43 deletions

View File

@ -13,10 +13,7 @@ export async function CodeBlock(props: {
return (
<div className="relative w-full text-sm">
{/* max-w-[calc(32rem-1.5rem-1.5rem)] */}
{/* <div className=""> */}
<p
// tabIndex={1}
className="[&>pre]:p-4 rounded-lg max-h-96 overflow-auto w-full"
style={{
overflowWrap: "break-word",
@ -28,7 +25,6 @@ export async function CodeBlock(props: {
}),
}}
/>
{/* </div> */}
<CopyButton className="absolute right-2 top-2" text={props.code} />
</div>
);

View File

@ -0,0 +1,35 @@
"use client";
import { CopyButton } from "@/components/CopyButton";
import type { StringLiteralUnion } from "shikiji";
import useSWR from "swr";
import { highlight } from "../server/highlight";
export function CodeBlockClient({
code,
lang,
}: {
code: string;
lang: StringLiteralUnion<string>;
}) {
const { data } = useSWR(code, async () => {
return highlight(code.trim(), lang);
});
return (
<div className="relative w-full text-sm">
{data && (
<p
className="[&>pre]:p-4 rounded-lg max-h-96 overflow-auto w-full"
style={{
overflowWrap: "break-word",
}}
dangerouslySetInnerHTML={{
__html: data,
}}
/>
)}
<CopyButton className="absolute right-2 top-2" text={code} />
</div>
);
}

View File

@ -14,10 +14,18 @@ export function LogsViewer({
logs,
hideTimestamp,
className,
}: { logs: LogsType; hideTimestamp?: boolean; className?: string }) {
stickToBottom = true,
}: {
logs: LogsType;
hideTimestamp?: boolean;
className?: string;
stickToBottom?: boolean;
}) {
const container = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!stickToBottom) return;
// console.log(logs.length, container.current);
if (container.current) {
const scrollHeight = container.current.scrollHeight;
@ -27,11 +35,12 @@ export function LogsViewer({
behavior: "smooth",
});
}
}, [logs.length]);
}, [logs.length, stickToBottom]);
return (
<div
ref={(ref) => {
if (!stickToBottom) return;
if (!container.current && ref) {
const scrollHeight = ref.scrollHeight;

View File

@ -1,15 +1,25 @@
"use client";
import useSWR from "swr";
import { DownloadButton } from "./DownloadButton";
import { getFileDownloadUrl } from "@/server/getFileDownloadUrl";
export async function OutputRender(props: {
export function OutputRender(props: {
run_id: string;
filename: string;
}) {
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
const url = await getFileDownloadUrl(
`outputs/runs/${props.run_id}/${props.filename}`,
);
const { data: url } = useSWR(
"run-outputs+" + props.run_id + props.filename,
async () => {
return await getFileDownloadUrl(
`outputs/runs/${props.run_id}/${props.filename}`,
);
},
);
if (!url) return <></>;
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
return (
<video controls autoPlay className="w-[400px]">
<source src={url} type="video/mp4" />
@ -25,17 +35,8 @@ export async function OutputRender(props: {
props.filename.endsWith(".jpg") ||
props.filename.endsWith(".jpeg")
) {
const url = await getFileDownloadUrl(
`outputs/runs/${props.run_id}/${props.filename}`,
);
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
} else {
const url = await getFileDownloadUrl(
`outputs/runs/${props.run_id}/${props.filename}`,
);
// console.log(url);
return <DownloadButton filename={props.filename} href={url} />;
}
}

View File

@ -1,12 +1,12 @@
"use client";
import { RunInputs } from "@/components/RunInputs";
import { RunOutputs } from "@/components/RunOutputs";
import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
@ -19,11 +19,8 @@ import {
} from "@/components/ui/tooltip";
import { getDuration, getRelativeTime } from "@/lib/getRelativeTime";
import { type findAllRuns } from "@/server/findAllRuns";
import { Suspense } from "react";
import { LiveStatus } from "./LiveStatus";
import { LogsType, LogsViewer } from "@/components/LogsViewer";
import { Button } from "@/components/ui/button";
import { Edit, ExternalLink } from "lucide-react";
import { LoadingWrapper } from "@/components/LoadingWrapper";
export function RunDisplay({
run,
@ -78,9 +75,9 @@ export function RunDisplay({
</DialogHeader>
<div className="max-h-96 overflow-y-scroll">
<RunInputs run={run} />
<Suspense>
<LoadingWrapper tag="output">
<RunOutputs run={run} />
</Suspense>
</LoadingWrapper>
</div>
{/* <div className="max-h-96 overflow-y-scroll">{view}</div> */}
</DialogContent>

View File

@ -8,7 +8,7 @@ import {
} from "@/components/ui/table";
import type { findAllRuns } from "@/server/findAllRuns";
export async function RunInputs({
export function RunInputs({
run,
}: {
run: Awaited<ReturnType<typeof findAllRuns>>[0];

View File

@ -1,3 +1,5 @@
"use client";
import {
Dialog,
DialogClose,
@ -9,7 +11,6 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { OutputRender } from "./OutputRender";
import { CodeBlock } from "@/components/CodeBlock";
import {
Table,
TableBody,
@ -24,11 +25,19 @@ import { Button } from "@/components/ui/button";
import { ExternalLink } from "lucide-react";
import { LogsViewer } from "@/components/LogsViewer";
import { CopyButton } from "@/components/CopyButton";
import useSWR from "swr";
import { CodeBlockClient } from "@/components/CodeBlockClient";
export async function RunOutputs({
export function RunOutputs({
run,
}: { run: Awaited<ReturnType<typeof findAllRuns>>[0] }) {
const outputs = await getRunsOutput(run.id);
const { data, isValidating, error } = useSWR(
"run-outputs+" + run.id,
async () => {
return await getRunsOutput(run.id);
},
);
return (
<Table className="table-fixed">
<TableHeader className="bg-background top-0 sticky">
@ -52,7 +61,7 @@ export async function RunOutputs({
<DialogHeader>
<DialogTitle>Run Log</DialogTitle>
</DialogHeader>
<LogsViewer logs={run.run_log} />
<LogsViewer logs={run.run_log} stickToBottom={false} />
<DialogFooter>
<CopyButton
className="w-fit aspect-auto p-4"
@ -74,7 +83,7 @@ export async function RunOutputs({
</TableCell>
</TableRow>
{outputs?.map((run) => {
{data?.map((run) => {
const fileName =
run.data.images?.[0].filename ||
run.data.files?.[0].filename ||
@ -85,7 +94,7 @@ export async function RunOutputs({
<TableRow key={run.id}>
<TableCell>Output</TableCell>
<TableCell className="">
<CodeBlock
<CodeBlockClient
code={JSON.stringify(run.data, null, 2)}
lang="json"
/>

View File

@ -29,7 +29,7 @@ export function RunsTable(props: {
const { data, error, isLoading, isValidating } = useSWR(
"runs+" + page,
async () => {
const data = await getAllRunstableContent({
const data = await findAllRunsWithCounts({
workflow_id: props.workflow_id,
limit: itemPerPage,
offset: (page - 1) * itemPerPage,
@ -68,7 +68,11 @@ export function RunsTable(props: {
<TableHead className="text-right">Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>{data?.table}</TableBody>
<TableBody>
{data?.allRuns.map((run) => (
<RunDisplay run={run} key={run.id} />
))}
</TableBody>
</Table>
</div>

View File

@ -1,16 +1,10 @@
"use server";
import { RunOutputs } from "@/components/RunOutputs";
import { db } from "@/db/db";
import { workflowRunOutputs } from "@/db/schema";
import { eq } from "drizzle-orm";
// export async function getRunsOutputDisplay(run_id: string) {
// return <RunOutputs run_id={run_id} />;
// }
export async function getRunsOutput(run_id: string) {
// throw new Error("Not implemented");
return await db
.select()
.from(workflowRunOutputs)

View File

@ -0,0 +1,18 @@
"use server";
import type { StringLiteralUnion } from "shikiji";
import { getHighlighter } from "shikiji";
export async function highlight(
code: string,
lang: StringLiteralUnion<string>,
) {
const highlighter = await getHighlighter({
themes: ["one-dark-pro"],
langs: [lang],
});
return highlighter.codeToHtml(code.trim(), {
lang: lang,
theme: "one-dark-pro",
});
}