Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { Dispatch, SetStateAction } from "react";
import { EnvironmentId } from "@t3tools/contracts";
import { beforeEach, describe, expect, it, vi } from "vite-plus/test";

const settingsHooks = vi.hoisted(() => ({
read: vi.fn(() => ({ providerInstances: {} })),
update: vi.fn(() => vi.fn()),
}));

const hooks = vi.hoisted(() => {
let cursor = 0;
let slots: unknown[] = [];
const nextIndex = () => cursor++;

return {
beginRender() {
cursor = 0;
},
reset() {
cursor = 0;
slots = [];
},
useMemo<T>(factory: () => T): T {
nextIndex();
return factory();
},
useMemoCache(size: number): unknown[] {
const index = nextIndex();
if (!slots[index]) {
slots[index] = Array.from({ length: size }, () => Symbol.for("react.memo_cache_sentinel"));
}
return slots[index] as unknown[];
},
useState<T>(initialValue: T | (() => T)): [T, Dispatch<SetStateAction<T>>] {
const index = nextIndex();
if (index >= slots.length) {
slots[index] =
typeof initialValue === "function" ? (initialValue as () => T)() : initialValue;
}
const setValue: Dispatch<SetStateAction<T>> = (nextValue) => {
const previous = slots[index] as T;
slots[index] =
typeof nextValue === "function" ? (nextValue as (value: T) => T)(previous) : nextValue;
};
return [slots[index] as T, setValue];
},
};
});

vi.mock("react", async (importOriginal) => {
const actual = await importOriginal<typeof import("react")>();
return {
...actual,
useMemo: hooks.useMemo,
useState: hooks.useState,
};
});

vi.mock("react/compiler-runtime", () => ({
c: hooks.useMemoCache,
}));

vi.mock("../../hooks/useSettings", () => ({
useEnvironmentSettings: settingsHooks.read,
useUpdateEnvironmentSettings: settingsHooks.update,
}));

import { AddProviderInstanceDialog } from "./AddProviderInstanceDialog";

const remoteEnvironmentId = EnvironmentId.make("remote-device");

describe("AddProviderInstanceDialog environment routing", () => {
beforeEach(() => {
hooks.reset();
settingsHooks.read.mockClear();
settingsHooks.update.mockClear();
});

it("reads and writes settings through the supplied environment", () => {
hooks.beginRender();
AddProviderInstanceDialog({
open: true,
environmentId: remoteEnvironmentId,
environmentLabel: "Remote device",
onOpenChange: vi.fn(),
});

expect(settingsHooks.read).toHaveBeenCalledWith(remoteEnvironmentId);
expect(settingsHooks.update).toHaveBeenCalledWith(remoteEnvironmentId);
});
});
24 changes: 16 additions & 8 deletions apps/web/src/components/settings/AddProviderInstanceDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { useMemo, useState } from "react";
import {
ProviderInstanceId,
ProviderDriverKind,
type EnvironmentId,
type ProviderInstanceConfig,
} from "@t3tools/contracts";

import { usePrimarySettings, useUpdatePrimarySettings } from "../../hooks/useSettings";
import { useEnvironmentSettings, useUpdateEnvironmentSettings } from "../../hooks/useSettings";
import { cn } from "../../lib/utils";
import { normalizeProviderAccentColor } from "../../providerInstances";
import { Button } from "../ui/button";
Expand Down Expand Up @@ -115,13 +116,20 @@ function validateInstanceId(id: string, existing: ReadonlySet<string>): string |
}

interface AddProviderInstanceDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
readonly open: boolean;
readonly environmentId: EnvironmentId;
readonly environmentLabel: string;
readonly onOpenChange: (open: boolean) => void;
}

export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderInstanceDialogProps) {
const settings = usePrimarySettings();
const updateSettings = useUpdatePrimarySettings();
export function AddProviderInstanceDialog({
open,
environmentId,
environmentLabel,
onOpenChange,
}: AddProviderInstanceDialogProps) {
const settings = useEnvironmentSettings(environmentId);
const updateSettings = useUpdateEnvironmentSettings(environmentId);

const [wizardStep, setWizardStep] = useState(0);
const [driver, setDriver] = useState<ProviderDriverKind>(DEFAULT_DRIVER_KIND);
Expand Down Expand Up @@ -227,8 +235,8 @@ export function AddProviderInstanceDialog({ open, onOpenChange }: AddProviderIns
<DialogHeader>
<DialogTitle>Add provider instance</DialogTitle>
<DialogDescription>
Configure an additional provider instance — for example, a second Codex install
pointed at a different workspace.
Configure an additional provider instance on {environmentLabel} — for example, a
second Codex install pointed at a different workspace.
</DialogDescription>
<AddProviderInstanceWizardSteps
currentStep={wizardStep}
Expand Down
Loading
Loading