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
2 changes: 0 additions & 2 deletions apps/desktop/src/ipc/DesktopIpcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import {
getLocalEnvironmentBootstraps,
getLocalEnvironmentBearerToken,
installRelayTelemetryEnabled,
getHomeEnvironmentId,
getSystemLocale,
getPreferredSystemLanguages,
getWindowFullscreenState,
Expand Down Expand Up @@ -155,7 +154,6 @@ export const installDesktopIpcHandlers = Effect.fn("desktop.ipc.installHandlers"
yield* ipc.handle(pasteAsText);
yield* ipc.handle(revealWindow);
yield* ipc.handle(probeRemoteEditors);
yield* ipc.handle(getHomeEnvironmentId);
yield* ipc.handle(getUpdateState);
yield* ipc.handle(setUpdateChannel);
yield* ipc.handle(downloadUpdate);
Expand Down
1 change: 0 additions & 1 deletion apps/desktop/src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const CLI_COMMAND_UNINSTALL_CHANNEL = "desktop:cli-command-uninstall";
export const GET_APP_BRANDING_CHANNEL = "desktop:get-app-branding";
export const GET_RELAY_TELEMETRY_ENABLED_CHANNEL = "desktop:get-relay-telemetry-enabled";
export const GET_SYSTEM_LOCALE_CHANNEL = "desktop:get-system-locale";
export const GET_HOME_ENVIRONMENT_ID_CHANNEL = "desktop:get-home-environment-id";
export const GET_PREFERRED_SYSTEM_LANGUAGES_CHANNEL = "desktop:get-preferred-system-languages";
export const GET_LOCAL_ENVIRONMENT_BOOTSTRAPS_CHANNEL = "desktop:get-local-environment-bootstraps";
export const GET_LOCAL_ENVIRONMENT_ENABLED_CHANNEL = "desktop:get-local-environment-enabled";
Expand Down
19 changes: 0 additions & 19 deletions apps/desktop/src/ipc/methods/window.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ vi.mock("electron", () => ({
BrowserWindow: { fromWebContents: ownerWindow },
}));

import * as DesktopEnvironment from "../../app/DesktopEnvironment.ts";
import * as DesktopBackendConfiguration from "../../backend/DesktopBackendConfiguration.ts";
import * as DesktopBackendManager from "../../backend/DesktopBackendManager.ts";
import * as DesktopBackendPool from "../../backend/DesktopBackendPool.ts";
Expand All @@ -34,7 +33,6 @@ import {
getLocalEnvironmentBootstraps,
installRelayTelemetryEnabled,
pickProjectFavicon,
getHomeEnvironmentId,
probeRemoteEditors,
readMedia,
} from "./window.ts";
Expand Down Expand Up @@ -388,20 +386,3 @@ it.effect.skipIf(HostProcess.Platform.defaultValue() === "win32")(
assert.include(editors, "webstorm");
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);

it.effect("reads the home's environment id and treats an unwritten home as none", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const stateDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-home-environment-" });
const read = getHomeEnvironmentId.handler(undefined).pipe(
Effect.provideService(DesktopEnvironment.DesktopEnvironment, {
path,
stateDir,
} as DesktopEnvironment.DesktopEnvironment["Service"]),
);
assert.isNull(yield* read);
yield* fs.writeFileString(path.join(stateDir, "environment-id"), "environment-1\n");
assert.equal(yield* read, "environment-1");
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);
16 changes: 0 additions & 16 deletions apps/desktop/src/ipc/methods/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,22 +390,6 @@ export const openSystemSettings = DesktopIpc.makeIpcMethod({
}),
});

export const getHomeEnvironmentId = DesktopIpc.makeIpcMethod({
channel: IpcChannels.GET_HOME_ENVIRONMENT_ID_CHANNEL,
payload: Schema.Undefined,
result: Schema.NullOr(Schema.String),
handler: Effect.fn("desktop.ipc.window.getHomeEnvironmentId")(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
return yield* fileSystem
.readFileString(environment.path.join(environment.stateDir, "environment-id"))
.pipe(
Effect.map((contents) => contents.trim() || null),
Effect.orElseSucceed(() => null),
);
}),
});

