mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-03-11 01:10:23 -07:00
Add end-to-end test for editing workspace and improve shutdown/database cleanup and edit-workspace behavior. Key changes: - features/editWorkspace.feature: new E2E scenario to verify save button behavior when enabling HTTP API and restarting a wiki. - src/main.ts: wrap before-quit cleanup in try/catch/finally, call databaseService.closeAllDatabases() early, and add logging to make shutdown order explicit. - src/services/database/*: add prepareDatabase pragmas (busy_timeout, synchronous) to SQLite config, make closeAppDatabase more robust with safer dataSource.destroy() handling, and add closeAllDatabases() to close all connections and backup stream to avoid better-sqlite3 crashes. - src/services/database/interface.ts: expose closeAllDatabases() in the service interface and IPC descriptor. - src/services/workspaces/interface.ts: mark runtime-only fields as non-config (add lastUrl, homeUrl, hibernated, active), move port to localOnlyFields and remove it from syncableConfigFields to avoid spurious save prompts. - src/services/workspacesView/index.ts: emit a test log marker ([test-id-WIKI_WORKER_RESTARTING]) when a workspace restart is initiated to help tests detect restart events. - src/windows/EditWorkspace/server.tsx: add data-testid attributes to server options accordion and HTTP API switch to support the new test selectors. - src/windows/EditWorkspace/useForm.ts: tighten effect dependencies and adjust originalWorkspace change handling to avoid unnecessary form resets during user edits. Why: fixes intermittent crashes on app quit related to better-sqlite3 by closing DBs first and finalizing resources, and stabilizes edit-workspace UI and tests by preventing runtime-only field changes from triggering save UI and by adding testable hooks.
52 lines
2.5 KiB
TypeScript
52 lines
2.5 KiB
TypeScript
import usePreviousValue from 'beautiful-react-hooks/usePreviousValue';
|
|
import { isEqual, omit } from 'lodash';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
import type { IWorkspace } from '@services/workspaces/interface';
|
|
|
|
export function useForm(
|
|
originalWorkspace?: IWorkspace,
|
|
requestRestartCountDown: () => void = () => {},
|
|
): [IWorkspace | undefined, (newValue: IWorkspace, requestSaveAndRestart?: boolean) => void, () => Promise<void>] {
|
|
const [workspace, workspaceSetter] = useState(originalWorkspace);
|
|
const [requestRestartAfterSave, requestRestartAfterSaveSetter] = useState(false);
|
|
const previous = usePreviousValue(originalWorkspace);
|
|
// initial observable value maybe undefined, we pass an non-null initial value to the form
|
|
useEffect(() => {
|
|
if (previous === undefined && originalWorkspace !== undefined) {
|
|
workspaceSetter(originalWorkspace);
|
|
}
|
|
}, [previous, originalWorkspace]);
|
|
|
|
// Sync workspace state with originalWorkspace after save to ensure save button disappears
|
|
useEffect(() => {
|
|
if (originalWorkspace !== undefined && workspace !== undefined && previous !== undefined) {
|
|
// If originalWorkspace changed after a save operation, update workspace state to match it
|
|
// Only check if originalWorkspace changed (not workspace), to avoid triggering on every user edit
|
|
if (!isEqual(originalWorkspace, previous)) {
|
|
// Check if the current form state matches the new originalWorkspace (excluding non-config fields)
|
|
if (isEqual(omit(workspace, ['metadata', 'lastNodeJSArgv']), omit(originalWorkspace, ['metadata', 'lastNodeJSArgv']))) {
|
|
workspaceSetter(originalWorkspace);
|
|
}
|
|
}
|
|
}
|
|
}, [originalWorkspace, previous]);
|
|
|
|
const onSave = useCallback(async () => {
|
|
if (workspace === undefined) {
|
|
return;
|
|
}
|
|
await window.service.workspace.update(workspace.id, workspace);
|
|
await window.service.native.log('info', '[test-id-WORKSPACE_SAVED]', { workspaceId: workspace.id, workspaceName: workspace.name });
|
|
if (requestRestartAfterSave) {
|
|
requestRestartCountDown();
|
|
}
|
|
}, [workspace, requestRestartAfterSave, requestRestartCountDown]);
|
|
const setterWithRestartOption = (newValue: IWorkspace, requestSaveAndRestart?: boolean) => {
|
|
workspaceSetter(newValue);
|
|
if (requestSaveAndRestart === true && !isEqual(newValue, originalWorkspace)) {
|
|
requestRestartAfterSaveSetter(true);
|
|
}
|
|
};
|
|
return [workspace, setterWithRestartOption, onSave];
|
|
}
|