267 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
| <script lang="ts" context="module">
 | |
| 	export type Task = {
 | |
| 		id: string;
 | |
| 		user_id: string;
 | |
| 		model_id: string;
 | |
| 		status: number;
 | |
| 		status_message: string;
 | |
| 		user_confirmed: number;
 | |
| 		compacted: number;
 | |
| 		type: number;
 | |
| 		created: string;
 | |
| 		result: string;
 | |
| 	};
 | |
| 	export const TaskType = {
 | |
| 		TASK_FAILED_RUNNING: -2,
 | |
| 		TASK_FAILED_CREATION: -1,
 | |
| 		TASK_PREPARING: 0,
 | |
| 		TASK_TODO: 1,
 | |
| 		TASK_PICKED_UP: 2,
 | |
| 		TASK_RUNNING: 3,
 | |
| 		TASK_DONE: 4
 | |
| 	};
 | |
| 	export const TaskTypeStrings: Record<number, string> = {
 | |
| 		[-2]: 'Task failed running',
 | |
| 		[-1]: 'Failed to create task',
 | |
| 		0: 'Preparing task',
 | |
| 		1: 'Task to do',
 | |
| 		2: 'Task picked up by a runner',
 | |
| 		3: 'Task running',
 | |
| 		4: 'Task complete'
 | |
| 	};
 | |
| 	export const TaskTypeIcons: Record<number, string> = {
 | |
| 		[-2]: 'bi-exclamation-octagon-fill',
 | |
| 		[-1]: 'bi-exclamation-diamond-fill',
 | |
| 		0: 'database-fill-gear',
 | |
| 		1: 'database-fill-up',
 | |
| 		2: 'database-fill-lock',
 | |
| 		3: 'database-fill-gear',
 | |
| 		4: 'database-fill-check'
 | |
| 	};
 | |
| 	export const TaskTypeColors: Record<number, string> = {
 | |
| 		[-2]: 'red',
 | |
| 		[-1]: 'red',
 | |
| 		0: 'blue',
 | |
| 		1: 'blue',
 | |
| 		2: 'orange',
 | |
| 		3: 'orange',
 | |
| 		4: 'green'
 | |
| 	};
 | |
| </script>
 | |
| 
 | |
| <script lang="ts">
 | |
| 	import { post, showMessage } from 'src/lib/requests.svelte';
 | |
| 	import type { Model } from '../+page.svelte';
 | |
| 	import MessageSimple from 'src/lib/MessageSimple.svelte';
 | |
| 	import Tooltip from 'src/lib/Tooltip.svelte';
 | |
| 
 | |
| 	let { model }: { model: Model } = $props();
 | |
| 
 | |
| 	let page = $state(0);
 | |
| 	let showNext = $state(false);
 | |
| 	let task_list = $state<Task[]>([]);
 | |
| 
 | |
