add favorite system and other small tweaks and fixes.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -23,6 +23,10 @@ func Project(g *gin.RouterGroup, db database.Database) {
|
|||||||
if setting := c.Query("expiring"); setting != "" {
|
if setting := c.Query("expiring"); setting != "" {
|
||||||
filter.Expiring = setting == "true"
|
filter.Expiring = setting == "true"
|
||||||
}
|
}
|
||||||
|
if setting := c.Query("favorite"); setting != "" {
|
||||||
|
favorite := setting == "true"
|
||||||
|
filter.Favorite = &favorite
|
||||||
|
}
|
||||||
|
|
||||||
return l.ListProjects(c, filter)
|
return l.ListProjects(c, filter)
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilte
|
|||||||
if filter.Expiring {
|
if filter.Expiring {
|
||||||
sq = sq.Where("end_time IS NOT NULL")
|
sq = sq.Where("end_time IS NOT NULL")
|
||||||
}
|
}
|
||||||
|
if filter.Favorite != nil {
|
||||||
|
sq = sq.Where(squirrel.Eq{"favorite": *filter.Favorite})
|
||||||
|
}
|
||||||
|
|
||||||
sq = sq.OrderBy("active", "created_time DESC")
|
sq = sq.OrderBy("active", "created_time DESC")
|
||||||
|
|
||||||
@@ -62,9 +65,9 @@ func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilte
|
|||||||
func (r *projectRepository) Insert(ctx context.Context, project models.Project) error {
|
func (r *projectRepository) Insert(ctx context.Context, project models.Project) error {
|
||||||
_, err := r.db.NamedExecContext(ctx, `
|
_, err := r.db.NamedExecContext(ctx, `
|
||||||
INSERT INTO project(
|
INSERT INTO project(
|
||||||
project_id, user_id, name, description, icon, active, created_time, end_time, status_tag
|
project_id, user_id, name, description, icon, active, created_time, end_time, status_tag, favorite
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:project_id, :user_id, :name, :description, :icon, :active, :created_time, :end_time, :status_tag
|
:project_id, :user_id, :name, :description, :icon, :active, :created_time, :end_time, :status_tag, :favorite
|
||||||
)
|
)
|
||||||
`, &project)
|
`, &project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -82,7 +85,8 @@ func (r *projectRepository) Update(ctx context.Context, project models.Project)
|
|||||||
icon = :icon,
|
icon = :icon,
|
||||||
active = :active,
|
active = :active,
|
||||||
end_time = :end_time,
|
end_time = :end_time,
|
||||||
status_tag = :status_tag
|
status_tag = :status_tag,
|
||||||
|
favorite = :favorite
|
||||||
WHERE project_id=:project_id
|
WHERE project_id=:project_id
|
||||||
`, &project)
|
`, &project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE project
|
||||||
|
ADD COLUMN favorite BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE project
|
||||||
|
DROP COLUMN favorite;
|
||||||
|
-- +goose StatementEnd
|
||||||
@@ -15,6 +15,7 @@ type Project struct {
|
|||||||
CreatedTime time.Time `json:"createdTime" db:"created_time"`
|
CreatedTime time.Time `json:"createdTime" db:"created_time"`
|
||||||
EndTime *time.Time `json:"endTime" db:"end_time"`
|
EndTime *time.Time `json:"endTime" db:"end_time"`
|
||||||
StatusTag *string `json:"statusTag" db:"status_tag"`
|
StatusTag *string `json:"statusTag" db:"status_tag"`
|
||||||
|
Favorite bool `json:"favorite" db:"favorite"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (project *Project) Update(update ProjectUpdate) {
|
func (project *Project) Update(update ProjectUpdate) {
|
||||||
@@ -43,6 +44,9 @@ func (project *Project) Update(update ProjectUpdate) {
|
|||||||
if update.ClearStatusTag {
|
if update.ClearStatusTag {
|
||||||
project.StatusTag = nil
|
project.StatusTag = nil
|
||||||
}
|
}
|
||||||
|
if update.Favorite != nil {
|
||||||
|
project.Favorite = *update.Favorite
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectUpdate struct {
|
type ProjectUpdate struct {
|
||||||
@@ -54,6 +58,7 @@ type ProjectUpdate struct {
|
|||||||
ClearEndTime bool `json:"clearEndTime"`
|
ClearEndTime bool `json:"clearEndTime"`
|
||||||
StatusTag *string `json:"statusTag"`
|
StatusTag *string `json:"statusTag"`
|
||||||
ClearStatusTag bool `json:"clearStatusTag"`
|
ClearStatusTag bool `json:"clearStatusTag"`
|
||||||
|
Favorite *bool `json:"favorite"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectResult struct {
|
type ProjectResult struct {
|
||||||
@@ -64,6 +69,7 @@ type ProjectResult struct {
|
|||||||
type ProjectFilter struct {
|
type ProjectFilter struct {
|
||||||
UserID string
|
UserID string
|
||||||
Active *bool
|
Active *bool
|
||||||
|
Favorite *bool
|
||||||
Expiring bool
|
Expiring bool
|
||||||
IDs []string
|
IDs []string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export class StufflogClient {
|
|||||||
return data.project;
|
return data.project;
|
||||||
}
|
}
|
||||||
|
|
||||||
async listProjects({active, expiring}: ProjectFilter): Promise<ProjectResult[]> {
|
async listProjects({active, expiring, favorite}: ProjectFilter): Promise<ProjectResult[]> {
|
||||||
let queries = [];
|
let queries = [];
|
||||||
if (active != null) {
|
if (active != null) {
|
||||||
queries.push(`active=${active}`);
|
queries.push(`active=${active}`);
|
||||||
@@ -68,6 +68,9 @@ export class StufflogClient {
|
|||||||
if (expiring != null) {
|
if (expiring != null) {
|
||||||
queries.push(`expiring=${expiring}`);
|
queries.push(`expiring=${expiring}`);
|
||||||
}
|
}
|
||||||
|
if (favorite != null) {
|
||||||
|
queries.push(`favorite=${favorite}`)
|
||||||
|
}
|
||||||
|
|
||||||
const query = queries.length > 0 ? `?${queries.join("&")}` : "";
|
const query = queries.length > 0 ? `?${queries.join("&")}` : "";
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
export let open: ModalData = {name: "none"};
|
export let open: ModalData = {name: "none"};
|
||||||
export let disabled: boolean = false;
|
export let disabled: boolean = false;
|
||||||
export let compact: boolean = false;
|
export let compact: boolean = false;
|
||||||
|
export let compacter: boolean = false;
|
||||||
export let tiny: boolean = false;
|
export let tiny: boolean = false;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="boi" class:disabled class:compact class:tiny on:click={handleClick}><slot></slot></div>
|
<div class="boi" class:disabled class:compact class:compacter class:tiny on:click={handleClick}><slot></slot></div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div.boi {
|
div.boi {
|
||||||
@@ -52,6 +53,13 @@
|
|||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.boi.compacter {
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 0 1ch;
|
||||||
|
border-width: 3px;
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
div.boi.tiny {
|
div.boi.tiny {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import EveryMinute from "./EveryMinute.svelte";
|
|||||||
|
|
||||||
export let fromValue: string;
|
export let fromValue: string;
|
||||||
export let toValue: string;
|
export let toValue: string;
|
||||||
export let disabled: boolean;
|
export let disabled: boolean = false;
|
||||||
export let styled: boolean;
|
export let styled: boolean;
|
||||||
export let noFuture: boolean;
|
export let noFuture: boolean;
|
||||||
export let label: string = "Time Period";
|
export let label: string = "Time Period";
|
||||||
@@ -23,8 +23,11 @@ import EveryMinute from "./EveryMinute.svelte";
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
for (const option of options) {
|
for (const option of options) {
|
||||||
|
console.log(formatFormTime(option.from), fromValue, formatFormTime(option.to), toValue);
|
||||||
if (formatFormTime(option.from) === fromValue && formatFormTime(option.to) === toValue) {
|
if (formatFormTime(option.from) === fromValue && formatFormTime(option.to) === toValue) {
|
||||||
selected = option.id;
|
selected = option.id;
|
||||||
|
console.log("-- SELECTED")
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import goalStore, { fpGoalStore } from "../stores/goal";
|
import goalStore, { fpGoalStore } from "../stores/goal";
|
||||||
import logStore from "../stores/logs";
|
import logStore from "../stores/logs";
|
||||||
|
import markStale from "../stores/markStale";
|
||||||
import projectStore, { fpProjectStore } from "../stores/project";
|
import projectStore, { fpProjectStore } from "../stores/project";
|
||||||
|
|
||||||
let lastFocus = new Date();
|
let lastFocus = new Date();
|
||||||
@@ -13,11 +14,7 @@
|
|||||||
|
|
||||||
lastFocus = new Date();
|
lastFocus = new Date();
|
||||||
|
|
||||||
goalStore.markStale();
|
markStale("*");
|
||||||
fpGoalStore.markStale();
|
|
||||||
projectStore.markStale();
|
|
||||||
fpProjectStore.markStale();
|
|
||||||
logStore.markStale();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ import TimeProgress from "./TimeProgress.svelte";
|
|||||||
{entry.name}
|
{entry.name}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<slot name="pre-annotation"></slot>
|
||||||
{#each annotations as annotation (annotation)}
|
{#each annotations as annotation (annotation)}
|
||||||
<div class="annotation">
|
<div class="annotation">
|
||||||
<Icon block name={annotation} />
|
<Icon block name={annotation} />
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import stuffLogClient from "../clients/stufflog";
|
||||||
|
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
import type { TaskResult } from "../models/task";
|
import type { TaskResult } from "../models/task";
|
||||||
|
import markStale from "../stores/markStale";
|
||||||
import type { ModalData } from "../stores/modal";
|
import type { ModalData } from "../stores/modal";
|
||||||
import IS_MOBILE from "../utils/phone-check";
|
import IS_MOBILE from "../utils/phone-check";
|
||||||
|
import Icon from "./Icon.svelte";
|
||||||
import Option from "./Option.svelte";
|
import Option from "./Option.svelte";
|
||||||
import OptionRow from "./OptionRow.svelte";
|
import OptionRow from "./OptionRow.svelte";
|
||||||
import ParentEntry from "./ParentEntry.svelte";
|
import ParentEntry from "./ParentEntry.svelte";
|
||||||
@@ -29,6 +33,24 @@
|
|||||||
let onholdTasks: TaskResult[] = [];
|
let onholdTasks: TaskResult[] = [];
|
||||||
let failedTasks: TaskResult[] = [];
|
let failedTasks: TaskResult[] = [];
|
||||||
let nonHiddenTasks: TaskResult[] = [];
|
let nonHiddenTasks: TaskResult[] = [];
|
||||||
|
let toggling = false;
|
||||||
|
|
||||||
|
function toggleFavorite() {
|
||||||
|
if (toggling) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toggling = true
|
||||||
|
|
||||||
|
stuffLogClient.updateProject(project.id, {
|
||||||
|
favorite: !project.favorite,
|
||||||
|
}).then(() => {
|
||||||
|
markStale("project");
|
||||||
|
}).catch(err => {
|
||||||
|
console.warn("Failed to toggle favorite:", err);
|
||||||
|
}).finally(() => {
|
||||||
|
toggling = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
$: mdAddTask = {name:"task.add", project};
|
$: mdAddTask = {name:"task.add", project};
|
||||||
$: mdProjectEdit = {name:"project.edit", project};
|
$: mdProjectEdit = {name:"project.edit", project};
|
||||||
@@ -58,8 +80,12 @@
|
|||||||
hideIcon={hideIcon}
|
hideIcon={hideIcon}
|
||||||
showTimeProgress={!hideProgress}
|
showTimeProgress={!hideProgress}
|
||||||
removeHook={removeHook}
|
removeHook={removeHook}
|
||||||
annotations={isFake ? ["list"] : []}
|
|
||||||
>
|
>
|
||||||
|
<div slot="pre-annotation" class="favorite" class:enabled={project.favorite} class:toggling on:click={toggleFavorite}>
|
||||||
|
{#if !isFake}
|
||||||
|
<Icon block name="star" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{#if showAllOptions}
|
{#if showAllOptions}
|
||||||
<OptionRow>
|
<OptionRow>
|
||||||
<Option open={mdAddTask}>Add Task</Option>
|
<Option open={mdAddTask}>Add Task</Option>
|
||||||
@@ -78,3 +104,21 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</ParentEntry>
|
</ParentEntry>
|
||||||
</StatusColor>
|
</StatusColor>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.favorite {
|
||||||
|
margin: auto 0;
|
||||||
|
padding: 0 0.5ch;
|
||||||
|
line-height: 0em;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.favorite.enabled {
|
||||||
|
color: #e7e55e
|
||||||
|
}
|
||||||
|
|
||||||
|
div.favorite.toggling {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { group } from "console";
|
import type Project from "../models/project";
|
||||||
import type Project from "../models/project";
|
|
||||||
import authStore from "../stores/auth";
|
|
||||||
import projectStore from "../stores/project";
|
import projectStore from "../stores/project";
|
||||||
|
|
||||||
interface OptGroup {
|
interface OptGroup {
|
||||||
|
|||||||
@@ -7,8 +7,12 @@
|
|||||||
import selectionStore from "../stores/selection";
|
import selectionStore from "../stores/selection";
|
||||||
import ProjectEntry from "./ProjectEntry.svelte";
|
import ProjectEntry from "./ProjectEntry.svelte";
|
||||||
import QlList from "./QLList.svelte";
|
import QlList from "./QLList.svelte";
|
||||||
|
import Boi from "../components/Boi.svelte";
|
||||||
|
import type { ModalData } from "../stores/modal";
|
||||||
|
|
||||||
export let projects: ProjectResult[];
|
export let projects: ProjectResult[];
|
||||||
|
|
||||||
|
const mdProjectAdd: ModalData = {name: "project.add"};
|
||||||
|
|
||||||
let expiringProjects: ProjectResult[];
|
let expiringProjects: ProjectResult[];
|
||||||
let activeProjects: ProjectResult[];
|
let activeProjects: ProjectResult[];
|
||||||
@@ -53,6 +57,7 @@
|
|||||||
|
|
||||||
<div class="quest-log">
|
<div class="quest-log">
|
||||||
<div class="list">
|
<div class="list">
|
||||||
|
<Boi compacter open={mdProjectAdd}>Add Project</Boi>
|
||||||
<QlList label="Deadlines" projects={expiringProjects} />
|
<QlList label="Deadlines" projects={expiringProjects} />
|
||||||
<QlList label="Active" projects={activeProjects} />
|
<QlList label="Active" projects={activeProjects} />
|
||||||
<QlList label="To Do" projects={ideaProjects} />
|
<QlList label="To Do" projects={ideaProjects} />
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ import ItemSelect from "../components/ItemSelect.svelte";
|
|||||||
<input disabled={deletion} name="secondaryItemAmount" type="number" bind:value={secondaryItemAmount} />
|
<input disabled={deletion} name="secondaryItemAmount" type="number" bind:value={secondaryItemAmount} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Checkbox disabled={deletion} bind:checked={markInactive} label="Mark task inactive/completed." />
|
<Checkbox disabled={!creation} bind:checked={markInactive} label="Mark task inactive/completed." />
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import stuffLogClient from "../clients/stufflog";
|
import stuffLogClient from "../clients/stufflog";
|
||||||
|
import Checkbox from "../components/Checkbox.svelte";
|
||||||
import IconSelect from "../components/IconSelect.svelte";
|
import IconSelect from "../components/IconSelect.svelte";
|
||||||
import Modal from "../components/Modal.svelte";
|
import Modal from "../components/Modal.svelte";
|
||||||
import StatusTagSelect from "../components/StatusTagSelect.svelte";
|
import StatusTagSelect from "../components/StatusTagSelect.svelte";
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
statusTag: "to do",
|
statusTag: "to do",
|
||||||
createdTime: "",
|
createdTime: "",
|
||||||
tasks: [],
|
tasks: [],
|
||||||
|
favorite: false,
|
||||||
}
|
}
|
||||||
let verb = "Add";
|
let verb = "Add";
|
||||||
if (md.name === "project.edit" || md.name === "project.delete") {
|
if (md.name === "project.edit" || md.name === "project.delete") {
|
||||||
@@ -37,6 +39,7 @@
|
|||||||
let description = project.description;
|
let description = project.description;
|
||||||
let statusTag = project.statusTag || "";
|
let statusTag = project.statusTag || "";
|
||||||
let icon = project.icon;
|
let icon = project.icon;
|
||||||
|
let favorite = project.favorite;
|
||||||
let error = null;
|
let error = null;
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
@@ -44,13 +47,15 @@
|
|||||||
loading = true;
|
loading = true;
|
||||||
error = null;
|
error = null;
|
||||||
|
|
||||||
|
const iconChanged = icon !== project.icon;
|
||||||
|
|
||||||
if (creation) {
|
if (creation) {
|
||||||
stuffLogClient.createProject({
|
stuffLogClient.createProject({
|
||||||
active: statusTag === "",
|
active: statusTag === "",
|
||||||
endTime: ( endTime == "" ) ? null : new Date(endTime),
|
endTime: ( endTime == "" ) ? null : new Date(endTime),
|
||||||
statusTag: statusTag || null,
|
statusTag: statusTag || null,
|
||||||
|
|
||||||
name, description, icon,
|
name, description, icon, favorite,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
markStale("project", "task");
|
markStale("project", "task");
|
||||||
modalStore.close();
|
modalStore.close();
|
||||||
@@ -76,10 +81,12 @@
|
|||||||
statusTag: statusTag || null,
|
statusTag: statusTag || null,
|
||||||
clearStatusTag: statusTag === "",
|
clearStatusTag: statusTag === "",
|
||||||
|
|
||||||
name, description, icon,
|
name, description, icon, favorite,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
projectStore.markStale();
|
markStale("project", "task");
|
||||||
fpProjectStore.markStale();
|
if (iconChanged) {
|
||||||
|
markStale("log");
|
||||||
|
}
|
||||||
modalStore.close();
|
modalStore.close();
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
error = err.message ? err.message : err.toString();
|
error = err.message ? err.message : err.toString();
|
||||||
@@ -107,6 +114,8 @@
|
|||||||
<label for="statusTag">Status</label>
|
<label for="statusTag">Status</label>
|
||||||
<StatusTagSelect disabled={deletion} bind:value={statusTag} />
|
<StatusTagSelect disabled={deletion} bind:value={statusTag} />
|
||||||
|
|
||||||
|
<Checkbox disabled={deletion} bind:checked={favorite} label="Mark as favorite." />
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<button disabled={loading} type="submit">{verb} Project</button>
|
<button disabled={loading} type="submit">{verb} Project</button>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export default interface Project {
|
|||||||
icon: IconName
|
icon: IconName
|
||||||
active: boolean
|
active: boolean
|
||||||
createdTime: string
|
createdTime: string
|
||||||
|
favorite: boolean
|
||||||
endTime?: string
|
endTime?: string
|
||||||
statusTag?: string
|
statusTag?: string
|
||||||
}
|
}
|
||||||
@@ -18,6 +19,7 @@ export interface ProjectResult extends Project {
|
|||||||
|
|
||||||
export interface ProjectFilter {
|
export interface ProjectFilter {
|
||||||
active?: boolean
|
active?: boolean
|
||||||
|
favorite?: boolean
|
||||||
expiring?: boolean
|
expiring?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ export interface ProjectInput {
|
|||||||
active: boolean
|
active: boolean
|
||||||
endTime?: string | Date
|
endTime?: string | Date
|
||||||
statusTag?: string
|
statusTag?: string
|
||||||
|
favorite?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProjectUpdate {
|
export interface ProjectUpdate {
|
||||||
@@ -39,4 +42,5 @@ export interface ProjectUpdate {
|
|||||||
clearEndTime?: boolean
|
clearEndTime?: boolean
|
||||||
statusTag?: string
|
statusTag?: string
|
||||||
clearStatusTag?: boolean
|
clearStatusTag?: boolean
|
||||||
|
favorite?: boolean
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
import RefreshSelection from "../components/RefreshSelection.svelte";
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
import type { ProjectResult } from "../models/project";
|
import type { ProjectResult } from "../models/project";
|
||||||
import { fpGoalStore } from "../stores/goal";
|
import { fpGoalStore } from "../stores/goal";
|
||||||
import { fpProjectStore } from "../stores/project";
|
import { fpProjectStore, fpProjectStore2 } from "../stores/project";
|
||||||
import { fpTaskStore } from "../stores/tasks";
|
import { fpTaskStore } from "../stores/tasks";
|
||||||
|
|
||||||
let fakeMap: {[projectId: string]: boolean} = {}
|
let fakeMap: {[projectId: string]: boolean} = {}
|
||||||
@@ -39,6 +39,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if ($fpProjectStore2.stale && !$fpProjectStore2.loading) {
|
||||||
|
fpProjectStore2.load({
|
||||||
|
favorite: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
const individualTasks = $fpTaskStore.tasks
|
const individualTasks = $fpTaskStore.tasks
|
||||||
.filter(t => $fpProjectStore.projects.find(p => p.id === t.projectId) == null)
|
.filter(t => $fpProjectStore.projects.find(p => p.id === t.projectId) == null)
|
||||||
@@ -92,11 +100,15 @@
|
|||||||
<h1>Upcoming Deadlines</h1>
|
<h1>Upcoming Deadlines</h1>
|
||||||
{/if}
|
{/if}
|
||||||
{#each sortedProjects as project (project.id)}
|
{#each sortedProjects as project (project.id)}
|
||||||
<ProjectEntry isFake={fakeMap[project.id]} linkProject hideInactive project={project} />
|
<ProjectEntry isFake={fakeMap[project.id]} hideInactive project={project} />
|
||||||
{/each}
|
{/each}
|
||||||
{#if !$fpProjectStore.loading && $fpProjectStore.projects.length === 0}
|
|
||||||
<EmptyList icon="check" text="All good!" />
|
{#if !$fpProjectStore2.loading || $fpProjectStore2.projects.length > 0}
|
||||||
|
<h1>Starred Projects</h1>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#each $fpProjectStore2.projects as project (project.id)}
|
||||||
|
<ProjectEntry hideInactive project={project} />
|
||||||
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<RefreshSelection />
|
<RefreshSelection />
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
let groupedLogs: {day: number, text: string, logs: LogResult[]}[] = [];
|
let groupedLogs: {day: number, text: string, logs: LogResult[]}[] = [];
|
||||||
let minTime = formatFormTime($logStore.filter.minTime || startOfWeek(new Date()));
|
let minTime = formatFormTime($logStore.filter.minTime || startOfWeek(new Date()));
|
||||||
let maxTime = formatFormTime(endOfWeek(new Date()));
|
let maxTime = formatFormTime($logStore.filter.maxTime || endOfWeek(new Date()));
|
||||||
let emptyMessage = `No logs since ${formatWeekdayDate(minTime)}.`;
|
let emptyMessage = `No logs since ${formatWeekdayDate(minTime)}.`;
|
||||||
let error = "";
|
let error = "";
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Boi from "../components/Boi.svelte";
|
|
||||||
import QuestLog from "../components/QuestLog.svelte";
|
import QuestLog from "../components/QuestLog.svelte";
|
||||||
import RefreshSelection from "../components/RefreshSelection.svelte";
|
import RefreshSelection from "../components/RefreshSelection.svelte";
|
||||||
import type { ModalData } from "../stores/modal";
|
|
||||||
import projectStore from "../stores/project";
|
import projectStore from "../stores/project";
|
||||||
|
|
||||||
const mdProjectAdd: ModalData = {name: "project.add"};
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (($projectStore.stale || $projectStore.filter.active != null) && !$projectStore.loading) {
|
if (($projectStore.stale || $projectStore.filter.active != null) && !$projectStore.loading) {
|
||||||
projectStore.load({});
|
projectStore.load({});
|
||||||
@@ -16,7 +12,6 @@
|
|||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<QuestLog projects={$projectStore.projects} />
|
<QuestLog projects={$projectStore.projects} />
|
||||||
<Boi open={mdProjectAdd}>Add Project</Boi>
|
|
||||||
</div>
|
</div>
|
||||||
<RefreshSelection />
|
<RefreshSelection />
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,34 @@
|
|||||||
import goalStore, { fpGoalStore } from "./goal";
|
import goalStore, { fpGoalStore } from "./goal";
|
||||||
import groupStore from "./group";
|
import groupStore from "./group";
|
||||||
import logStore from "./logs";
|
import logStore from "./logs";
|
||||||
import projectStore, { fpProjectStore } from "./project";
|
import projectStore, { fpProjectStore, fpProjectStore2 } from "./project";
|
||||||
import taskStore, { fpTaskStore } from "./tasks";
|
import taskStore, { fpTaskStore } from "./tasks";
|
||||||
|
|
||||||
type ModelName = "goal" | "project" | "task" | "group" | "item" | "log"
|
type ModelName = "goal" | "project" | "task" | "group" | "item" | "log" | "*"
|
||||||
|
|
||||||
export default function markStale(...models: ModelName[]) {
|
export default function markStale(...models: ModelName[]) {
|
||||||
if (models.includes("goal")) {
|
const markAll = models.includes("*");
|
||||||
|
|
||||||
|
if (markAll || models.includes("goal")) {
|
||||||
goalStore.markStale();
|
goalStore.markStale();
|
||||||
fpGoalStore.markStale();
|
fpGoalStore.markStale();
|
||||||
}
|
}
|
||||||
if (models.includes("project")) {
|
if (markAll || models.includes("project")) {
|
||||||
projectStore.markStale();
|
projectStore.markStale();
|
||||||
fpProjectStore.markStale();
|
fpProjectStore.markStale();
|
||||||
|
fpProjectStore2.markStale();
|
||||||
}
|
}
|
||||||
if (models.includes("task")) {
|
if (markAll || models.includes("task")) {
|
||||||
taskStore.markStale();
|
taskStore.markStale();
|
||||||
fpTaskStore.markStale();
|
fpTaskStore.markStale();
|
||||||
}
|
}
|
||||||
if (models.includes("group")) {
|
if (markAll || models.includes("group")) {
|
||||||
groupStore.markStale();
|
groupStore.markStale();
|
||||||
}
|
}
|
||||||
if (models.includes("item")) {
|
if (markAll || models.includes("item")) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
if (models.includes("log")) {
|
if (markAll || models.includes("log")) {
|
||||||
logStore.markStale();
|
logStore.markStale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,4 +35,5 @@ function createProjectStore() {
|
|||||||
const projectStore = createProjectStore();
|
const projectStore = createProjectStore();
|
||||||
|
|
||||||
export default projectStore;
|
export default projectStore;
|
||||||
export const fpProjectStore = createProjectStore();
|
export const fpProjectStore = createProjectStore();
|
||||||
|
export const fpProjectStore2 = createProjectStore();
|
||||||
Reference in New Issue
Block a user