diff --git a/src/components/RedirectCreator.svelte b/src/components/RedirectCreator.svelte
index 4827935..24e47f3 100644
--- a/src/components/RedirectCreator.svelte
+++ b/src/components/RedirectCreator.svelte
@@ -12,7 +12,7 @@
|
|
- |
+ |
|
|
@@ -31,4 +31,8 @@
tr:nth-child(2n) {
background-color: #2a2a2a;
}
+
+ .desc textarea {
+ resize: none;
+ }
diff --git a/src/types/target.ts b/src/types/target.ts
index af78106..9b681da 100644
--- a/src/types/target.ts
+++ b/src/types/target.ts
@@ -14,13 +14,13 @@ export interface Redirect {
active: boolean;
}
-export function routeEqual(a: Route, b: Route): boolean {
- if (b == null) return false;
+export function routeEqual(a: Route | null, b: Route | null): boolean {
+ if (a == null || b == null) return false;
return a.src === b.src && a.dst === b.dst && a.desc === b.desc && a.flags === b.flags && a.active === b.active;
}
-export function redirectEqual(a: Redirect, b: Redirect): boolean {
- if (b == null) return false;
+export function redirectEqual(a: Redirect | null, b: Redirect | null): boolean {
+ if (a == null || b == null) return false;
return a.src === b.src && a.dst === b.dst && a.desc === b.desc && a.flags === b.flags && a.active === b.active;
}
diff --git a/src/views/VioletView.svelte b/src/views/VioletView.svelte
index 72907d1..640b34e 100644
--- a/src/views/VioletView.svelte
+++ b/src/views/VioletView.svelte
@@ -5,7 +5,7 @@
import RouteRow from "../components/RouteRow.svelte";
import {getBearer, loginStore, parseJwt, type LoginStore} from "../stores/login";
import type {CSPair} from "../types/cspair";
- import {type Route, type Redirect} from "../types/target";
+ import {type Route, type Redirect, routeEqual, redirectEqual} from "../types/target";
import {domainOption} from "../stores/domain-option";
const apiViolet = import.meta.env.VITE_API_VIOLET;
@@ -36,42 +36,108 @@
return p.endsWith(domain);
}
- let promiseForRoutes = new Promise((res, rej) => {
- fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
- .then(x => {
- if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
- return x.json();
+ let promiseForRoutes: Promise;
+ let promiseForRedirects: Promise;
+
+ reloadRoutes();
+ reloadRedirects();
+
+ function reloadRoutes() {
+ promiseForRoutes = new Promise((res, rej) => {
+ fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
+ .then(x => {
+ if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
+ return x.json();
+ })
+ .then(x => {
+ let routes = x as Route[];
+ routes.forEach(x => {
+ routeData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
+ });
+ res();
+ })
+ .catch(x => rej(x));
+ });
+ }
+
+ function reloadRedirects() {
+ promiseForRedirects = new Promise((res, rej) => {
+ fetch(apiViolet + "/redirect", {headers: {Authorization: getBearer()}})
+ .then(x => {
+ if (x.status != 200) throw new Error("Unexpected status code: " + x.status);
+ return x.json();
+ })
+ .then(x => {
+ let redirects = x as Redirect[];
+ redirects.forEach(x => {
+ redirectData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
+ });
+ res();
+ })
+ .catch(x => rej(x));
+ });
+ }
+
+ interface Savable {
+ type: "del" | "ins";
+ v: T;
+ p?: Promise;
+ }
+
+ function saveChanges() {
+ let routePromises = routeSrcs
+ .map(x => routeData[x])
+ .filter(x => x.client != null || x.server != null)
+ .filter(x => !routeEqual(x.client, x.server))
+ .map((x: CSPair): Savable> => {
+ if (x.client == null && x.server != null) return {type: "del", v: x};
+ return {type: "ins", v: x};
})
- .then(x => {
- let routes = x as Route[];
- routes.forEach(x => {
- routeData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
+ .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
+ .map(x => {
+ x.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);
});
- res();
+ });
+
+ let redirectPromises = redirectSrcs
+ .map(x => redirectData[x])
+ .filter(x => x.client != null || x.server != null)
+ .filter(x => !redirectEqual(x.client, x.server))
+ .map((x: CSPair): Savable> => {
+ if (x.client == null && x.server != null) return {type: "del", v: x};
+ return {type: "ins", v: x};
})
- .catch(x => rej(x));
- });
- let promiseForRedirects = new Promise((res, rej) => {
- fetch(apiViolet + "/redirect", {headers: {Authorization: getBearer()}})
- .then(x => {
- if (x.status != 200) throw new Error("Unexpected status code: " + x.status);
- return x.json();
- })
- .then(x => {
- let redirects = x as Redirect[];
- redirects.forEach(x => {
- redirectData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
+ .sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
+ .map(x => {
+ x.p = fetch(apiViolet + "/route", {
+ 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);
});
- res();
- })
- .catch(x => rej(x));
- });
+ });
+
+ Promise.all(routePromises).then(_ => {
+ reloadRoutes();
+ });
+ Promise.all(redirectPromises).then(_ => {
+ reloadRedirects();
+ });
+ }
Warning: This is currently still under development and does not update the routes and redirects on the server
+
+
Routes
{#await promiseForRoutes}
Loading...
@@ -99,7 +165,7 @@
{
const x = e.detail;
- routeData[x.src] = {client: x, server: null};
+ routeData[x.src] = {client: x, server: routeData[x.src]?.server};
routeSrcs.push(x.src);
routeSrcs = routeSrcs;
}}
@@ -137,7 +203,7 @@
{
const x = e.detail;
- redirectData[x.src] = {client: x, server: null};
+ redirectData[x.src] = {client: x, server: redirectData[x.src]?.server};
redirectSrcs.push(x.src);
redirectSrcs = redirectSrcs;
}}
|