diff --git a/src/stores/target.ts b/src/stores/target.ts index 567caba..aaada8c 100644 --- a/src/stores/target.ts +++ b/src/stores/target.ts @@ -4,3 +4,29 @@ import type {Redirect, Route} from "../types/target"; export const routesTable = writable<{[key: string]: CSPair}>({}); export const redirectsTable = writable<{[key: string]: CSPair}>({}); + +export interface Pair { + a: A; + b: B; +} + +function getTableArray(table: {[key: string]: CSPair}, keys: Array): Array>> { + return keys.map(x => ({a: x, b: table[x]})); +} + +export interface CountStats { + created: number; + modified: number; + removed: number; +} + +export function tableCountStats(table: {[key: string]: CSPair}, keys: Array, equality: (a: T, b: T) => boolean): CountStats { + let list = getTableArray(table, keys) + .map(x => x.b) + .filter(x => x.client != null || x.server != null); + return { + created: list.filter(x => x.server == null).length, + modified: list.filter(x => x.server != null && x.client != null && !equality(x.client, x.server)).length, + removed: list.filter(x => x.client == null).length, + }; +} diff --git a/src/views/RedirectsView.svelte b/src/views/RedirectsView.svelte index da5da95..5b2768e 100644 --- a/src/views/RedirectsView.svelte +++ b/src/views/RedirectsView.svelte @@ -5,7 +5,7 @@ import type {CSPair} from "../types/cspair"; import {type Redirect, redirectEqual} from "../types/target"; import {domainOption} from "../stores/domain-option"; - import {redirectsTable} from "../stores/target"; + import {redirectsTable, type CountStats, tableCountStats} from "../stores/target"; const apiViolet = import.meta.env.VITE_API_VIOLET; @@ -17,6 +17,10 @@ .filter(x => domainFilter(x, $domainOption)) .sort((a, b) => a.localeCompare(b)); + let rowStats: CountStats = {created: 0, modified: 0, removed: 0}; + + $: rowStats = tableCountStats($redirectsTable, tableKeys, redirectEqual); + function domainFilter(src: string, domain: string) { if (domain == "*") return true; let n = src.indexOf("/"); @@ -141,7 +145,16 @@ @@ -187,19 +200,12 @@ height: 50px; background-color: #2c2c2c; box-shadow: 0 -4px 8px #0003, 0 -6px 20px #00000030; + display: flex; + flex-direction: row; - button { - background-color: #04aa6d; - border: none; - box-shadow: none; - box-sizing: border-box; - color: black; - cursor: pointer; - font-size: 20px; - font-weight: 700; - line-height: 24px; - height: 50px; - padding: 4px 16px; + .meta-info { + line-height: 50px; + padding-inline: 16px; } } diff --git a/src/views/RoutesView.svelte b/src/views/RoutesView.svelte index ca9fbce..2686ed6 100644 --- a/src/views/RoutesView.svelte +++ b/src/views/RoutesView.svelte @@ -5,7 +5,7 @@ import type {CSPair} from "../types/cspair"; import {type Route, routeEqual} from "../types/target"; import {domainOption} from "../stores/domain-option"; - import {routesTable} from "../stores/target"; + import {routesTable, type CountStats, tableCountStats} from "../stores/target"; const apiViolet = import.meta.env.VITE_API_VIOLET; @@ -17,6 +17,10 @@ .filter(x => domainFilter(x, $domainOption)) .sort((a, b) => a.localeCompare(b)); + let rowStats: CountStats = {created: 0, modified: 0, removed: 0}; + + $: rowStats = tableCountStats($routesTable, tableKeys, routeEqual); + function domainFilter(src: string, domain: string) { if (domain == "*") return true; let n = src.indexOf("/"); @@ -141,6 +145,15 @@ @@ -186,5 +199,12 @@ height: 50px; background-color: #2c2c2c; box-shadow: 0 -4px 8px #0003, 0 -6px 20px #00000030; + display: flex; + flex-direction: row; + + .meta-info { + line-height: 50px; + padding-inline: 16px; + } }