diff --git a/src/types/cspair.ts b/src/types/cspair.ts index 2baed15..264d96d 100644 --- a/src/types/cspair.ts +++ b/src/types/cspair.ts @@ -1,6 +1,6 @@ -export type CSPair = {client: T; server: T} | CSPairNotC | CSPairNotS; -export type CSPairNotC = {client: null; server: T}; -export type CSPairNotS = {client: T; server: null}; +export type CSPair = {client: T; server: T; p: Promise} | CSPairNotC | CSPairNotS; +export type CSPairNotC = {client: null; server: T; p: Promise}; +export type CSPairNotS = {client: T; server: null; p: Promise}; export function noCPair(pair: CSPair): pair is CSPairNotC { return pair.client == null; diff --git a/src/views/RedirectsView.svelte b/src/views/RedirectsView.svelte index 96ba750..b43a5ed 100644 --- a/src/views/RedirectsView.svelte +++ b/src/views/RedirectsView.svelte @@ -8,10 +8,10 @@ const apiViolet = import.meta.env.VITE_API_VIOLET; - let redirectData: {[key: string]: CSPair} = {}; + let tableData: {[key: string]: CSPair} = {}; let redirectSrcs: string[] = []; - $: redirectSrcs = Object.entries(redirectData) + $: redirectSrcs = Object.entries(tableData) .filter(x => x[1].client != null || x[1].server != null) .map(x => x[0]) .filter(x => domainFilter(x, $domainOption)) @@ -26,12 +26,10 @@ return p.endsWith(domain); } - let promiseForRedirects: Promise; + let promiseForRedirects: Promise = reloadRedirects(true); - reloadRedirects(); - - function reloadRedirects() { - promiseForRedirects = new Promise((res, rej) => { + function reloadRedirects(firstLoad: boolean = false): Promise { + return new Promise((res, rej) => { fetch(apiViolet + "/redirect", {headers: {Authorization: getBearer()}}) .then(x => { if (x.status != 200) throw new Error("Unexpected status code: " + x.status); @@ -41,9 +39,12 @@ let redirects = x as Redirect[]; let y: {[key: string]: CSPair} = {}; redirects.forEach(x => { - y[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x}; + tableData[x.src] = { + client: firstLoad || !tableData[x.src] ? JSON.parse(JSON.stringify(x)) : tableData[x.src]?.client, + server: x, + p: Promise.resolve(), + }; }); - redirectData = y; res(); }) .catch(x => rej(x)); @@ -52,33 +53,35 @@ interface Savable { type: "del" | "ins"; - v: T; - p?: Promise; + v: CSPair; } function saveChanges() { let redirectPromises = redirectSrcs - .map(x => redirectData[x]) + .map(x => tableData[x]) .filter(x => x.client != null || x.server != null) .filter(x => !redirectEqual(x.client, x.server)) - .map((x: CSPair): Savable> => { + .map((x: CSPair): Savable => { if (x.client == null && x.server != null) return {type: "del", v: x}; return {type: "ins", v: x}; }) .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0)) .map(x => { - x.p = fetch(apiViolet + "/redirect", { + x.v.p = fetch(apiViolet + "/redirect", { method: x.type == "del" ? "DELETE" : "POST", headers: {Authorization: getBearer()}, body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Redirect).src} : x.v.client), }).then(x => { if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); }); + return x.v.p; }); - Promise.all(redirectPromises).then(_ => { - reloadRedirects(); - }); + Promise.all(redirectPromises) + .then(_ => reloadRedirects()) + .catch(_ => { + alert("Some rows failed to save changes"); + }); } @@ -107,7 +110,7 @@ { const x = e.detail; - redirectData[x.src] = {client: x, server: redirectData[x.src]?.server}; + tableData[x.src] = {client: x, server: tableData[x.src]?.server, p: Promise.resolve()}; redirectSrcs.push(x.src); redirectSrcs = redirectSrcs; }} @@ -115,11 +118,13 @@ {#each redirectSrcs as src (src)} - {#if redirectData[src]} - - {:else} - Error loading row for {src} - {/if} + {#await tableData[src].p} + Loading... + {:then _} + + {:catch err} + Error loading row for {src}: {err} + {/await} {/each} diff --git a/src/views/RoutesView.svelte b/src/views/RoutesView.svelte index fad2f34..64f2d5f 100644 --- a/src/views/RoutesView.svelte +++ b/src/views/RoutesView.svelte @@ -26,12 +26,10 @@ return p.endsWith(domain); } - let promiseForRoutes: Promise; + let promiseForRoutes: Promise = reloadRoutes(true); - reloadRoutes(); - - function reloadRoutes() { - promiseForRoutes = new Promise((res, rej) => { + function reloadRoutes(firstLoad: boolean = false): Promise { + return new Promise((res, rej) => { fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}}) .then(x => { if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); @@ -41,9 +39,12 @@ let routes = x as Route[]; let y: {[key: string]: CSPair} = {}; routes.forEach(x => { - y[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x}; + tableData[x.src] = { + client: firstLoad || !tableData[x.src] ? JSON.parse(JSON.stringify(x)) : tableData[x.src]?.client, + server: x, + p: Promise.resolve(), + }; }); - tableData = y; res(); }) .catch(x => rej(x)); @@ -52,8 +53,7 @@ interface Savable { type: "del" | "ins"; - v: T; - p?: Promise; + v: CSPair; } function saveChanges() { @@ -61,24 +61,27 @@ .map(x => tableData[x]) .filter(x => x.client != null || x.server != null) .filter(x => !routeEqual(x.client, x.server)) - .map((x: CSPair): Savable> => { + .map((x: CSPair): Savable => { if (x.client == null && x.server != null) return {type: "del", v: x}; return {type: "ins", v: x}; }) .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0)) .map(x => { - x.p = fetch(apiViolet + "/route", { + x.v.p = fetch(apiViolet + "/route", { method: x.type == "del" ? "DELETE" : "POST", headers: {Authorization: getBearer()}, body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Route).src} : x.v.client), }).then(x => { if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); }); + return x.v.p; }); - Promise.all(routePromises).then(_ => { - reloadRoutes(); - }); + Promise.all(routePromises) + .then(_ => reloadRoutes()) + .catch(_ => { + alert("Some rows failed to save changes"); + }); } @@ -106,7 +109,7 @@ { const x = e.detail; - tableData[x.src] = {client: x, server: tableData[x.src]?.server}; + tableData[x.src] = {client: x, server: tableData[x.src]?.server, p: Promise.resolve()}; tableKeys.push(x.src); tableKeys = tableKeys; }} @@ -114,11 +117,13 @@ {#each tableKeys as src (src)} - {#if tableData[src]} + {#await tableData[src].p} + Loading... + {:then _} - {:else} - Error loading row for {src} - {/if} + {:catch err} + Error loading row for {src}: {err} + {/await} {/each}