From 3eb0439e87a1ac4b5657211a3cb1670f8b6e58ca Mon Sep 17 00:00:00 2001 From: Matthieu Viry Date: Fri, 23 Aug 2024 15:26:25 +0200 Subject: [PATCH] Allow to reload a project by giving its url in the query string --- src/AppPage.tsx | 62 ++++++++++++++++++++++++++++--------- src/helpers/query-string.ts | 21 +++++++++++++ 2 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 src/helpers/query-string.ts diff --git a/src/AppPage.tsx b/src/AppPage.tsx index eff931c40..16fc7b823 100644 --- a/src/AppPage.tsx +++ b/src/AppPage.tsx @@ -25,6 +25,7 @@ import { toggleDarkMode } from './helpers/darkmode'; import { clickLinkFromBlob } from './helpers/exports'; import { draggedElementsAreFiles, droppedElementsAreFiles, prepareFilterAndStoreFiles } from './helpers/fileUpload'; import { round } from './helpers/math'; +import parseQueryString from './helpers/query-string'; import { initDb, storeProject } from './helpers/storage'; // Sub-components @@ -262,6 +263,8 @@ const reloadFromProjectObject = async ( await yieldOrContinue('smooth'); // The state we want to use + // TODO: we should check the integrity of the project object + // either by using a schema, by checking the presence of the required fields... const { version, applicationSettings, @@ -286,6 +289,30 @@ const reloadFromProjectObject = async ( setReloadingProject(false); }; +const projectFromQueryString = async (): Promise => { + let projectDefinition; + if (window.location.search) { + const qs = parseQueryString(window.location.search); + const reloadUrl = qs.reload.startsWith('http') ? qs.reload : undefined; + if (typeof (window.history.replaceState) !== 'undefined') { + // replaceState should avoid creating a new entry on the history + const obj = { + Page: window.location.search, + Url: window.location.pathname, + }; + window.history.replaceState(obj, obj.Page, obj.Url); + } + if (reloadUrl) { + const response = await fetch(reloadUrl); + if (response.ok) { + const project = await response.json(); + projectDefinition = project; + } + } + } + return projectDefinition; +}; + const AppPage: () => JSX.Element = () => { const { setLocale, LL } = useI18nContext(); // Do we have a selected langage stored in the local storage ? @@ -466,21 +493,26 @@ const AppPage: () => JSX.Element = () => { width: '660px', }); }); - - // Is there a project in the DB ? - const project = await db.projects.toArray(); - // If there is a project, propose to reload it - if (project.length > 0) { - const { date, data } = project[0]; - setNiceAlertStore({ - show: true, - content: () =>

{ LL().Alerts.ReloadLastProject(date.toLocaleDateString())}

, - confirmCallback: () => { - setGlobalStore({ userHasAddedLayer: true }); - reloadFromProjectObject(data); - }, - focusOn: 'confirm', - }); + // Is there a project in the query string ? + const projectQs = await projectFromQueryString(); + if (projectQs) { + reloadFromProjectObject(projectQs); + } else { + // If not, we check if there is a project in the local DB + const projects = await db.projects.toArray(); + // If there is a project, propose to reload it + if (projects.length > 0) { + const { date, data } = projects[0]; + setNiceAlertStore({ + show: true, + content: () =>

{LL().Alerts.ReloadLastProject(date.toLocaleDateString())}

, + confirmCallback: () => { + setGlobalStore({ userHasAddedLayer: true }); + reloadFromProjectObject(data); + }, + focusOn: 'confirm', + }); + } } // We only keep the last project in the DB // so at this point we can delete all projects diff --git a/src/helpers/query-string.ts b/src/helpers/query-string.ts new file mode 100644 index 000000000..dfbbaa118 --- /dev/null +++ b/src/helpers/query-string.ts @@ -0,0 +1,21 @@ +export default function parseQueryString(search: string) { + const args = search.substring(1).split('&'); + const argsParsed: { [key: string]: (string | true) } & { 'reload': string } = { + reload: '', + }; + let arg; + let kvp; + let key; + for (let i = 0; i < args.length; i += 1) { + arg = args[i]; + if (arg.indexOf('=') === -1) { + argsParsed[decodeURIComponent(arg).trim()] = true; + } else { + kvp = arg.split('='); + key = decodeURIComponent(kvp[0]).trim(); + // const value = decodeURIComponent(kvp[1]).trim(); + argsParsed[key] = decodeURIComponent(kvp[1]).trim(); + } + } + return argsParsed; +}