Merge pull request #124 from WhiskyChoy/codex/windows-recent-project-scope

fix: re-authorize recent project directories before opening
This commit is contained in:
Hanjin Bae 2026-04-07 20:34:38 +09:00 committed by GitHub
commit d9cf9d461e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 54 additions and 1 deletions

View file

@ -7,6 +7,7 @@ mod uv;
mod zotero; mod zotero;
use std::path::Path; use std::path::Path;
use tauri_plugin_fs::FsExt;
use tauri::{Emitter, Manager, WebviewUrl, WebviewWindowBuilder}; use tauri::{Emitter, Manager, WebviewUrl, WebviewWindowBuilder};
/// Entry point for the `--tectonic-compile` subprocess mode. /// Entry point for the `--tectonic-compile` subprocess mode.
@ -198,6 +199,21 @@ fn create_new_window(app: tauri::AppHandle) -> Result<(), String> {
Ok(()) Ok(())
} }
#[tauri::command]
fn allow_project_directory(app: tauri::AppHandle, root_path: String) -> Result<(), String> {
let fs_scope = app.fs_scope();
fs_scope
.allow_directory(&root_path, true)
.map_err(|e| format!("Failed to allow project directory: {}", e))?;
let asset_scope = app.state::<tauri::scope::Scopes>();
asset_scope
.allow_directory(&root_path, true)
.map_err(|e| format!("Failed to allow project assets: {}", e))?;
Ok(())
}
// --- Debug logging from JS (survives white-screen crashes) --- // --- Debug logging from JS (survives white-screen crashes) ---
#[tauri::command] #[tauri::command]
@ -349,6 +365,7 @@ pub fn run() {
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
create_new_window, create_new_window,
allow_project_directory,
detect_editors, detect_editors,
open_in_editor, open_in_editor,
js_log, js_log,

View file

@ -1,5 +1,6 @@
import { describe, it, expect, beforeEach, vi } from "vitest"; import { describe, it, expect, beforeEach, vi } from "vitest";
import { writeTextFile } from "@tauri-apps/plugin-fs"; import { invoke } from "@tauri-apps/api/core";
import { readDir, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
import { import {
useDocumentStore, useDocumentStore,
getCurrentPdfBytes, getCurrentPdfBytes,
@ -42,6 +43,7 @@ function makeFile(overrides: Partial<ProjectFile> = {}): ProjectFile {
describe("useDocumentStore", () => { describe("useDocumentStore", () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks();
clearPdfBytesCache(); clearPdfBytesCache();
useDocumentStore.setState({ useDocumentStore.setState({
projectRoot: "/project", projectRoot: "/project",
@ -83,6 +85,38 @@ describe("useDocumentStore", () => {
}); });
}); });
describe("openProject", () => {
it("re-authorizes the project directory before scanning", async () => {
const projectPath = "E:\\overleaf-cache\\论文项目";
let resolveAuthorization!: () => void;
const authorizationPromise = new Promise<void>((resolve) => {
resolveAuthorization = resolve;
});
vi.mocked(invoke).mockReturnValue(
authorizationPromise as ReturnType<typeof invoke>,
);
vi.mocked(readDir).mockResolvedValue([
{ name: "main.tex", isDirectory: false },
] as any);
vi.mocked(readTextFile).mockResolvedValue("\\documentclass{article}");
const openProjectPromise = useDocumentStore
.getState()
.openProject(projectPath);
expect(invoke).toHaveBeenCalledWith("allow_project_directory", {
rootPath: projectPath,
});
expect(readDir).not.toHaveBeenCalled();
resolveAuthorization();
await openProjectPromise;
expect(readDir).toHaveBeenCalled();
});
});
describe("insertAtCursor", () => { describe("insertAtCursor", () => {
it("inserts text at cursor position", () => { it("inserts text at cursor position", () => {
useDocumentStore.getState().insertAtCursor(", Beautiful"); useDocumentStore.getState().insertAtCursor(", Beautiful");

View file

@ -1,4 +1,5 @@
import { create } from "zustand"; import { create } from "zustand";
import { invoke } from "@tauri-apps/api/core";
import { import {
scanProjectFolder, scanProjectFolder,
readTexFileContent, readTexFileContent,
@ -266,6 +267,7 @@ export const useDocumentStore = create<DocumentState>()((set, get) => ({
openProject: async (rootPath: string) => { openProject: async (rootPath: string) => {
log.info(`Opening project: ${rootPath}`); log.info(`Opening project: ${rootPath}`);
await invoke("allow_project_directory", { rootPath });
const { files: fsFiles, folders: fsFolders } = const { files: fsFiles, folders: fsFolders } =
await scanProjectFolder(rootPath); await scanProjectFolder(rootPath);
const projectFiles: ProjectFile[] = []; const projectFiles: ProjectFile[] = [];