hide completed tasks in projects, and add individual deadline tasks to front page.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
+4
-4
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ type TaskResult struct {
|
||||
type TaskFilter struct {
|
||||
UserID string
|
||||
Active *bool
|
||||
Expiring *bool
|
||||
IDs []string
|
||||
ItemIDs []string
|
||||
ProjectIDs []string
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()}));
|
||||
|
||||
@@ -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();
|
||||
Reference in New Issue
Block a user