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 CSPairNotC<T> = {client: null; server: T};
export type CSPairNotS<T> = {client: T; server: null};
export type CSPair<T> = {client: T; server: T; p: Promise<void>} | CSPairNotC<T> | CSPairNotS<T>;
export type CSPairNotC<T> = {client: null; server: T; p: Promise<void>};
export type CSPairNotS<T> = {client: T; server: null; p: Promise<void>};
export function noCPair<T>(pair: CSPair<T>): pair is CSPairNotC<T> {
return pair.client == null;

View File

@ -8,10 +8,10 @@
const apiViolet = import.meta.env.VITE_API_VIOLET;
let redirectData: {[key: string]: CSPair<Redirect>} = {};
let tableData: {[key: string]: CSPair<Redirect>} = {};
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<void>;
let promiseForRedirects: Promise<void> = reloadRedirects(true);
reloadRedirects();
function reloadRedirects() {
promiseForRedirects = new Promise<void>((res, rej) => {
function reloadRedirects(firstLoad: boolean = false): Promise<void> {
return new Promise<void>((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<Redirect>} = {};
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<T> {
type: "del" | "ins";
v: T;
p?: Promise<void>;
v: CSPair<T>;
}
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<Redirect>): Savable<CSPair<Redirect>> => {
.map((x: CSPair<Redirect>): Savable<Redirect> => {
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");
});
}
</script>
@ -107,7 +110,7 @@
<RedirectCreator
on:make={e => {
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 @@
</thead>
<tbody>
{#each redirectSrcs as src (src)}
{#if redirectData[src]}
<RedirectRow bind:value={redirectData[src]} />
{:else}
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{#await tableData[src].p}
<tr><td colspan="5">Loading...</td></tr>
{:then _}
<RedirectRow bind:value={tableData[src]} />
{:catch err}
<tr><td colspan="5">Error loading row for {src}: {err}</td></tr>
{/await}
{/each}
</tbody>
</table>

View File

@ -26,12 +26,10 @@
return p.endsWith(domain);
}
let promiseForRoutes: Promise<void>;
let promiseForRoutes: Promise<void> = reloadRoutes(true);
reloadRoutes();
function reloadRoutes() {
promiseForRoutes = new Promise<void>((res, rej) => {
function reloadRoutes(firstLoad: boolean = false): Promise<void> {
return new Promise<void>((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<Route>} = {};
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<T> {
type: "del" | "ins";
v: T;
p?: Promise<void>;
v: CSPair<T>;
}
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<Route>): Savable<CSPair<Route>> => {
.map((x: CSPair<Route>): Savable<Route> => {
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");
});
}
</script>
@ -106,7 +109,7 @@
<RouteCreator
on:make={e => {
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 @@
</thead>
<tbody>
{#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]} />
{:else}
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{:catch err}
<tr><td colspan="5">Error loading row for {src}: {err}</td></tr>
{/await}
{/each}
</tbody>
</table>