Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions .github/workflows/fe-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,13 @@ jobs:
version: latest
- name: Run Biome
run: biome check . --reporter=github
working-directory: ./frontend
tsc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install
working-directory: ./frontend
- uses: pnpm/action-setup@v4
- run: pnpm install
- run: pnpm turbo build:engine
- name: Run TypeScript Compiler
run: pnpm ts-check
working-directory: ./frontend
2 changes: 1 addition & 1 deletion frontend/src/app/billing/plan-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function PlanCard({
<p>Includes:</p>
<ul className="text-muted-foreground mt-2 space-y-1">
{features?.map((feature, index) => (
<li key={feature.label}>
<li key={index}>
<Icon icon={feature.icon} /> {feature.label}
</li>
))}
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/app/data-providers/cloud-data-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Clerk } from "@clerk/clerk-js";
import { type Rivet, RivetClient } from "@rivet-gg/cloud";
import { fetcher } from "@rivetkit/engine-api-full/core";
import { infiniteQueryOptions, queryOptions } from "@tanstack/react-query";
import { infiniteQueryOptions, QueryKey, queryOptions, UseQueryOptions } from "@tanstack/react-query";
import { cloudEnv } from "@/lib/env";
import { queryClient } from "@/queries/global";
import { RECORDS_PER_PAGE } from "./default-data-provider";
Expand All @@ -19,13 +19,17 @@ function createClient({ clerk }: { clerk: Clerk }) {
token: async () => {
return (await clerk.session?.getToken()) || "";
},
// @ts-expect-error
fetcher: async (args) => {
Object.keys(args.headers).forEach((key) => {
Object.keys(args.headers || {}).forEach((key) => {
if (key.toLowerCase().startsWith("x-fern-")) {
delete args.headers[key];
delete args.headers?.[key];
}
});
return await fetcher(args);
return await fetcher(
// @ts-expect-error
args
);
},
});
}
Expand Down Expand Up @@ -207,7 +211,6 @@ export const createOrganizationContext = ({
mutationKey: ["projects"],
mutationFn: async (data: {
displayName: string;
nameId: string;
}) => {
const response = await client.projects.create({
displayName: data.displayName,
Expand Down Expand Up @@ -350,7 +353,6 @@ export const createNamespaceContext = ({
...createEngineNamespaceContext({
...parent,
namespace: engineNamespaceName,
namespaceId: engineNamespaceId,
engineToken: token,
client: createEngineClient(cloudEnv().VITE_APP_API_URL, {
token,
Expand Down
46 changes: 35 additions & 11 deletions frontend/src/app/data-providers/engine-data-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { type Rivet, RivetClient } from "@rivetkit/engine-api-full";
import { type FetchFunction, fetcher } from "@rivetkit/engine-api-full/core";
import { fetcher } from "@rivetkit/engine-api-full/core";
import {
infiniteQueryOptions,
mutationOptions,
QueryKey,
QueryOptions,
queryOptions,
UseQueryOptions,
} from "@tanstack/react-query";
Expand All @@ -17,15 +16,14 @@ import {
} from "@/components/actors";
import { engineEnv } from "@/lib/env";
import { convertStringToId } from "@/lib/utils";
import { queryClient } from "@/queries/global";
import { noThrow, shouldRetryAllExpect403 } from "@/queries/utils";
import {
ActorQueryOptions,
ActorQueryOptionsSchema,
createDefaultGlobalContext,
type DefaultDataProvider,
RECORDS_PER_PAGE,
} from "./default-data-provider";
import z from "zod";

const mightRequireAuth = __APP_TYPE__ === "engine";

Expand Down Expand Up @@ -133,6 +131,7 @@ export const createGlobalContext = (opts: {
export const createNamespaceContext = ({
namespace,
client,
...parent
}: { namespace: string; } & ReturnType<
typeof createGlobalContext
>) => {
Expand Down Expand Up @@ -407,7 +406,7 @@ export const createNamespaceContext = ({
enabled: !!opts.runnerUrl,
queryFn: async ({ signal: abortSignal }) => {
const res =
await client.runnerConfigs.serverlessHealthCheck(
await client.runnerConfigsServerlessHealthCheck(
{
url: opts.runnerUrl,
headers: opts.headers,
Expand Down Expand Up @@ -553,7 +552,7 @@ export const createNamespaceContext = ({
name: string;
config: Record<string, Rivet.RunnerConfig>;
}) => {
const response = await client.runnerConfigs.upsert(name, {
const response = await client.runnerConfigsUpsert(name, {
namespace,
datacenters: config,
});
Expand All @@ -572,7 +571,7 @@ export const createNamespaceContext = ({
...opts,
mutationKey: ["runner-config", "delete"] as QueryKey,
mutationFn: async (name: string) => {
await client.runnerConfigs.delete(name, { namespace });
await client.runnerConfigsDelete(name, { namespace });
},
retry: shouldRetryAllExpect403,
meta: {
Expand All @@ -587,7 +586,7 @@ export const createNamespaceContext = ({
queryKey: [{ namespace }, "runners", "configs", opts] as QueryKey,
initialPageParam: undefined as string | undefined,
queryFn: async ({ signal: abortSignal, pageParam }) => {
const response = await client.runnerConfigs.list(
const response = await client.runnerConfigsList(
{
namespace,
cursor: pageParam ?? undefined,
Expand Down Expand Up @@ -630,7 +629,7 @@ export const createNamespaceContext = ({
queryKey: [{ namespace }, "runners", "config", opts] as QueryKey,
enabled: !!opts.name,
queryFn: async ({ signal: abortSignal }) => {
const response = await client.runnerConfigs.list(
const response = await client.runnerConfigsList(
{
namespace,
runnerNames: opts.name,
Expand All @@ -653,13 +652,13 @@ export const createNamespaceContext = ({
},
});
},
engineAdminTokenQueryOptions(): UseQueryOptions<string> {
engineAdminTokenQueryOptions() {
return queryOptions({
staleTime: 1000,
gcTime: 1000,
queryKey: [{ namespace }, "tokens", "engine-admin"] as QueryKey,
queryFn: async () => {
return ls.engineCredentials.get(getConfig().apiUrl) || "";
return (ls.engineCredentials.get(getConfig().apiUrl) || "") as string;
},
meta: {
mightRequireAuth,
Expand Down Expand Up @@ -699,3 +698,28 @@ function transformActor(a: Rivet.Actor): Actor {
],
};
}

type RunnerConfig = [
string,
{
datacenters: Record<string, { metadata?: { provider?: string } }>;
},
];

export function hasMetadataProvider(metadata: unknown): metadata is { provider?: string } {
return z.object({ provider: z.string().optional() }).safeParse(metadata).success;
}

export function hasProvider(
configs: [string, Rivet.RunnerConfigsListResponseRunnerConfigsValue][] | undefined,
providers: string[],
): boolean {
if (!configs) return false;
return configs.some(([, config]) =>
Object.values(config.datacenters).some(
(datacenter) =>
datacenter.metadata && hasMetadataProvider(datacenter.metadata) && datacenter.metadata.provider &&
providers.includes(datacenter.metadata.provider),
),
);
}
4 changes: 3 additions & 1 deletion frontend/src/app/dialogs/connect-manual-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default function CreateProjectFrameContent({
type="single"
className="border rounded-md gap-0"
value={mode}
onValueChange={setMode}
onValueChange={(mode) => {
setMode(mode === "serverfull" ? "serverless" : "serverfull");
}}
>
<ToggleGroupItem
value="serverless"
Expand Down
12 changes: 4 additions & 8 deletions frontend/src/app/dialogs/connect-vercel-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
Frame,
getConfig,
} from "@/components";
import { type Region, useEngineCompatDataProvider } from "@/components/actors";
import { type Region, useCloudNamespaceDataProvider, useEngineCompatDataProvider, useEngineNamespaceDataProvider } from "@/components/actors";
import { cloudEnv } from "@/lib/env";
import { queryClient } from "@/queries/global";
import { type JoinStepSchemas, StepperForm } from "../forms/stepper-form";
Expand All @@ -36,17 +36,13 @@ interface CreateProjectFrameContentProps extends DialogContentProps { }
function usePublishableToken() {
return match(__APP_TYPE__)
.with("cloud", () => {
const routeContext = useRouteContext({
from: "/_context/_cloud/orgs/$organization/projects/$project/ns/$namespace/connect",
select: (ctx) => ctx.dataProvider,
});
return useSuspenseQuery(
routeContext.publishableTokenQueryOptions(),
useCloudNamespaceDataProvider().publishableTokenQueryOptions(),
).data;
})
.with("engine", () => {
return useSuspenseQuery(
useEngineCompatDataProvider().engineAdminTokenQueryOptions(),
useEngineNamespaceDataProvider().engineAdminTokenQueryOptions(),
).data;
})
.otherwise(() => {
Expand Down Expand Up @@ -225,7 +221,7 @@ function FormStepper({
// }

function StepApiRoute() {
const plan = useWatch<FormValues>({ name: "plan" as const });
const plan = useWatch({ name: "plan" });
return <ConnectVercelForm.IntegrationCode plan={plan || "hobby"} />;
}

Expand Down
1 change: 0 additions & 1 deletion frontend/src/app/dialogs/create-namespace-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export default function CreateNamespacesFrameContent() {
onSubmit={async (values) => {
await mutateAsync({
displayName: values.name,
name: values.slug || convertStringToId(values.name),
});
}}
defaultValues={{ name: "", slug: "" }}
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/app/forms/edit-runner-config-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const formSchema = z.object({
requestLifespan: z.coerce.number().positive(),
runnersMargin: z.coerce.number().min(0),
slotsPerRunner: z.coerce.number().positive(),
headers: z.array(z.string()).default([]),
headers: z.array(z.array(z.string())).default([]),
});

export type FormValues = z.infer<typeof formSchema>;
Expand Down Expand Up @@ -179,8 +179,8 @@ export const SlotsPerRunner = ({ className }: { className?: string }) => {
};

export const Headers = function Headers() {
const { control, setValue } = useFormContext();
const { fields, append, remove } = useFieldArray<FormValues>({
const { control, setValue, watch } = useFormContext();
const { fields, append, remove } = useFieldArray({
name: "headers",
control,
});
Expand Down Expand Up @@ -226,7 +226,7 @@ col-span-full flex-1"
<Input
placeholder="Enter a value"
className="w-full"
value={field[0]}
value={watch(`headers.${index}.0`)}
onChange={(e) => {
setValue(
`headers.${index}.0`,
Expand Down Expand Up @@ -258,7 +258,7 @@ col-span-full flex-1"
<Input
placeholder="Enter a value"
className="w-full"
value={field[1]}
value={watch(`headers.${index}.1`)}
onChange={(e) => {
setValue(
`headers.${index}.1`,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const Sidebar = ({
ref,
...props
}: {
ref?: RefObject<ImperativePanelHandle>;
ref?: RefObject<ImperativePanelHandle | null>;
} & ComponentProps<typeof ResizablePanel>) => {
const sidebarMinWidth = useContext(SidebarDimensionsContext);
return (
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/app/runner-config-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from "@/components";
import { ActorRegion } from "@/components/actors";
import { REGION_LABEL } from "@/components/matchmaker/lobby-region";
import { hasMetadataProvider } from "./data-providers/engine-data-provider";

interface RunnerConfigsTableProps {
isLoading?: boolean;
Expand Down Expand Up @@ -142,7 +143,7 @@ function Row({
<WithTooltip
content={config.serverless?.url || "-"}
trigger={
<DiscreteCopyButton value={config.serverless?.url}>
<DiscreteCopyButton value={config.serverless?.url || ""}>
<span>
{config.serverless?.url &&
config.serverless.url.length > 32
Expand All @@ -159,7 +160,7 @@ function Row({

<TableCell>
<div className="flex gap-2 justify-end">
{config.serverless ? (
{config.serverless && hasMetadataProvider(config.metadata) ? (
<WithTooltip
content="Edit provider settings"
trigger={
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/actors/actor-events-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ function EventContainer({
ref,
children,
}: {
ref: React.RefObject<HTMLDivElement>;
ref: React.RefObject<HTMLDivElement | null>;
children: React.ReactNode;
}) {
return (
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/actors/actor-events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,14 @@ ActorEvents.Skeleton = () => {
};

function useScrollToBottom(
ref: React.RefObject<HTMLDivElement>,
ref: React.RefObject<HTMLDivElement | null>,
deps: unknown[],
) {
const [settings] = useActorDetailsSettings();
const follow = useRef(true);
const shouldFollow = () => settings.autoFollowLogs && follow.current;
useResizeObserver({
// @ts-expect-error -- TS2322 -- Type 'HTMLDivElement' is not assignable to type 'Element | null'.
ref,
onResize: () => {
if (shouldFollow()) {
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/actors/actor-region.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
import { Flex, WithTooltip } from "@/components";
import {
getRegionKey,
getRegionLabel,
REGION_LABEL,
RegionIcon,
} from "../matchmaker/lobby-region";
Expand Down Expand Up @@ -34,16 +35,16 @@ export function ActorRegion({
<RegionIcon region={regionKey} className="w-4 min-w-4" />
<span data-slot="label">
{showLabel === "abbreviated"
? regionKey.toUpperCase()
: (REGION_LABEL[regionKey] ?? REGION_LABEL.unknown)}
? regionKey?.toUpperCase()
: getRegionLabel(regionKey)}
</span>
</Flex>
);
}

return (
<WithTooltip
content={REGION_LABEL[regionKey] ?? REGION_LABEL.unknown}
content={getRegionLabel(regionKey)}
trigger={
<Flex
gap="2"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/actors/actors-layout-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { assertNonNullable } from "../lib/utils";
import type { ImperativePanelHandle } from "../ui/resizable";

export interface ActorsLayoutContextValue {
detailsRef: RefObject<ImperativePanelHandle>;
detailsRef: RefObject<ImperativePanelHandle | null>;
isDetailsColCollapsed: boolean;
}

Expand Down
Loading
Loading