@@ -128,11 +128,13 @@ function Datacenter({ actorId }: { actorId: ActorId }) {
}
if (!datacenter) {
- return
-;
+ return
-;
}
return (
-
{datacenter}
+
+ {datacenter}
+
);
}
diff --git a/frontend/src/components/actors/guard-connectable-inspector.tsx b/frontend/src/components/actors/guard-connectable-inspector.tsx
index 1fa782acd6..e720138d59 100644
--- a/frontend/src/components/actors/guard-connectable-inspector.tsx
+++ b/frontend/src/components/actors/guard-connectable-inspector.tsx
@@ -1,3 +1,4 @@
+/** biome-ignore-all lint/correctness/useHookAtTopLevel: safe guarded by build consts */
import { faPowerOff, faSpinnerThird, Icon } from "@rivet-gg/icons";
import {
useInfiniteQuery,
@@ -5,8 +6,9 @@ import {
useQuery,
useSuspenseQuery,
} from "@tanstack/react-query";
-import { useMatch } from "@tanstack/react-router";
+import { useMatch, useRouteContext } from "@tanstack/react-router";
import { createContext, type ReactNode, useContext, useMemo } from "react";
+import { useLocalStorage } from "usehooks-ts";
import { useInspectorCredentials } from "@/app/credentials-context";
import { createInspectorActorContext } from "@/queries/actor-inspector";
import { DiscreteCopyButton } from "../copy-area";
@@ -32,19 +34,17 @@ export function GuardConnectableInspector({
actorId,
children,
}: GuardConnectableInspectorProps) {
- const filters = useFiltersValue({ includeEphemeral: true });
- const {
- data: { destroyedAt, sleepingAt, pendingAllocationAt, startedAt } = {},
- } = useQuery({
- ...useDataProvider().actorQueryOptions(actorId),
- refetchInterval: 1000,
- select: (data) => ({
- destroyedAt: data.destroyedAt,
- sleepingAt: data.sleepingAt,
- pendingAllocationAt: data.pendingAllocationAt,
- startedAt: data.startedAt,
- }),
- });
+ const { data: { destroyedAt, pendingAllocationAt, startedAt } = {} } =
+ useQuery({
+ ...useDataProvider().actorQueryOptions(actorId),
+ refetchInterval: 1000,
+ select: (data) => ({
+ destroyedAt: data.destroyedAt,
+ sleepingAt: data.sleepingAt,
+ pendingAllocationAt: data.pendingAllocationAt,
+ startedAt: data.startedAt,
+ }),
+ });
if (destroyedAt) {
return (
@@ -56,34 +56,6 @@ export function GuardConnectableInspector({
);
}
- if (sleepingAt) {
- if (filters.wakeOnSelect?.value?.[0] === "1") {
- return (
-
-
-
- }
- >
- {children}
-
- );
- }
- return (
-
- Unavailable for sleeping Actors.
-
-
- }
- >
- {children}
-
- );
- }
-
if (pendingAllocationAt && !startedAt) {
return (
}>
@@ -187,7 +159,6 @@ function useActorRunner({ actorId }: { actorId: ActorId }) {
} = useQuery({
...useEngineCompatDataProvider().runnerByNameQueryOptions({
runnerName: actor.runner,
- namespace: match.params.namespace,
}),
retryDelay: 10_000,
refetchInterval: 1000,
@@ -201,16 +172,36 @@ function useActorRunner({ actorId }: { actorId: ActorId }) {
};
}
+function useEngineToken() {
+ if (__APP_TYPE__ === "cloud") {
+ const { data } = useQuery(
+ useRouteContext({
+ from: "/_context/_cloud/orgs/$organization/projects/$project/ns/$namespace",
+ }).dataProvider.publishableTokenQueryOptions(),
+ );
+ return data;
+ }
+ const [data] = useLocalStorage(
+ ls.engineCredentials.key(getConfig().apiUrl),
+ "",
+ { serializer: JSON.stringify, deserializer: JSON.parse },
+ );
+ return data;
+}
+
function useActorEngineContext({ actorId }: { actorId: ActorId }) {
const { actor, runner, isLoading } = useActorRunner({ actorId });
+ const engineToken = useEngineToken();
const actorContext = useMemo(() => {
- return createInspectorActorContext({
- url: getConfig().apiUrl,
- token: (runner?.metadata?.inspectorToken as string) || "",
- engineToken: ls.engineCredentials.get(getConfig().apiUrl) || "",
- });
- }, [runner?.metadata?.inspectorToken]);
+ return engineToken
+ ? createInspectorActorContext({
+ url: getConfig().apiUrl,
+ token: (runner?.metadata?.inspectorToken as string) || "",
+ engineToken,
+ })
+ : null;
+ }, [runner?.metadata?.inspectorToken, engineToken]);
return { actorContext, actor, runner, isLoading };
}
@@ -240,6 +231,24 @@ function ActorEngineProvider({
);
}
+ if (!actorContext) {
+ return (
+
+ Unable to connect to the Actor's Inspector.
+
+ Check that your application is running and that your
+ network allows connections to the Inspector URL.
+
+
+ }
+ >
+ {children}
+
+ );
+ }
+
return (
{children}
@@ -267,7 +276,8 @@ function NoRunnerInfo({ runner }: { runner: string }) {
}
function WakeUpActorButton({ actorId }: { actorId: ActorId }) {
- const { runner, actorContext } = useActorEngineContext({ actorId });
+ const actorContext = useActor();
+ const { runner } = useActorRunner({ actorId });
const { mutate, isPending } = useMutation(
actorContext.actorWakeUpMutationOptions(actorId),
@@ -287,9 +297,8 @@ function WakeUpActorButton({ actorId }: { actorId: ActorId }) {
}
function AutoWakeUpActor({ actorId }: { actorId: ActorId }) {
- const { runner, actor, actorContext } = useActorEngineContext({
- actorId,
- });
+ const actorContext = useActor();
+ const { actor, runner } = useActorRunner({ actorId });
useQuery(
actorContext.actorAutoWakeUpQueryOptions(actorId, {
@@ -315,12 +324,63 @@ function InspectorGuard({
}: {
actorId: ActorId;
children: ReactNode;
+}) {
+ const filters = useFiltersValue({ includeEphemeral: true });
+
+ const { data: { sleepingAt } = {} } = useQuery({
+ ...useDataProvider().actorQueryOptions(actorId),
+ refetchInterval: 1000,
+ select: (data) => ({
+ destroyedAt: data.destroyedAt,
+ sleepingAt: data.sleepingAt,
+ pendingAllocationAt: data.pendingAllocationAt,
+ startedAt: data.startedAt,
+ }),
+ });
+
+ if (sleepingAt) {
+ if (filters.wakeOnSelect?.value?.[0] === "1") {
+ return (
+
+
+
+ }
+ >
+ {children}
+
+ );
+ }
+ return (
+
+ Unavailable for sleeping Actors.
+
+
+ }
+ >
+ {children}
+
+ );
+ }
+ return (
+ {children}
+ );
+}
+
+function InspectorGuardInner({
+ actorId,
+ children,
+}: {
+ actorId: ActorId;
+ children: ReactNode;
}) {
const { isError } = useQuery({
...useActor().actorPingQueryOptions(actorId),
enabled: true,
});
-
if (isError) {
return (
);
}
+
return children;
}
diff --git a/frontend/src/components/lib/utils.ts b/frontend/src/components/lib/utils.ts
index 0279c02bc8..a56ac55a4e 100644
--- a/frontend/src/components/lib/utils.ts
+++ b/frontend/src/components/lib/utils.ts
@@ -25,6 +25,7 @@ export const ls = {
localStorage.clear();
},
engineCredentials: {
+ key: (url: string) => btoa(`engine-credentials-${JSON.stringify(url)}`),
set: (url: string, token: string) => {
ls.set(
btoa(`engine-credentials-${JSON.stringify(url)}`),
diff --git a/frontend/src/queries/actor-inspector.ts b/frontend/src/queries/actor-inspector.ts
index 6dd8ab9dc4..4b842a4590 100644
--- a/frontend/src/queries/actor-inspector.ts
+++ b/frontend/src/queries/actor-inspector.ts
@@ -13,7 +13,9 @@ export const createInspectorActorContext = ({
token: string;
engineToken?: string;
}) => {
- const def = createDefaultActorContext();
+ const def = createDefaultActorContext({
+ hash: btoa(url + inspectorToken + (engineToken || "")).slice(0, 8),
+ });
const newUrl = new URL(url);
if (!newUrl.pathname.endsWith("inspect")) {
newUrl.pathname = `${ensureTrailingSlash(newUrl.pathname)}inspect`;