Add string based sorting and fix issues with target management views

This commit is contained in:
Melon 2024-06-23 15:45:22 +01:00
parent 6adc2b11cc
commit 9b72a57ff0
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
5 changed files with 87 additions and 44 deletions

View File

@ -28,6 +28,10 @@ export class RestTable<T extends object> implements IPromiseLike<RestTable<T>> {
return this.errorReason;
}
makeItem(x: T): RestItem<T> {
return new RestItem(this, x);
}
reload() {
(async () => {
try {
@ -37,7 +41,7 @@ export class RestTable<T extends object> implements IPromiseLike<RestTable<T>> {
if (f.status != 200) throw new Error("Unexpected status code: " + f.status);
let fJson = await f.json();
let rows = fJson as T[];
this.rows = rows.map(x => new RestItem(this, x));
this.rows = rows.map(x => this.makeItem(x));
this.loading = false;
this.updateSubs();
} catch (err) {
@ -82,10 +86,25 @@ export class RestItem<T extends object> implements IPromiseLike<RestItem<T>> {
this.subs.forEach(x => x(this));
}
setLoading(loading: boolean) {
this.loading = loading;
this.updateSubs();
}
setErrorReason(errorReason: string) {
this.errorReason = errorReason;
}
key(): string {
return this.table.keyFunc(this.data);
}
keyUrl(): string {
let keyPath = "/" + this.key();
if (keyPath === "/") keyPath = "";
return this.table.apiUrl + keyPath;
}
isLoading(): boolean {
return this.loading;
}
@ -94,40 +113,36 @@ export class RestItem<T extends object> implements IPromiseLike<RestItem<T>> {
return this.errorReason;
}
update(data: T): Promise<void> {
this.loading = true;
this.updateSubs();
return LOGIN.clientRequest(this.table.apiUrl + "/" + this.key(), {
method: "PUT",
body: JSON.stringify(this.data),
})
.then(x => {
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
this.data = data;
this.loading = false;
this.updateSubs();
})
.catch(x => {
this.loading = false;
this.updateSubs();
});
async update(data: T, options?: RequestInit): Promise<void> {
this.setLoading(true);
if (!options)
options = {
method: "PUT",
body: JSON.stringify(this.data),
};
try {
const x = await LOGIN.clientRequest(this.keyUrl(), options);
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
this.data = data;
this.setLoading(false);
} catch (err) {
this.setErrorReason("Failed to update item " + this.key());
this.setLoading(false);
}
}
remove(): Promise<void> {
this.loading = true;
this.updateSubs();
return LOGIN.clientRequest(this.table.apiUrl + "/" + this.key(), {method: "DELETE"})
.then(x => {
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
this.table.rows = this.table.rows.filter(x => this.table.keyFunc(x.data) !== this.key());
this.loading = false;
this.updateSubs();
})
.catch(x => {
this.errorReason = "Failed to remove item " + this.table.keyFunc(this.data);
this.loading = false;
this.updateSubs();
});
async remove(options?: RequestInit): Promise<void> {
this.setLoading(true);
if (!options) options = {method: "DELETE"};
try {
const x = await LOGIN.clientRequest(this.keyUrl(), options);
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
this.table.rows = this.table.rows.filter(x_1 => this.table.keyFunc(x_1.data) !== this.key());
this.setLoading(false);
} catch (err) {
this.setErrorReason("Failed to remove item " + this.key());
this.setLoading(false);
}
}
subscribe(run: Subscriber<RestItem<T>>): Unsubscriber {

29
src/utils/target-table.ts Normal file
View File

@ -0,0 +1,29 @@
import {RestItem, RestTable} from "./rest-table";
interface Target {
src: string;
}
export class TargetTable<T extends Target> extends RestTable<T> {
constructor(apiUrl: string, keyFunc: (item: T) => string) {
super(apiUrl, keyFunc);
}
makeItem(x: T): RestItem<T> {
return new TargetItem(this, x);
}
}
export class TargetItem<T extends Target> extends RestItem<T> {
constructor(table: TargetTable<T>, data: T) {
super(table, data);
}
update(data: T): Promise<void> {
return super.update(data, {method: "POST", body: JSON.stringify({...data, src: data.src})});
}
remove(): Promise<void> {
return super.remove({method: "DELETE", body: JSON.stringify({src: this.data.src})});
}
}

View File

@ -1,9 +1,7 @@
<script lang="ts">
import PromiseLike from "../components/PromiseLike.svelte";
import PromiseTable from "../components/PromiseTable.svelte";
import X from "../icons/X.svelte";
import {domainOption} from "../stores/domain-option";
import {LOGIN} from "../utils/login";
import {RestItem, RestTable} from "../utils/rest-table";
const apiOrchid = import.meta.env.VITE_API_ORCHID;

View File

@ -15,8 +15,8 @@
branches: string[];
}
function rowsDomainFilter(rows: RestItem<Site>[], domain: string): RestItem<Site>[] {
return rows.filter(x => domainFilter(x.data.domain, domain));
function rowOrdering(rows: RestItem<Site>[], domain: string): RestItem<Site>[] {
return rows.filter(x => domainFilter(x.data.domain, domain)).sort((a, b) => a.data.domain.localeCompare(b.data.domain));
}
function domainFilter(src: string, domain: string) {
@ -64,7 +64,7 @@
</tr>
<svelte:fragment slot="rows" let:value>
{#each rowsDomainFilter(value.rows, $domainOption) as item}
{#each rowOrdering(value.rows, $domainOption) as item}
<PromiseLike value={item}>
<tr slot="loading" class="empty-row">
<td colspan="100">
@ -105,7 +105,6 @@
grid-template-columns: repeat(2, auto);
justify-content: left;
align-content: center;
gap: 8px;
div a {
display: block;

View File

@ -5,8 +5,10 @@
</script>
<script lang="ts">
import {TargetTable} from "../utils/target-table";
import {domainOption} from "../stores/domain-option";
import {RestItem, RestTable} from "../utils/rest-table";
import {RestItem} from "../utils/rest-table";
import PromiseTable from "../components/PromiseTable.svelte";
import PromiseLike from "../components/PromiseLike.svelte";
@ -14,10 +16,10 @@
export let apiUrl: string;
let table = new RestTable<T>(apiUrl, (item: T) => item.src);
let table = new TargetTable<T>(apiUrl, (item: T) => item.src);
function rowsDomainFilter(rows: RestItem<T>[], domain: string): RestItem<T>[] {
return rows.filter(x => domainFilter(x.data, domain));
function rowOrdering(rows: RestItem<T>[], domain: string): RestItem<T>[] {
return rows.filter(x => domainFilter(x.data, domain)).sort((a, b) => a.data.src.localeCompare(b.data.src));
}
function domainFilter(item: T, domain: string): boolean {
@ -41,7 +43,7 @@
</tr>
<svelte:fragment slot="rows" let:value>
{#each rowsDomainFilter(value.rows, $domainOption) as item}
{#each rowOrdering(value.rows, $domainOption) as item}
<PromiseLike value={item}>
<tr slot="loading" class="empty-row">
<td colspan="100">