Skip to content

Commit 3b32f9e

Browse files
committed
feat(studio): studio v2, inspector v3
1 parent a220919 commit 3b32f9e

40 files changed

+1830
-1140
lines changed

frontend/apps/hub/src/domains/project/components/actors/actors-provider.tsx

Lines changed: 368 additions & 385 deletions
Large diffs are not rendered by default.

frontend/apps/studio/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"@rivet-gg/icons": "workspace:*",
2121
"@sentry/react": "^8.26.0",
2222
"@sentry/vite-plugin": "^2.22.2",
23+
"@tanstack/react-query": "^5.81.5",
24+
"@tanstack/react-query-devtools": "^5.81.5",
2325
"@tanstack/react-router": "^1.114.25",
2426
"@tanstack/react-table": "^8.20.6",
2527
"@tanstack/router-devtools": "^1.114.25",

frontend/apps/studio/public/logo.svg

Lines changed: 10 additions & 2 deletions
Loading

frontend/apps/studio/src/app.tsx

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ import * as Sentry from "@sentry/react";
1111
import { RouterProvider, createRouter } from "@tanstack/react-router";
1212
import { Suspense } from "react";
1313
import { routeTree } from "./routeTree.gen";
14-
import { withAtomEffect } from "jotai-effect";
15-
import {
16-
actorFiltersAtom,
17-
currentActorIdAtom,
18-
pickActorListFilters,
19-
} from "@rivet-gg/components/actors";
20-
import { useAtom } from "jotai";
14+
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
15+
import { QueryClientProvider } from "@tanstack/react-query";
16+
import { queryClient } from "./queries/global";
2117

