Skip to content

Commit

Permalink
chore: Added stretch loader to dashboard UI
Browse files Browse the repository at this point in the history
  • Loading branch information
matvp91 committed Aug 31, 2024
1 parent 7ff557e commit ebc369d
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 16 deletions.
4 changes: 3 additions & 1 deletion packages/api/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export const contract = c.router({
getSpec: {
method: "GET",
path: "/spec.json",
responses: {},
responses: {
200: c.type<Record<string, any>>(),
},
},
});
1 change: 1 addition & 0 deletions packages/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"ldrs": "^1.0.2",
"lucide-react": "^0.424.0",
"pretty-ms": "^9.1.0",
"react": "^18.3.1",
Expand Down
7 changes: 6 additions & 1 deletion packages/dashboard/src/components/JobLogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ type JobLogsProps = {
};

export function JobLogs({ id }: JobLogsProps) {
const { data } = tsr.getJobLogs.useSuspenseQuery({
const { data } = tsr.getJobLogs.useQuery({
queryKey: ["jobs", id, "logs"],
queryData: { params: { id } },
refetchInterval: 2000,
});

if (!data) {
return null;
}

const logs = data.body;

return (
Expand Down
21 changes: 19 additions & 2 deletions packages/dashboard/src/components/OpenApiReference.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
import { ApiReferenceReact } from "@scalar/api-reference-react";
import { tsr } from "@/tsr";
import "@scalar/api-reference-react/style.css";
import { useEffect } from "react";

type OpenApiReferenceProps = {
url: string;
onLoad(): void;
};

export function OpenApiReference({ url }: OpenApiReferenceProps) {
export function OpenApiReference({ url, onLoad }: OpenApiReferenceProps) {
const { data } = tsr.getSpec.useQuery({
queryKey: ["spec"],
});

useEffect(() => {
if (data) {
onLoad();
}
}, [data]);

if (!data) {
return null;
}

return (
<ApiReferenceReact
configuration={{
hideDownloadButton: true,
withDefaultFonts: false,
spec: {
url: `${url}/spec.json`,
content: data.body,
},
servers: [
{
Expand Down
17 changes: 17 additions & 0 deletions packages/dashboard/src/components/StretchLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { cn } from "@/lib/utils";
import "ldrs/cardio";

// Default values shown

type StretchLoaderProps = {
className?: string;
};

export function StretchLoader({ className }: StretchLoaderProps) {
return (
<div className={cn("flex justify-center items-center min-h-44", className)}>
{/* @ts-expect-error */}
<l-cardio size="50" stroke="4" speed="2" color="#7600ff"></l-cardio>
</div>
);
}
22 changes: 16 additions & 6 deletions packages/dashboard/src/hooks/useJob.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import { tsr } from "@/tsr";
import { useEffect, useRef } from "react";
import type { JobDto } from "@/tsr";

export function useJob(id: string) {
const { data: jobData } = tsr.getJob.useSuspenseQuery({
const lastResultRef = useRef<JobDto>();

const { data } = tsr.getJob.useQuery({
queryKey: ["jobsFromRoot", id],
queryData: { params: { id }, query: { fromRoot: true } },
refetchInterval: 2000,
});

const rootJob = jobData.body;
const job = findJob(rootJob, id);
if (!job) {
throw new Error("Job not found in tree.");
useEffect(() => {
if (data) {
lastResultRef.current = data.body;
}
}, [data]);

const rootJob = data?.body ?? lastResultRef.current;
if (!rootJob) {
return null;
}

return [job, rootJob] as const;
const job = findJob(rootJob, id);

return { job, rootJob };
}

function findJob(job: JobDto, id: string): JobDto | null {
Expand Down
8 changes: 7 additions & 1 deletion packages/dashboard/src/pages/ApiEmbedPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ const LazyOpenApiReference = lazy(() =>
);

export function ApiEmbedPage() {
return <LazyOpenApiReference url={import.meta.env.VITE_API_URL} />;
const onLoad = () => {
window.parent.postMessage("mixwave_openapi_loaded", "*");
};

return (
<LazyOpenApiReference url={import.meta.env.VITE_API_URL} onLoad={onLoad} />
);
}
26 changes: 25 additions & 1 deletion packages/dashboard/src/pages/ApiPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
import { StretchLoader } from "@/components/StretchLoader";
import { useEffect, useState } from "react";

export function ApiPage() {
return <iframe className="w-full h-full" src="/embed/api" />;
const [loaded, setLoaded] = useState(false);

useEffect(() => {
const onMessage = () => {
setLoaded(true);
};

window.addEventListener("message", onMessage);

return () => window.removeEventListener("message", onMessage);
}, []);

return (
<div className="w-full h-full">
{loaded ? null : (
<div className="absolute inset-0 bg-white">
<StretchLoader />
</div>
)}
<iframe className="w-full h-full" src="/embed/api" />
</div>
);
}
9 changes: 8 additions & 1 deletion packages/dashboard/src/pages/JobPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import { JobView } from "@/components/JobView";
import { Button } from "@/components/ui/button";
import { getShortId } from "@/lib/helpers";
import { useJob } from "@/hooks/useJob";
import { StretchLoader } from "@/components/StretchLoader";

export function JobPage() {
const { id } = useParams() as { id: string };
const [job, rootJob] = useJob(id);
const result = useJob(id);

if (!result) {
return <StretchLoader />;
}

const { job, rootJob } = result;

return (
<div className="min-h-full flex flex-col grow bg-white">
Expand Down
11 changes: 8 additions & 3 deletions packages/dashboard/src/pages/JobsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@ import { JobsFilter } from "@/components/JobsFilter";
import { useQueryParams } from "@/hooks/useQueryParams";
import { JobsStats } from "@/components/JobsStats";
import { filterJobs } from "@/lib/jobs-filter";
import { StretchLoader } from "@/components/StretchLoader";
import type { JobsFilterData } from "@/components/types";

export function JobsPage() {
const { data } = tsr.getJobs.useSuspenseQuery({
const [filter, setFilter] = useQueryParams<JobsFilterData>({});

const { data } = tsr.getJobs.useQuery({
queryKey: ["jobs"],
refetchInterval: 2000,
});

const [filter, setFilter] = useQueryParams<JobsFilterData>({});
if (!data) {
return <StretchLoader />;
}

const filteredJobs = filterJobs(data.body, filter);

return (
<div className="min-h-full bg-[#fafafa]">
<Container className="py-4">
<Container className="py-4 min-h-full">
<h1 className="text-lg font-medium">Jobs</h1>
<div className="my-4 flex items-center">
<JobsStats jobs={filteredJobs} />
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ebc369d

Please sign in to comment.