Make functional and test publishing

This commit is contained in:
Melon 2023-10-25 16:59:59 +01:00
parent 97a2cf089b
commit 944af0d8d9
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
10 changed files with 235 additions and 117 deletions

View File

@ -37,8 +37,10 @@
on:click={() => {
$loginStore = null;
localStorage.removeItem("login-session");
}}>Logout</button
}}
>
Logout
</button>
</div>
{/if}
</header>
@ -52,7 +54,6 @@
{/each}
</div>
<div id="option-view">
<h2>{sidebarSelection.name}</h2>
<svelte:component this={sidebarSelection.view} />
</div>
{/if}
@ -120,7 +121,8 @@
height: calc(100% - 70px);
#sidebar {
width: 200px;
width: 150px;
min-width: 150px;
button {
background-color: #2c2c2c;

View File

@ -61,6 +61,7 @@ body {
margin: 0;
}
code {
code,
.code-font {
font-family: 'Fira Code', monospace;
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
export let value: number = 0;
export let editable: boolean;
export let editable: boolean = false;
export let keys: Key[];
let isEditing: boolean;

View File

@ -0,0 +1,53 @@
<script lang="ts">
import {type CSPair, noCPair, noSPair} from "../types/cspair";
import {type Route, redirectKeys, redirectEqual} from "../types/target";
import Flags from "./Flags.svelte";
export let redirect: CSPair<Route>;
function resetRedirect(): any {
redirect.client = JSON.parse(JSON.stringify(redirect.server));
}
</script>
{#if noCPair(redirect)}
<tr class="deleted">
<td class="code-font">{redirect.server.src}</td>
<td><input type="text" class="code-font" disabled bind:value={redirect.server.dst} size={redirect.server.dst.length + 2} /></td>
<td><Flags value={redirect.server.flags} keys={redirectKeys} /></td>
<td><input type="checkbox" disabled checked={false} /></td>
<td><button on:click={() => resetRedirect()}>Restore</button></td>
</tr>
{:else}
<tr class:created={noSPair(redirect)} class:modified={noSPair(redirect) || !redirectEqual(redirect.client, redirect.server)}>
<td class="code-font">{redirect.client.src}</td>
<td><input type="text" class="code-font" bind:value={redirect.client.dst} size={redirect.client.dst.length + 2} /></td>
<td><Flags bind:value={redirect.client.flags} editable keys={redirectKeys} /></td>
<td><input type="checkbox" bind:checked={redirect.client.active} /></td>
<td>
{#if !noSPair(redirect)}
<button on:click={() => resetRedirect()}>Reset</button>
{/if}
<button on:click={() => (redirect.client = null)}>Delete</button>
</td>
</tr>
{/if}
<style lang="scss">
tr.created {
background-color: #1a5100;
}
tr.modified {
background-color: #515100;
}
tr.deleted {
background-color: #510000;
}
td input[type="text"] {
font-family: "Fira Code";
padding: 4px;
}
</style>

View File

@ -0,0 +1,52 @@
<script lang="ts">
import {type CSPair, noCPair, noSPair} from "../types/cspair";
import {type Route, routeKeys, routeEqual} from "../types/target";
import Flags from "./Flags.svelte";
export let route: CSPair<Route>;
function resetRoute(): any {
route.client = JSON.parse(JSON.stringify(route.server));
}
</script>
{#if noCPair(route)}
<tr class="deleted">
<td class="code-font">{route.server.src}</td>
<td><input type="text" class="code-font" disabled bind:value={route.server.dst} size={route.server.dst.length + 2} /></td>
<td><Flags value={route.server.flags} keys={routeKeys} /></td>
<td><input type="checkbox" disabled checked={false} /></td>
<td><button on:click={() => resetRoute()}>Restore</button></td>
</tr>
{:else}
<tr class:created={noSPair(route)} class:modified={noSPair(route) || !routeEqual(route.client, route.server)}>
<td class="code-font">{route.client.src}</td>
<td><input type="text" class="code-font" bind:value={route.client.dst} size={route.client.dst.length + 2} /></td>
<td><Flags bind:value={route.client.flags} editable keys={routeKeys} /></td>
<td><input type="checkbox" bind:checked={route.client.active} /></td>
<td>
{#if !noSPair(route)}
<button on:click={() => resetRoute()}>Reset</button>
{/if}
<button on:click={() => (route.client = null)}>Delete</button>
</td>
</tr>
{/if}
<style lang="scss">
tr.created {
background-color: #1a5100;
}
tr.modified {
background-color: #515100;
}
tr.deleted {
background-color: #510000;
}
td input[type="text"] {
padding: 4px;
}
</style>

11
src/types/cspair.ts Normal file
View File

@ -0,0 +1,11 @@
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 function noCPair<T>(pair: CSPair<T>): pair is CSPairNotC<T> {
return pair.client == null;
}
export function noSPair<T>(pair: CSPair<T>): pair is CSPairNotS<T> {
return pair.server == null;
}

39
src/types/target.ts Normal file
View File

@ -0,0 +1,39 @@
export interface Route {
src: string;
dst: string;
flags: number;
active: boolean;
}
export interface Redirect {
src: string;
dst: string;
flags: number;
active: boolean;
}
export function routeEqual(a: Route, b: Route): boolean {
if (b == null) return false;
return a.src === b.src && a.dst === b.dst && a.flags === b.flags && a.active === b.active;
}
export function redirectEqual(a: Redirect, b: Redirect): boolean {
if (b == null) return false;
return a.src === b.src && a.dst === b.dst && a.flags === b.flags && a.active === b.active;
}
export const routeKeys = [
{char: "p", name: "Prefix Path"},
{char: "a", name: "Absolute Path"},
{char: "c", name: "CORS"},
{char: "s", name: "Secure Mode"},
{char: "h", name: "Forward Host"},
{char: "f", name: "Forward Address"},
{char: "i", name: "Ignore Certificate"},
{char: "w", name: "Websocket"},
];
export const redirectKeys = [
{char: "p", name: "Prefix Path"},
{char: "a", name: "Absolute Path"},
];

View File

@ -1 +1 @@
<div>No options available here</div>
<div style="padding:8px;background-color:#bb7900;">Warning: This is currently still under development</div>

View File

@ -1 +1 @@
<div>No options available here: {import.meta.env.VITE_API_ORCHID}</div>
<div style="padding:8px;background-color:#bb7900;">Warning: This is currently still under development</div>

View File

@ -1,67 +1,30 @@
<script lang="ts">
import Flags from "../components/Flags.svelte";
import RedirectRow from "../components/RedirectRow.svelte";
import RouteRow from "../components/RouteRow.svelte";
import {getBearer} from "../stores/login";
import type {CSPair} from "../types/cspair";
import {type Route, type Redirect, redirectEqual, redirectKeys} from "../types/target";
const apiViolet = import.meta.env.VITE_API_VIOLET;
const routeKeys = [
{char: "p", name: "Prefix Path"},
{char: "a", name: "Absolute Path"},
{char: "c", name: "CORS"},
{char: "s", name: "Secure Mode"},
{char: "h", name: "Forward Host"},
{char: "f", name: "Forward Address"},
{char: "i", name: "Ignore Certificate"},
{char: "w", name: "Websocket"},
];
let routeData: {[key: string]: CSPair<Route>} = {};
let redirectData: {[key: string]: CSPair<Redirect>} = {};
const redirectKeys = [
{char: "p", name: "Prefix Path"},
{char: "a", name: "Absolute Path"},
];
let routeSrcs: string[] = [];
let redirectSrcs: string[] = [];
interface Route {
src: string;
dst: string;
flags: number;
active: boolean;
}
interface Redirect {
src: string;
dst: string;
flags: number;
active: boolean;
}
type CSPair<T> = {client: T; server: T} | CSPairNotC<T> | CSPairNotS<T>;
type CSPairNotC<T> = {client: null; server: T};
type CSPairNotS<T> = {client: T; server: null};
let routeData: Map<string, CSPair<Route>> = new Map();
let redirectData: Map<string, CSPair<Redirect>> = new Map();
let routeSrcs: Set<string> = new Set();
let redirectSrcs: Set<string> = new Set();
$: routeSrcs = Object.entries(routeData)
.filter(x => x[1].client != null || x[1].server != null)
.map(x => x[0])
.sort((a, b) => a.localeCompare(b));
$: redirectSrcs = Object.entries(redirectData)
.filter(x => x[1].client != null || x[1].server != null)
.map(x => x[0])
.sort((a, b) => a.localeCompare(b));
$: console.log(routeData);
function routeEqual(a: Route, b: Route): boolean {
return a.src === b.src && a.dst === b.dst && a.flags === b.flags && a.active === b.active;
}
function redirectEqual(a: Route, b: Route): boolean {
return a.src === b.src && a.dst === b.dst && a.flags === b.flags && a.active === b.active;
}
function noCPair<T>(pair: CSPair<T>): pair is CSPairNotC<T> {
return pair.client == null;
}
function noSPair<T>(pair: CSPair<T>): pair is CSPairNotS<T> {
return pair.server == null;
}
let promiseForRoutes = new Promise<void>((res, rej) => {
fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
.then(x => {
@ -71,7 +34,7 @@
.then(x => {
let routes = x as Route[];
routes.forEach(x => {
routeData.set(x.src, {client: JSON.parse(JSON.stringify(x)), server: x});
routeData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
});
res();
})
@ -86,7 +49,7 @@
.then(x => {
let redirects = x as Redirect[];
redirects.forEach(x => {
redirectData.set(x.src, {client: JSON.parse(JSON.stringify(x)), server: x});
redirectData[x.src] = {client: JSON.parse(JSON.stringify(x)), server: x};
});
res();
})
@ -94,43 +57,33 @@
});
</script>
<div style="padding:8px;background-color:#bb7900;">
Warning: This is currently still under development and does not update the routes and redirects on the server
</div>
<h2>Routes</h2>
{#await promiseForRoutes}
<div>Loading...</div>
{:then}
<table>
<tr>
<th>Source</th>
<th>Destination</th>
<th>Flags</th>
<th>Active</th>
</tr>
{#each routeSrcs as src (src)}
{@const route = routeData.get(src)}
{#if route}
{#if noCPair(route)}
<tr class="deleted">
<td>{route.server.src}</td>
<td>{route.server.dst}</td>
<td><Flags bind:value={route.flags} editable keys={routeKeys} /></td>
<td><input type="checkbox" bind:checked={route.active} /></td>
</tr>
<thead>
<tr>
<th>Source</th>
<th>Destination</th>
<th>Flags</th>
<th>Active</th>
<th>Option</th>
</tr>
</thead>
<tbody>
{#each routeSrcs as src (src)}
{#if routeData[src]}
<RouteRow bind:route={routeData[src]} />
{:else}
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{@const isCreated = !route.server}
{@const isDeleted = !route.client}
<tr class:created={isCreated} class:modified={isCreated || !routeEqual(route.client, route.server)} class:deleted={isDeleted}>
<td>{route.client.src}</td>
<td>{route.client.dst}</td>
<td><Flags bind:value={route.flags} editable keys={routeKeys} /></td>
<td><input type="checkbox" bind:checked={route.active} /></td>
<td>
{#if !isCreated}
<button on:click={() => resetRoute(i, serverRoute)}>Reset</button>
{/if}
</td>
</tr>
{/if}
{/each}
{/each}
</tbody>
</table>
{:catch err}
<div>{err}</div>
@ -141,27 +94,24 @@
<div>Loading...</div>
{:then}
<table>
<tr>
<th>Source</th>
<th>Destination</th>
<th>Flags</th>
<th>Active</th>
</tr>
{#each clientRedirects as redirect, i (redirect.src)}
{@const serverRedirect = getServerRedirect(redirect.src)}
{@const isNew = serverRedirect == undefined}
<tr class:created={isNew} class:modified={isNew || !redirectEqual(redirect, serverRedirect)}>
<td>{redirect.src}</td>
<td>{redirect.dst}</td>
<td><Flags bind:value={redirect.flags} editable keys={redirectKeys} /></td>
<td><input type="checkbox" bind:checked={redirect.active} /></td>
<td>
{#if !isNew}
<button on:click={() => resetRedirect(i, serverRedirect)}>Reset</button>
{/if}
</td>
<thead>
<tr>
<th>Source</th>
<th>Destination</th>
<th>Flags</th>
<th>Active</th>
<th>Option</th>
</tr>
{/each}
</thead>
<tbody>
{#each redirectSrcs as src (src)}
{#if redirectData[src]}
<RedirectRow bind:redirect={redirectData[src]} />
{:else}
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{/each}
</tbody>
</table>
{:catch err}
<div>{err}</div>
@ -169,12 +119,22 @@
<style lang="scss">
table {
> tr.created {
background-color: #1a5100;
border-collapse: collapse;
border-spacing: 0;
width: 100%;
thead {
background-color: #04aa6d;
}
> tr.modified {
background-color: #515100;
:global(th),
:global(td) {
padding: 11px 8px 11px 8px;
text-align: center;
}
td:nth-child(2n) {
background-color: #38444d;
}
}
</style>