Loggest thine Stuff
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

172 lines
5.5 KiB

<script lang="ts">
import { getStores } from "$app/stores";
import { sl3 } from "$lib/clients/sl3";
import Modal from "$lib/components/common/Modal.svelte";
import ModalBody from "$lib/components/common/ModalBody.svelte";
import { getModalContext } from "$lib/components/contexts/ModalContext.svelte";
import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte";
import { getSprintListContext } from "$lib/components/contexts/SprintListContext.svelte";
import PartInput from "$lib/components/controls/PartInput.svelte";
import SprintKindSelect from "$lib/components/controls/SprintKindSelect.svelte";
import TimeRangeInput from "$lib/components/controls/TimeRangeInput.svelte";
import Checkbox from "$lib/components/layout/Checkbox.svelte";
import type Scope from "$lib/models/scope";
import type Sprint from "$lib/models/sprint";
import { SprintKind, type SprintInput, type SprintInputPart } from "$lib/models/sprint";
import { formatFormTime } from "$lib/utils/date";
import { partsDiff } from "$lib/utils/sprint";
const {currentModal, closeModal} = getModalContext();
const {scope} = getScopeContext();
const {reloadSprintList} = getSprintListContext();
const {page} = getStores();
let sprint: SprintInput
let sprintId: number
let scopeId: number
let oldParts: SprintInputPart[]
let intervalName: string;
let openedDate: Date
let op: string
let error: string
let loading: boolean
let show: boolean
$: switch ($currentModal.name) {
case "sprint.create":
initCreate($scope)
break;
case "sprint.edit":
initEdit($currentModal.sprint)
break;
default:
loading = false;
error = null;
show = false;
}
function initCreate(scope: Scope) {
sprint = {
name: "",
description: "",
fromTime: "",
toTime: "",
kind: SprintKind.Stats,
aggregateName: "",
aggregateRequired: 0,
isCoarse: false,
isTimed: false,
isUnweighted: false,
parts: [],
}
intervalName = "this_month";
scopeId = scope.id;
op = "Create"
openedDate = new Date();
show = true;
}
function initEdit(current: Sprint) {
sprint = {
name: current.name,
description: current.description,
fromTime: formatFormTime(current.fromTime),
toTime: formatFormTime(current.toTime),
kind: current.kind,
aggregateName: current.aggregateName,
aggregateRequired: current.aggregateRequired,
isCoarse: current.isCoarse,
isTimed: current.isTimed,
isUnweighted: current.isUnweighted,
};
sprintId = current.id;
scopeId = current.scopeId;
intervalName = "specific_dates";
if (sprint.kind === SprintKind.Stats) {
sprint.parts = current.progress.map(p => ({partId: p.id, required: p.required}));
} else {
sprint.parts = current.partIds.map(p => ({partId: p, required: 0}));
}
oldParts = [...sprint.parts];
op = "Edit"
openedDate = new Date();
show = true;
}
async function submit() {
error = null;
loading = true;
const submission: SprintInput = {
...sprint,
fromTime: new Date(sprint.fromTime).toISOString(),
toTime: new Date(sprint.toTime).toISOString(),
}
try {
switch (op) {
case "Create":
await sl3(fetch, $page.stuff.idToken).createSprint(scopeId, submission);
break;
case "Edit":
await sl3(fetch, $page.stuff.idToken).updateSprint(scopeId, sprintId, submission);
const {added, removed} = partsDiff(oldParts, submission.parts)
for (const part of added) {
await sl3(fetch, $page.stuff.idToken).upsertSprintPart(scopeId, sprintId, part).catch(() => {});
}
for (const part of removed) {
await sl3(fetch, $page.stuff.idToken).deleteSprintPart(scopeId, sprintId, part).catch(() => {});
}
break;
}
await reloadSprintList();
closeModal();
} catch(err) {
if (err.statusCode != null) {
error = err.statusMessage;
} else {
error = err
}
} finally {
loading = false;
}
}
</script>
<form on:submit|preventDefault={submit}>
<Modal wide closable show={show} verb={op} noun="sprint" disabled={loading} error={error}>
<ModalBody>
<label for="name">Name</label>
<input name="name" type="text" bind:value={sprint.name} />
<label for="description">Description</label>
<textarea name="description" bind:value={sprint.description} />
<label for="time">Time</label>
<TimeRangeInput openDate={openedDate} bind:from={sprint.fromTime} bind:to={sprint.toTime} bind:intervalName={intervalName} />
<label for="aggregateName">Aggregate Name</label>
<input name="aggregateName" type="text" bind:value={sprint.aggregateName} />
{#if sprint.kind != SprintKind.Items}
<label for="aggregateValue">Aggregate Goal</label>
<input name="aggregateValue" type="number" bind:value={sprint.aggregateRequired} />
{/if}
<Checkbox bind:checked={sprint.isTimed} label="Sprint is timed" />
<Checkbox bind:checked={sprint.isCoarse} label="Show only aggregate" />
<Checkbox bind:checked={sprint.isUnweighted} label="Aggregate is unweighted" />
</ModalBody>
<ModalBody>
<label for="kind">Kind</label>
<SprintKindSelect disabled={op === "Edit"} bind:kind={sprint.kind} />
<label for="parts">Parts</label>
<PartInput bind:value={sprint.parts} kind={sprint.kind} scopeId={scopeId} />
</ModalBody>
</Modal>
</form>