Display task status in TaskDisplay
This commit is contained in:
parent
b20594d6b9
commit
af57e530f8
6 changed files with 88 additions and 20 deletions
|
@ -6,6 +6,7 @@
|
|||
import type { TasksFile, TaskDescriptor } from "./task-loader";
|
||||
import { createNodesAndEdges } from "./graph-types";
|
||||
import { taskForce } from "./task-force";
|
||||
import { taskStatuses } from './task-status-cache'
|
||||
import { grabTaskStates, isLoggedIn } from "./ksp-task-grabber";
|
||||
import type { TaskStatus } from "./ksp-task-grabber"
|
||||
|
||||
|
@ -20,7 +21,6 @@
|
|||
let clientHeight: number;
|
||||
let clientWidth: number;
|
||||
let svgElement: SVGElement;
|
||||
let taskStatuses = new Map<string, TaskStatus>();
|
||||
|
||||
// this prevents svelte from updating nodes and edges
|
||||
// when we update nodes and edges
|
||||
|
@ -94,17 +94,6 @@
|
|||
}
|
||||
|
||||
|
||||
if (isLoggedIn()) {
|
||||
const cachedTaskStatuses = localStorage.getItem("taskStatuses-cache")
|
||||
if (cachedTaskStatuses) {
|
||||
try { taskStatuses = new Map(JSON.parse(cachedTaskStatuses)) } catch(e) { console.warn(e) }
|
||||
}
|
||||
grabTaskStates(tasks.tasks.map(t => t.id)).then(t => {
|
||||
taskStatuses = t
|
||||
localStorage.setItem("taskStatuses-cache", JSON.stringify(Array.from(t.entries())))
|
||||
})
|
||||
}
|
||||
|
||||
// start simulation and center view on create
|
||||
onMount(() => {
|
||||
// set center of the SVG at (0,0)
|
||||
|
@ -155,7 +144,7 @@
|
|||
on:click={nodeClick(task.task)}
|
||||
on:hoveringChange={nodeHover(task.task)}
|
||||
on:positionChange={() => { tasks = tasks; }}
|
||||
status={taskStatuses.get(task.id)}
|
||||
status={$taskStatuses.get(task.id)}
|
||||
draggingEnabled={nodeDraggingEnabled}
|
||||
on:dblclick={nodeDoubleClick(task.task)} />
|
||||
{/each}
|
||||
|
|
|
@ -83,11 +83,23 @@
|
|||
fill: #69b3a2
|
||||
}
|
||||
.submitted ellipse {
|
||||
fill: red
|
||||
fill: red; /* TODO */
|
||||
}
|
||||
.solved ellipse {
|
||||
fill: green; /* TODO */
|
||||
}
|
||||
</style>
|
||||
|
||||
<g on:mouseenter={enter} on:mouseleave={leave} on:click={click} on:mousedown={dragStart} on:mouseup={dragStop} on:mousemove={drag} class={status && status.submitted ? "submitted" : ""} on:dblclick={dblclick}>
|
||||
<g on:mouseenter={enter}
|
||||
on:mouseleave={leave}
|
||||
on:click={click}
|
||||
on:mousedown={dragStart}
|
||||
on:mouseup={dragStop}
|
||||
on:mousemove={drag}
|
||||
on:dblclick={dblclick}
|
||||
class={status == null ? "" :
|
||||
status.solved ? "solved" :
|
||||
status.submitted ? "submitted" : ""}>
|
||||
<ellipse rx={ellipse_rx} ry={20} {cx} {cy} />
|
||||
<text
|
||||
bind:this={text_element}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<script type="ts">
|
||||
import { grabAssignment, grabSolution } from "./ksp-task-grabber";
|
||||
import type { TaskStatus } from "./ksp-task-grabber";
|
||||
import { nonNull } from './helpers'
|
||||
import App from "./App.svelte";
|
||||
import { taskStatuses } from "./task-status-cache";
|
||||
export let taskId: string | null | undefined
|
||||
|
||||
export let showSolution: boolean = false
|
||||
|
@ -9,11 +11,26 @@ import App from "./App.svelte";
|
|||
taskId
|
||||
showSolution = false
|
||||
}
|
||||
|
||||
let status: TaskStatus | undefined
|
||||
$: if (taskId) status = $taskStatuses.get(taskId)
|
||||
</script>
|
||||
<style>
|
||||
div {
|
||||
text-align: justify;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
}
|
||||
.header div {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.header .status {
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
|
@ -21,7 +38,22 @@ import App from "./App.svelte";
|
|||
{#await grabAssignment(nonNull(taskId))}
|
||||
Načítám úlohu
|
||||
{:then task}
|
||||
{@html task.titleHtml}
|
||||
<div class="header">
|
||||
<div class="title"><h3>{task.name}</h3></div>
|
||||
|
||||
<div class="status">
|
||||
<p>
|
||||
{task.id} | {task.points} bodů
|
||||
{#if status && status.submitted}
|
||||
{#if nonNull(status).solved}
|
||||
| Vyřešeno 🥳
|
||||
{:else}
|
||||
| odevzdáno za {nonNull(status).points} bod{ "ů yyy"[nonNull(status).points] ?? "ů" }
|
||||
{/if}
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{@html task.description}
|
||||
<div class="clearfloat" />
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { TasksFile } from "./task-loader";
|
||||
import { refresh } from './task-status-cache'
|
||||
|
||||
export let promise: Promise<TasksFile>;
|
||||
|
||||
|
@ -8,6 +9,7 @@
|
|||
let err: any | null = null;
|
||||
promise.then(
|
||||
(d) => {
|
||||
refresh(d.tasks.map(t => t.id))
|
||||
data = d;
|
||||
},
|
||||
(e) => {
|
||||
|
|
|
@ -19,6 +19,7 @@ export type TaskStatus = {
|
|||
id: string
|
||||
name: string
|
||||
submitted: boolean
|
||||
solved: boolean
|
||||
points: number
|
||||
maxPoints: number
|
||||
type: string
|
||||
|
@ -80,15 +81,17 @@ function parseTask(startElementId: string, doc: HTMLDocument): TaskAssignmentDat
|
|||
|
||||
let e = titleElement
|
||||
|
||||
const titleMatch = /(\d-Z?\d+-\d+) (.*?)( \((\d+) bod.*\))?/.exec(e.innerText.trim())
|
||||
const titleMatch = /^(\d+-Z?\d+-\d+) (.*?)( \((\d+) bod.*\))?$/.exec(e.innerText.trim())
|
||||
if (!titleMatch) {
|
||||
var [_, id, name, __, points] = ["", startElementId, "Neznámé jméno úlohy", "", ""]
|
||||
} else {
|
||||
var [_, id, name, __, points] = titleMatch
|
||||
}
|
||||
|
||||
e = e.nextElementSibling as HTMLElement
|
||||
|
||||
while (e.nextElementSibling &&
|
||||
e.nextElementSibling?.tagName.toLowerCase() == "hr")
|
||||
e.tagName.toLowerCase() == "hr")
|
||||
e = e.nextElementSibling as HTMLElement
|
||||
|
||||
while (!e.classList.contains("story") &&
|
||||
|
@ -124,11 +127,12 @@ function parseTaskStatuses(doc: HTMLDocument): TaskStatus[] {
|
|||
const type = r.cells[1].innerText.trim()
|
||||
const name = r.cells[2].innerText.trim()
|
||||
const pointsStr = r.cells[4].innerText.trim()
|
||||
const pointsMatch = /(–|\d+) *\/ *(\d+)/.exec(pointsStr)
|
||||
const pointsMatch = /((–|\.|\d)+) *\/ *(\d+)/.exec(pointsStr)
|
||||
if (!pointsMatch) throw new Error()
|
||||
const points = +pointsMatch[1]
|
||||
const maxPoints = +pointsMatch[2]
|
||||
return { id, name, submitted, type, points, maxPoints }
|
||||
const solved = r.classList.contains("zs-submitted")
|
||||
return { id, name, submitted, type, points, maxPoints, solved }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
29
frontend/src/task-status-cache.ts
Normal file
29
frontend/src/task-status-cache.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { grabTaskStates, isLoggedIn} from "./ksp-task-grabber"
|
||||
import type { TaskStatus } from "./ksp-task-grabber"
|
||||
import { readable } from 'svelte/store';
|
||||
|
||||
let writeFn: (value: Map<string, TaskStatus>) => void = null!;
|
||||
let lastVal = new Map<string, TaskStatus>()
|
||||
if (isLoggedIn()) {
|
||||
const cachedTaskStatuses = localStorage.getItem("taskStatuses-cache")
|
||||
if (cachedTaskStatuses) {
|
||||
lastVal = new Map(JSON.parse(cachedTaskStatuses))
|
||||
}
|
||||
}
|
||||
export const taskStatuses = readable(lastVal, write => {
|
||||
writeFn = v => { lastVal = v; write(v); }
|
||||
})
|
||||
|
||||
console.log(isLoggedIn())
|
||||
|
||||
|
||||
|
||||
export function refresh(ids: string[]) {
|
||||
if (!isLoggedIn()) return;
|
||||
|
||||
grabTaskStates(ids).then(t => {
|
||||
const tt = Array.from(t.entries())
|
||||
writeFn(new Map(Array.from(lastVal.entries()).concat(tt)))
|
||||
localStorage.setItem("taskStatuses-cache", JSON.stringify(tt))
|
||||
})
|
||||
}
|
Reference in a new issue