Smoother route and redirect saving changes

This commit is contained in:
Melon 2023-10-30 12:30:48 +00:00
parent ca21c244fc
commit 3e22444b4f
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
3 changed files with 55 additions and 45 deletions

View File

@ -1,6 +1,6 @@
export type CSPair<T> = {client: T; server: T} | CSPairNotC<T> | CSPairNotS<T>; export type CSPair<T> = {client: T; server: T; p: Promise<void>} | CSPairNotC<T> | CSPairNotS<T>;
export type CSPairNotC<T> = {client: null; server: T}; export type CSPairNotC<T> = {client: null; server: T; p: Promise<void>};
export type CSPairNotS<T> = {client: T; server: null}; export type CSPairNotS<T> = {client: T; server: null; p: Promise<void>};
export function noCPair<T>(pair: CSPair<T>): pair is CSPairNotC<T> { export function noCPair<T>(pair: CSPair<T>): pair is CSPairNotC<T> {
return pair.client == null; return pair.client == null;

View File

@ -8,10 +8,10 @@
const apiViolet = import.meta.env.VITE_API_VIOLET; const apiViolet = import.meta.env.VITE_API_VIOLET;
let redirectData: {[key: string]: CSPair<Redirect>} = {}; let tableData: {[key: string]: CSPair<Redirect>} = {};
let redirectSrcs: string[] = []; let redirectSrcs: string[] = [];
$: redirectSrcs = Object.entries(redirectData) $: redirectSrcs = Object.entries(tableData)
.filter(x => x[1].client != null || x[1].server != null) .filter(x => x[1].client != null || x[1].server != null)
.map(x => x[0]) .map(x => x[0])
.filter(x => domainFilter(x, $domainOption)) .filter(x => domainFilter(x, $domainOption))
@ -26,12 +26,10 @@
return p.endsWith(domain); return p.endsWith(domain);
} }
let promiseForRedirects: Promise<void>; let promiseForRedirects: Promise<void> = reloadRedirects(true);
reloadRedirects(); function reloadRedirects(firstLoad: boolean = false): Promise<void> {
return new Promise<void>((res, rej) => {
function reloadRedirects() {
promiseForRedirects = new Promise<void>((res, rej) => {
fetch(apiViolet + "/redirect", {headers: {Authorization: getBearer()}}) fetch(apiViolet + "/redirect", {headers: {Authorization: getBearer()}})
.then(x => { .then(x => {
if (x.status != 200) throw new Error("Unexpected status code: " + x.status); if (x.status != 200) throw new Error("Unexpected status code: " + x.status);
@ -41,9 +39,12 @@
let redirects = x as Redirect[]; let redirects = x as Redirect[];
let y: {[key: string]: CSPair<Redirect>} = {}; let y: {[key: string]: CSPair<Redirect>} = {};
redirects.forEach(x => { 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(); res();
}) })
.catch(x => rej(x)); .catch(x => rej(x));
@ -52,32 +53,34 @@
interface Savable<T> { interface Savable<T> {
type: "del" | "ins"; type: "del" | "ins";
v: T; v: CSPair<T>;
p?: Promise<void>;
} }
function saveChanges() { function saveChanges() {
let redirectPromises = redirectSrcs let redirectPromises = redirectSrcs
.map(x => redirectData[x]) .map(x => tableData[x])
.filter(x => x.client != null || x.server != null) .filter(x => x.client != null || x.server != null)
.filter(x => !redirectEqual(x.client, x.server)) .filter(x => !redirectEqual(x.client, x.server))
.map((x: CSPair<Redirect>): Savable<CSPair<Redirect>> => { .map((x: CSPair<Redirect>): Savable<Redirect> => {
if (x.client == null && x.server != null) return {type: "del", v: x}; if (x.client == null && x.server != null) return {type: "del", v: x};
return {type: "ins", v: x}; return {type: "ins", v: x};
}) })
.sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0)) .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
.map(x => { .map(x => {
x.p = fetch(apiViolet + "/redirect", { x.v.p = fetch(apiViolet + "/redirect", {
method: x.type == "del" ? "DELETE" : "POST", method: x.type == "del" ? "DELETE" : "POST",
headers: {Authorization: getBearer()}, headers: {Authorization: getBearer()},
body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Redirect).src} : x.v.client), body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Redirect).src} : x.v.client),
}).then(x => { }).then(x => {
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
}); });
return x.v.p;
}); });
Promise.all(redirectPromises).then(_ => { Promise.all(redirectPromises)
reloadRedirects(); .then(_ => reloadRedirects())
.catch(_ => {
alert("Some rows failed to save changes");
}); });
} }
</script> </script>
@ -107,7 +110,7 @@
<RedirectCreator <RedirectCreator
on:make={e => { on:make={e => {
const x = e.detail; 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.push(x.src);
redirectSrcs = redirectSrcs; redirectSrcs = redirectSrcs;
}} }}
@ -115,11 +118,13 @@
</thead> </thead>
<tbody> <tbody>
{#each redirectSrcs as src (src)} {#each redirectSrcs as src (src)}
{#if redirectData[src]} {#await tableData[src].p}
<RedirectRow bind:value={redirectData[src]} /> <tr><td colspan="5">Loading...</td></tr>
{:else} {:then _}
<tr><td colspan="5">Error loading row for {src}</td></tr> <RedirectRow bind:value={tableData[src]} />
{/if} {:catch err}
<tr><td colspan="5">Error loading row for {src}: {err}</td></tr>
{/await}
{/each} {/each}
</tbody> </tbody>
</table> </table>

View File

@ -26,12 +26,10 @@
return p.endsWith(domain); return p.endsWith(domain);
} }
let promiseForRoutes: Promise<void>; let promiseForRoutes: Promise<void> = reloadRoutes(true);
reloadRoutes(); function reloadRoutes(firstLoad: boolean = false): Promise<void> {
return new Promise<void>((res, rej) => {
function reloadRoutes() {
promiseForRoutes = new Promise<void>((res, rej) => {
fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}}) fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
.then(x => { .then(x => {
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
@ -41,9 +39,12 @@
let routes = x as Route[]; let routes = x as Route[];
let y: {[key: string]: CSPair<Route>} = {}; let y: {[key: string]: CSPair<Route>} = {};
routes.forEach(x => { 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(); res();
}) })
.catch(x => rej(x)); .catch(x => rej(x));
@ -52,8 +53,7 @@
interface Savable<T> { interface Savable<T> {
type: "del" | "ins"; type: "del" | "ins";
v: T; v: CSPair<T>;
p?: Promise<void>;
} }
function saveChanges() { function saveChanges() {
@ -61,23 +61,26 @@
.map(x => tableData[x]) .map(x => tableData[x])
.filter(x => x.client != null || x.server != null) .filter(x => x.client != null || x.server != null)
.filter(x => !routeEqual(x.client, x.server)) .filter(x => !routeEqual(x.client, x.server))
.map((x: CSPair<Route>): Savable<CSPair<Route>> => { .map((x: CSPair<Route>): Savable<Route> => {
if (x.client == null && x.server != null) return {type: "del", v: x}; if (x.client == null && x.server != null) return {type: "del", v: x};
return {type: "ins", v: x}; return {type: "ins", v: x};
}) })
.sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0)) .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
.map(x => { .map(x => {
x.p = fetch(apiViolet + "/route", { x.v.p = fetch(apiViolet + "/route", {
method: x.type == "del" ? "DELETE" : "POST", method: x.type == "del" ? "DELETE" : "POST",
headers: {Authorization: getBearer()}, headers: {Authorization: getBearer()},
body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Route).src} : x.v.client), body: JSON.stringify(x.type == "del" ? {src: (x.v.server as Route).src} : x.v.client),
}).then(x => { }).then(x => {
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status); if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
}); });
return x.v.p;
}); });
Promise.all(routePromises).then(_ => { Promise.all(routePromises)
reloadRoutes(); .then(_ => reloadRoutes())
.catch(_ => {
alert("Some rows failed to save changes");
}); });
} }
</script> </script>
@ -106,7 +109,7 @@
<RouteCreator <RouteCreator
on:make={e => { on:make={e => {
const x = e.detail; 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.push(x.src);
tableKeys = tableKeys; tableKeys = tableKeys;
}} }}
@ -114,11 +117,13 @@
</thead> </thead>
<tbody> <tbody>
{#each tableKeys as src (src)} {#each tableKeys as src (src)}
{#if tableData[src]} {#await tableData[src].p}
<tr><td colspan="5">Loading...</td></tr>
{:then _}
<RouteRow bind:value={tableData[src]} /> <RouteRow bind:value={tableData[src]} />
{:else} {:catch err}
<tr><td colspan="5">Error loading row for {src}</td></tr> <tr><td colspan="5">Error loading row for {src}: {err}</td></tr>
{/if} {/await}
{/each} {/each}
</tbody> </tbody>
</table> </table>