mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
Opens .ipynb files in a native notebook editor, in a project or LightEdit. - crates/ide-notebook: lossless nbformat documents (unchanged notebooks save byte-for-byte, unknown fields kept, external changes detected) and owned local kernels over ZMQ via kernelspec — the selected Python environment only needs ipykernel, no Jupyter server. - ide-host owns notebook documents per project incarnation and admits one execution batch at a time; outputs stream over IPC channels and kernel status is an IdeEvent. - src/features/notebook: virtualized Python/Markdown cells, insert/delete/move/change type, Run Cell / Run All (Shift+Enter), interrupt, restart, interpreter selection from ide-sdk discovery, shared split views. Raw/unknown cells stay read-only. - Custom editor kinds take part in dirty state, save/save all, undo/redo and Save/Don't Save/Cancel; closing editors from other features awaits that decision. - Outputs: text, tracebacks, PNG/JPEG and sanitized SVG inline; HTML sanitized in a sandboxed iframe without allow-same-origin; JavaScript output is shown as inert source. - Explicit launches (opening a notebook from the OS) win over session restoration. Closes #131 Co-authored-by: dvictor357 <[email protected]>
71 lines
2.4 KiB
TypeScript
71 lines
2.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const openProject = vi.fn();
|
|
|
|
vi.mock("@/platform/ipc", async (orig) => {
|
|
const real = await orig<typeof import("@/platform/ipc")>();
|
|
return {
|
|
...real,
|
|
isTauri: () => true,
|
|
commands: { ...real.commands, settingsGet: async () => ({ general: { reopenLastProject: true } }) },
|
|
};
|
|
});
|
|
vi.mock("@tauri-apps/api/window", () => ({ getCurrentWindow: () => ({ label: "main" }) }));
|
|
vi.mock("@/platform/project", async (orig) => {
|
|
const real = await orig<typeof import("@/platform/project")>();
|
|
return { ...real, openProject: (p: string) => openProject(p) };
|
|
});
|
|
|
|
const { reopenLastProject, _resetSessionForTests } = await import("./session");
|
|
const { provideStartupLaunch, useProject } = await import("@/platform/project");
|
|
|
|
beforeEach(() => {
|
|
openProject.mockReset();
|
|
useProject.setState({ project: null, lightEdit: false });
|
|
sessionStorage.clear();
|
|
localStorage.setItem("openidea.session.openProject", "/p/last");
|
|
_resetSessionForTests();
|
|
});
|
|
|
|
describe("reopenLastProject", () => {
|
|
it("waits for the command-line project instead of opening the last one too", async () => {
|
|
let finishLaunch!: () => void;
|
|
provideStartupLaunch(
|
|
new Promise<void>((resolve) => {
|
|
finishLaunch = () => {
|
|
useProject.setState({ project: { root: "/p/launch" } as never });
|
|
resolve();
|
|
};
|
|
}),
|
|
);
|
|
const reopened = reopenLastProject();
|
|
await new Promise((r) => setTimeout(r, 0));
|
|
expect(openProject).not.toHaveBeenCalled();
|
|
finishLaunch();
|
|
await reopened;
|
|
expect(openProject).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it.each(["last session", "window session"])(
|
|
"keeps launched loose files instead of restoring the %s project",
|
|
async (remembered) => {
|
|
if (remembered === "window session") sessionStorage.setItem("openidea.window.project", "/p/window");
|
|
provideStartupLaunch(
|
|
Promise.resolve().then(() => {
|
|
useProject.setState({ lightEdit: true });
|
|
}),
|
|
);
|
|
await reopenLastProject();
|
|
expect(openProject).not.toHaveBeenCalled();
|
|
expect(useProject.getState().lightEdit).toBe(true);
|
|
expect(useProject.getState().project).toBeNull();
|
|
},
|
|
);
|
|
|
|
it("reopens the last project when the launch named none", async () => {
|
|
provideStartupLaunch(Promise.resolve());
|
|
await reopenLastProject();
|
|
expect(openProject).toHaveBeenCalledWith("/p/last");
|
|
});
|
|
});
|