| 	export async function getList() {
 | |
| 		try {
 | |
| 			const res = await post('tasks/list', {
 | |
| 				model_id: model.id,
 | |
| 				page: page
 | |
| 			});
 | |
| 			showNext = res.show_next;
 | |
| 			task_list = res.task_list;
 | |
| 		} catch (e) {
 | |
| 			console.error('TODO notify user', e);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	$effect(() => {
 | |
| 		if (model) {
 | |
| 			getList();
 | |
| 		}
 | |
| 	});
 | |
| 
 | |
| 	let userPreceptionMessages: MessageSimple;
 | |
| 	// This returns a function that performs the call and does not do the call it self
 | |
| 	function userPreception(task: string, agree: number) {
 | |
| 		return async function () {
 | |
| 			try {
 | |
| 				await post('task/agreement', {
 | |
| 					id: task,
 | |
| 					agreement: agree
 | |
| 				});
 | |
| 				getList();
 | |
| 			} catch (e) {
 | |
| 				showMessage(e, userPreception);
 | |
| 			}
 | |
| 		};
 | |
| 	}
 | |
| </script>
 | |
| 
 | |
| <div>
 | |
| 	<h2>Tasks</h2>
 | |
| 	<MessageSimple bind:this={userPreceptionMessages} />
 | |
| 	<table>
 | |
| 		<thead>
 | |
| 			<tr>
 | |
| 				<th> Task type </th>
 | |
| 				<th>
 | |
| 					<!-- Img -->
 | |
| 				</th>
 | |
| 				<th> User Confirmed </th>
 | |
| 				<th> Result </th>
 | |
| 				<th> Status </th>
 | |
| 				<th> Status Message </th>
 | |
| 				<th> Created </th>
 | |
| 			</tr>
 | |
| 		</thead>
 | |
| 		<tbody>
 | |
| 			{#each task_list as task}
 | |
| 				<tr>
 | |
| 					<td>
 | |
| 						{#if task.type == 1}
 | |
| 							Image Run
 | |
| 						{:else if task.type == 2}
 | |
| 							Model training
 | |
| 						{:else if task.type == 3}
 | |
| 							Model Re-training
 | |
| 						{:else}
 | |
| 							{task.type}
 | |
| 						{/if}
 | |
| 					</td>
 | |
| 					<td class="text-center">
 | |
| 						{#if task.type == 1}
 | |
| 							<img
 | |
| 								alt=""
 | |
| 								src="/api/savedData/{model.id}/tasks/{task.id}.{model.format}"
 | |
| 								height="30px"
 | |
| 								width="30px"
 | |
| 								style="object-fit: contain;"
 | |
| 							/>
 | |
| 						{:else if [2, 3].includes(task.type)}{:else}
 | |
| 							TODO Show more information {task.status}
 | |
| 						{/if}
 | |
| 					</td>
 | |
| 					<td>
 | |
| 						{#if task.type == 1}
 | |
| 							{#if task.status == 4}
 | |
| 								{#if task.user_confirmed == 0}
 | |
| 									User has not agreed to the result of this task
 | |
| 								{:else if task.user_confirmed == -1}
 | |
| 									User has disagred with the result of this task
 | |
| 								{:else if task.user_confirmed == 1}
 | |
| 									User has aggred with the result of this task
 | |
| 								{:else}
 | |
| 									TODO {task.user_confirmed}
 | |
| 								{/if}
 | |
| 								<div>
 | |
| 									{#if task.user_confirmed != 1}
 | |
| 										<Tooltip title="Agree with the result of the task">
 | |
| 											<button type="button" on:click={userPreception(task.id, 1)}>
 | |
| 												<span class="bi bi-check"></span>
 | |
| 											</button>
 | |
| 										</Tooltip>
 | |
| 									{/if}
 | |
| 									{#if task.user_confirmed != -1}
 | |
| 										<Tooltip title="Disagree with the result">
 | |
| 											<button class="danger" type="button" on:click={userPreception(task.id, -1)}>
 | |
| 												<span class="bi bi-x-lg"></span>
 | |
| 											</button>
 | |
| 										</Tooltip>
 | |
| 									{/if}
 | |
| 								</div>
 | |
| 							{:else}
 | |
| 								-
 | |
| 							{/if}
 | |
| 						{:else if [2, 3].includes(task.type)}{:else}
 | |
| 							TODO Handle {task.type}
 | |
| 						{/if}
 | |
| 					</td>
 | |
| 					<td>
 | |
| 						{#if task.status == 4}
 | |
| 							{#if task.type == 1}
 | |
| 								{@const temp = JSON.parse(task.result)}
 | |
| 								{temp.class}({Math.round(temp.confidence * 100000) / 1000}%)
 | |
| 							{:else}
 | |
| 								{task.result}
 | |
| 							{/if}
 | |
| 						{/if}
 | |
| 					</td>
 | |
| 					<td style="text-align: center;">
 | |
| 						<Tooltip title={TaskTypeStrings[task.status]}>
 | |
| 							<span
 | |
| 								class="bi bi-{TaskTypeIcons[task.status]}"
 | |
| 								style="color: {TaskTypeColors[task.status]}; font-size: 1.5em;"
 | |
| 							>
 | |
| 							</span>
 | |
| 						</Tooltip>
 | |
| 					</td>
 | |
| 					<td>
 | |
| 						{task.status_message}
 | |
| 					</td>
 | |
| 					<td>
 | |
| 						{new Date(task.created).toLocaleString()}
 | |
| 					</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>
 | |
| 
 | |
| <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>
 |