Gisle Aune
4 years ago
17 changed files with 365 additions and 46 deletions
-
60api/task.go
-
5database/postgres/project.go
-
98database/postgres/tasks.go
-
15migrations/postgres/20210403142913_create_table_task_link.sql
-
10models/task.go
-
15services/loader.go
-
3svelte-ui/src/App.svelte
-
14svelte-ui/src/clients/stufflog.ts
-
5svelte-ui/src/components/ProgressNumbers.svelte
-
3svelte-ui/src/components/ProjectEntry.svelte
-
14svelte-ui/src/components/ProjectSelect.svelte
-
48svelte-ui/src/components/TaskEntry.svelte
-
36svelte-ui/src/components/TaskSelect.svelte
-
69svelte-ui/src/forms/TaskLinkForm.svelte
-
6svelte-ui/src/models/task.ts
-
2svelte-ui/src/pages/QLPage.svelte
-
8svelte-ui/src/stores/modal.ts
@ -0,0 +1,15 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE TABLE task_link ( |
||||
|
project_id CHAR(16) NOT NULL, |
||||
|
task_id CHAR(16) NOT NULL, |
||||
|
|
||||
|
PRIMARY KEY (project_id, task_id), |
||||
|
UNIQUE (task_id, project_id) |
||||
|
); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP TABLE task_link; |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,36 @@ |
|||||
|
<script lang="ts"> |
||||
|
import projectStore from "../stores/project"; |
||||
|
|
||||
|
export let value = ""; |
||||
|
export let name = ""; |
||||
|
export let disabled = false; |
||||
|
export let optional = false; |
||||
|
|
||||
|
$: { |
||||
|
if ($projectStore.stale && !$projectStore.loading) { |
||||
|
projectStore.load({}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
$: { |
||||
|
if ($projectStore.projects.length > 0 && value === "" && !optional) { |
||||
|
const nonEmpty = $projectStore.projects.find(g => g.tasks.length > 0); |
||||
|
if (nonEmpty != null) { |
||||
|
value = nonEmpty.tasks[0].id; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<select name={name} bind:value={value} disabled={disabled || $projectStore.loading}> |
||||
|
{#if optional} |
||||
|
<option value={""} selected={"" === value}>None</option> |
||||
|
{/if} |
||||
|
{#each $projectStore.projects as project (project.id)} |
||||
|
<optgroup label={project.name}> |
||||
|
{#each project.tasks as task (task.id)} |
||||
|
<option value={task.id} selected={task.id === value}>{task.name}</option> |
||||
|
{/each} |
||||
|
</optgroup> |
||||
|
{/each} |
||||
|
</select> |
@ -0,0 +1,69 @@ |
|||||
|
<script lang="ts"> |
||||
|
import stuffLogClient from "../clients/stufflog"; |
||||
|
import Modal from "../components/Modal.svelte"; |
||||
|
import ProjectSelect from "../components/ProjectSelect.svelte"; |
||||
|
import TaskSelect from "../components/TaskSelect.svelte"; |
||||
|
import markStale from "../stores/markStale"; |
||||
|
import modalStore from "../stores/modal"; |
||||
|
|
||||
|
export let deletion = false; |
||||
|
export let creation = false; |
||||
|
|
||||
|
const md = $modalStore; |
||||
|
|
||||
|
let projectId = ""; |
||||
|
let taskId = ""; |
||||
|
let verb = "Add"; |
||||
|
|
||||
|
if (md.name === "tasklink.delete") { |
||||
|
projectId = md.project.id; |
||||
|
taskId = md.task.id; |
||||
|
verb = "Delete"; |
||||
|
} else if (md.name === "tasklink.add") { |
||||
|
projectId = (md.project||{id:""}).id; |
||||
|
taskId = (md.task||{id:""}).id; |
||||
|
} else { |
||||
|
throw new Error(`Wrong form ${md.name}`) |
||||
|
} |
||||
|
|
||||
|
let error = null; |
||||
|
let loading = false; |
||||
|
|
||||
|
function onSubmit() { |
||||
|
loading = true; |
||||
|
error = null; |
||||
|
|
||||
|
if (creation) { |
||||
|
stuffLogClient.createTaskLink(projectId, taskId).then(() => { |
||||
|
markStale("goal", "project"); |
||||
|
modalStore.close(); |
||||
|
}).catch(err => { |
||||
|
error = err.message ? err.message : err.toString(); |
||||
|
}).finally(() => { |
||||
|
loading = false; |
||||
|
}) |
||||
|
} else if (deletion) { |
||||
|
stuffLogClient.deleteTaskLink(projectId, taskId).then(() => { |
||||
|
markStale("goal", "project"); |
||||
|
modalStore.close(); |
||||
|
}).catch(err => { |
||||
|
error = err.message ? err.message : err.toString(); |
||||
|
}).finally(() => { |
||||
|
loading = false; |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<Modal show title="{verb} Link" error={error} closable on:close={modalStore.close}> |
||||
|
<form on:submit|preventDefault={onSubmit}> |
||||
|
<label for="taskId">Source Task</label> |
||||
|
<TaskSelect disabled={deletion} name="taskId" bind:value={taskId} /> |
||||
|
<label for="projectId">Destination Project</label> |
||||
|
<ProjectSelect disabled={deletion} name="projectId" bind:value={projectId} /> |
||||
|
|
||||
|
<hr /> |
||||
|
|
||||
|
<button disabled={loading} type="submit">{verb} Link</button> |
||||
|
</form> |
||||
|
</Modal> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue