diff --git a/database/postgres/tasks.go b/database/postgres/tasks.go index 2b52404..a7126e7 100644 --- a/database/postgres/tasks.go +++ b/database/postgres/tasks.go @@ -51,7 +51,7 @@ func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([] } sq = sq.InnerJoin("project AS p ON task.project_id = p.project_id") - sq = sq.OrderBy("active DESC", "created_time") + sq = sq.OrderBy("active DESC", "status_tag ASC", "created_time") query, args, err := sq.ToSql() if err != nil { @@ -73,9 +73,9 @@ func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([] func (r *taskRepository) Insert(ctx context.Context, task models.Task) error { _, err := r.db.NamedExecContext(ctx, ` INSERT INTO task ( - task_id, user_id, item_id, project_id, item_amount, name, description, active, created_time, end_time + task_id, user_id, item_id, project_id, item_amount, name, description, active, created_time, end_time, status_tag ) VALUES ( - :task_id, :user_id, :item_id, :project_id, :item_amount, :name, :description, :active, :created_time, :end_time + :task_id, :user_id, :item_id, :project_id, :item_amount, :name, :description, :active, :created_time, :end_time, :status_tag ) `, &task) if err != nil { @@ -93,7 +93,8 @@ func (r *taskRepository) Update(ctx context.Context, task models.Task) error { name = :name, description = :description, active = :active, - end_time = :end_time + end_time = :end_time, + status_tag = :status_tag WHERE task_id=:task_id `, &task) if err != nil { diff --git a/migrations/postgres/20210124104325_rename_project_status_tag_todo.sql b/migrations/postgres/20210124104325_rename_project_status_tag_todo.sql new file mode 100644 index 0000000..62697e8 --- /dev/null +++ b/migrations/postgres/20210124104325_rename_project_status_tag_todo.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +UPDATE project SET status_tag='to do' WHERE status_tag='idea'; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'Nothing to do'; +-- +goose StatementEnd diff --git a/migrations/postgres/20210124104330_rename_project_status_tag_onhold.sql b/migrations/postgres/20210124104330_rename_project_status_tag_onhold.sql new file mode 100644 index 0000000..97d2d0e --- /dev/null +++ b/migrations/postgres/20210124104330_rename_project_status_tag_onhold.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +UPDATE project SET status_tag='on hold' WHERE status_tag='postponed'; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'Nothing to do'; +-- +goose StatementEnd diff --git a/migrations/postgres/20210124105003_add_task_column_status_tag.sql b/migrations/postgres/20210124105003_add_task_column_status_tag.sql new file mode 100644 index 0000000..b7de6db --- /dev/null +++ b/migrations/postgres/20210124105003_add_task_column_status_tag.sql @@ -0,0 +1,11 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE task + ADD COLUMN status_tag TEXT DEFAULT NULL; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE task + DROP COLUMN status_tag; +-- +goose StatementEnd diff --git a/migrations/postgres/20210124110913_update_task_default_inactive_tag.sql b/migrations/postgres/20210124110913_update_task_default_inactive_tag.sql new file mode 100644 index 0000000..50216c2 --- /dev/null +++ b/migrations/postgres/20210124110913_update_task_default_inactive_tag.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +UPDATE task SET status_tag='completed' WHERE active=false; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'Nothing to do'; +-- +goose StatementEnd diff --git a/models/task.go b/models/task.go index ea8c756..3b6bf46 100644 --- a/models/task.go +++ b/models/task.go @@ -17,6 +17,7 @@ type Task struct { Active bool `json:"active" db:"active"` CreatedTime time.Time `json:"createdTime" db:"created_time"` EndTime *time.Time `json:"endTime" db:"end_time"` + StatusTag *string `json:"statusTag" db:"status_tag"` } func (task *Task) Update(update TaskUpdate) { @@ -42,16 +43,24 @@ func (task *Task) Update(update TaskUpdate) { if update.ClearEndTime { task.EndTime = nil } + if update.StatusTag != nil { + task.StatusTag = update.StatusTag + } + if update.ClearStatusTag { + task.StatusTag = nil + } } type TaskUpdate struct { - ItemID *string `json:"itemId"` - ItemAmount *int `json:"itemAmount"` - Name *string `json:"name"` - Description *string `json:"description"` - Active *bool `json:"active"` - EndTime *time.Time `json:"endTime"` - ClearEndTime bool `json:"clearEndTime"` + ItemID *string `json:"itemId"` + ItemAmount *int `json:"itemAmount"` + Name *string `json:"name"` + Description *string `json:"description"` + Active *bool `json:"active"` + EndTime *time.Time `json:"endTime"` + ClearEndTime bool `json:"clearEndTime"` + StatusTag *string `json:"statusTag"` + ClearStatusTag bool `json:"clearStatusTag"` } type TaskResult struct { diff --git a/svelte-ui/src/components/Progress.svelte b/svelte-ui/src/components/Progress.svelte index 7165b67..5786d77 100644 --- a/svelte-ui/src/components/Progress.svelte +++ b/svelte-ui/src/components/Progress.svelte @@ -60,7 +60,7 @@ // Mark it non-segmented if the target is too high. This prevents a clunky progress bar, // or a browser freeze if you set the target very high. - nonSegmented = (target >= 50); + nonSegmented = (target >= 60); } $: { diff --git a/svelte-ui/src/components/ProjectEntry.svelte b/svelte-ui/src/components/ProjectEntry.svelte index dc77d44..a4a9aca 100644 --- a/svelte-ui/src/components/ProjectEntry.svelte +++ b/svelte-ui/src/components/ProjectEntry.svelte @@ -1,15 +1,12 @@ - + Delete {/if} - {#each project.tasks as task (task.id)} - {#if !hideInactive || task.active} - - {/if} - {/each} + {#if hideInactive} + + {:else} + + + + + + {/if} diff --git a/svelte-ui/src/components/ProjectIcon.svelte b/svelte-ui/src/components/ProjectIcon.svelte index f4a0030..f1f0a62 100644 --- a/svelte-ui/src/components/ProjectIcon.svelte +++ b/svelte-ui/src/components/ProjectIcon.svelte @@ -5,37 +5,11 @@ interface ProjectLike { icon?: IconName - active?: boolean - statusTag?: string } export let project: ProjectLike - export let selected: boolean; - - let completed: boolean; - let failed: boolean; - let postponed: boolean; - let idea: boolean; - - $: completed = !project.active && project.statusTag === "completed"; - $: failed = !project.active && project.statusTag === "failed"; - $: postponed = !project.active && project.statusTag === "postponed"; - $: idea = !project.active && project.statusTag === "idea"; - + - - \ No newline at end of file diff --git a/svelte-ui/src/components/QLListItem.svelte b/svelte-ui/src/components/QLListItem.svelte index 7c40cdc..34bc656 100644 --- a/svelte-ui/src/components/QLListItem.svelte +++ b/svelte-ui/src/components/QLListItem.svelte @@ -22,7 +22,7 @@ $: completed = !project.active; - +
diff --git a/svelte-ui/src/components/QuestLog.svelte b/svelte-ui/src/components/QuestLog.svelte index b78258b..588b866 100644 --- a/svelte-ui/src/components/QuestLog.svelte +++ b/svelte-ui/src/components/QuestLog.svelte @@ -20,9 +20,9 @@ $: activeProjects = projects.filter(p => p.active && !p.endTime).sort((a,b) => a.name.localeCompare(b.name)); $: inactiveProjects = projects.filter(p => !p.active).sort((a,b) => a.name.localeCompare(b.name)); $: completedProjects = inactiveProjects.filter(p => p.statusTag === "completed" || p.statusTag == null); - $: failedProjects = inactiveProjects.filter(p => p.statusTag === "failed" || p.statusTag == null); - $: postponedProjects = inactiveProjects.filter(p => p.statusTag === "postponed" || p.statusTag == null); - $: ideaProjects = inactiveProjects.filter(p => p.statusTag === "idea" || p.statusTag == null); + $: failedProjects = inactiveProjects.filter(p => p.statusTag === "failed" || p.statusTag === "declined"); + $: postponedProjects = inactiveProjects.filter(p => p.statusTag === "on hold" || p.statusTag === "postponed"); + $: ideaProjects = inactiveProjects.filter(p => p.statusTag === "to do" || p.statusTag === "idea"); $: { if (project === null && projects.length > 0) { @@ -38,9 +38,9 @@
+ + - -
diff --git a/svelte-ui/src/components/StatusColor.svelte b/svelte-ui/src/components/StatusColor.svelte index 9c55899..5c71595 100644 --- a/svelte-ui/src/components/StatusColor.svelte +++ b/svelte-ui/src/components/StatusColor.svelte @@ -1,42 +1,58 @@ -
+
\ No newline at end of file diff --git a/svelte-ui/src/components/StatusTagSelect.svelte b/svelte-ui/src/components/StatusTagSelect.svelte new file mode 100644 index 0000000..f6d5ffd --- /dev/null +++ b/svelte-ui/src/components/StatusTagSelect.svelte @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/svelte-ui/src/components/TaskEntry.svelte b/svelte-ui/src/components/TaskEntry.svelte index 2dd990f..5499d29 100644 --- a/svelte-ui/src/components/TaskEntry.svelte +++ b/svelte-ui/src/components/TaskEntry.svelte @@ -4,11 +4,12 @@ import type { ModalData } from "../stores/modal"; import ChildEntry from "./ChildEntry.svelte"; import DateSpan from "./DateSpan.svelte"; - import Icon from "./Icon.svelte"; import ItemLink from "./ItemLink.svelte"; -import Markdown from "./Markdown.svelte"; + import Markdown from "./Markdown.svelte"; import Option from "./Option.svelte"; import OptionRow from "./OptionRow.svelte"; + import StatusColor from "./StatusColor.svelte"; + import TaskIcon from "./TaskIcon.svelte"; export let task: TaskResult = null; export let project: Project = null; @@ -28,74 +29,38 @@ import Markdown from "./Markdown.svelte"; $: mdTaskDelete = {name: "task.delete", task: {...task, project}}; - -
- {#if !task.active} - - - {task.completedAmount} / {task.itemAmount} - - {:else} - {task.completedAmount} / {task.itemAmount} - {/if} -
- - - {#if task.logs.length > 0} - - {/if} - - {#if showAllOptions} - - - {/if} - - {#if showLogs && task.logs.length > 0} -
- {#each task.logs as log (log.id)} -
-
-
- -
-
- {/each} + + +
+
- {/if} -
+ + + {#if task.logs.length > 0} + + {/if} + + {#if showAllOptions} + + + {/if} + + {#if showLogs && task.logs.length > 0} +
+ {#each task.logs as log (log.id)} +
+
+
+ +
+
+ {/each} +
+ {/if} + +
\ No newline at end of file diff --git a/svelte-ui/src/components/TaskList.svelte b/svelte-ui/src/components/TaskList.svelte new file mode 100644 index 0000000..f124bd8 --- /dev/null +++ b/svelte-ui/src/components/TaskList.svelte @@ -0,0 +1,30 @@ + + +{#if tasks.length > 0} +

{header}

+ {#each tasks as task (task.id)} + + {/each} +{/if} + + \ No newline at end of file diff --git a/svelte-ui/src/external/icons.ts b/svelte-ui/src/external/icons.ts index 35ac92a..1e812b1 100644 --- a/svelte-ui/src/external/icons.ts +++ b/svelte-ui/src/external/icons.ts @@ -72,6 +72,28 @@ import { faMoon } from "@fortawesome/free-solid-svg-icons/faMoon"; import { faCloudMoon } from "@fortawesome/free-solid-svg-icons/faCloudMoon"; import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; +import { faFilter } from "@fortawesome/free-solid-svg-icons/faFilter"; +import { faShoppingBag } from "@fortawesome/free-solid-svg-icons/faShoppingBag"; +import { faTags } from "@fortawesome/free-solid-svg-icons/faTags"; +import { faBalanceScale } from "@fortawesome/free-solid-svg-icons/faBalanceScale"; +import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner"; +import { faHourglass } from "@fortawesome/free-solid-svg-icons/faHourglass"; +import { faCalendar } from "@fortawesome/free-solid-svg-icons/faCalendar"; +import { faWeight } from "@fortawesome/free-solid-svg-icons/faWeight"; +import { faAnchor } from "@fortawesome/free-solid-svg-icons/faAnchor"; +import { faAngry } from "@fortawesome/free-solid-svg-icons/faAngry"; +import { faAnkh } from "@fortawesome/free-solid-svg-icons/faAnkh"; +import { faDumbbell } from "@fortawesome/free-solid-svg-icons/faDumbbell"; +import { faDollarSign } from "@fortawesome/free-solid-svg-icons/faDollarSign"; +import { faExpand } from "@fortawesome/free-solid-svg-icons/faExpand"; +import { faFeather } from "@fortawesome/free-solid-svg-icons/faFeather"; +import { faFingerprint } from "@fortawesome/free-solid-svg-icons/faFingerprint"; +import { faPaintBrush } from "@fortawesome/free-solid-svg-icons/faPaintBrush"; +import { faPaintRoller } from "@fortawesome/free-solid-svg-icons/faPaintRoller"; +import { faPastafarianism } from "@fortawesome/free-solid-svg-icons/faPastafarianism"; +import { faSpider } from "@fortawesome/free-solid-svg-icons/faSpider"; +import { faStroopwafel } from "@fortawesome/free-solid-svg-icons/faStroopwafel"; +import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch"; const icons = { "question": faQuestion, @@ -148,6 +170,28 @@ const icons = { "cloud_moon": faCloudMoon, "chevron_right": faChevronRight, "chevron_down": faChevronDown, + "filter": faFilter, + "shopping_bag": faShoppingBag, + "tags": faTags, + "balance_scale": faBalanceScale, + "spinner": faSpinner, + "hourglass": faHourglass, + "calendar": faCalendar, + "weight": faWeight, + "anchor": faAnchor, + "angry": faAngry, + "ankh": faAnkh, + "dumbbell": faDumbbell, + "dollar_sign": faDollarSign, + "expand": faExpand, + "feather": faFeather, + "fingerprint": faFingerprint, + "paint_brush": faPaintBrush, + "paint_roller": faPaintRoller, + "pastafarianism": faPastafarianism, + "spider": faSpider, + "stroopwafel": faStroopwafel, + "bottle_opener": faSearch, }; export type IconName = keyof typeof icons; diff --git a/svelte-ui/src/forms/ProjectForm.svelte b/svelte-ui/src/forms/ProjectForm.svelte index 73f3777..61954f7 100644 --- a/svelte-ui/src/forms/ProjectForm.svelte +++ b/svelte-ui/src/forms/ProjectForm.svelte @@ -3,6 +3,7 @@ import Checkbox from "../components/Checkbox.svelte"; import IconSelect from "../components/IconSelect.svelte"; import Modal from "../components/Modal.svelte"; +import StatusTagSelect from "../components/StatusTagSelect.svelte"; import { iconNames } from "../external/icons"; import type { ProjectResult } from "../models/project"; import markStale from "../stores/markStale"; @@ -103,13 +104,8 @@ - + +
diff --git a/svelte-ui/src/forms/TaskForm.svelte b/svelte-ui/src/forms/TaskForm.svelte index 34730af..7f3a360 100644 --- a/svelte-ui/src/forms/TaskForm.svelte +++ b/svelte-ui/src/forms/TaskForm.svelte @@ -1,8 +1,8 @@