Browse Source

hide completed tasks in projects, and add individual deadline tasks to front page.

main
Gisle Aune 3 years ago
parent
commit
48ba7c8693
  1. 8
      api/task.go
  2. 7
      database/postgres/tasks.go
  3. 1
      models/task.go
  4. 14
      svelte-ui/src/clients/stufflog.ts
  5. 8
      svelte-ui/src/components/ProjectEntry.svelte
  6. 3
      svelte-ui/src/models/group.ts
  7. 3
      svelte-ui/src/models/item.ts
  8. 5
      svelte-ui/src/models/project.ts
  9. 9
      svelte-ui/src/models/task.ts
  10. 37
      svelte-ui/src/pages/FrontPage.svelte
  11. 4
      svelte-ui/src/pages/ProjectPage.svelte
  12. 1
      svelte-ui/src/stores/project.ts
  13. 38
      svelte-ui/src/stores/tasks.ts

8
api/task.go

@ -14,15 +14,15 @@ import (
func Task(g *gin.RouterGroup, db database.Database) {
l := services.Loader{DB: db}
defaultActive := true
g.GET("/", handler("tasks", func(c *gin.Context) (interface{}, error) {
filter := models.TaskFilter{}
if setting := c.Query("active"); setting != "" {
active := setting == "true"
filter.Active = &active
} else {
filter.Active = &defaultActive
}
if setting := c.Query("expiring"); setting != "" {
expiring := setting == "true"
filter.Expiring = &expiring
}
return l.ListTasks(c, filter)

7
database/postgres/tasks.go

@ -33,6 +33,13 @@ func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([]
if filter.Active != nil {
sq = sq.Where(squirrel.Eq{"task.active": *filter.Active})
}
if filter.Expiring != nil {
if *filter.Expiring {
sq = sq.Where("task.end_time IS NOT NULL")
} else {
sq = sq.Where("task.end_time IS NULL")
}
}
if filter.IDs != nil {
sq = sq.Where(squirrel.Eq{"task.task_id": filter.IDs})
}

1
models/task.go

@ -60,6 +60,7 @@ type TaskResult struct {
type TaskFilter struct {
UserID string
Active *bool
Expiring *bool
IDs []string
ItemIDs []string
ProjectIDs []string

14
svelte-ui/src/clients/stufflog.ts

@ -1,7 +1,7 @@
import { getJwt } from "./amplify";
import type { GoalFilter, GoalInput, GoalResult, GoalUpdate } from "../models/goal";
import type { ProjectFilter, ProjectInput, ProjectResult, ProjectUpdate } from "../models/project";
import type { TaskInput, TaskResult, TaskUpdate } from "../models/task";
import type { TaskFilter, TaskInput, TaskResult, TaskUpdate } from "../models/task";
import type { LogFilter, LogInput, LogResult, LogUpdate } from "../models/log";
import type { GroupInput, GroupResult, GroupUpdate } from "../models/group";
import type { ItemInput, ItemResult, ItemUpdate } from "../models/item";
@ -134,8 +134,16 @@ export class StufflogClient {
return data.task;
}
async listTasks(active?: boolean): Promise<TaskResult[]> {
let query = (active != null) ? `?active=${active}` : "";
async listTasks({active, expiring}: TaskFilter): Promise<TaskResult[]> {
let queries = [];
if (active != null) {
queries.push(`active=${active}`);
}
if (expiring != null) {
queries.push(`expiring=${expiring}`);
}
const query = queries.length > 0 ? `?${queries.join("&")}` : "";
const data = await this.fetch("GET", `/api/task/${query}`);
return data.tasks;

8
svelte-ui/src/components/ProjectEntry.svelte

@ -1,5 +1,6 @@
<script lang="ts">
import type { IconName } from "../external/icons";
import TaskAddForm from "../forms/TaskAddForm.svelte";
import type { ProjectResult } from "../models/project";
import type { ModalData } from "../stores/modal";
import DaysLeft from "./DaysLeft.svelte";
@ -10,16 +11,15 @@
export let project: ProjectResult = null;
export let showAllOptions: boolean = false;
export let hideInactive: boolean = false;
let iconName: IconName = "question";
let mdAddTask: ModalData;
let mdProjectAdd: ModalData;
let mdProjectEdit: ModalData;
let mdProjectDelete: ModalData;
$: iconName = project.icon as IconName;
$: mdAddTask = {name:"task.add", project};
$: mdProjectAdd = {name:"project.add"};
$: mdProjectEdit = {name:"project.edit", project};
$: mdProjectDelete = {name:"project.delete", project};
</script>
@ -47,7 +47,9 @@
{/if}
<div class="list" class:full={showAllOptions}>
{#each project.tasks as task (task.id)}
<TaskEntry showAllOptions={showAllOptions} task={task} />
{#if !hideInactive || task.active}
<TaskEntry showAllOptions={showAllOptions} task={task} />
{/if}
{/each}
</div>
</div>

3
svelte-ui/src/models/group.ts

@ -1,9 +1,10 @@
import type { IconName } from "../external/icons";
import type Item from "./item";
export default interface Group {
id: string
name: string
icon: string
icon: IconName
description: string
}

3
svelte-ui/src/models/item.ts

@ -1,10 +1,11 @@
import type { IconName } from "../external/icons";
import type Group from "./group";
export default interface Item {
id: string
groupId: string
groupWeight: number
icon: string
icon: IconName
name: string
description: string
}

5
svelte-ui/src/models/project.ts

@ -1,10 +1,11 @@
import type { IconName } from "../external/icons";
import type { TaskResult } from "./task";
export default interface Project {
id: string
name: string
description: string
icon: string
icon: IconName
active: boolean
createdTime: string
endTime?: string
@ -22,7 +23,7 @@ export interface ProjectFilter {
export interface ProjectInput {
name: string
description: string
icon: string
icon: IconName
active: boolean
endTime?: string | Date
}

9
svelte-ui/src/models/task.ts

@ -1,3 +1,4 @@
import type { IconName } from "../external/icons";
import type Item from "./item";
import type Log from "./log";
@ -8,18 +9,22 @@ export default interface Task {
itemAmount: number
name: string
description: string
icon: string
icon: IconName
active: boolean
createdTime: string
endTime?: string
}
export interface TaskResult extends Task {
item: Item
logs: Log[]
completedAmount: number
}
export interface TaskFilter {
active?: boolean
expiring?: boolean
}
export interface TaskInput {
itemId: string
projectId: string

37
svelte-ui/src/pages/FrontPage.svelte

@ -1,9 +1,13 @@
<script>
<script lang="ts">
import EmptyList from "../components/EmptyList.svelte";
import GoalEntry from "../components/GoalEntry.svelte";
import ProjectEntry from "../components/ProjectEntry.svelte";
import type { ProjectResult } from "../models/project";
import { fpGoalStore } from "../stores/goal";
import { fpProjectStore } from "../stores/project";
import { fpTaskStore } from "../stores/tasks";
let fakeProject: ProjectResult
$: {
if ($fpGoalStore.stale && !$fpGoalStore.loading) {
@ -14,6 +18,15 @@
}
}
$: {
if ($fpTaskStore.stale && !$fpTaskStore.loading) {
fpTaskStore.load({
active: true,
expiring: true,
})
}
}
$: {
if ($fpProjectStore.stale && !$fpProjectStore.loading) {
fpProjectStore.load({
@ -22,6 +35,21 @@
});
}
}
$: {
fakeProject = {
id: "P_fakeProject",
active: true,
createdTime: new Date().toISOString(),
description: "",
icon: "list",
name: "Individual Tasks",
tasks: $fpTaskStore.tasks.filter(t => $fpProjectStore.projects.find(p => p.id === t.id) == null),
endTime: null,
}
console.log(fakeProject, $fpTaskStore);
}
</script>
<div class="page">
@ -41,9 +69,12 @@
<h1>Upcoming Deadlines</h1>
{/if}
{#each $fpProjectStore.projects as project (project.id)}
<ProjectEntry project={project} />
<ProjectEntry hideInactive project={project} />
{/each}
{#if !$fpProjectStore.loading && $fpProjectStore.projects.length === 0}
{#if fakeProject.tasks.length > 0}
<ProjectEntry project={fakeProject} />
{/if}
{#if fakeProject.tasks.length === 0 && !$fpProjectStore.loading && $fpProjectStore.projects.length === 0}
<EmptyList icon="check" text="All good!" />
{/if}
</div>

4
svelte-ui/src/pages/ProjectPage.svelte

@ -28,10 +28,10 @@
<div class="page">
<div class="options">
<Checkbox centered bind:checked={showInactive} label="Show inactive projects." />
<Checkbox centered bind:checked={showInactive} label="Show completed tasks and projects." />
</div>
{#each $projectStore.projects as project (project.id)}
<ProjectEntry showAllOptions project={project} />
<ProjectEntry hideInactive={!showInactive} showAllOptions project={project} />
{/each}
<Boi open={mdProjectAdd}>Add Project</Boi>
</div>

1
svelte-ui/src/stores/project.ts

@ -25,7 +25,6 @@ function createProjectStore() {
},
async load(filter: ProjectFilter) {
console.log(filter);
update(v => ({...v, loading: true, stale: false, filter}));
const projects = await stuffLogClient.listProjects(filter);
update(v => ({...v, loading: false, projects: projects.reverse()}));

38
svelte-ui/src/stores/tasks.ts

@ -0,0 +1,38 @@
import { writable } from "svelte/store";
import stuffLogClient from "../clients/stufflog";
import type { TaskFilter, TaskResult } from "../models/task";
interface TaskStoreData {
loading: boolean
stale: boolean
filter: TaskFilter
tasks: TaskResult[]
}
function createTaskStore() {
const {update, subscribe} = writable<TaskStoreData>({
loading: false,
stale: true,
filter: {},
tasks: [],
});
return {
subscribe,
markStale() {
update(v => ({...v, stale: true}));
},
async load(filter: TaskFilter) {
update(v => ({...v, loading: true, stale: false, filter}));
const tasks = await stuffLogClient.listTasks(filter);
update(v => ({...v, loading: false, tasks: [...tasks]}));
},
}
}
const taskStore = createTaskStore();
export default taskStore;
export const fpTaskStore = createTaskStore();
Loading…
Cancel
Save