add multiple statuses to proejcts, though it's a bit hacked on.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import Icon from "./Icon.svelte";
|
||||
import LinkHook from "./LinkHook.svelte";
|
||||
import Markdown from "./Markdown.svelte";
|
||||
import ProjectIcon from "./ProjectIcon.svelte";
|
||||
import ProjectProgress from "./ProjectProgress.svelte";
|
||||
import TimeProgress from "./TimeProgress.svelte";
|
||||
|
||||
@@ -24,6 +25,7 @@ import TimeProgress from "./TimeProgress.svelte";
|
||||
project?: EntryIconHolder
|
||||
tasks?: TaskResult[]
|
||||
active?: boolean
|
||||
statusName?: string
|
||||
}
|
||||
|
||||
export let entry: EntryCommon;
|
||||
@@ -50,7 +52,11 @@ import TimeProgress from "./TimeProgress.svelte";
|
||||
<LinkHook id={entry.id} />
|
||||
{#if !hideIcon}
|
||||
<div class="icon" class:completed={entry.active === false}>
|
||||
<Icon block name={iconName} />
|
||||
{#if entry.active != null}
|
||||
<ProjectIcon project={entry} />
|
||||
{:else}
|
||||
<Icon block name={iconName} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="body">
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
export let gray = false;
|
||||
export let titlePercentageOnly = false;
|
||||
export let titleTime = false;
|
||||
export let contextColor = false;
|
||||
|
||||
let offClass = COLORS[0];
|
||||
let onClass = COLORS[1];
|
||||
@@ -52,6 +53,10 @@
|
||||
onClass = "gray"
|
||||
offClass = "none"
|
||||
}
|
||||
if (contextColor) {
|
||||
onClass = "sccpb"
|
||||
offClass = "none"
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -8,6 +8,7 @@ import Composition from "./Composition.svelte";
|
||||
import Option from "./Option.svelte";
|
||||
import OptionRow from "./OptionRow.svelte";
|
||||
import ParentEntry from "./ParentEntry.svelte";
|
||||
import StatusColor from "./StatusColor.svelte";
|
||||
import TaskEntry from "./TaskEntry.svelte";
|
||||
|
||||
export let project: ProjectResult = null;
|
||||
@@ -26,24 +27,26 @@ import Composition from "./Composition.svelte";
|
||||
$: mdProjectDelete = {name:"project.delete", project};
|
||||
</script>
|
||||
|
||||
<ParentEntry
|
||||
full={showAllOptions}
|
||||
entry={project}
|
||||
headerLink={linkProject ? "/projects#"+project.id : ""}
|
||||
hideProgress={hideProgress}
|
||||
hideIcon={hideIcon}
|
||||
showTimeProgress={!hideProgress}
|
||||
>
|
||||
{#if showAllOptions}
|
||||
<OptionRow>
|
||||
<Option open={mdAddTask}>Add Task</Option>
|
||||
<Option open={mdProjectEdit}>Edit</Option>
|
||||
<Option open={mdProjectDelete}>Delete</Option>
|
||||
</OptionRow>
|
||||
{/if}
|
||||
{#each project.tasks as task (task.id)}
|
||||
{#if !hideInactive || task.active}
|
||||
<TaskEntry showAllOptions={showAllOptions} task={task} project={project} />
|
||||
<StatusColor selected project={project}>
|
||||
<ParentEntry
|
||||
full={showAllOptions}
|
||||
entry={project}
|
||||
headerLink={linkProject ? "/projects#"+project.id : ""}
|
||||
hideProgress={hideProgress}
|
||||
hideIcon={hideIcon}
|
||||
showTimeProgress={!hideProgress}
|
||||
>
|
||||
{#if showAllOptions}
|
||||
<OptionRow>
|
||||
<Option open={mdAddTask}>Add Task</Option>
|
||||
<Option open={mdProjectEdit}>Edit</Option>
|
||||
<Option open={mdProjectDelete}>Delete</Option>
|
||||
</OptionRow>
|
||||
{/if}
|
||||
{/each}
|
||||
</ParentEntry>
|
||||
{#each project.tasks as task (task.id)}
|
||||
{#if !hideInactive || task.active}
|
||||
<TaskEntry showAllOptions={showAllOptions} task={task} project={project} />
|
||||
{/if}
|
||||
{/each}
|
||||
</ParentEntry>
|
||||
</StatusColor>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import type { IconName } from "../external/icons";
|
||||
|
||||
import Icon from "./Icon.svelte";
|
||||
|
||||
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";
|
||||
</script>
|
||||
|
||||
<span class:selected class:completed class:failed class:postponed class:idea>
|
||||
<Icon block name={project.icon} />
|
||||
</span>
|
||||
|
||||
<style>
|
||||
span { color: #444; }
|
||||
span.selected { color: #666; }
|
||||
span.completed { color: #484; }
|
||||
span.completed.selected { color: #78ff78; }
|
||||
span.failed { color: #884844; }
|
||||
span.failed.selected { color: #ff9878; }
|
||||
span.postponed { color: #446d88; }
|
||||
span.postponed.selected { color: #78c9ff; }
|
||||
span.idea { color: #878844; }
|
||||
span.idea.selected { color: #fffd78; }
|
||||
</style>
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
interface ProjectLike {
|
||||
tasks?: TaskResult[]
|
||||
statusTag?: string
|
||||
}
|
||||
|
||||
export let project: ProjectLike;
|
||||
@@ -18,4 +19,4 @@
|
||||
$: progressTarget = Math.max((project.tasks||[]).map(t => t.itemAmount * t.item.groupWeight).reduce((n,m) => n+m, 0), 1);
|
||||
</script>
|
||||
|
||||
<Progress thin green count={progressAmount} target={progressTarget} />
|
||||
<Progress thin contextColor count={progressAmount} target={progressTarget} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { ProjectResult } from "../models/project";
|
||||
import QlListItem from "./QLListItem.svelte";
|
||||
import QlListItem from "./QLListItem.svelte";
|
||||
|
||||
export let projects: ProjectResult[];
|
||||
export let label: string = "";
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
import selectionStore from "../stores/selection";
|
||||
import DaysLeft from "./DaysLeft.svelte";
|
||||
import Icon from "./Icon.svelte";
|
||||
import ProjectIcon from "./ProjectIcon.svelte";
|
||||
import ProjectProgress from "./ProjectProgress.svelte";
|
||||
import TimeProgress from "./TimeProgress.svelte";
|
||||
import StatusColor from "./StatusColor.svelte";
|
||||
import TimeProgress from "./TimeProgress.svelte";
|
||||
|
||||
export let project: ProjectResult;
|
||||
|
||||
@@ -20,25 +22,27 @@ import TimeProgress from "./TimeProgress.svelte";
|
||||
$: completed = !project.active;
|
||||
</script>
|
||||
|
||||
<div class="ql-list-item" on:click={handleClick} class:selected>
|
||||
<div class="icon" class:completed>
|
||||
<Icon block name={project.icon} />
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="name">
|
||||
<div class="content">{project.name}</div>
|
||||
<StatusColor project={project} selected={selected}>
|
||||
<div class="ql-list-item" on:click={handleClick} class:selected>
|
||||
<div class="icon sccfg" class:completed>
|
||||
<Icon block name={project.icon} />
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="name">
|
||||
<div class="content">{project.name}</div>
|
||||
{#if project.endTime}
|
||||
<div class="times">
|
||||
<DaysLeft compact startTime={project.createdTime} endTime={project.endTime} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<ProjectProgress project={project} />
|
||||
{#if project.endTime}
|
||||
<div class="times">
|
||||
<DaysLeft compact startTime={project.createdTime} endTime={project.endTime} />
|
||||
</div>
|
||||
<TimeProgress startTime={project.createdTime} endTime={project.endTime} />
|
||||
{/if}
|
||||
</div>
|
||||
<ProjectProgress project={project} />
|
||||
{#if project.endTime}
|
||||
<TimeProgress startTime={project.createdTime} endTime={project.endTime} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</StatusColor>
|
||||
|
||||
<style>
|
||||
div.ql-list-item {
|
||||
@@ -54,33 +58,22 @@ import TimeProgress from "./TimeProgress.svelte";
|
||||
cursor: pointer;
|
||||
}
|
||||
div.ql-list-item:hover {
|
||||
color: #ccc;
|
||||
background-color: #191919;
|
||||
}
|
||||
|
||||
div.ql-list-item.selected {
|
||||
background-color: #222;
|
||||
color: #aaa;
|
||||
}
|
||||
div.ql-list-item:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
div.icon {
|
||||
color: #444;
|
||||
|
||||
div.icon {
|
||||
padding: 0.3em 0.5ch;
|
||||
padding-right: 1ch;
|
||||
padding-top: 0.4em;
|
||||
}
|
||||
div.ql-list-item.selected div.icon {
|
||||
color: #666;
|
||||
}
|
||||
div.icon.completed {
|
||||
color: #484;
|
||||
}
|
||||
div.ql-list-item.selected div.icon.completed {
|
||||
color: #78ff78;
|
||||
}
|
||||
div.ql-list-item:hover div.icon {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
div.header {
|
||||
flex-grow: 1;
|
||||
|
||||
@@ -8,13 +8,21 @@
|
||||
|
||||
let expiringProjects: ProjectResult[];
|
||||
let activeProjects: ProjectResult[];
|
||||
let inactiveProjects: ProjectResult[];
|
||||
let completedProjects: ProjectResult[];
|
||||
let failedProjects: ProjectResult[];
|
||||
let posponedProjects: ProjectResult[];
|
||||
let ideaProjects: ProjectResult[];
|
||||
let project: ProjectResult = null;
|
||||
|
||||
$: project = $selectionStore.hash.startsWith("P") ? projects.find(p => p.id === $selectionStore.hash) : null;
|
||||
$: expiringProjects = projects.filter(p => p.active && p.endTime).sort((a,b) => Date.parse(a.endTime) - Date.parse(b.endTime));
|
||||
$: activeProjects = projects.filter(p => p.active && !p.endTime).sort((a,b) => a.name.localeCompare(b.name));
|
||||
$: completedProjects = projects.filter(p => !p.active).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);
|
||||
|
||||
$: {
|
||||
if (project === null && projects.length > 0) {
|
||||
@@ -31,6 +39,9 @@
|
||||
<QlList label="Deadlines" projects={expiringProjects} />
|
||||
<QlList label="Active" projects={activeProjects} />
|
||||
<QlList label="Completed" projects={completedProjects} />
|
||||
<QlList label="Postponed" projects={postponedProjects} />
|
||||
<QlList label="Ideas" projects={ideaProjects} />
|
||||
<QlList label="Failed" projects={failedProjects} />
|
||||
</div>
|
||||
<div class="body">
|
||||
{#if project != null}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
interface ProjectLike {
|
||||
active: boolean
|
||||
statusTag?: string
|
||||
}
|
||||
|
||||
export let selected = false;
|
||||
export let project: ProjectLike;
|
||||
|
||||
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";
|
||||
|
||||
</script>
|
||||
|
||||
<div class="status-color-context" class:selected class:completed class:failed class:postponed class:idea>
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.status-color-context :global(.sccfg) { color: #444 !important; }
|
||||
.status-color-context.selected :global(.sccfg) { color: #666 !important; }
|
||||
.status-color-context :global(.sccpb) { background-color: #78ff78 !important; }
|
||||
.status-color-context.completed :global(.sccfg) { color: #484 !important; }
|
||||
.status-color-context.completed.selected :global(.sccfg) { color: #78ff78 !important; }
|
||||
.status-color-context.completed :global(.sccpb) { background-color: #78ff78 !important; }
|
||||
.status-color-context.failed :global(.sccfg) { color: #852a24 !important; }
|
||||
.status-color-context.failed.selected :global(.sccfg) { color: #ff4545 !important; }
|
||||
.status-color-context.failed :global(.sccpb) { background-color: #ff4545 !important; }
|
||||
.status-color-context.postponed :global(.sccfg) { color: #446d88 !important; }
|
||||
.status-color-context.postponed.selected :global(.sccfg) { color: #78c9ff !important; }
|
||||
.status-color-context.postponed :global(.sccpb) { background-color: #78c9ff !important; }
|
||||
.status-color-context.idea :global(.sccfg) { color: #878844 !important; }
|
||||
.status-color-context.idea.selected :global(.sccfg) { color: #e7e55e !important; }
|
||||
.status-color-context.idea :global(.sccpb) { background-color: #e7e55e !important; }
|
||||
</style>
|
||||
@@ -34,7 +34,7 @@
|
||||
let endTime = formatFormTime(project.endTime);
|
||||
let name = project.name;
|
||||
let description = project.description;
|
||||
let completed = !project.active;
|
||||
let statusTag = project.statusTag || "";
|
||||
let icon = project.icon;
|
||||
let error = null;
|
||||
let loading = false;
|
||||
@@ -45,8 +45,9 @@
|
||||
|
||||
if (creation) {
|
||||
stuffLogClient.createProject({
|
||||
active: !completed,
|
||||
active: statusTag === "",
|
||||
endTime: ( endTime == "" ) ? null : new Date(endTime),
|
||||
statusTag: statusTag || null,
|
||||
|
||||
name, description, icon,
|
||||
}).then(() => {
|
||||
@@ -70,7 +71,8 @@
|
||||
stuffLogClient.updateProject(project.id, {
|
||||
endTime: ( endTime == "" ) ? null : new Date(endTime),
|
||||
clearEndTime: ( endTime == "" ),
|
||||
active: !completed,
|
||||
active: statusTag === "",
|
||||
statusTag: statusTag || null,
|
||||
|
||||
name, description, icon,
|
||||
}).then(() => {
|
||||
@@ -100,8 +102,14 @@
|
||||
<IconSelect disabled={deletion} bind:value={icon} />
|
||||
<label for="endTime">Deadline (Optional)</label>
|
||||
<input disabled={deletion} name="endTime" type="datetime-local" bind:value={endTime} />
|
||||
<Checkbox disabled={deletion} bind:checked={completed} label="Project is completed." />
|
||||
|
||||
<label for="statusTag">Status</label>
|
||||
<select name="statusTag" bind:value={statusTag} disabled={deletion}>
|
||||
<option value="" selected={"" === statusTag}>Active / In Progress</option>
|
||||
<option value="completed" selected={"completed" === statusTag}>Completed</option>
|
||||
<option value="failed" selected={"failed" === statusTag}>Failed</option>
|
||||
<option value="postponed" selected={"postponed" === statusTag}>Postponed</option>
|
||||
<option value="idea" selected={"idea" === statusTag}>Idea</option>
|
||||
</select>
|
||||
<hr />
|
||||
|
||||
<button disabled={loading} type="submit">{verb} Project</button>
|
||||
|
||||
@@ -9,6 +9,7 @@ export default interface Project {
|
||||
active: boolean
|
||||
createdTime: string
|
||||
endTime?: string
|
||||
statusTag?: string
|
||||
}
|
||||
|
||||
export interface ProjectResult extends Project {
|
||||
@@ -26,6 +27,7 @@ export interface ProjectInput {
|
||||
icon: IconName
|
||||
active: boolean
|
||||
endTime?: string | Date
|
||||
statusTag?: string
|
||||
}
|
||||
|
||||
export interface ProjectUpdate {
|
||||
@@ -35,4 +37,6 @@ export interface ProjectUpdate {
|
||||
active?: boolean
|
||||
endTime?: string | Date
|
||||
clearEndTime?: boolean
|
||||
statusTag?: string
|
||||
clearStatusTag?: boolean
|
||||
}
|
||||
Reference in New Issue
Block a user