Adds a shared, persisted auto-save preference for workspace text-file editing, defaulted to on, surfaced as a toolbar toggle in both the Files modal and right-dock Files view. - Add useAutoSavePreference hook: persists the fn-file-editor-auto-save localStorage preference, broadcasts same-window changes via a custom event (storage events only reach other documents), and defaults to true. - Extend useWorkspaceFileEditor with an autoSave flag that debounces (800ms) and triggers save() for a loaded, editable file with real pending changes, keyed by workspace+file+content to avoid re-firing on failed writes. - Add an Auto-save toggle button to FileEditor's toolbar (autoSaveEnabled/onToggleAutoSave/canToggleAutoSave props), hidden for read-only/preview/binary files. - Wire the shared preference into FileBrowserModal and DockFilesView, disabling auto-save for binary files in the modal. - Add fileEditor.autoSave / fileEditor.toggleAutoSave i18n strings and document the new default behavior in docs/dashboard-guide.md. - Add/extend tests covering the new hook, debounced auto-save behavior, and toolbar toggle wiring across FileEditor, FileBrowserModal, and DockFilesView. Files changed: docs/dashboard-guide.md | 3 + .../dashboard/app/components/DockFilesView.tsx | 6 +- .../dashboard/app/components/FileBrowserModal.tsx | 20 ++-- packages/dashboard/app/components/FileEditor.tsx | 17 +++- .../components/__tests__/DockFilesView.test.tsx | 37 ++++++- .../components/__tests__/FileBrowserModal.test.tsx | 86 +++++++++++++--- .../app/components/__tests__/FileEditor.test.tsx | 56 +++++++++++ .../hooks/__tests__/useAutoSavePreference.test.ts | 66 +++++++++++++ .../hooks/__tests__/useWorkspaceFileEditor.test.ts | 108 +++++++++++++++++++++ .../dashboard/app/hooks/useAutoSavePreference.ts | 79 +++++++++++++++ .../dashboard/app/hooks/useWorkspaceFileEditor.ts | 47 ++++++++- packages/i18n/locales/en/app.json | 2 + 12 files changed, 500 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-7866 Fusion-Task-Lineage: 0604de18-666d-4872-abce-2a3886c9ea55 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { FILE_EDITOR_AUTO_SAVE_STORAGE_KEY, useAutoSavePreference } from "../useAutoSavePreference";
|
|
|
|
describe("useAutoSavePreference", () => {
|
|
beforeEach(() => {
|
|
vi.restoreAllMocks();
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
it("defaults to enabled when no preference is stored", () => {
|
|
const { result } = renderHook(() => useAutoSavePreference());
|
|
|
|
expect(result.current.autoSaveEnabled).toBe(true);
|
|
});
|
|
|
|
it("reads a stored false preference", () => {
|
|
window.localStorage.setItem(FILE_EDITOR_AUTO_SAVE_STORAGE_KEY, "false");
|
|
|
|
const { result } = renderHook(() => useAutoSavePreference());
|
|
|
|
expect(result.current.autoSaveEnabled).toBe(false);
|
|
});
|
|
|
|
it("toggles and persists the preference", () => {
|
|
const { result } = renderHook(() => useAutoSavePreference());
|
|
|
|
act(() => result.current.toggleAutoSave());
|
|
|
|
expect(result.current.autoSaveEnabled).toBe(false);
|
|
expect(window.localStorage.getItem(FILE_EDITOR_AUTO_SAVE_STORAGE_KEY)).toBe("false");
|
|
});
|
|
|
|
it("sets and persists an explicit preference", () => {
|
|
const { result } = renderHook(() => useAutoSavePreference());
|
|
|
|
act(() => result.current.setAutoSaveEnabled(false));
|
|
expect(result.current.autoSaveEnabled).toBe(false);
|
|
expect(window.localStorage.getItem(FILE_EDITOR_AUTO_SAVE_STORAGE_KEY)).toBe("false");
|
|
|
|
act(() => result.current.setAutoSaveEnabled(true));
|
|
expect(result.current.autoSaveEnabled).toBe(true);
|
|
expect(window.localStorage.getItem(FILE_EDITOR_AUTO_SAVE_STORAGE_KEY)).toBe("true");
|
|
});
|
|
|
|
it("updates when another document changes storage", () => {
|
|
const { result } = renderHook(() => useAutoSavePreference());
|
|
|
|
act(() => {
|
|
window.localStorage.setItem(FILE_EDITOR_AUTO_SAVE_STORAGE_KEY, "false");
|
|
window.dispatchEvent(new StorageEvent("storage", { key: FILE_EDITOR_AUTO_SAVE_STORAGE_KEY, newValue: "false" }));
|
|
});
|
|
|
|
expect(result.current.autoSaveEnabled).toBe(false);
|
|
});
|
|
|
|
it("syncs multiple same-window editor instances", () => {
|
|
const first = renderHook(() => useAutoSavePreference());
|
|
const second = renderHook(() => useAutoSavePreference());
|
|
|
|
act(() => first.result.current.setAutoSaveEnabled(false));
|
|
|
|
expect(first.result.current.autoSaveEnabled).toBe(false);
|
|
expect(second.result.current.autoSaveEnabled).toBe(false);
|
|
});
|
|
});
|