diff --git a/packages/app/src/hooks/useSaveProject.ts b/packages/app/src/hooks/useSaveProject.ts index beb62cc20..78ae86519 100644 --- a/packages/app/src/hooks/useSaveProject.ts +++ b/packages/app/src/hooks/useSaveProject.ts @@ -30,18 +30,23 @@ export function useSaveProject() { saving = toast.info('Saving project'); }, 500); - await ioProvider.saveProjectDataNoPrompt(newProject, { testSuites }, loadedProject.path); + try { + await ioProvider.saveProjectDataNoPrompt(newProject, { testSuites }, loadedProject.path); - if (saving != null) { - toast.dismiss(saving); - } - clearTimeout(savingTimeout); + if (saving != null) { + toast.dismiss(saving); + } + clearTimeout(savingTimeout); - toast.success('Project saved'); - setLoadedProject({ - loaded: true, - path: loadedProject.path, - }); + toast.success('Project saved'); + setLoadedProject({ + loaded: true, + path: loadedProject.path, + }); + } catch (cause) { + clearTimeout(savingTimeout); + toast.error('Failed to save project'); + } } async function saveProjectAs() { @@ -57,26 +62,31 @@ export function useSaveProject() { saving = toast.info('Saving project'); }, 500); - const filePath = await ioProvider.saveProjectData(newProject, { testSuites }); + try { + const filePath = await ioProvider.saveProjectData(newProject, { testSuites }); - if (saving != null) { - toast.dismiss(saving); - } - clearTimeout(savingTimeout); + if (saving != null) { + toast.dismiss(saving); + } + clearTimeout(savingTimeout); - if (filePath) { - toast.success('Project saved'); - setLoadedProject({ - loaded: true, - path: filePath, - }); - setOpenedProjects((projects) => ({ - ...projects, - [project.metadata.id]: { - project, - fsPath: filePath, - }, - })); + if (filePath) { + toast.success('Project saved'); + setLoadedProject({ + loaded: true, + path: filePath, + }); + setOpenedProjects((projects) => ({ + ...projects, + [project.metadata.id]: { + project, + fsPath: filePath, + }, + })); + } + } catch (cause) { + clearTimeout(savingTimeout); + toast.error('Failed to save project'); } } diff --git a/packages/app/src/io/TauriIOProvider.ts b/packages/app/src/io/TauriIOProvider.ts index 4916442c0..55feaf30d 100644 --- a/packages/app/src/io/TauriIOProvider.ts +++ b/packages/app/src/io/TauriIOProvider.ts @@ -132,7 +132,7 @@ export class TauriIOProvider implements IOProvider { async loadProjectDataNoPrompt(path: string): Promise<{ project: Project; testData: TrivetData }> { const data = await readTextFile(path); - const [projectData, attachedData] = deserializeProject(data); + const [projectData, attachedData] = deserializeProject(data, path); const trivetData = attachedData.trivet ? deserializeTrivetData(attachedData.trivet as SerializedTrivetData) diff --git a/packages/core/src/model/Project.ts b/packages/core/src/model/Project.ts index a13001477..90f4b26f7 100644 --- a/packages/core/src/model/Project.ts +++ b/packages/core/src/model/Project.ts @@ -12,6 +12,7 @@ export type Project = { title: string; description: string; mainGraphId?: GraphId; + path?: string; }; plugins?: PluginLoadSpec[]; diff --git a/packages/core/src/utils/serialization/serialization.ts b/packages/core/src/utils/serialization/serialization.ts index e29b38515..8759f7125 100644 --- a/packages/core/src/utils/serialization/serialization.ts +++ b/packages/core/src/utils/serialization/serialization.ts @@ -19,9 +19,12 @@ export function serializeProject(project: Project, attachedData?: AttachedData): return projectV4Serializer(project, attachedData); } -export function deserializeProject(serializedProject: unknown): [Project, AttachedData] { +export function deserializeProject(serializedProject: unknown, path: string | null = null): [Project, AttachedData] { try { - return projectV4Deserializer(serializedProject); + const result = projectV4Deserializer(serializedProject); + if (path !== null) + result[0].metadata.path = path; + return result; } catch (err) { if (err instanceof yaml.YAMLError) { yamlProblem(err); diff --git a/packages/core/src/utils/serialization/serialization_v4.ts b/packages/core/src/utils/serialization/serialization_v4.ts index 20e81c0c9..e38a3fd26 100644 --- a/packages/core/src/utils/serialization/serialization_v4.ts +++ b/packages/core/src/utils/serialization/serialization_v4.ts @@ -93,8 +93,16 @@ export function graphV4Deserializer(data: unknown): NodeGraph { } export function projectV4Serializer(project: Project, attachedData?: AttachedData): unknown { + const filteredProject = { + ...project, + metadata: { + ...project.metadata, + path: undefined, + } + } + // Make sure all data is ordered deterministically first - const stabilized = JSON.parse(stableStringify(toSerializedProject(project, attachedData))); + const stabilized = JSON.parse(stableStringify(toSerializedProject(filteredProject, attachedData))); const serialized = yaml.stringify( { diff --git a/packages/core/test/testUtils.ts b/packages/core/test/testUtils.ts index 8b4d7e6f6..a475237c2 100644 --- a/packages/core/test/testUtils.ts +++ b/packages/core/test/testUtils.ts @@ -22,11 +22,11 @@ export async function loadTestGraphInProcessor(graphName: string) { export async function loadProjectFromFile(path: string): Promise { const content = await readFile(path, { encoding: 'utf8' }); - return loadProjectFromString(content); + return loadProjectFromString(content, path); } -export function loadProjectFromString(content: string): Project { - const [project] = deserializeProject(content); +export function loadProjectFromString(content: string, path: string | null = null): Project { + const [project] = deserializeProject(content, path); return project; }