add support for project inactivity, added new checkbox component.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -14,15 +14,11 @@ import (
|
||||
func Project(g *gin.RouterGroup, db database.Database) {
|
||||
l := services.Loader{DB: db}
|
||||
|
||||
defaultActive := true
|
||||
|
||||
g.GET("/", handler("projects", func(c *gin.Context) (interface{}, error) {
|
||||
filter := models.ProjectFilter{}
|
||||
if setting := c.Query("active"); setting != "" {
|
||||
active := setting == "true"
|
||||
filter.Active = &active
|
||||
} else {
|
||||
filter.Active = &defaultActive
|
||||
}
|
||||
if setting := c.Query("expiring"); setting != "" {
|
||||
filter.Expiring = setting == "true"
|
||||
|
||||
@@ -40,7 +40,7 @@ func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilte
|
||||
sq = sq.Where("end_time IS NOT NULL")
|
||||
}
|
||||
|
||||
sq = sq.OrderBy("created_time DESC")
|
||||
sq = sq.OrderBy("active", "created_time DESC")
|
||||
|
||||
query, args, err := sq.ToSql()
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import Icon from "./Icon.svelte";
|
||||
|
||||
export let checked = false;
|
||||
export let centered = false;
|
||||
export let disabled = false;
|
||||
export let label = "(Missing label property)";
|
||||
|
||||
function handleClick() {
|
||||
if (!disabled) {
|
||||
checked = !checked;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="checkbox" class:centered on:click={handleClick}>
|
||||
<div class="box" class:disabled class:checked class:unchecked={!checked}>
|
||||
<Icon name="check" />
|
||||
</div>
|
||||
<div class="label">{label}</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div.checkbox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
div.checkbox.centered {
|
||||
margin: auto
|
||||
}
|
||||
|
||||
div.box {
|
||||
border: 0.5px solid;
|
||||
padding: 0.025em 0.5ch;
|
||||
padding-top: 0.25em;
|
||||
background-color: #111;
|
||||
color: #555;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
div.box.checked {
|
||||
color: #fC1;
|
||||
background-color: #5c4d20;
|
||||
}
|
||||
div.box.disabled {
|
||||
color: #777;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
div.box.unchecked :global(*) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
div.label {
|
||||
margin: auto 0;
|
||||
margin-left: 1ch;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
</style>
|
||||
@@ -25,7 +25,7 @@
|
||||
</script>
|
||||
|
||||
<div class="project">
|
||||
<div class="icon"><Icon block name={iconName} /></div>
|
||||
<div class="icon" class:inactive={!project.active}><Icon block name={iconName} /></div>
|
||||
<div class="body">
|
||||
<div class="header">
|
||||
<div class="name">{project.name}</div>
|
||||
@@ -66,6 +66,9 @@
|
||||
padding-top: 0.125em;
|
||||
color: #333;
|
||||
}
|
||||
div.icon.inactive {
|
||||
color: #484;
|
||||
}
|
||||
div.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -91,4 +94,13 @@
|
||||
padding: 0;
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
div.icon {
|
||||
color: #777;
|
||||
}
|
||||
div.icon.inactive {
|
||||
color: #78ff78;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import stuffLogClient from "../clients/stufflog";
|
||||
import Checkbox from "../components/Checkbox.svelte";
|
||||
import Modal from "../components/Modal.svelte";
|
||||
import goalStore, { fpGoalStore } from "../stores/goal";
|
||||
import logStore from "../stores/logs";
|
||||
@@ -54,8 +55,7 @@ import logStore from "../stores/logs";
|
||||
<input name="loggedTime" type="datetime-local" bind:value={loggedTime} />
|
||||
<label for="description">Description</label>
|
||||
<textarea name="description" bind:value={description} />
|
||||
<input id="markInactive" type="checkbox" bind:checked={markInactive} />
|
||||
<label for="markInactive">Complete Task</label>
|
||||
<Checkbox bind:checked={markInactive} label="Mark task inactive/completed." />
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import stuffLogClient from "../clients/stufflog";
|
||||
import Checkbox from "../components/Checkbox.svelte";
|
||||
import IconSelect from "../components/IconSelect.svelte";
|
||||
import Modal from "../components/Modal.svelte";
|
||||
import type { IconName } from "../external/icons";
|
||||
@@ -14,6 +15,7 @@
|
||||
const project = md.project;
|
||||
|
||||
let endTime = project.endTime ? formatFormTime(project.endTime) : "";
|
||||
let active = project.active;
|
||||
let name = project.name;
|
||||
let description = project.description;
|
||||
let icon = project.icon as IconName;
|
||||
@@ -21,11 +23,10 @@
|
||||
|
||||
function onSubmit() {
|
||||
stuffLogClient.updateProject(project.id, {
|
||||
active: true,
|
||||
endTime: ( endTime == "" ) ? null : new Date(endTime),
|
||||
clearEndTime: ( endTime == "" ),
|
||||
|
||||
name, description, icon,
|
||||
name, active, description, icon,
|
||||
}).then(() => {
|
||||
projectStore.markStale();
|
||||
fpProjectStore.markStale();
|
||||
@@ -52,6 +53,7 @@
|
||||
<IconSelect bind:value={icon} />
|
||||
<label for="endTime">Deadline (Optional)</label>
|
||||
<input name="endTime" type="datetime-local" bind:value={endTime} />
|
||||
<Checkbox bind:checked={active} label="Project is active/incomplete." />
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import stuffLogClient from "../clients/stufflog";
|
||||
import Checkbox from "../components/Checkbox.svelte";
|
||||
import Modal from "../components/Modal.svelte";
|
||||
import goalStore, { fpGoalStore } from "../stores/goal";
|
||||
import modalStore from "../stores/modal";
|
||||
@@ -15,7 +16,7 @@
|
||||
let name = task.name;
|
||||
let description = task.description;
|
||||
let itemAmount = task.itemAmount;
|
||||
let active = task.active;
|
||||
let completed = !task.active;
|
||||
let endTime = task.endTime ? formatFormTime(task.endTime) : "";
|
||||
let error = null;
|
||||
|
||||
@@ -50,8 +51,7 @@
|
||||
<input disabled name="itemAmount" type="number" value={itemAmount} />
|
||||
<label for="endTime">Deadline (Optional)</label>
|
||||
<input disabled name="endTime" type="datetime-local" value={endTime} />
|
||||
<input id="active" type="checkbox" checked={active} />
|
||||
<label for="active">Task is active/incomplete</label>
|
||||
<Checkbox disabled bind:checked={completed} label="Task is completed." />
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import stuffLogClient from "../clients/stufflog";
|
||||
import Checkbox from "../components/Checkbox.svelte";
|
||||
import Modal from "../components/Modal.svelte";
|
||||
import goalStore, { fpGoalStore } from "../stores/goal";
|
||||
import modalStore from "../stores/modal";
|
||||
@@ -15,7 +16,7 @@
|
||||
let name = task.name;
|
||||
let description = task.description;
|
||||
let itemAmount = task.itemAmount;
|
||||
let active = task.active;
|
||||
let completed = !task.active;
|
||||
let endTime = task.endTime ? formatFormTime(task.endTime) : "";
|
||||
let error = null;
|
||||
|
||||
@@ -23,8 +24,9 @@
|
||||
stuffLogClient.updateTask(task.id, {
|
||||
endTime: (endTime == "") ? null : new Date(endTime),
|
||||
clearEndTime: endTime == "",
|
||||
active: !completed,
|
||||
|
||||
name, description, itemAmount, active,
|
||||
name, description, itemAmount,
|
||||
}).then(() => {
|
||||
projectStore.markStale();
|
||||
fpProjectStore.markStale();
|
||||
@@ -53,8 +55,7 @@
|
||||
<input name="itemAmount" type="number" bind:value={itemAmount} />
|
||||
<label for="endTime">Deadline (Optional)</label>
|
||||
<input name="endTime" type="datetime-local" bind:value={endTime} />
|
||||
<input id="active" type="checkbox" bind:checked={active} />
|
||||
<label for="active">Task is active/incomplete</label>
|
||||
<Checkbox bind:checked={completed} label="Task is completed." />
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export default interface Project {
|
||||
name: string
|
||||
description: string
|
||||
icon: string
|
||||
active: string
|
||||
active: boolean
|
||||
createdTime: string
|
||||
endTime?: string
|
||||
}
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
<script lang="ts">
|
||||
import Boi from "../components/Boi.svelte";
|
||||
import Checkbox from "../components/Checkbox.svelte";
|
||||
import ProjectEntry from "../components/ProjectEntry.svelte";
|
||||
import type { ModalData } from "../stores/modal";
|
||||
import projectStore from "../stores/project";
|
||||
|
||||
const mdProjectAdd: ModalData = {name: "project.add"};
|
||||
let showInactive = ($projectStore.filter.active === null);
|
||||
|
||||
$: {
|
||||
if (showInactive && $projectStore.filter.active === true) {
|
||||
projectStore.markStale();
|
||||
}
|
||||
if (!showInactive && $projectStore.filter.active == null) {
|
||||
projectStore.markStale();
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
if ($projectStore.stale && !$projectStore.loading) {
|
||||
projectStore.load({
|
||||
active: true,
|
||||
active: showInactive ? null : true,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="page">
|
||||
<div class="options">
|
||||
<Checkbox centered bind:checked={showInactive} label="Show inactive projects." />
|
||||
</div>
|
||||
{#each $projectStore.projects as project (project.id)}
|
||||
<ProjectEntry showAllOptions project={project} />
|
||||
{/each}
|
||||
@@ -31,4 +45,9 @@
|
||||
margin-top: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div.options {
|
||||
display: flex;
|
||||
margin: 1em auto;
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@ import type { ProjectFilter, ProjectResult } from "../models/project";
|
||||
interface ProjectStoreData {
|
||||
loading: boolean
|
||||
stale: boolean
|
||||
filter: ProjectFilter
|
||||
projects: ProjectResult[]
|
||||
}
|
||||
|
||||
@@ -12,6 +13,7 @@ function createProjectStore() {
|
||||
const {update, subscribe} = writable<ProjectStoreData>({
|
||||
loading: false,
|
||||
stale: true,
|
||||
filter: {},
|
||||
projects: [],
|
||||
});
|
||||
|
||||
@@ -23,9 +25,10 @@ function createProjectStore() {
|
||||
},
|
||||
|
||||
async load(filter: ProjectFilter) {
|
||||
update(v => ({...v, loading: true, filter}));
|
||||
console.log(filter);
|
||||
update(v => ({...v, loading: true, stale: false, filter}));
|
||||
const projects = await stuffLogClient.listProjects(filter);
|
||||
update(v => ({...v, loading: false, stale: false, projects: projects.reverse()}));
|
||||
update(v => ({...v, loading: false, projects: projects.reverse()}));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user