2218
declare module "@tanstack/react-router" {
2319
interface Register {
@@ -36,42 +32,26 @@ export const router = createRouter({
3632
},
3733
});
3834

39-
const effect = withAtomEffect(actorFiltersAtom, (get, set) => {
40-
// set initial values
41-
const search = router.state.location.search;
42-
43-
const filters = pickActorListFilters(search);
44-
45-
set(actorFiltersAtom, filters);
46-
set(currentActorIdAtom, router.state.location.search.actorId);
47-
});
48-
49-
const effect2 = withAtomEffect(actorFiltersAtom, (get, set) => {
50-
return router.subscribe("onResolved", (event) => {
51-
set(actorFiltersAtom, pickActorListFilters(event.toLocation.search));
52-
set(currentActorIdAtom, event.toLocation.search.actorId);
53-
});
54-
});
55-
5635
function InnerApp() {
57-
useAtom(effect);
58-
useAtom(effect2);
59-
6036
return <RouterProvider router={router} />;
6137
}
6238

6339
export function App() {
6440
return (
65-
<ConfigProvider value={getConfig()}>
66-
<ThirdPartyProviders>
67-
<Suspense fallback={<FullscreenLoading />}>
68-
<TooltipProvider>
69-
<InnerApp />
70-
</TooltipProvider>
71-
</Suspense>
72-
</ThirdPartyProviders>
73-
74-
<Toaster />
75-
</ConfigProvider>
41+
<QueryClientProvider client={queryClient}>
42+
<ConfigProvider value={getConfig()}>
43+
<ThirdPartyProviders>
44+
<Suspense fallback={<FullscreenLoading />}>
45+
<TooltipProvider>
46+
<InnerApp />
47+
</TooltipProvider>
48+
</Suspense>
49+
</ThirdPartyProviders>
50+
51+
<Toaster />
52+
</ConfigProvider>
53+
54+
<ReactQueryDevtools client={queryClient} />
55+
</QueryClientProvider>
7656
);
7757
}

frontend/apps/studio/src/components/actors.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ import {
33
ActorsActorDetails,
44
ActorsActorEmptyDetails,
55
ActorsListPreview,
6-
currentActorAtom,
76
} from "@rivet-gg/components/actors";
87
import { useNavigate, useSearch } from "@tanstack/react-router";
9-
import { useAtomValue } from "jotai";
108

119
export function Actors({ actorId }: { actorId: string | undefined }) {
1210
return (
@@ -27,16 +25,15 @@ export function Actors({ actorId }: { actorId: string | undefined }) {
2725
}
2826

2927
function Actor() {
30-
const actor = useAtomValue(currentActorAtom);
3128
const navigate = useNavigate();
32-
const { tab } = useSearch({ from: "/_layout/" });
29+
const { tab, actorId } = useSearch({ from: "/_layout/" });
3330

34-
if (!actor) {
31+
if (!actorId) {
3532
return null;
3633
}
3734
return (
3835
<ActorsActorDetails
39-
actor={actor}
36+
actorId={actorId}
4037
tab={tab}
4138
onTabChange={(tab) => {
4239
navigate({

frontend/apps/studio/src/components/layout.tsx

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { connectionStateAtom } from "@/stores/manager";
2-
import { cn, DocsSheet, ShimmerLine } from "@rivet-gg/components";
1+
import { cn, DocsSheet } from "@rivet-gg/components";
2+
import { useManagerInspector } from "@rivet-gg/components/actors";
33
import { Header as RivetHeader, NavItem } from "@rivet-gg/components/header";
4-
import { faGithub, Icon } from "@rivet-gg/icons";
4+
import {
5+
faCheck,
6+
faGithub,
7+
faSpinnerThird,
8+
faTriangleExclamation,
9+
Icon,
10+
} from "@rivet-gg/icons";
511
import { Link } from "@tanstack/react-router";
6-
import { useAtomValue } from "jotai";
712
import type { PropsWithChildren, ReactNode } from "react";
813

914
interface RootProps {
@@ -30,15 +35,58 @@ const VisibleInFull = ({ children }: PropsWithChildren) => {
3035
);
3136
};
3237

38+
function ConnectionStatus() {
39+
const ws = useManagerInspector();
40+
41+
if (ws.isConnecting) {
42+
return (
43+
<p className="animate-in fade-in">
44+
Connecting to{" "}
45+
<span className="underline underline-offset-2">
46+
localhost:6420
47+
</span>
48+
<Icon icon={faSpinnerThird} className="animate-spin ml-2" />
49+
</p>
50+
);
51+
}
52+
53+
if (ws.isDisconnected) {
54+
return (
55+
<p className="text-red-500 animate-shake">
56+
Couldn't connect to{" "}
57+
<span className="underline underline-offset-2">
58+
localhost:6420
59+
</span>
60+
<Icon icon={faTriangleExclamation} className="ml-2" />
61+
</p>
62+
);
63+
}
64+
65+
if (ws.isConnected) {
66+
return (
67+
<p className="text-primary animate-in fade-in">
68+
Connected to{" "}
69+
<span className="underline underline-offset-2">
70+
localhost:6420
71+
</span>
72+
<Icon icon={faCheck} className="ml-2" />
73+
</p>
74+
);
75+
}
76+
}
77+
3378
const Header = () => {
34-
const connectionStatus = useAtomValue(connectionStateAtom);
3579
return (
3680
<RivetHeader
37-
logo={<img src="/logo.svg" alt="Rivet.gg" className="h-6" />}
38-
addons={
39-
connectionStatus !== "connected" ? (
40-
<ShimmerLine className="-bottom-1" />
41-
) : null
81+
className="bg-stripes"
82+
logo={
83+
<>
84+
<img src="/logo.svg" alt="Rivet.gg" className="h-6" />{" "}
85+
Studio
86+
<div className="text-xs font-mono text-muted-foreground">
87+
<ConnectionStatus />
88+
</div>
89+
</>
4290
}
4391
links={
4492
<>

frontend/apps/studio/src/index.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@
3030
@apply ml-[-50px] mt-[-4px];
3131
content: counter(step);
3232
}
33+
34+
.bg-stripes {
35+
background: repeating-linear-gradient(
36+
45deg,
37+
/* biome-ignore lint/correctness/noUnknownFunction: tailwind functions */
38+
theme("colors.primary.DEFAULT" / 8%),
39+
/* biome-ignore lint/correctness/noUnknownFunction: tailwind functions */
40+
theme("colors.primary.DEFAULT" / 5%) 20px,
41+
transparent 20px,
42+
transparent 40px
43+
);
44+
}
3345
}
3446

3547
:root {

frontend/apps/studio/src/queries/global.ts

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { getConfig, timing, toast } from "@rivet-gg/components";
2-
import { broadcastQueryClient } from "@tanstack/query-broadcast-client-experimental";
3-
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
1+
import { toast } from "@rivet-gg/components";
2+
import { MutationCache, QueryCache, QueryClient } from "@tanstack/react-query";
43
import {
5-
MutationCache,
6-
MutationObserver,
7-
QueryCache,
8-
QueryClient,
9-
} from "@tanstack/react-query";
10-
import superjson from "superjson";
4+
actorsQueryOptions,
5+
actorQueryOptions,
6+
type Actor,
7+
ActorFeature,
8+
actorLogsQueryOptions,
9+
regionsQueryOptions,
10+
} from "@rivet-gg/components/actors";
1111

1212
const queryCache = new QueryCache();
1313

@@ -36,13 +36,81 @@ export const queryClient = new QueryClient({
3636
mutationCache,
3737
});
3838

39-
export const queryClientPersister = createSyncStoragePersister({
40-
storage: window.localStorage,
41-
serialize: superjson.stringify,
42-
deserialize: superjson.parse,
39+
const actors = [
40+
{
41+
id: "actor-1",
42+
name: "Actor 1",
43+
key: ["string", "string"],
44+
region: "local",
45+
createdAt: new Date().toISOString(),
46+
features: [ActorFeature.Logs, ActorFeature.Config],
47+
},
48+
{
49+
id: "actor-2",
50+
name: "Actor 2",
51+
key: ["string", "string"],
52+
region: "remote",
53+
createdAt: new Date().toISOString(),
54+
},
55+
{
56+
id: "actor-3",
57+
name: "Actor 3",
58+
key: ["string", "string"],
59+
region: "remote",
60+
createdAt: new Date().toISOString(),
61+
},
62+
];
63+
64+
queryClient.setQueryDefaults(actorsQueryOptions().queryKey, {
65+
queryFn: () => {
66+
return actors;
67+
},
68+
// @ts-expect-error
69+
getNextPageParam: (lastPage) => {
70+
return undefined;
71+
},
4372
});
4473

45-
broadcastQueryClient({
46-
queryClient,
47-
broadcastChannel: "rivet-gg-hub",
74+
queryClient.setQueryDefaults(actorQueryOptions("actor-1").queryKey, {
75+
queryFn: () => {
76+
return actors[0];
77+
},
78+
});
79+
80+
queryClient.setQueryDefaults(actorLogsQueryOptions("actor-1").queryKey, {
81+
queryFn: () => {
82+
return [
83+
{
84+
id: "log-1",
85+
message: "Log message 1",
86+
level: "info",
87+
timestamp: new Date().toISOString(),
88+
},
89+
{
90+
id: "log-2",
91+
message: "Log message 2",
92+
level: "error",
93+
timestamp: new Date().toISOString(),
94+
},
95+
];
96+
},
97+
});
98+
99+
queryClient.setQueryDefaults(regionsQueryOptions().queryKey, {
100+
queryFn: () => {
101+
return [
102+
{
103+
id: "local",
104+
name: "Local",
105+
},
106+
];
107+
},
108+
});
109+
queryClient.setQueryData(regionsQueryOptions().queryKey, () => {
110+
return [
111+
{
112+
id: "local",
113+
name: "Local",
114+
},
115+
];
48116
});

frontend/apps/studio/src/routes/__root.tsx

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
55
import { zodValidator } from "@tanstack/zod-adapter";
66
import { usePostHog } from "posthog-js/react";
77
import { z } from "zod";
8-
import * as Layout from "@/components/layout";
98
import { Suspense } from "react";
109
import { useDialog } from "@rivet-gg/components/actors";
1110

@@ -91,26 +90,10 @@ function Modals() {
9190
// </PageLayout.Root>
9291
// );
9392
// }
94-
95-
function Root() {
96-
return (
97-
<Layout.Root>
98-
<Layout.VisibleInFull>
99-
<Layout.Header />
100-
<Layout.Main>
101-
{/* <Modals /> */}
102-
<Outlet />
103-
</Layout.Main>
104-
</Layout.VisibleInFull>
105-
<Layout.Footer />
106-
</Layout.Root>
107-
);
108-
}
109-
11093
function RootRoute() {
11194
return (
11295
<>
113-
<Root />
96+
<Outlet />
11497
<Suspense>
11598
<Modals />
11699
</Suspense>

0 commit comments

Comments
 (0)