Files
fyp/webpage/src/routes/models/edit/ModelTable.svelte

346 lines
11 KiB
Svelte

<script lang="ts" context="module">
export type Image = {
file_path: string;
mode: number;
status: number;
id: string;
};
</script>
<script lang="ts">
import Tabs from 'src/lib/Tabs.svelte';
import type { Class } from './ModelData.svelte';
import { get, postFormData, rdelete } from 'src/lib/requests.svelte';
import type { Model } from './+page.svelte';
import FileUpload from 'src/lib/FileUpload.svelte';
import MessageSimple from 'src/lib/MessageSimple.svelte';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{reload: void}>();
let selected_class: Class | undefined = $state();
let { classes, model } = $props<{ classes: Class[]; model: Model }>();
let page = $state(0);
let showNext = $state(false);
let image_list = $state<Image[]>([]);
function setActiveClass(c: Class, tb_fn: (name: string) => () => void) {
selected_class = c;
tb_fn(c.name)();
}
$effect(() => {
selected_class = classes[0];
});
async function getList() {
try {
let url = new URLSearchParams();
url.append('id', selected_class?.id ?? '');
url.append('page', `${page}`);
let res = await get('models/data/list?' + url.toString());
showNext = res.showNext;
image_list = res.image_list;
} catch (e) {
console.error('TODO notify user', e);
}
}
$effect(() => {
if (selected_class) {
page = 0;
}
});
$effect(() => {
if (selected_class) {
getList();
}
});
let file: File | undefined = $state();
let uploadImage: MessageSimple;
let uploading = $state(Promise.resolve());
async function uploadZip() {
uploadImage.clear();
if (!file) return;
uploading = new Promise(() => {});
let form = new FormData();
form.append('id', model.id);
form.append('file', file, 'upload.zip');
try {
await postFormData('models/data/class/upload', form);
dispatch('reload');
} catch (e) {
if (e instanceof Response) {
uploadImage.display(await e.json());
} else {
uploadImage.display('');
}
}
uploading = Promise.resolve();
}
function deleteDataPoint(id: string) {
try {
rdelete('models/data/point', { id })
getList()
} catch (e) {
console.error('TODO notify user', e);
}
}
</script>
{#if classes.length == 0}
TODO CREATE TABLE
{:else}
<Tabs active={classes[0]?.name} let:isActive>
<div class="buttons" slot="buttons" let:setActive let:isActive>
<!-- TODO Auto Load 1st -->
<div>
{#each classes as item}
<button
on:click={() => setActiveClass(item, setActive)}
class="tab"
class:selected={isActive(item.name)}
>
{item.name}
{#if model.model_type == 2}
{#if item.status == 1}
<span class="bi bi-book" style="color: orange;" />
{:else if item.status == 2}
<span class="bi bi-book" style="color: green;" />
{:else if item.status == 3}
<span class="bi bi-check" style="color: green;" />
{/if}
{/if}
</button>
{/each}
</div>
<button on:click={() => {
setActive("-----New Class-----")();
selected_class = undefined;
}}>
<span class="bi bi-plus" />
</button>
</div>
{#if selected_class == undefined && isActive('-----New Class-----')}
<div class="content selected">
<h2>
Add New Class
</h2>
<form on:submit|preventDefault={uploadZip}>
<fieldset class="file-upload" >
<label for="file">Data file</label>
<div class="form-msg">
Please provide a file that has the training and testing data<br/>
The file must have 2 folders one with testing images and one with training images. <br/>
Each of the folders will contain the classes of the model. The folders must be the same in testing and training.
The class folders must have the images for the classes.
<pre>
training\
class1\
img1.png
img2.png
img2.png
...
class2\
img1.png
img2.png
img2.png
...
...
testing\
class1\
img1.png
img2.png
img2.png
...
class2\
img1.png
img2.png
img2.png
...
...
</pre>
</div>
<FileUpload replace_slot bind:file={file} accept="application/zip" notExpand >
<img src="/imgs/upload-icon.png" alt="" />
<span>
Upload Zip File
</span>
<div slot="replaced" style="display: inline;">
<img src="/imgs/upload-icon.png" alt="" />
<span>
File selected
</span>
</div>
</FileUpload>
</fieldset>
<MessageSimple bind:this={uploadImage} />
{#if file}
{#await uploading}
<button disabled>
Uploading
</button>
{:then}
<button>
Add
</button>
{/await}
{/if}
</form>
</div>
{/if}
{#if selected_class}
<div class="content selected">
{#if model.model_type == 2}
{#if selected_class?.status == 1}
<h2>
Class to train
</h2>
{:else if selected_class?.status == 2}
<h2>
Class training
</h2>
{:else if selected_class?.status == 3}
<h2>
Class trained
</h2>
{/if}
{/if}
<table>
<thead>
<tr>
<th> File Path </th>
<th> Mode </th>
<th>
<!-- Img -->
</th>
<th>
<!-- Status -->
</th>
<th>
<!-- Remove -->
</th>
</tr>
</thead>
<tbody>
{#each image_list as image}
<tr>
<td>
{#if image.file_path == 'id://'}
Managed
{:else}
{image.file_path}
{/if}
</td>
<td>
{#if image.mode == 2}
Testing
{:else}
Training
{/if}
</td>
<td class="text-center">
{#if image.file_path == 'id://'}
<img
alt=""
src="/api/savedData/{model.id}/data/{image.id}.{model.format}"
height="30px"
width="30px"
style="object-fit: contain;"
/>
{:else}
TODO img {image.file_path}
{/if}
</td>
<td class="text-center">
{#if image.status == 1}
<span class="bi bi-check-circle-fill" style="color: green"></span>
{:else}
<span class="bi bi-exclamation-triangle-fill" style="color: red"></span>
{/if}
</td>
<td style="width: 3ch">
<button class="danger" on:click={() => deleteDataPoint(image.id)}>
<span class="bi bi-trash"></span>
</button>
</td>
</tr>
{/each}
</tbody>
</table>
<div class="flex justify-center align-center">
<div class="grow-1 flex justify-end align-center">
{#if page > 0}
<button on:click={() => (page -= 1)}> Prev </button>
{/if}
</div>
<div style="padding: 10px;">
{page}
</div>
<div class="grow-1 flex justify-start align-center">
{#if showNext}
<button on:click={() => (page += 1)}> Next </button>
{/if}
</div>
</div>
</div>
{/if}
</Tabs>
{/if}
<style lang="scss">
.buttons {
width: 100%;
display: flex;
justify-content: space-between;
&>button {
margin: 3px 5px;
}
}
table {
width: 100%;
box-shadow: 0 2px 8px 1px #66666622;
border-radius: 10px;
border-collapse: collapse;
overflow: hidden;
}
table thead {
background: #60606022;
}
table tr td,
table tr th {
border-left: 1px solid #22222244;
padding: 15px;
}
table tr td:first-child,
table tr th:first-child {
border-left: none;
}
table tr td button,
table tr td .button {
padding: 5px 10px;
box-shadow: 0 2px 5px 1px #66666655;
}
</style>