multiple fixes
This commit is contained in:
parent
0ac6ac8dce
commit
0c0d16c846
@ -136,17 +136,16 @@ func processZipFile(c *Context, model *BaseModel) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if paths[0] != "training" {
|
if paths[0] == "training" {
|
||||||
training = InsertIfNotPresent(training, paths[1])
|
training = InsertIfNotPresent(training, paths[1])
|
||||||
} else if paths[0] != "testing" {
|
} else if paths[0] == "testing" {
|
||||||
testing = InsertIfNotPresent(testing, paths[1])
|
testing = InsertIfNotPresent(testing, paths[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(testing, training) {
|
if !reflect.DeepEqual(testing, training) {
|
||||||
c.Logger.Info("Diff", "testing", testing, "training", training)
|
c.Logger.Warn("Diff", "testing", testing, "training", training)
|
||||||
failed("Testing and Training datesets are diferent")
|
c.Logger.Warn("Testing and traing datasets differ")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base_path := path.Join("savedData", model.Id, "data")
|
base_path := path.Join("savedData", model.Id, "data")
|
||||||
|
@ -37,7 +37,7 @@ func ReadJPG(scope *op.Scope, imagePath string, channels int64) *image.Image {
|
|||||||
return image.Scale(0, 255)
|
return image.Scale(0, 255)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runModelNormal(base BasePack, model *BaseModel, def_id string, inputImage *tf.Tensor) (order int, confidence float32, err error) {
|
func runModelNormal(model *BaseModel, def_id string, inputImage *tf.Tensor) (order int, confidence float32, err error) {
|
||||||
order = 0
|
order = 0
|
||||||
err = nil
|
err = nil
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ func ClassifyTask(base BasePack, task Task) (err error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
base.GetLogger().Info("Running model normal", "model", model.Id, "def", def_id)
|
base.GetLogger().Info("Running model normal", "model", model.Id, "def", def_id)
|
||||||
vi, confidence, err = runModelNormal(base, model, def_id, inputImage)
|
vi, confidence, err = runModelNormal(model, def_id, inputImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to run model")
|
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to run model")
|
||||||
return
|
return
|
||||||
|
@ -1298,12 +1298,6 @@ func generateExpandableDefinition(c BasePack, model *BaseModel, target_accuracy
|
|||||||
|
|
||||||
order++
|
order++
|
||||||
|
|
||||||
// handle the errors inside the pervious if block
|
|
||||||
if err != nil {
|
|
||||||
failed()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the blocks
|
// Create the blocks
|
||||||
loop := int((math.Log(float64(model.Width)) / math.Log(float64(10))))
|
loop := int((math.Log(float64(model.Width)) / math.Log(float64(10))))
|
||||||
|
|
||||||
|
@ -27,5 +27,11 @@ module.exports = {
|
|||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
rules: {
|
||||||
|
'svelte/no-at-html-tags': 'off',
|
||||||
|
|
||||||
|
// TODO remove this
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
class="icon"
|
class="icon"
|
||||||
class:adapt={replace_slot && file && !notExpand}
|
class:adapt={replace_slot && file && !notExpand}
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => fileInput.click()}
|
onclick={() => fileInput.click()}
|
||||||
>
|
>
|
||||||
{#if replace_slot && file}
|
{#if replace_slot && file}
|
||||||
<slot name="replaced" {file}>
|
<slot name="replaced" {file}>
|
||||||
@ -54,6 +54,6 @@
|
|||||||
required
|
required
|
||||||
{accept}
|
{accept}
|
||||||
bind:this={fileInput}
|
bind:this={fileInput}
|
||||||
on:change={onChange}
|
onchange={onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
<script context="module" lang="ts">
|
|
||||||
export type DisplayFn = (
|
|
||||||
msg: string,
|
|
||||||
options?: {
|
|
||||||
type?: 'error' | 'success';
|
|
||||||
timeToShow?: number;
|
|
||||||
}
|
|
||||||
) => void;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
let message = $state<string | undefined>(undefined);
|
|
||||||
let type = $state<'error' | 'success'>('error');
|
|
||||||
|
|
||||||
let timeout: number | undefined = undefined;
|
|
||||||
|
|
||||||
export function clear() {
|
|
||||||
if (timeout) clearTimeout(timeout);
|
|
||||||
message = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function display(
|
|
||||||
msg: string,
|
|
||||||
options?: {
|
|
||||||
type?: 'error' | 'success';
|
|
||||||
timeToShow?: number;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (timeout) clearTimeout(timeout);
|
|
||||||
|
|
||||||
if (!msg) {
|
|
||||||
message = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { type: l_type, timeToShow } = options ?? { type: 'error', timeToShow: undefined };
|
|
||||||
|
|
||||||
if (l_type) {
|
|
||||||
type = l_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = msg;
|
|
||||||
|
|
||||||
if (timeToShow) {
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
message = undefined;
|
|
||||||
timeout = undefined;
|
|
||||||
}, timeToShow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if message}
|
|
||||||
<div class="form-msg {type}">
|
|
||||||
{message}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let { title } = $props<{ title: string }>();
|
let { title }: { title: string } = $props();
|
||||||
|
|
||||||
let isHovered = $state(false);
|
let isHovered = $state(false);
|
||||||
let x = $state(0);
|
let x = $state(0);
|
||||||
@ -30,10 +30,10 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={div}
|
bind:this={div}
|
||||||
on:mouseover={mouseOver}
|
onmouseover={mouseOver}
|
||||||
on:mouseleave={mouseLeave}
|
onmouseleave={mouseLeave}
|
||||||
on:mousemove={mouseMove}
|
onmousemove={mouseMove}
|
||||||
on:focus={focus}
|
onfocus={focus}
|
||||||
role="tooltip"
|
role="tooltip"
|
||||||
class="tooltipContainer"
|
class="tooltipContainer"
|
||||||
>
|
>
|
||||||
|
6
webpage/src/lib/utils.ts
Normal file
6
webpage/src/lib/utils.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export function preventDefault(fn: any) {
|
||||||
|
return function (event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
fn.call(this, event);
|
||||||
|
};
|
||||||
|
}
|
@ -12,7 +12,7 @@
|
|||||||
let width = $state(0);
|
let width = $state(0);
|
||||||
let height = $state(0);
|
let height = $state(0);
|
||||||
|
|
||||||
function drag(simulation: any) {
|
function drag(simulation: d3.Simulation<d3.HierarchyNode<Base>, undefined>) {
|
||||||
function dragstarted(event: any, d: any) {
|
function dragstarted(event: any, d: any) {
|
||||||
if (!event.active) simulation.alphaTarget(0.3).restart();
|
if (!event.active) simulation.alphaTarget(0.3).restart();
|
||||||
d.fx = d.x;
|
d.fx = d.x;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
import { userStore } from '../UserStore.svelte';
|
import { userStore } from '../UserStore.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let submitted = $state(false);
|
let submitted = $state(false);
|
||||||
|
|
||||||
@ -39,7 +40,7 @@
|
|||||||
<div class="login-page">
|
<div class="login-page">
|
||||||
<div>
|
<div>
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<form on:submit|preventDefault={onSubmit} class:submitted>
|
<form onsubmit={preventDefault(onSubmit)} class:submitted>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="email">Email</label>
|
<label for="email">Email</label>
|
||||||
<input type="email" required name="email" bind:value={loginData.email} />
|
<input type="email" required name="email" bind:value={loginData.email} />
|
||||||
|
@ -85,11 +85,4 @@
|
|||||||
.list-header .expand {
|
.list-header .expand {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-header .button,
|
|
||||||
.list-header button {
|
|
||||||
padding: 10px 10px;
|
|
||||||
height: calc(100% - 20px);
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
|
||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let submitted = $state(false);
|
let submitted = $state(false);
|
||||||
|
|
||||||
@ -44,7 +45,7 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
<h1>Create new Model</h1>
|
<h1>Create new Model</h1>
|
||||||
<form class:submitted on:submit|preventDefault={onSubmit}>
|
<form class:submitted onsubmit={preventDefault(onSubmit)}>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<input id="name" name="name" required bind:value={data.name} />
|
<input id="name" name="name" required bind:value={data.name} />
|
||||||
|
@ -30,18 +30,18 @@
|
|||||||
import BaseModelInfo from './BaseModelInfo.svelte';
|
import BaseModelInfo from './BaseModelInfo.svelte';
|
||||||
import DeleteModel from './DeleteModel.svelte';
|
import DeleteModel from './DeleteModel.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { get, rdelete } from 'src/lib/requests.svelte';
|
import { get, rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||||
import MessageSimple from '$lib/MessageSimple.svelte';
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
import ModelData from './ModelData.svelte';
|
import ModelData from './ModelData.svelte';
|
||||||
import DeleteZip from './DeleteZip.svelte';
|
import DeleteZip from './DeleteZip.svelte';
|
||||||
import RunModel from './RunModel.svelte';
|
import RunModel from './RunModel.svelte';
|
||||||
|
|
||||||
import Tabs from 'src/lib/Tabs.svelte';
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
import TasksDataPage from './TasksDataPage.svelte';
|
import TasksDataPage from './TasksDataPage.svelte';
|
||||||
import ModelDataPage from './ModelDataPage.svelte';
|
import ModelDataPage from './ModelDataPage.svelte';
|
||||||
|
|
||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
|
||||||
let model: Promise<Model> = $state(new Promise(() => {}));
|
let model: Promise<Model> = $state(new Promise(() => {}));
|
||||||
let _model: Model | undefined = $state(undefined);
|
let _model: Model | undefined = $state(undefined);
|
||||||
@ -92,10 +92,7 @@
|
|||||||
getModel();
|
getModel();
|
||||||
});
|
});
|
||||||
|
|
||||||
let resetMessages: MessageSimple;
|
|
||||||
async function resetModel() {
|
async function resetModel() {
|
||||||
resetMessages.display('');
|
|
||||||
|
|
||||||
let _model = await model;
|
let _model = await model;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -105,11 +102,7 @@
|
|||||||
|
|
||||||
getModel();
|
getModel();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not reset model!');
|
||||||
resetMessages.display(await e.json());
|
|
||||||
} else {
|
|
||||||
resetMessages.display('Could not reset model!');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +140,8 @@
|
|||||||
<div slot="buttons" let:setActive let:isActive>
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
on:click|preventDefault={setActive('model')}
|
type="button"
|
||||||
|
onclick={setActive('model')}
|
||||||
class:selected={isActive('model')}
|
class:selected={isActive('model')}
|
||||||
>
|
>
|
||||||
Model
|
Model
|
||||||
@ -155,7 +149,8 @@
|
|||||||
{#if _model && [2, 3, 4, 5, 6, 7, -6, -7].includes(_model.status)}
|
{#if _model && [2, 3, 4, 5, 6, 7, -6, -7].includes(_model.status)}
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
on:click|preventDefault={setActive('model-data')}
|
type="button"
|
||||||
|
onclick={setActive('model-data')}
|
||||||
class:selected={isActive('model-data')}
|
class:selected={isActive('model-data')}
|
||||||
>
|
>
|
||||||
Model Data
|
Model Data
|
||||||
@ -164,7 +159,8 @@
|
|||||||
{#if _model && [5, 6, 7, -6, -7].includes(_model.status)}
|
{#if _model && [5, 6, 7, -6, -7].includes(_model.status)}
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
on:click|preventDefault={setActive('tasks')}
|
type="button"
|
||||||
|
onclick={setActive('tasks')}
|
||||||
class:selected={isActive('tasks')}
|
class:selected={isActive('tasks')}
|
||||||
>
|
>
|
||||||
Tasks
|
Tasks
|
||||||
@ -172,7 +168,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if _model}
|
{#if _model}
|
||||||
<ModelDataPage model={_model} on:reload={getModel} active={isActive('model-data')} />
|
<ModelDataPage model={_model} onreload={getModel} active={isActive('model-data')} />
|
||||||
<TasksDataPage model={_model} active={isActive('tasks')} />
|
<TasksDataPage model={_model} active={isActive('tasks')} />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="content" class:selected={isActive('model')}>
|
<div class="content" class:selected={isActive('model')}>
|
||||||
@ -200,12 +196,12 @@
|
|||||||
<!-- PRE TRAINING STATUS -->
|
<!-- PRE TRAINING STATUS -->
|
||||||
{:else if m.status == 2}
|
{:else if m.status == 2}
|
||||||
<BaseModelInfo model={m} />
|
<BaseModelInfo model={m} />
|
||||||
<ModelData model={m} on:reload={getModel} />
|
<ModelData model={m} onreload={getModel} />
|
||||||
<!-- {{ template "train-model-card" . }} -->
|
<!-- {{ template "train-model-card" . }} -->
|
||||||
<DeleteModel model={m} />
|
<DeleteModel model={m} />
|
||||||
{:else if m.status == -2}
|
{:else if m.status == -2}
|
||||||
<BaseModelInfo model={m} />
|
<BaseModelInfo model={m} />
|
||||||
<DeleteZip model={m} on:reload={getModel} />
|
<DeleteZip model={m} onreload={getModel} />
|
||||||
<DeleteModel model={m} />
|
<DeleteModel model={m} />
|
||||||
{:else if m.status == 3}
|
{:else if m.status == 3}
|
||||||
<BaseModelInfo model={m} />
|
<BaseModelInfo model={m} />
|
||||||
@ -215,10 +211,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if m.status == -3 || m.status == -4}
|
{:else if m.status == -3 || m.status == -4}
|
||||||
<BaseModelInfo model={m} />
|
<BaseModelInfo model={m} />
|
||||||
<form on:submit|preventDefault={resetModel}>
|
<form onsubmit={preventDefault(resetModel)}>
|
||||||
Failed Prepare for training.<br />
|
Failed Prepare for training.<br />
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<MessageSimple bind:this={resetMessages} />
|
|
||||||
<button class="danger"> Try Again </button>
|
<button class="danger"> Try Again </button>
|
||||||
</form>
|
</form>
|
||||||
<DeleteModel model={m} />
|
<DeleteModel model={m} />
|
||||||
@ -337,7 +332,7 @@
|
|||||||
<div class="card">Model expading... Processing ZIP file</div>
|
<div class="card">Model expading... Processing ZIP file</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if m.status == -6}
|
{#if m.status == -6}
|
||||||
<DeleteZip model={m} on:reload={getModel} expand />
|
<DeleteZip model={m} onreload={getModel} expand />
|
||||||
{/if}
|
{/if}
|
||||||
{#if m.status == -7}
|
{#if m.status == -7}
|
||||||
<form>
|
<form>
|
||||||
@ -346,7 +341,7 @@
|
|||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{#if m.model_type == 2}
|
{#if m.model_type == 2}
|
||||||
<ModelData simple model={m} on:reload={getModel} />
|
<ModelData simple model={m} onreload={getModel} />
|
||||||
{/if}
|
{/if}
|
||||||
<DeleteModel model={m} />
|
<DeleteModel model={m} />
|
||||||
{:else}
|
{:else}
|
||||||
@ -383,10 +378,4 @@
|
|||||||
table tr th:first-child {
|
table tr th:first-child {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table tr td button,
|
|
||||||
table tr td .button {
|
|
||||||
padding: 5px 10px;
|
|
||||||
box-shadow: 0 2px 5px 1px #66666655;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
let { model } = $props<{ model: Model }>();
|
let { model }: { model: Model } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card model-card">
|
<div class="card model-card">
|
||||||
|
@ -1,39 +1,31 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import { rdelete } from '$lib/requests.svelte';
|
import { rdelete, showMessage } from '$lib/requests.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
|
||||||
let { model } = $props<{ model: Model }>();
|
let { model }: { model: Model } = $props();
|
||||||
let name: string = $state('');
|
let name: string = $state('');
|
||||||
let submmited: boolean = $state(false);
|
let submmited: boolean = $state(false);
|
||||||
|
|
||||||
let messageSimple: MessageSimple;
|
|
||||||
|
|
||||||
async function deleteModel() {
|
async function deleteModel() {
|
||||||
submmited = true;
|
submmited = true;
|
||||||
messageSimple.display('');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await rdelete('models/delete', { id: model.id, name });
|
await rdelete('models/delete', { id: model.id, name });
|
||||||
goto('/models');
|
goto('/models');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not delete the model');
|
||||||
messageSimple.display(await e.json());
|
|
||||||
} else {
|
|
||||||
messageSimple.display('Could not delete the model');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form on:submit|preventDefault={deleteModel} class:submmited class="danger-bg">
|
<form onsubmit={deleteModel} class:submmited class="danger-bg">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="name">
|
<label for="name">
|
||||||
To delete this model please type "{model.name}":
|
To delete this model please type "{model.name}":
|
||||||
</label>
|
</label>
|
||||||
<input name="name" id="name" required bind:value={name} />
|
<input name="name" id="name" required bind:value={name} />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={messageSimple} />
|
|
||||||
<button class="danger"> Delete </button>
|
<button class="danger"> Delete </button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,32 +1,30 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { rdelete } from 'src/lib/requests.svelte';
|
import { rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let message: MessageSimple;
|
let {
|
||||||
|
model,
|
||||||
let { model, expand } = $props<{ model: Model; expand?: boolean }>();
|
expand,
|
||||||
|
onreload = () => {}
|
||||||
const dispatch = createEventDispatcher<{ reload: void }>();
|
}: {
|
||||||
|
model: Model;
|
||||||
|
expand?: boolean;
|
||||||
|
onreload?: () => void;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
async function deleteZip() {
|
async function deleteZip() {
|
||||||
message.clear();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await rdelete('models/data/delete-zip-file', { id: model.id });
|
await rdelete('models/data/delete-zip-file', { id: model.id });
|
||||||
dispatch('reload');
|
onreload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not delete the zip file');
|
||||||
message.display(await e.json());
|
|
||||||
} else {
|
|
||||||
message.display('Could not delete the zip file');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form on:submit|preventDefault={deleteZip}>
|
<form onsubmit={preventDefault(deleteZip)}>
|
||||||
{#if expand}
|
{#if expand}
|
||||||
Failed to proccess the zip file.<br />
|
Failed to proccess the zip file.<br />
|
||||||
Delete file and upload a correct version do add more classes.<br />
|
Delete file and upload a correct version do add more classes.<br />
|
||||||
@ -37,6 +35,5 @@
|
|||||||
<br />
|
<br />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<MessageSimple bind:this={message} />
|
|
||||||
<button class="danger"> Delete Zip File </button>
|
<button class="danger"> Delete Zip File </button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,38 +1,29 @@
|
|||||||
<script lang="ts" context="module">
|
|
||||||
export type Class = {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
status: number;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import FileUpload from 'src/lib/FileUpload.svelte';
|
import FileUpload from 'src/lib/FileUpload.svelte';
|
||||||
import Tabs from 'src/lib/Tabs.svelte';
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import { postFormData, get } from 'src/lib/requests.svelte';
|
import type { Class } from './types';
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
import { postFormData, get, showMessage } from 'src/lib/requests.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import ModelTable from './ModelTable.svelte';
|
import ModelTable from './ModelTable.svelte';
|
||||||
import TrainModel from './TrainModel.svelte';
|
import TrainModel from './TrainModel.svelte';
|
||||||
import ZipStructure from './ZipStructure.svelte';
|
import ZipStructure from './ZipStructure.svelte';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let { model, simple } = $props<{ model: Model; simple?: boolean }>();
|
let {
|
||||||
|
model,
|
||||||
|
simple,
|
||||||
|
onreload = () => {}
|
||||||
|
}: { model: Model; simple?: boolean; onreload?: () => void } = $props();
|
||||||
|
|
||||||
let classes: Class[] = $state([]);
|
let classes: Class[] = $state([]);
|
||||||
let has_data: boolean = $state(false);
|
let has_data: boolean = $state(false);
|
||||||
|
|
||||||
let file: File | undefined = $state();
|
let file: File | undefined = $state();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
|
||||||
reload: void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
let uploading: Promise<void> = $state(Promise.resolve());
|
let uploading: Promise<void> = $state(Promise.resolve());
|
||||||
let numberOfInvalidImages = $state(0);
|
let numberOfInvalidImages = $state(0);
|
||||||
|
|
||||||
let uploadImage: MessageSimple;
|
|
||||||
|
|
||||||
async function uploadZip() {
|
async function uploadZip() {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
@ -44,13 +35,9 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await postFormData('models/data/upload', form);
|
await postFormData('models/data/upload', form);
|
||||||
dispatch('reload');
|
onreload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not upload data');
|
||||||
uploadImage.display(await e.json());
|
|
||||||
} else {
|
|
||||||
uploadImage.display('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uploading = Promise.resolve();
|
uploading = Promise.resolve();
|
||||||
@ -67,8 +54,8 @@
|
|||||||
classes = data.classes;
|
classes = data.classes;
|
||||||
numberOfInvalidImages = data.number_of_invalid_images;
|
numberOfInvalidImages = data.number_of_invalid_images;
|
||||||
has_data = data.has_data;
|
has_data = data.has_data;
|
||||||
} catch {
|
} catch (e) {
|
||||||
return;
|
showMessage(e, notificationStore, 'Could not get information on classes');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -80,22 +67,22 @@
|
|||||||
<p>You need to upload data so the model can train.</p>
|
<p>You need to upload data so the model can train.</p>
|
||||||
<Tabs active="upload" let:isActive>
|
<Tabs active="upload" let:isActive>
|
||||||
<div slot="buttons" let:setActive let:isActive>
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
<button class="tab" class:selected={isActive('upload')} on:click={setActive('upload')}>
|
<button class="tab" class:selected={isActive('upload')} onclick={setActive('upload')}>
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
class:selected={isActive('create-class')}
|
class:selected={isActive('create-class')}
|
||||||
on:click={setActive('create-class')}
|
onclick={setActive('create-class')}
|
||||||
>
|
>
|
||||||
Create Class
|
Create Class
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" class:selected={isActive('api')} on:click={setActive('api')}>
|
<button class="tab" class:selected={isActive('api')} onclick={setActive('api')}>
|
||||||
Api
|
Api
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('upload')}>
|
<div class="content" class:selected={isActive('upload')}>
|
||||||
<form on:submit|preventDefault={uploadZip}>
|
<form onsubmit={preventDefault(uploadZip)}>
|
||||||
<fieldset class="file-upload">
|
<fieldset class="file-upload">
|
||||||
<label for="file">Data file</label>
|
<label for="file">Data file</label>
|
||||||
<div class="form-msg">
|
<div class="form-msg">
|
||||||
@ -115,7 +102,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={uploadImage} />
|
|
||||||
{#if file}
|
{#if file}
|
||||||
{#await uploading}
|
{#await uploading}
|
||||||
<button disabled> Uploading </button>
|
<button disabled> Uploading </button>
|
||||||
@ -126,7 +112,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('create-class')}>
|
<div class="content" class:selected={isActive('create-class')}>
|
||||||
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
<ModelTable {classes} {model} {onreload} />
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('api')}>TODO</div>
|
<div class="content" class:selected={isActive('api')}>TODO</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
@ -139,33 +125,11 @@
|
|||||||
These images will be delete when the model trains.
|
These images will be delete when the model trains.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<Tabs active="create-class" let:isActive>
|
<ModelTable {classes} {model} {onreload} />
|
||||||
<div slot="buttons" let:setActive let:isActive>
|
|
||||||
<button
|
|
||||||
class="tab"
|
|
||||||
class:selected={isActive('create-class')}
|
|
||||||
on:click={setActive('create-class')}
|
|
||||||
>
|
|
||||||
Create Class
|
|
||||||
</button>
|
|
||||||
<button class="tab" class:selected={isActive('api')} on:click={setActive('api')}>
|
|
||||||
Api
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="content" class:selected={isActive('create-class')}>
|
|
||||||
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
|
||||||
</div>
|
|
||||||
<div class="content" class:selected={isActive('api')}>TODO</div>
|
|
||||||
</Tabs>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if classes.some((item) => item.status == 1) && ![-6, 6].includes(model.status)}
|
{#if classes.some((item) => item.status == 1) && ![-6, 6].includes(model.status)}
|
||||||
<TrainModel
|
<TrainModel number_of_invalid_images={numberOfInvalidImages} {model} {has_data} {onreload} />
|
||||||
number_of_invalid_images={numberOfInvalidImages}
|
|
||||||
{model}
|
|
||||||
{has_data}
|
|
||||||
on:reload={() => dispatch('reload')}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import ModelData from './ModelData.svelte';
|
import ModelData from './ModelData.svelte';
|
||||||
import { post, showMessage } from 'src/lib/requests.svelte';
|
import { post, showMessage } from 'src/lib/requests.svelte';
|
||||||
@ -7,9 +6,11 @@
|
|||||||
import type { ModelStats } from './types';
|
import type { ModelStats } from './types';
|
||||||
import DeleteZip from './DeleteZip.svelte';
|
import DeleteZip from './DeleteZip.svelte';
|
||||||
|
|
||||||
let { model, active }: { model: Model; active?: boolean } = $props();
|
let {
|
||||||
|
model,
|
||||||
const dispatch = createEventDispatcher<{ reload: void }>();
|
active,
|
||||||
|
onreload = () => {}
|
||||||
|
}: { model: Model; active?: boolean; onreload?: () => void } = $props();
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (active) getData();
|
if (active) getData();
|
||||||
@ -34,14 +35,14 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if [-6, -2].includes(model.status)}
|
{#if [-6, -2].includes(model.status)}
|
||||||
<DeleteZip {model} on:reload={() => dispatch('reload')} expand />
|
<DeleteZip {model} {onreload} expand />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<ModelData
|
<ModelData
|
||||||
{model}
|
{model}
|
||||||
on:reload={() => {
|
onreload={() => {
|
||||||
getData();
|
getData();
|
||||||
dispatch('reload');
|
onreload();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div><canvas bind:this={ctx} /></div>
|
<div><canvas bind:this={ctx}></canvas></div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
canvas {
|
canvas {
|
||||||
|
@ -1,33 +1,24 @@
|
|||||||
<script lang="ts" context="module">
|
|
||||||
export type Image = {
|
|
||||||
file_path: string;
|
|
||||||
mode: number;
|
|
||||||
status: number;
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Tabs from 'src/lib/Tabs.svelte';
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
import type { Class } from './ModelData.svelte';
|
import type { Class, Image } from './types';
|
||||||
import { post, postFormData, rdelete, showMessage } from 'src/lib/requests.svelte';
|
import { post, postFormData, rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import FileUpload from 'src/lib/FileUpload.svelte';
|
import FileUpload from 'src/lib/FileUpload.svelte';
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import ZipStructure from './ZipStructure.svelte';
|
import ZipStructure from './ZipStructure.svelte';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
const dispatch = createEventDispatcher<{ reload: void }>();
|
import { preventDefault } from 'src/lib/utils.js';
|
||||||
|
import CreateNewClass from './api/CreateNewClass.svelte';
|
||||||
|
|
||||||
let selected_class: Class | undefined = $state();
|
let selected_class: Class | undefined = $state();
|
||||||
|
|
||||||
let { classes, model }: { classes: Class[]; model: Model } = $props();
|
let { classes, model, onreload }: { classes: Class[]; model: Model; onreload?: () => void } =
|
||||||
|
$props();
|
||||||
|
|
||||||
let createClass: { className: string } = $state({
|
let createClass: { className: string } = $state({
|
||||||
className: ''
|
className: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
let page = $state(0);
|
let page = $state(-1);
|
||||||
let showNext = $state(false);
|
let showNext = $state(false);
|
||||||
let image_list = $state<Image[]>([]);
|
let image_list = $state<Image[]>([]);
|
||||||
|
|
||||||
@ -41,6 +32,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function getList() {
|
async function getList() {
|
||||||
|
console.log(page);
|
||||||
try {
|
try {
|
||||||
let res = await post('models/data/list', {
|
let res = await post('models/data/list', {
|
||||||
id: selected_class?.id ?? '',
|
id: selected_class?.id ?? '',
|
||||||
@ -53,19 +45,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (selected_class) {
|
if (selected_class) {
|
||||||
page = 0;
|
page = 0;
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let file: File | undefined = $state();
|
let file: File | undefined = $state();
|
||||||
let uploadImage: MessageSimple;
|
|
||||||
let uploading = $state(Promise.resolve());
|
let uploading = $state(Promise.resolve());
|
||||||
|
|
||||||
async function uploadZip() {
|
async function uploadZip() {
|
||||||
uploadImage.clear();
|
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
uploading = new Promise(() => {});
|
uploading = new Promise(() => {});
|
||||||
@ -76,19 +69,14 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await postFormData('models/data/class/upload', form);
|
await postFormData('models/data/class/upload', form);
|
||||||
dispatch('reload');
|
if (onreload) onreload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Failed to upload');
|
||||||
uploadImage.display(await e.json());
|
|
||||||
} else {
|
|
||||||
uploadImage.display('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uploading = Promise.resolve();
|
uploading = Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
let createNewClassMessages: MessageSimple;
|
|
||||||
async function createNewClass() {
|
async function createNewClass() {
|
||||||
try {
|
try {
|
||||||
const r = await post('models/data/class/new', {
|
const r = await post('models/data/class/new', {
|
||||||
@ -100,7 +88,7 @@
|
|||||||
classes = classes;
|
classes = classes;
|
||||||
getList();
|
getList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showMessage(e, createNewClassMessages);
|
showMessage(e, notificationStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,12 +97,11 @@
|
|||||||
rdelete('models/data/point', { id });
|
rdelete('models/data/point', { id });
|
||||||
getList();
|
getList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('TODO notify user', e);
|
showMessage(e, notificationStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let addFile: File | undefined = $state();
|
let addFile: File | undefined = $state();
|
||||||
let addImageMessages: MessageSimple;
|
|
||||||
let adding = $state(Promise.resolve());
|
let adding = $state(Promise.resolve());
|
||||||
let uploadImageDialog: HTMLDialogElement;
|
let uploadImageDialog: HTMLDialogElement;
|
||||||
async function addImage() {
|
async function addImage() {
|
||||||
@ -136,7 +123,7 @@
|
|||||||
addFile = undefined;
|
addFile = undefined;
|
||||||
getList();
|
getList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showMessage(e, addImageMessages);
|
showMessage(e, notificationStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -151,30 +138,30 @@
|
|||||||
{#each classes as item}
|
{#each classes as item}
|
||||||
<button
|
<button
|
||||||
style="width: auto; white-space: nowrap;"
|
style="width: auto; white-space: nowrap;"
|
||||||
on:click={() => setActiveClass(item, setActive)}
|
onclick={() => setActiveClass(item, setActive)}
|
||||||
class="tab"
|
class="tab"
|
||||||
class:selected={isActive(item.name)}
|
class:selected={isActive(item.name)}
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
{#if model.model_type == 2}
|
{#if model.model_type == 2}
|
||||||
{#if item.status == 1}
|
{#if item.status == 1}
|
||||||
<span class="bi bi-book" style="color: orange;" />
|
<span class="bi bi-book" style="color: orange;"></span>
|
||||||
{:else if item.status == 2}
|
{:else if item.status == 2}
|
||||||
<span class="bi bi-book" style="color: green;" />
|
<span class="bi bi-book" style="color: green;"></span>
|
||||||
{:else if item.status == 3}
|
{:else if item.status == 3}
|
||||||
<span class="bi bi-check" style="color: green;" />
|
<span class="bi bi-check" style="color: green;"></span>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
on:click={() => {
|
onclick={() => {
|
||||||
setActive('-----New Class-----')();
|
setActive('-----New Class-----')();
|
||||||
selected_class = undefined;
|
selected_class = undefined;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span class="bi bi-plus" />
|
<span class="bi bi-plus"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{#if selected_class == undefined && isActive('-----New Class-----')}
|
{#if selected_class == undefined && isActive('-----New Class-----')}
|
||||||
@ -184,21 +171,31 @@
|
|||||||
<div slot="buttons" let:setActive let:isActive>
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
on:click|preventDefault={setActive('zip')}
|
type="button"
|
||||||
|
onclick={setActive('zip')}
|
||||||
class:selected={isActive('zip')}
|
class:selected={isActive('zip')}
|
||||||
>
|
>
|
||||||
Zip
|
Zip
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="tab"
|
class="tab"
|
||||||
on:click|preventDefault={setActive('empty')}
|
type="button"
|
||||||
|
onclick={setActive('empty')}
|
||||||
class:selected={isActive('empty')}
|
class:selected={isActive('empty')}
|
||||||
>
|
>
|
||||||
Empty Class
|
Empty Class
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="tab"
|
||||||
|
type="button"
|
||||||
|
onclick={setActive('api')}
|
||||||
|
class:selected={isActive('api')}
|
||||||
|
>
|
||||||
|
API
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('zip')}>
|
<div class="content" class:selected={isActive('zip')}>
|
||||||
<form on:submit|preventDefault={uploadZip}>
|
<form onsubmit={preventDefault(uploadZip)}>
|
||||||
<fieldset class="file-upload">
|
<fieldset class="file-upload">
|
||||||
<label for="file">Data file</label>
|
<label for="file">Data file</label>
|
||||||
<div class="form-msg">
|
<div class="form-msg">
|
||||||
@ -218,7 +215,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={uploadImage} />
|
|
||||||
{#if file}
|
{#if file}
|
||||||
{#await uploading}
|
{#await uploading}
|
||||||
<button disabled> Uploading </button>
|
<button disabled> Uploading </button>
|
||||||
@ -229,7 +225,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('empty')}>
|
<div class="content" class:selected={isActive('empty')}>
|
||||||
<form on:submit|preventDefault={createNewClass}>
|
<form onsubmit={preventDefault(createNewClass)}>
|
||||||
<div class="form-msg">
|
<div class="form-msg">
|
||||||
This Creates an empty class that allows images to be added after
|
This Creates an empty class that allows images to be added after
|
||||||
</div>
|
</div>
|
||||||
@ -237,10 +233,12 @@
|
|||||||
<label for="className">Class Name</label>
|
<label for="className">Class Name</label>
|
||||||
<input required name="className" bind:value={createClass.className} />
|
<input required name="className" bind:value={createClass.className} />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={createNewClassMessages} />
|
|
||||||
<button> Create New Class </button>
|
<button> Create New Class </button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content" class:selected={isActive('api')}>
|
||||||
|
<CreateNewClass {model} />
|
||||||
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -258,7 +256,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
Class to train
|
Class to train
|
||||||
{/if}
|
{/if}
|
||||||
<button on:click={() => uploadImageDialog.showModal()}> Upload Image </button>
|
<button onclick={() => uploadImageDialog.showModal()}> Upload Image </button>
|
||||||
</h2>
|
</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -314,7 +312,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 3ch">
|
<td style="width: 3ch">
|
||||||
<button class="danger" on:click={() => deleteDataPoint(image.id)}>
|
<button class="danger" onclick={() => deleteDataPoint(image.id)}>
|
||||||
<span class="bi bi-trash"></span>
|
<span class="bi bi-trash"></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -325,7 +323,7 @@
|
|||||||
<div class="flex justify-center align-center">
|
<div class="flex justify-center align-center">
|
||||||
<div class="grow-1 flex justify-end align-center">
|
<div class="grow-1 flex justify-end align-center">
|
||||||
{#if page > 0}
|
{#if page > 0}
|
||||||
<button on:click={() => (page -= 1)}> Prev </button>
|
<button onclick={() => (page -= 1)}> Prev </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -335,7 +333,7 @@
|
|||||||
|
|
||||||
<div class="grow-1 flex justify-start align-center">
|
<div class="grow-1 flex justify-start align-center">
|
||||||
{#if showNext}
|
{#if showNext}
|
||||||
<button on:click={() => (page += 1)}> Next </button>
|
<button onclick={() => (page += 1)}> Next </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -345,7 +343,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<dialog class="newImageDialog" bind:this={uploadImageDialog}>
|
<dialog class="newImageDialog" bind:this={uploadImageDialog}>
|
||||||
<form on:submit|preventDefault={addImage}>
|
<form onsubmit={preventDefault(addImage)}>
|
||||||
<fieldset class="file-upload">
|
<fieldset class="file-upload">
|
||||||
<label for="file">Data file</label>
|
<label for="file">Data file</label>
|
||||||
<div class="form-msg">
|
<div class="form-msg">
|
||||||
@ -365,7 +363,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={addImageMessages} />
|
|
||||||
{#if addFile}
|
{#if addFile}
|
||||||
{#await adding}
|
{#await adding}
|
||||||
<button disabled> Uploading </button>
|
<button disabled> Uploading </button>
|
||||||
@ -415,10 +412,4 @@
|
|||||||
table tr th:first-child {
|
table tr th:first-child {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table tr td button,
|
|
||||||
table tr td .button {
|
|
||||||
padding: 5px 10px;
|
|
||||||
box-shadow: 0 2px 5px 1px #66666655;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,20 +2,22 @@
|
|||||||
import { post, postFormData, showMessage } from 'src/lib/requests.svelte';
|
import { post, postFormData, showMessage } from 'src/lib/requests.svelte';
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import FileUpload from 'src/lib/FileUpload.svelte';
|
import FileUpload from 'src/lib/FileUpload.svelte';
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import { createEventDispatcher, onDestroy } from 'svelte';
|
|
||||||
import Spinner from 'src/lib/Spinner.svelte';
|
import Spinner from 'src/lib/Spinner.svelte';
|
||||||
import type { Task } from './tasks/TasksTable.svelte';
|
import type { Task } from './tasks/types';
|
||||||
import Tabs from 'src/lib/Tabs.svelte';
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
import hljs from 'highlight.js';
|
import hljs from 'highlight.js';
|
||||||
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let { model } = $props<{ model: Model }>();
|
let {
|
||||||
|
model,
|
||||||
|
onupload = () => {},
|
||||||
|
ontaskReload = () => {}
|
||||||
|
}: { model: Model; onupload?: () => void; ontaskReload?: () => void } = $props();
|
||||||
|
|
||||||
let file: File | undefined = $state();
|
let file: File | undefined = $state();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{ upload: void; taskReload: void }>();
|
|
||||||
|
|
||||||
let _result: Promise<Task> = $state(new Promise(() => {}));
|
let _result: Promise<Task> = $state(new Promise(() => {}));
|
||||||
let run = $state(false);
|
let run = $state(false);
|
||||||
|
|
||||||
@ -32,7 +34,7 @@
|
|||||||
const r = await post('tasks/task', { id: last_task });
|
const r = await post('tasks/task', { id: last_task });
|
||||||
if ([0, 1, 2, 3].includes(r.status)) {
|
if ([0, 1, 2, 3].includes(r.status)) {
|
||||||
setTimeout(reloadLastTimeout, 500);
|
setTimeout(reloadLastTimeout, 500);
|
||||||
setTimeout(() => dispatch('taskReload'), 500);
|
setTimeout(ontaskReload, 500);
|
||||||
} else {
|
} else {
|
||||||
_result = Promise.resolve(r);
|
_result = Promise.resolve(r);
|
||||||
}
|
}
|
||||||
@ -59,7 +61,7 @@
|
|||||||
showMessage(e, notificationStore, 'Could not run the model');
|
showMessage(e, notificationStore, 'Could not run the model');
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch('upload');
|
onupload();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@ -71,10 +73,10 @@
|
|||||||
|
|
||||||
<Tabs active="upload" let:isActive>
|
<Tabs active="upload" let:isActive>
|
||||||
<div class="buttons" slot="buttons" let:setActive let:isActive>
|
<div class="buttons" slot="buttons" let:setActive let:isActive>
|
||||||
<button class="tab" class:selected={isActive('upload')} on:click={setActive('upload')}>
|
<button class="tab" class:selected={isActive('upload')} onclick={setActive('upload')}>
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" class:selected={isActive('api')} on:click={setActive('api')}> Api </button>
|
<button class="tab" class:selected={isActive('api')} onclick={setActive('api')}> Api </button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('api')}>
|
<div class="content" class:selected={isActive('api')}>
|
||||||
<div class="codeinfo">
|
<div class="codeinfo">
|
||||||
@ -134,7 +136,7 @@ const r = await fetch('${window.location.protocol}//${window.location.hostname}/
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive('upload')}>
|
<div class="content" class:selected={isActive('upload')}>
|
||||||
<form on:submit|preventDefault={submit} style="box-shadow: none;">
|
<form onsubmit={preventDefault(submit)} style="box-shadow: none;">
|
||||||
<fieldset class="file-upload">
|
<fieldset class="file-upload">
|
||||||
<label for="file">Image</label>
|
<label for="file">Image</label>
|
||||||
<div class="form-msg">Run image through them model and get the result</div>
|
<div class="form-msg">Run image through them model and get the result</div>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { post } from 'src/lib/requests.svelte';
|
|
||||||
import type { Model } from 'src/routes/models/edit/+page.svelte';
|
import type { Model } from 'src/routes/models/edit/+page.svelte';
|
||||||
import RunModel from './RunModel.svelte';
|
import RunModel from './RunModel.svelte';
|
||||||
import TasksTable from './tasks/TasksTable.svelte';
|
import TasksTable from './tasks/TasksTable.svelte';
|
||||||
@ -12,7 +11,7 @@
|
|||||||
|
|
||||||
{#if active}
|
{#if active}
|
||||||
<div class="content selected">
|
<div class="content selected">
|
||||||
<RunModel {model} on:upload={() => table.getList()} on:taskReload={() => table.getList()} />
|
<RunModel {model} onupload={() => table.getList()} ontaskReload={() => table.getList()} />
|
||||||
<TasksTable {model} bind:this={table} />
|
<TasksTable {model} bind:this={table} />
|
||||||
<Stats {model} />
|
<Stats {model} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
import type { Model } from './+page.svelte';
|
import type { Model } from './+page.svelte';
|
||||||
import { post } from 'src/lib/requests.svelte';
|
import { post, showMessage } from 'src/lib/requests.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let { number_of_invalid_images, has_data, model } = $props<{
|
let {
|
||||||
|
number_of_invalid_images,
|
||||||
|
has_data,
|
||||||
|
model,
|
||||||
|
onreload = () => {}
|
||||||
|
}: {
|
||||||
number_of_invalid_images: number;
|
number_of_invalid_images: number;
|
||||||
has_data: boolean;
|
has_data: boolean;
|
||||||
model: Model;
|
model: Model;
|
||||||
}>();
|
onreload?: () => void;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
let data = $state({
|
let data = $state({
|
||||||
model_type: 'simple',
|
model_type: 'simple',
|
||||||
@ -18,46 +24,32 @@
|
|||||||
|
|
||||||
let submitted = $state(false);
|
let submitted = $state(false);
|
||||||
|
|
||||||
let dispatch = createEventDispatcher<{ reload: void }>();
|
|
||||||
|
|
||||||
let messages: MessageSimple;
|
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
messages.clear();
|
|
||||||
submitted = true;
|
submitted = true;
|
||||||
try {
|
try {
|
||||||
await post('models/train', {
|
await post('models/train', {
|
||||||
id: model.id,
|
id: model.id,
|
||||||
...data
|
...data
|
||||||
});
|
});
|
||||||
dispatch('reload');
|
onreload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not start the training of the model');
|
||||||
messages.display(await e.json());
|
|
||||||
} else {
|
|
||||||
messages.display('Could not start the training of the model');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitRetrain() {
|
async function submitRetrain() {
|
||||||
messages.clear();
|
|
||||||
submitted = true;
|
submitted = true;
|
||||||
try {
|
try {
|
||||||
await post('model/train/retrain', { id: model.id });
|
await post('model/train/retrain', { id: model.id });
|
||||||
dispatch('reload');
|
onreload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not start the training of the model');
|
||||||
messages.display(await e.json());
|
|
||||||
} else {
|
|
||||||
messages.display('Could not start the training of the model');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if model.status == 2}
|
{#if model.status == 2}
|
||||||
<form class:submitted on:submit|preventDefault={submit}>
|
<form class:submitted onsubmit={preventDefault(submit)}>
|
||||||
{#if has_data}
|
{#if has_data}
|
||||||
{#if number_of_invalid_images > 0}
|
{#if number_of_invalid_images > 0}
|
||||||
<p class="danger">
|
<p class="danger">
|
||||||
@ -65,7 +57,6 @@
|
|||||||
These images will be delete when the model trains.
|
These images will be delete when the model trains.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<MessageSimple bind:this={messages} />
|
|
||||||
<!-- TODO expading mode -->
|
<!-- TODO expading mode -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend> Model Type </legend>
|
<legend> Model Type </legend>
|
||||||
@ -111,7 +102,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
{:else}
|
{:else}
|
||||||
<form class:submitted on:submit|preventDefault={submitRetrain}>
|
<form class:submitted onsubmit={submitRetrain}>
|
||||||
{#if has_data}
|
{#if has_data}
|
||||||
<h2>This model has new classes and can be expanded</h2>
|
<h2>This model has new classes and can be expanded</h2>
|
||||||
{#if number_of_invalid_images > 0}
|
{#if number_of_invalid_images > 0}
|
||||||
@ -120,7 +111,6 @@
|
|||||||
These images will be delete when the model trains.
|
These images will be delete when the model trains.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<MessageSimple bind:this={messages} />
|
|
||||||
<button> Retrain </button>
|
<button> Retrain </button>
|
||||||
{:else}
|
{:else}
|
||||||
<h2>To train the model please provide data to the model first</h2>
|
<h2>To train the model please provide data to the model first</h2>
|
||||||
|
27
webpage/src/routes/models/edit/api/CreateNewClass.svelte
Normal file
27
webpage/src/routes/models/edit/api/CreateNewClass.svelte
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import hljs from 'highlight.js';
|
||||||
|
import type { Model } from '../+page.svelte';
|
||||||
|
|
||||||
|
let { model }: { model: Model } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
To create a new class via the API you can:
|
||||||
|
<pre style="font-family: Fira Code;">{@html hljs.highlight(
|
||||||
|
`let form = new FormData();
|
||||||
|
form.append('json_data', JSON.stringify({
|
||||||
|
id: '${model.id}',
|
||||||
|
name: 'New class name'
|
||||||
|
}));
|
||||||
|
form.append('file', file, 'file');
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append('response-type', 'application/json');
|
||||||
|
headers.append('token', token);
|
||||||
|
|
||||||
|
const r = await fetch('${window.location.protocol}//${window.location.hostname}/models/data/class/new', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: headers,
|
||||||
|
body: form
|
||||||
|
});`,
|
||||||
|
{ language: 'javascript' }
|
||||||
|
).value}</pre>
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import type { Model } from '../+page.svelte';
|
import type { Model } from '../+page.svelte';
|
||||||
import { post, showMessage } from 'src/lib/requests.svelte';
|
import { post, showMessage } from 'src/lib/requests.svelte';
|
||||||
import type { DataPoint, TasksStatsDay } from 'src/types/stats/task';
|
import type { DataPoint, TasksStatsDay } from 'src/types/stats/task';
|
||||||
@ -124,7 +124,6 @@
|
|||||||
nc_error: 'Non Classfication Error',
|
nc_error: 'Non Classfication Error',
|
||||||
nc_success: 'Non Classfication Success'
|
nc_success: 'Non Classfication Success'
|
||||||
};
|
};
|
||||||
let t = s.total;
|
|
||||||
let labels = new Array(24).fill(0).map((_, i) => i);
|
let labels = new Array(24).fill(0).map((_, i) => i);
|
||||||
lineChart = new Chart(line, {
|
lineChart = new Chart(line, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { post, showMessage } from 'src/lib/requests.svelte';
|
import { post, showMessage } from 'src/lib/requests.svelte';
|
||||||
import type { Model } from '../+page.svelte';
|
import type { Model } from '../+page.svelte';
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
|
||||||
import Tooltip from 'src/lib/Tooltip.svelte';
|
import Tooltip from 'src/lib/Tooltip.svelte';
|
||||||
|
|
||||||
import type { Task } from './types';
|
import type { Task } from './types';
|
||||||
@ -70,7 +69,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let userPreceptionMessages: MessageSimple;
|
|
||||||
// This returns a function that performs the call and does not do the call it self
|
// This returns a function that performs the call and does not do the call it self
|
||||||
function userPreception(task: string, agree: number) {
|
function userPreception(task: string, agree: number) {
|
||||||
return async function () {
|
return async function () {
|
||||||
@ -89,7 +87,6 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Tasks</h2>
|
<h2>Tasks</h2>
|
||||||
<MessageSimple bind:this={userPreceptionMessages} />
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -146,14 +143,14 @@
|
|||||||
<div>
|
<div>
|
||||||
{#if task.user_confirmed != 1}
|
{#if task.user_confirmed != 1}
|
||||||
<Tooltip title="Agree with the result of the task">
|
<Tooltip title="Agree with the result of the task">
|
||||||
<button type="button" on:click={userPreception(task.id, 1)}>
|
<button type="button" onclick={userPreception(task.id, 1)}>
|
||||||
<span class="bi bi-check"></span>
|
<span class="bi bi-check"></span>
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
||||||
{#if task.user_confirmed != -1}
|
{#if task.user_confirmed != -1}
|
||||||
<Tooltip title="Disagree with the result">
|
<Tooltip title="Disagree with the result">
|
||||||
<button class="danger" type="button" on:click={userPreception(task.id, -1)}>
|
<button class="danger" type="button" onclick={userPreception(task.id, -1)}>
|
||||||
<span class="bi bi-x-lg"></span>
|
<span class="bi bi-x-lg"></span>
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -198,7 +195,7 @@
|
|||||||
<div class="flex justify-center align-center">
|
<div class="flex justify-center align-center">
|
||||||
<div class="grow-1 flex justify-end align-center">
|
<div class="grow-1 flex justify-end align-center">
|
||||||
{#if page > 0}
|
{#if page > 0}
|
||||||
<button on:click={() => (page -= 1)}> Prev </button>
|
<button onclick={() => (page -= 1)}> Prev </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -208,7 +205,7 @@
|
|||||||
|
|
||||||
<div class="grow-1 flex justify-start align-center">
|
<div class="grow-1 flex justify-start align-center">
|
||||||
{#if showNext}
|
{#if showNext}
|
||||||
<button on:click={() => (page += 1)}> Next </button>
|
<button onclick={() => (page += 1)}> Next </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -219,10 +216,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
& > button {
|
|
||||||
margin: 3px 5px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
@ -3,3 +3,16 @@ export type ModelStats = Array<{
|
|||||||
training: number;
|
training: number;
|
||||||
testing: number;
|
testing: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export type Class = {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
status: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Image = {
|
||||||
|
file_path: string;
|
||||||
|
mode: number;
|
||||||
|
status: number;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
import { userStore } from '../UserStore.svelte';
|
import { userStore } from '../UserStore.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
let submitted = $state(false);
|
let submitted = $state(false);
|
||||||
|
|
||||||
@ -39,7 +40,7 @@
|
|||||||
<div class="login-page">
|
<div class="login-page">
|
||||||
<div>
|
<div>
|
||||||
<h1>Register</h1>
|
<h1>Register</h1>
|
||||||
<form on:submit|preventDefault={onSubmit} class:submitted>
|
<form onsubmit={preventDefault(onSubmit)} class:submitted>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="username">Username</label>
|
<label for="username">Username</label>
|
||||||
<input required name="username" bind:value={loginData.username} />
|
<input required name="username" bind:value={loginData.username} />
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
import { post } from 'src/lib/requests.svelte';
|
import { post, showMessage } from 'src/lib/requests.svelte';
|
||||||
import MessageSimple, { type DisplayFn } from 'src/lib/MessageSimple.svelte';
|
|
||||||
import TokenTable from './TokenTable.svelte';
|
import TokenTable from './TokenTable.svelte';
|
||||||
import DeleteUser from './DeleteUser.svelte';
|
import DeleteUser from './DeleteUser.svelte';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!userStore.isLogin()) {
|
if (!userStore.isLogin()) {
|
||||||
@ -26,12 +27,8 @@
|
|||||||
let submiitedEmail = $state(false);
|
let submiitedEmail = $state(false);
|
||||||
let submiitedPassword = $state(false);
|
let submiitedPassword = $state(false);
|
||||||
|
|
||||||
let msgEmail: MessageSimple;
|
|
||||||
let msgPassword: MessageSimple;
|
|
||||||
|
|
||||||
async function onSubmitEmail() {
|
async function onSubmitEmail() {
|
||||||
submiitedEmail = true;
|
submiitedEmail = true;
|
||||||
msgEmail.display('');
|
|
||||||
|
|
||||||
if (!userStore.user) return;
|
if (!userStore.user) return;
|
||||||
|
|
||||||
@ -44,31 +41,31 @@
|
|||||||
...userStore.user,
|
...userStore.user,
|
||||||
...req
|
...req
|
||||||
};
|
};
|
||||||
msgEmail.display('User updated successufly!', { type: 'success', timeToShow: 10000 });
|
notificationStore.add({
|
||||||
|
message: 'User updated successufly!',
|
||||||
|
type: 'success',
|
||||||
|
timeToLive: 10000
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not update email');
|
||||||
msgEmail.display(await e.json());
|
|
||||||
} else {
|
|
||||||
msgEmail.display('Could not update email');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmitPassword() {
|
async function onSubmitPassword() {
|
||||||
submiitedPassword = true;
|
submiitedPassword = true;
|
||||||
msgPassword.display('');
|
|
||||||
if (!userStore.user) return;
|
if (!userStore.user) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await post('user/info/password', passwordData);
|
await post('user/info/password', passwordData);
|
||||||
passwordData = { old_password: '', password: '', password2: '' };
|
passwordData = { old_password: '', password: '', password2: '' };
|
||||||
msgPassword.display('Password updated successufly!', { type: 'success', timeToShow: 10000 });
|
|
||||||
|
notificationStore.add({
|
||||||
|
message: 'Password updated successufly!',
|
||||||
|
type: 'success',
|
||||||
|
timeToLive: 10000
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
showMessage(e, notificationStore, 'Could not update password');
|
||||||
msgPassword.display(await e.json());
|
|
||||||
} else {
|
|
||||||
msgPassword.display('Could not update password');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -80,15 +77,14 @@
|
|||||||
<div class="login-page">
|
<div class="login-page">
|
||||||
<div>
|
<div>
|
||||||
<h1>User Infomation</h1>
|
<h1>User Infomation</h1>
|
||||||
<form on:submit|preventDefault={onSubmitEmail} class:submiitedEmail>
|
<form onsubmit={onSubmitEmail} class:submiitedEmail>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="email">Email</label>
|
<label for="email">Email</label>
|
||||||
<input type="email" required name="email" bind:value={email} />
|
<input type="email" required name="email" bind:value={email} />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={msgEmail} />
|
|
||||||
<button> Update </button>
|
<button> Update </button>
|
||||||
</form>
|
</form>
|
||||||
<form on:submit|preventDefault={onSubmitPassword} class:submiitedPassword>
|
<form onsubmit={preventDefault(onSubmitPassword)} class:submiitedPassword>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="old_password">Old Password</label>
|
<label for="old_password">Old Password</label>
|
||||||
<input
|
<input
|
||||||
@ -106,7 +102,6 @@
|
|||||||
<label for="password2">Repeat New Password</label>
|
<label for="password2">Repeat New Password</label>
|
||||||
<input required bind:value={passwordData.password2} name="password2" type="password" />
|
<input required bind:value={passwordData.password2} name="password2" type="password" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={msgPassword} />
|
|
||||||
<div>
|
<div>
|
||||||
<button> Update </button>
|
<button> Update </button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,36 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {createEventDispatcher} from 'svelte';
|
|
||||||
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
|
||||||
import Tooltip from 'src/lib/Tooltip.svelte';
|
import Tooltip from 'src/lib/Tooltip.svelte';
|
||||||
import 'src/styles/forms.css';
|
import 'src/styles/forms.css';
|
||||||
import {post} from 'src/lib/requests.svelte';
|
import { post } from 'src/lib/requests.svelte';
|
||||||
import Spinner from 'src/lib/Spinner.svelte';
|
import Spinner from 'src/lib/Spinner.svelte';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
|
|
||||||
|
let { onreload = () => {} }: { onreload?: () => void } = $props();
|
||||||
const dispatch = createEventDispatcher<{reload: void}>();
|
|
||||||
|
|
||||||
let addNewToken = $state(false);
|
let addNewToken = $state(false);
|
||||||
|
|
||||||
let messages: MessageSimple;
|
|
||||||
|
|
||||||
let expiry_date: HTMLInputElement = $state(undefined as any);
|
let expiry_date: HTMLInputElement = $state(undefined as any);
|
||||||
|
|
||||||
type NewToken = {
|
|
||||||
name: string,
|
|
||||||
expiry: number,
|
|
||||||
token: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
let token: Promise<NewToken> | undefined = $state();
|
type NewToken = {
|
||||||
|
name: string;
|
||||||
|
expiry: number;
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
let token: Promise<NewToken> | undefined = $state();
|
||||||
|
|
||||||
let newToken: {
|
let newToken: {
|
||||||
name: string;
|
name: string;
|
||||||
expiry: string;
|
expiry: string;
|
||||||
password: string;
|
password: string;
|
||||||
} = $state({
|
} = $state({
|
||||||
name: '',
|
name: '',
|
||||||
expiry: '',
|
expiry: '',
|
||||||
password: '',
|
password: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
async function createToken(e: SubmitEvent & { currentTarget: HTMLFormElement }) {
|
async function createToken(e: SubmitEvent & { currentTarget: HTMLFormElement }) {
|
||||||
@ -47,86 +43,85 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const r = await post("user/token/add", {
|
const r = await post('user/token/add', {
|
||||||
name: newToken.name,
|
name: newToken.name,
|
||||||
expiry: expiry,
|
expiry: expiry,
|
||||||
password: newToken.password,
|
password: newToken.password
|
||||||
});
|
});
|
||||||
token = Promise.resolve(r)
|
token = Promise.resolve(r);
|
||||||
setTimeout(() => dispatch('reload'), 500)
|
setTimeout(onreload, 500);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
token = undefined;
|
token = undefined;
|
||||||
console.error("Notify user", e)
|
console.error('Notify user', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (expiry_date) {
|
if (expiry_date) {
|
||||||
if (isNaN(Number(newToken.expiry))) {
|
if (isNaN(Number(newToken.expiry))) {
|
||||||
expiry_date.setCustomValidity('Invalid Number');
|
expiry_date.setCustomValidity('Invalid Number');
|
||||||
} else {
|
} else {
|
||||||
expiry_date.setCustomValidity('');
|
expiry_date.setCustomValidity('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if addNewToken}
|
{#if addNewToken}
|
||||||
<div>
|
<div>
|
||||||
<h2>Add New Token</h2>
|
<h2>Add New Token</h2>
|
||||||
{#if !token}
|
{#if !token}
|
||||||
<form on:submit|preventDefault={createToken}>
|
<form onsubmit={preventDefault(createToken)}>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<input required bind:value={newToken.name} name="name" />
|
<input required bind:value={newToken.name} name="name" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="expiry_date">Expiry Date</label>
|
<label for="expiry_date">Expiry Date</label>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<input bind:this={expiry_date} bind:value={newToken.expiry} name="expiry_date" />
|
<input bind:this={expiry_date} bind:value={newToken.expiry} name="expiry_date" />
|
||||||
<Tooltip title="Time in seconds. Leave empty to last forever">
|
<Tooltip title="Time in seconds. Leave empty to last forever">
|
||||||
<span class="center-question bi bi-question-circle-fill" />
|
<span class="center-question bi bi-question-circle-fill"></span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="password">Password</label>
|
<label for="password">Password</label>
|
||||||
<input required bind:value={newToken.password} name="password" />
|
<input required bind:value={newToken.password} name="password" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={messages} />
|
<div>
|
||||||
<div>
|
<button> Update </button>
|
||||||
<button> Update </button>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
{:else}
|
||||||
{:else}
|
{#await token}
|
||||||
{#await token}
|
<Spinner /> Generating
|
||||||
<Spinner /> Generating
|
{:then t}
|
||||||
{:then t}
|
<h3>Token generated</h3>
|
||||||
<h3> Token generated </h3>
|
<form onsubmit={preventDefault(() => {})}>
|
||||||
<form on:submit|preventDefault={() => {}}>
|
<fieldset>
|
||||||
<fieldset>
|
<label for="token">Token</label>
|
||||||
<label for="token">Token</label>
|
<div class="flex">
|
||||||
<div class="flex">
|
<input value={t.token} oninput={(e) => e.preventDefault()} name="token" />
|
||||||
<input value={t.token} on:input={(e) => e.preventDefault() } name="token" />
|
<div style="width: 5em;">
|
||||||
<div style="width: 5em;">
|
<button onclick={() => navigator.clipboard.writeText(t.token)}>
|
||||||
<button on:click={() => navigator.clipboard.writeText(t.token)} >
|
<span class="bi bi-clipboard"></span>
|
||||||
<span class="bi bi-clipboard" />
|
</button>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
<div>
|
||||||
<div>
|
<button onclick={() => (token = undefined)}> Generate new token </button>
|
||||||
<button on:click={() => token = undefined}> Generate new token </button>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
{:catch e}
|
||||||
{:catch e}
|
{e}
|
||||||
{e}
|
{/await}
|
||||||
{/await}
|
{/if}
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div>
|
<div>
|
||||||
<button class="expander" on:click={() => (addNewToken = true)}> Add New Token </button>
|
<button class="expander" onclick={() => (addNewToken = true)}> Add New Token </button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
import { rdelete, showMessage } from 'src/lib/requests.svelte';
|
import { rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||||
|
import { preventDefault } from 'src/lib/utils';
|
||||||
import { userStore } from 'src/routes/UserStore.svelte';
|
import { userStore } from 'src/routes/UserStore.svelte';
|
||||||
|
|
||||||
let data = $state({ password: '' });
|
let data = $state({ password: '' });
|
||||||
@ -23,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="danger-bg" on:submit|preventDefault={deleteUser}>
|
<form class="danger-bg" onsubmit={preventDefault(deleteUser)}>
|
||||||
<h2 class="no-top-margin">Delete user</h2>
|
<h2 class="no-top-margin">Delete user</h2>
|
||||||
Deleting the user will delete all your data stored in the service including the images.
|
Deleting the user will delete all your data stored in the service including the images.
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import { post, rdelete } from 'src/lib/requests.svelte';
|
import { post, rdelete } from 'src/lib/requests.svelte';
|
||||||
import { userStore } from 'src/routes/UserStore.svelte';
|
import { userStore } from 'src/routes/UserStore.svelte';
|
||||||
|
|
||||||
import AddToken from './AddToken.svelte';
|
import AddToken from './AddToken.svelte';
|
||||||
|
|
||||||
let page = $state(0);
|
let page = $state(0);
|
||||||
let showNext = $state(false);
|
let showNext = $state(false);
|
||||||
@ -70,7 +70,7 @@
|
|||||||
{new Date(token.create_date).toLocaleString()}
|
{new Date(token.create_date).toLocaleString()}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="danger" on:click={() => removeToken(token)}>
|
<button class="danger" onclick={() => removeToken(token)}>
|
||||||
<span class="bi bi-trash"></span>
|
<span class="bi bi-trash"></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -81,7 +81,7 @@
|
|||||||
<div class="flex justify-center align-center">
|
<div class="flex justify-center align-center">
|
||||||
<div class="grow-1 flex justify-end align-center">
|
<div class="grow-1 flex justify-end align-center">
|
||||||
{#if page > 0}
|
{#if page > 0}
|
||||||
<button on:click={() => (page -= 1)}> Prev </button>
|
<button onclick={() => (page -= 1)}> Prev </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -91,25 +91,15 @@
|
|||||||
|
|
||||||
<div class="grow-1 flex justify-start align-center">
|
<div class="grow-1 flex justify-start align-center">
|
||||||
{#if showNext}
|
{#if showNext}
|
||||||
<button on:click={() => (page += 1)}> Next </button>
|
<button onclick={() => (page += 1)}> Next </button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AddToken on:reload={getList} />
|
<AddToken onreload={getList} />
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.buttons {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
& > button {
|
|
||||||
margin: 3px 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: 0 2px 8px 1px #66666622;
|
box-shadow: 0 2px 8px 1px #66666622;
|
||||||
@ -132,10 +122,4 @@
|
|||||||
table tr th:first-child {
|
table tr th:first-child {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table tr td button,
|
|
||||||
table tr td .button {
|
|
||||||
padding: 5px 10px;
|
|
||||||
box-shadow: 0 2px 5px 1px #66666655;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -65,6 +65,7 @@ button.expander::after {
|
|||||||
|
|
||||||
a.button {
|
a.button {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
height: 1.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
@ -190,3 +191,12 @@ form.danger-bg {
|
|||||||
background-color: var(--danger-transparent);
|
background-color: var(--danger-transparent);
|
||||||
border: 1px solid var(--danger);
|
border: 1px solid var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: 'Fira Code';
|
||||||
|
background-color: #f6f8fa;
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
@ -12,10 +12,10 @@ const config = {
|
|||||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
adapter: adapter(),
|
adapter: adapter(),
|
||||||
alias: {
|
alias: {
|
||||||
src: "src",
|
src: 'src',
|
||||||
routes: "src/routes",
|
routes: 'src/routes'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user