export const probeRemoteEditors = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PROBE_REMOTE_EDITORS_CHANNEL,
payload: Schema.Undefined,
Expand Down
2 changes: 0 additions & 2 deletions apps/desktop/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,6 @@ contextBridge.exposeInMainWorld("desktopBridge", {
openSystemSettings: (pane: string) =>
ipcRenderer.invoke(IpcChannels.OPEN_SYSTEM_SETTINGS_CHANNEL, pane),
probeRemoteEditors: () => ipcRenderer.invoke(IpcChannels.PROBE_REMOTE_EDITORS_CHANNEL, undefined),
getHomeEnvironmentId: () =>
ipcRenderer.invoke(IpcChannels.GET_HOME_ENVIRONMENT_ID_CHANNEL, undefined),
pasteAsText: () => ipcRenderer.invoke(IpcChannels.PASTE_AS_TEXT_CHANNEL, undefined),
onMenuAction: (listener) => {
const wrappedListener = (_event: Electron.IpcRendererEvent, action: unknown) => {
Expand Down
44 changes: 40 additions & 4 deletions apps/web/src/components/ChatView.sameHome.browser.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { createMemoryHistory } from "@tanstack/react-router";
import { scopeProjectRef } from "@t3tools/client-runtime/environment";
import { EnvironmentId, ThreadId } from "@t3tools/contracts";
import { AsyncResult } from "effect/reactivity";
import { DEFAULT_CLIENT_SETTINGS } from "@t3tools/contracts/settings";
import type * as Context from "effect/Context";
import { expect, it, vi } from "vite-plus/test";
import { page } from "vite-plus/test/browser";
import { page, userEvent } from "vite-plus/test/browser";

import { AppRoot } from "~/AppRoot";
import "~/index.css";
Expand All @@ -22,7 +23,24 @@ import {
} from "../../test/fakeEnvironment";
import { render } from "../../test/render";

const pickerState = vi.hoisted(() => ({ sameHome: false }));
const pickerState = vi.hoisted(() => ({ sameHome: false, openEditor: vi.fn() }));
vi.mock(import("~/state/server"), async (original) => {
const actual = await original();
const { Atom } = await import("effect/reactivity");
const editors = Atom.make(["vscode"] as const);
return { ...actual, serverAvailableEditorsAtom: () => editors };
});
vi.mock(import("~/state/use-atom-command"), async (original) => {
const actual = await original();
const { shellEnvironment } = await import("~/state/shell");
return {
...actual,
useAtomCommand: ((command, options) => {
const run = actual.useAtomCommand(command, options);
return Object.is(command, shellEnvironment.openInEditor) ? pickerState.openEditor : run;
}) as typeof actual.useAtomCommand,
};
});
vi.mock(import("~/state/environments"), async (original) => {
const actual = await original();
return {
Expand Down Expand Up @@ -63,9 +81,10 @@ vi.mock(import("~/rpc/requestLatencyState"), async (original) => ({
trackRpcRequestSent: () => {},
}));

it("keeps workspace editor controls and its shortcut target for a same-home service with another primary", async () => {
it("opens the selected same-home workspace by shortcut with another primary", async () => {
await page.viewport(1400, 900);
pickerState.sameHome = true;
pickerState.openEditor.mockReset().mockResolvedValue(AsyncResult.success(undefined));
using _reset = {
[Symbol.dispose]() {
pickerState.sameHome = false;
Expand Down Expand Up @@ -93,5 +112,22 @@ it("keeps workspace editor controls and its shortcut target for a same-home serv
const toggle = page.getByRole("button", { name: "Toggle thread details panel", exact: true });
if (toggle.element().getAttribute("aria-pressed") === "false") await toggle.click();
await expect.element(page.getByRole("group", { name: "Open in editor" })).toBeVisible();
expect(document.querySelector("[data-open-favorite-editor]")).not.toBeNull();
await expect
.element(page.getByRole("button", { name: "Open in VS Code", exact: true }))
.toBeEnabled();
await userEvent.keyboard("{Control>}o{/Control}");
await vi.waitFor(() =>
expect(pickerState.openEditor).toHaveBeenCalledExactlyOnceWith({
environmentId: ENVIRONMENT_ID,
input: { cwd: "/workspace/render", editor: "vscode" },
}),
);
await toggle.click();
await expect.element(page.getByRole("group", { name: "Open in editor" })).not.toBeInTheDocument();
await userEvent.keyboard("{Control>}o{/Control}");
await vi.waitFor(() => expect(pickerState.openEditor).toHaveBeenCalledTimes(2));
expect(pickerState.openEditor).toHaveBeenLastCalledWith({
environmentId: ENVIRONMENT_ID,
input: { cwd: "/workspace/render", editor: "vscode" },
});
});
8 changes: 4 additions & 4 deletions apps/web/src/remoteOpen.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function Resolution() {
}

it("marks only matching-home bearer execution and updates provenance when the mode stays local", async () => {
const getHomeEnvironmentId = vi.fn<() => Promise<string | null>>().mockResolvedValue(null);
vi.stubGlobal("desktopBridge", { getHomeEnvironmentId });
const getHostEnvironmentId = vi.fn<() => Promise<string | null>>().mockResolvedValue(null);
vi.stubGlobal("desktopBridge", { getHostEnvironmentId });
using _cleanup = {
[Symbol.dispose]() {
vi.unstubAllGlobals();
Expand All @@ -55,9 +55,9 @@ it("marks only matching-home bearer execution and updates provenance when the mo
</AppAtomRegistryProvider>,
);
await expect.element(screen.getByRole("status")).toHaveTextContent("local-exec/false");
await vi.waitFor(() => expect(getHomeEnvironmentId).toHaveResolvedWith(null));
await vi.waitFor(() => expect(getHostEnvironmentId).toHaveResolvedWith(null));

getHomeEnvironmentId.mockResolvedValue(environmentId);
getHostEnvironmentId.mockResolvedValue(environmentId);
appAtomRegistry.set(state.presentationAtom!, presentation("paired-service"));
await expect.element(screen.getByRole("status")).toHaveTextContent("local-exec/true");

Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/remoteOpen.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,13 @@ it("recognizes a same-home service after a missing ID without reloading the page
using _presentation = vi
.spyOn(environmentPresentations, "presentationAtom")
.mockReturnValue(presentationAtom);
const getHomeEnvironmentId = vi.fn<() => Promise<string | null>>().mockResolvedValue(null);
vi.stubGlobal("window", { desktopBridge: { getHomeEnvironmentId } });
const getHostEnvironmentId = vi.fn<() => Promise<string | null>>().mockResolvedValue(null);
vi.stubGlobal("window", { desktopBridge: { getHostEnvironmentId } });
try {
expect(readDesktopHomeEnvironmentId(environmentId)).toBeNull();
await vi.waitFor(() => expect(getHomeEnvironmentId).toHaveResolvedWith(null));
await vi.waitFor(() => expect(getHostEnvironmentId).toHaveResolvedWith(null));

getHomeEnvironmentId.mockResolvedValue(environmentId);
getHostEnvironmentId.mockResolvedValue(environmentId);
appAtomRegistry.set(presentationAtom, {
...presentation,
connection: { phase: "connected", error: null, traceId: null },
Expand All @@ -257,10 +257,10 @@ it("recognizes a same-home service after a missing ID without reloading the page
expect(readDesktopHomeEnvironmentId(environmentId)).toBe(environmentId);
});

const callsAfterConnecting = getHomeEnvironmentId.mock.calls.length;
const callsAfterConnecting = getHostEnvironmentId.mock.calls.length;
appAtomRegistry.set(presentationAtom, { ...presentation, serverConfig: null });
expect(readDesktopHomeEnvironmentId(environmentId)).toBe(environmentId);
expect(getHomeEnvironmentId).toHaveBeenCalledTimes(callsAfterConnecting);
expect(getHostEnvironmentId).toHaveBeenCalledTimes(callsAfterConnecting);

appAtomRegistry.set(presentationAtom, {
...presentation,
Expand All @@ -270,7 +270,7 @@ it("recognizes a same-home service after a missing ID without reloading the page
},
});
expect(readDesktopHomeEnvironmentId(environmentId)).toBeNull();
expect(getHomeEnvironmentId).toHaveBeenCalledTimes(callsAfterConnecting);
expect(getHostEnvironmentId).toHaveBeenCalledTimes(callsAfterConnecting);
} finally {
appAtomRegistry.dispose();
vi.unstubAllGlobals();
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/remoteOpen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const desktopHomeEnvironmentIdAtom = Atom.family((environmentId: EnvironmentId)
get.addFinalizer(() => {
active = false;
});
const read = window.desktopBridge?.getHomeEnvironmentId;
const read = window.desktopBridge?.getHostEnvironmentId;
read?.().then(
(id) => {
if (active && id !== null) get.setSelf(id);
Expand Down
2 changes: 0 additions & 2 deletions packages/contracts/src/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1120,8 +1120,6 @@ export interface DesktopBridge {
openSystemSettings: (pane: SystemSettingsPane) => Promise<boolean>;
checkSystemPermission: (pane: SystemSettingsPane) => Promise<boolean>;
probeRemoteEditors: () => Promise<readonly EditorId[]>;
/** The environment id stored in this desktop's T3 home; null before any server has written it. */
getHomeEnvironmentId: () => Promise<string | null>;
pasteAsText: () => Promise<void>;
onMenuAction: (listener: (action: string) => void) => () => void;
onSnapShotEvent: (listener: (event: DesktopSnapShotEvent) => void) => () => void;
Expand Down
Loading