From a8b07f844a17f469e747ee7cb46997750a9e0e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Lu=C3=ADs?= Date: Thu, 21 Nov 2024 12:49:13 -0300 Subject: [PATCH 1/4] add history schemas and types --- apps/spu-ui/src/lib/types.ts | 3 ++ packages/api/src/index.ts | 2 + packages/api/src/schemas/history.ts | 70 +++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 packages/api/src/schemas/history.ts diff --git a/apps/spu-ui/src/lib/types.ts b/apps/spu-ui/src/lib/types.ts index a7f6486..884ffab 100644 --- a/apps/spu-ui/src/lib/types.ts +++ b/apps/spu-ui/src/lib/types.ts @@ -9,3 +9,6 @@ type QueueResponse = z.infer; export type QueueItemProps = | QueueResponse["items"][number] | QueueResponse["runningItem"]; + +type HistoryResponse = z.infer; +export type HistoryItemProps = HistoryResponse["items"][number]; diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index dbc03fa..18af069 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -3,6 +3,7 @@ import type { AppRouter } from "./root"; import { appRouter } from "./root"; import common from "./schemas/common"; import devices from "./schemas/devices"; +import history from "./schemas/history"; import instructions from "./schemas/instructions"; import item from "./schemas/item"; import plans from "./schemas/plans"; @@ -16,6 +17,7 @@ const schemas = { plans, queue, item, + history, }; /** diff --git a/packages/api/src/schemas/history.ts b/packages/api/src/schemas/history.ts new file mode 100644 index 0000000..54d50a8 --- /dev/null +++ b/packages/api/src/schemas/history.ts @@ -0,0 +1,70 @@ +import { z } from "zod"; + +const getResponseSchema = z + .object({ + success: z.boolean(), + msg: z.string(), + items: z.array( + z.object({ + name: z.string(), + args: z.array(z.any()).optional().nullable(), + kwargs: z.record(z.any()).optional().nullable(), + item_type: z.string(), + user: z.string(), + user_group: z.string(), + item_uid: z.string().uuid(), + result: z + .object({ + exit_status: z.string().optional(), + run_uids: z.array(z.string()), + scan_ids: z.array(z.string()), + time_start: z.number(), + time_stop: z.number(), + msg: z.string().optional(), + traceback: z.string().optional(), + }) + .optional() + .nullable(), + }), + ), + plan_history_uid: z.string().uuid(), + }) + .transform((data) => { + const { + success, + msg, + items: unprocessedItems, + plan_history_uid, + ...unchanged + } = data; + + const items = unprocessedItems.map((item) => ({ + name: item.name, + args: item.args, + kwargs: item.kwargs, + itemType: item.item_type, + user: item.user, + userGroup: item.user_group, + itemUid: item.item_uid, + result: item.result + ? { + exitStatus: item.result.exit_status, + runUids: item.result.run_uids, + scanIds: item.result.scan_ids, + timeStart: item.result.time_start, + timeStop: item.result.time_stop, + msg: item.result.msg, + traceback: item.result.traceback, + } + : null, + })); + return { + success, + msg, + items, + planHistoryUid: plan_history_uid, + ...unchanged, + }; + }); + +export default { getResponseSchema }; From 09b27f601a8f9b7e2135602a51b982e277ca8a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Lu=C3=ADs?= Date: Thu, 21 Nov 2024 12:49:49 -0300 Subject: [PATCH 2/4] create history router add get and clear routes --- packages/api/src/root.ts | 2 ++ packages/api/src/router/history.ts | 50 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 packages/api/src/router/history.ts diff --git a/packages/api/src/root.ts b/packages/api/src/root.ts index af0bda7..56d19a7 100644 --- a/packages/api/src/root.ts +++ b/packages/api/src/root.ts @@ -1,6 +1,7 @@ import { consoleOutputRouter } from "./router/console-output"; import { devicesRouter } from "./router/devices"; import { environmentRouter } from "./router/environment"; +import { historyRouter } from "./router/history"; import { plansRouter } from "./router/plans"; import { postRouter } from "./router/post"; import { queueRouter } from "./router/queue"; @@ -15,6 +16,7 @@ export const appRouter = createTRPCRouter({ environment: environmentRouter, status: statusRouter, consoleOutput: consoleOutputRouter, + history: historyRouter, }); // export type definition of API diff --git a/packages/api/src/router/history.ts b/packages/api/src/router/history.ts new file mode 100644 index 0000000..8add2f0 --- /dev/null +++ b/packages/api/src/router/history.ts @@ -0,0 +1,50 @@ +import { createZodFetcher } from "zod-fetch"; +import { env } from "../../env"; +import commonSchemas from "../schemas/common"; +import history from "../schemas/history"; +import { protectedProcedure } from "../trpc"; + +export const historyRouter = { + get: protectedProcedure.query(async ({ ctx }) => { + const fetchURL = `${env.BLUESKY_HTTPSERVER_URL}/api/history/get`; + const fetchWithZod = createZodFetcher(); + try { + const res = await fetchWithZod(history.getResponseSchema, fetchURL, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${ctx.session.user.blueskyAccessToken}`, + }, + body: undefined, + }); + return res; + } catch (e) { + if (e instanceof Error) { + console.error(e); + throw new Error(e.message); + } + throw new Error("Unknown error"); + } + }), + clear: protectedProcedure.mutation(async ({ ctx }) => { + const fetchURL = `${env.BLUESKY_HTTPSERVER_URL}/api/history/clear`; + const fetchWithZod = createZodFetcher(); + try { + const res = await fetchWithZod(commonSchemas.response, fetchURL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${ctx.session.user.blueskyAccessToken}`, + }, + body: undefined, + }); + return res; + } catch (e) { + if (e instanceof Error) { + console.error(e); + throw new Error(e.message); + } + throw new Error("Unknown error"); + } + }), +} as const; From 2b1d0487da7342576b0be6f840cebe5e78d865b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Lu=C3=ADs?= Date: Thu, 21 Nov 2024 12:51:07 -0300 Subject: [PATCH 3/4] add history component new history component in tab with queue component, has the history list based on the queue list and a clear button --- .../spu-ui/src/app/_components/experiment.tsx | 40 ++++--- apps/spu-ui/src/app/_components/history.tsx | 112 ++++++++++++++++++ 2 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 apps/spu-ui/src/app/_components/history.tsx diff --git a/apps/spu-ui/src/app/_components/experiment.tsx b/apps/spu-ui/src/app/_components/experiment.tsx index 881c335..d4584a0 100644 --- a/apps/spu-ui/src/app/_components/experiment.tsx +++ b/apps/spu-ui/src/app/_components/experiment.tsx @@ -22,6 +22,7 @@ import { setSamples as setServerSamples, } from "../actions/samples"; import { Console } from "./console"; +import { History } from "./history"; import { Queue } from "./queue"; import { SampleItem } from "./sample"; import { Tray } from "./tray"; @@ -136,7 +137,19 @@ export default function Experiment({ return (
- + + + sample.tray === TRAY1)} + /> + + + sample.tray === TRAY2)} + /> +
Tray 1 @@ -151,21 +164,20 @@ export default function Experiment({ Clear Samples
- - sample.tray === TRAY1)} - /> - - - sample.tray === TRAY2)} - /> -
- + + + + + + + + + Queue + History + +
diff --git a/apps/spu-ui/src/app/_components/history.tsx b/apps/spu-ui/src/app/_components/history.tsx new file mode 100644 index 0000000..592a420 --- /dev/null +++ b/apps/spu-ui/src/app/_components/history.tsx @@ -0,0 +1,112 @@ +"use client"; + +import { Trash2Icon } from "lucide-react"; +import { cn } from "@sophys-web/ui"; +import { Badge } from "@sophys-web/ui/badge"; +import { Button } from "@sophys-web/ui/button"; +import { ScrollArea } from "@sophys-web/ui/scroll-area"; +import { toast } from "@sophys-web/ui/sonner"; +import type { HistoryItemProps } from "../../lib/types"; +import { kwargsResponseSchema } from "../../lib/schemas/acquisition"; +import { api } from "../../trpc/react"; + +function HistoryItem({ props }: { props: HistoryItemProps }) { + const { data: planParams } = kwargsResponseSchema.safeParse(props.kwargs); + const status = function () { + // how can I get the running item? + if (!props.result) { + return "oops"; + } + if (props.result.traceback) { + return "failed"; + } + return "completed"; + }; + + return ( +
  • +
    +
    + {planParams ? `${planParams.col}${planParams.row}` : "N/A"} + + {planParams ? planParams.sampleType.toUpperCase()[0] : "-"} + +
    +
    + {planParams ? ( +
    +

    {planParams.sampleTag}

    +

    + {`${planParams.tray} |`} + {planParams.sampleType !== "buffer" && + ` buffer: ${planParams.bufferTag} |`} + {` user: ${props.user}`} +

    +
    + ) : ( +
    +

    {`${props.name}`}

    +

    + {` user: ${props.user}`} +

    +
    + )} +
    + {status()} +
    +
  • + ); +} + +export function History() { + const utils = api.useUtils(); + const { data } = api.history.get.useQuery(undefined, {}); + const { mutate } = api.history.clear.useMutation({ + onSuccess: async () => { + toast.success("Queue cleared."); + await utils.history.invalidate(); + }, + }); + + return ( +
    +
    +

    Experiment History

    + + +
    +
    + + {data?.items.length === 0 ? ( +

    + History is empty. +

    + ) : ( +
      + {data?.items.map((item) => ( + + ))} +
    + )} +
    +
    +
    + ); +} From 271203f232e137b23eab48ddfde8f0578eaae410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Lu=C3=ADs?= Date: Thu, 21 Nov 2024 13:12:24 -0300 Subject: [PATCH 4/4] refetch history on mount --- apps/spu-ui/src/app/_components/history.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/spu-ui/src/app/_components/history.tsx b/apps/spu-ui/src/app/_components/history.tsx index 592a420..bc85b78 100644 --- a/apps/spu-ui/src/app/_components/history.tsx +++ b/apps/spu-ui/src/app/_components/history.tsx @@ -69,7 +69,9 @@ function HistoryItem({ props }: { props: HistoryItemProps }) { export function History() { const utils = api.useUtils(); - const { data } = api.history.get.useQuery(undefined, {}); + const { data } = api.history.get.useQuery(undefined, { + refetchOnMount: "always", + }); const { mutate } = api.history.clear.useMutation({ onSuccess: async () => { toast.success("Queue cleared."); @@ -83,6 +85,7 @@ export function History() {

    Experiment History