This commit is contained in:
+1
-1
@@ -68,7 +68,7 @@ func Task(g *gin.RouterGroup, db database.Database) {
|
|||||||
|
|
||||||
return &models.TaskResult{
|
return &models.TaskResult{
|
||||||
Task: task,
|
Task: task,
|
||||||
Logs: []*models.Log{},
|
Logs: []*models.LogWithSecondaryItem{},
|
||||||
Item: &item.Item,
|
Item: &item.Item,
|
||||||
CompletedAmount: 0,
|
CompletedAmount: 0,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
+11
-6
@@ -67,14 +67,19 @@ type LogResult struct {
|
|||||||
SecondaryItem *Item `json:"secondaryItem"`
|
SecondaryItem *Item `json:"secondaryItem"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogWithSecondaryItem struct {
|
||||||
|
Log
|
||||||
|
SecondaryItem *Item `json:"secondaryItem,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type LogFilter struct {
|
type LogFilter struct {
|
||||||
UserID string
|
UserID string
|
||||||
ProjectGroupIDs []string
|
ProjectGroupIDs []string
|
||||||
ProjectIDs []string
|
ProjectIDs []string
|
||||||
TaskIDs []string
|
TaskIDs []string
|
||||||
ItemIDs []string
|
ItemIDs []string
|
||||||
MinTime *time.Time
|
MinTime *time.Time
|
||||||
MaxTime *time.Time
|
MaxTime *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogRepository interface {
|
type LogRepository interface {
|
||||||
|
|||||||
+4
-4
@@ -79,10 +79,10 @@ type TaskWithProject struct {
|
|||||||
|
|
||||||
type TaskResult struct {
|
type TaskResult struct {
|
||||||
Task
|
Task
|
||||||
Item *Item `json:"item"`
|
Item *Item `json:"item"`
|
||||||
Logs []*Log `json:"logs"`
|
Logs []*LogWithSecondaryItem `json:"logs"`
|
||||||
CompletedAmount int `json:"completedAmount"`
|
CompletedAmount int `json:"completedAmount"`
|
||||||
Project *Project `json:"project,omitempty"`
|
Project *Project `json:"project,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskFilter struct {
|
type TaskFilter struct {
|
||||||
|
|||||||
+104
-10
@@ -251,6 +251,12 @@ func (l *Loader) FindProject(ctx context.Context, id string) (*models.ProjectRes
|
|||||||
UserID: auth.UserID(ctx),
|
UserID: auth.UserID(ctx),
|
||||||
TaskIDs: taskIDs,
|
TaskIDs: taskIDs,
|
||||||
})
|
})
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.SecondaryItemID == nil {
|
||||||
|
itemIDs.Add(*log.SecondaryItemID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -265,12 +271,26 @@ func (l *Loader) FindProject(ctx context.Context, id string) (*models.ProjectRes
|
|||||||
result.Tasks = make([]*models.TaskResult, len(tasks))
|
result.Tasks = make([]*models.TaskResult, len(tasks))
|
||||||
for i, task := range tasks {
|
for i, task := range tasks {
|
||||||
result.Tasks[i] = &models.TaskResult{
|
result.Tasks[i] = &models.TaskResult{
|
||||||
Logs: []*models.Log{},
|
Logs: []*models.LogWithSecondaryItem{},
|
||||||
}
|
}
|
||||||
result.Tasks[i].Task = *task
|
result.Tasks[i].Task = *task
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if log.TaskID == task.ID {
|
if log.TaskID == task.ID {
|
||||||
result.Tasks[i].Logs = append(result.Tasks[i].Logs, log)
|
log := models.LogWithSecondaryItem{
|
||||||
|
Log: *log,
|
||||||
|
SecondaryItem: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
for _, item := range items {
|
||||||
|
if item.ID == *log.SecondaryItemID {
|
||||||
|
log.SecondaryItem = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Tasks[i].Logs = append(result.Tasks[i].Logs, &log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
@@ -280,6 +300,10 @@ func (l *Loader) FindProject(ctx context.Context, id string) (*models.ProjectRes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, log := range result.Tasks[i].Logs {
|
for _, log := range result.Tasks[i].Logs {
|
||||||
|
if project.StartTime != nil && log.LoggedTime.Before(*project.StartTime) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
result.Tasks[i].CompletedAmount += log.Amount(result.Tasks[i].ItemID)
|
result.Tasks[i].CompletedAmount += log.Amount(result.Tasks[i].ItemID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,6 +343,11 @@ func (l *Loader) ListProjects(ctx context.Context, filter models.ProjectFilter)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
itemIDs.Add(*log.SecondaryItemID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||||
UserID: auth.UserID(ctx),
|
UserID: auth.UserID(ctx),
|
||||||
@@ -350,11 +379,25 @@ func (l *Loader) ListProjects(ctx context.Context, filter models.ProjectFilter)
|
|||||||
|
|
||||||
taskResult := &models.TaskResult{
|
taskResult := &models.TaskResult{
|
||||||
Task: *task,
|
Task: *task,
|
||||||
Logs: []*models.Log{},
|
Logs: []*models.LogWithSecondaryItem{},
|
||||||
}
|
}
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if log.TaskID == task.ID {
|
if log.TaskID == task.ID {
|
||||||
taskResult.Logs = append(taskResult.Logs, log)
|
log := models.LogWithSecondaryItem{
|
||||||
|
Log: *log,
|
||||||
|
SecondaryItem: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
for _, item := range items {
|
||||||
|
if item.ID == *log.SecondaryItemID {
|
||||||
|
log.SecondaryItem = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
taskResult.Logs = append(taskResult.Logs, &log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
@@ -364,6 +407,10 @@ func (l *Loader) ListProjects(ctx context.Context, filter models.ProjectFilter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, log := range taskResult.Logs {
|
for _, log := range taskResult.Logs {
|
||||||
|
if project.StartTime != nil && log.LoggedTime.Before(*project.StartTime) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
taskResult.CompletedAmount += log.Amount(taskResult.ItemID)
|
taskResult.CompletedAmount += log.Amount(taskResult.ItemID)
|
||||||
}
|
}
|
||||||
results[i].Tasks = append(results[i].Tasks, taskResult)
|
results[i].Tasks = append(results[i].Tasks, taskResult)
|
||||||
@@ -468,7 +515,7 @@ func (l *Loader) FindTask(ctx context.Context, id string) (*models.TaskResult, e
|
|||||||
|
|
||||||
result.Item, _ = l.DB.Items().Find(ctx, task.ItemID)
|
result.Item, _ = l.DB.Items().Find(ctx, task.ItemID)
|
||||||
result.Project, _ = l.DB.Projects().Find(ctx, task.ProjectID)
|
result.Project, _ = l.DB.Projects().Find(ctx, task.ProjectID)
|
||||||
result.Logs, err = l.DB.Logs().List(ctx, models.LogFilter{
|
logs, err := l.DB.Logs().List(ctx, models.LogFilter{
|
||||||
UserID: task.UserID,
|
UserID: task.UserID,
|
||||||
TaskIDs: []string{task.ID},
|
TaskIDs: []string{task.ID},
|
||||||
})
|
})
|
||||||
@@ -476,8 +523,34 @@ func (l *Loader) FindTask(ctx context.Context, id string) (*models.TaskResult, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, log := range result.Logs {
|
itemIds := stringset.New()
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
itemIds.Add(*log.SecondaryItemID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||||
|
UserID: task.UserID,
|
||||||
|
IDs: itemIds.Strings(),
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, log := range logs {
|
||||||
result.CompletedAmount += log.Amount(result.ItemID)
|
result.CompletedAmount += log.Amount(result.ItemID)
|
||||||
|
log := models.LogWithSecondaryItem{
|
||||||
|
Log: *log,
|
||||||
|
SecondaryItem: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
for _, item := range items {
|
||||||
|
if item.ID == *log.SecondaryItemID {
|
||||||
|
log.SecondaryItem = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Logs = append(result.Logs, &log)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -509,7 +582,11 @@ func (l *Loader) ListTasks(ctx context.Context, filter models.TaskFilter) ([]*mo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
itemIDs.Add(*log.SecondaryItemID)
|
||||||
|
}
|
||||||
|
}
|
||||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||||
UserID: auth.UserID(ctx),
|
UserID: auth.UserID(ctx),
|
||||||
IDs: itemIDs.Strings(),
|
IDs: itemIDs.Strings(),
|
||||||
@@ -530,13 +607,30 @@ func (l *Loader) ListTasks(ctx context.Context, filter models.TaskFilter) ([]*mo
|
|||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
result := &models.TaskResult{
|
result := &models.TaskResult{
|
||||||
Task: *task,
|
Task: *task,
|
||||||
Logs: []*models.Log{},
|
Logs: []*models.LogWithSecondaryItem{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if log.TaskID == task.ID {
|
if log.TaskID != task.ID {
|
||||||
result.Logs = append(result.Logs, log)
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.CompletedAmount += log.Amount(result.ItemID)
|
||||||
|
log := models.LogWithSecondaryItem{
|
||||||
|
Log: *log,
|
||||||
|
SecondaryItem: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.SecondaryItemID != nil {
|
||||||
|
for _, item := range items {
|
||||||
|
if item.ID == *log.SecondaryItemID {
|
||||||
|
log.SecondaryItem = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Logs = append(result.Logs, &log)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type Item from "../models/item";
|
||||||
|
import type { ProjectResult } from "../models/project";
|
||||||
|
import Icon from "./Icon.svelte";
|
||||||
|
|
||||||
|
interface ListEntry {
|
||||||
|
item: Item
|
||||||
|
amount: number
|
||||||
|
target: number
|
||||||
|
extras: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export let project: ProjectResult;
|
||||||
|
|
||||||
|
let list: ListEntry[] = [];
|
||||||
|
|
||||||
|
$: {
|
||||||
|
list = [];
|
||||||
|
for (const task of project.tasks) {
|
||||||
|
let entry = list.find(e => e.item.id === task.item.id);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = {item: task.item, amount: 0, target: 0, extras: 0};
|
||||||
|
list.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.completedAmount > task.itemAmount) {
|
||||||
|
entry.extras += task.completedAmount - task.itemAmount;
|
||||||
|
entry.amount += task.itemAmount;
|
||||||
|
} else {
|
||||||
|
entry.amount += task.completedAmount;
|
||||||
|
}
|
||||||
|
entry.target += task.itemAmount;
|
||||||
|
|
||||||
|
for (const log of task.logs) {
|
||||||
|
if (log.secondaryItem != null) {
|
||||||
|
let entry = list.find(e => e.item.id === log.secondaryItemId);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = {item: log.secondaryItem, amount: 0, target: 0, extras: 0};
|
||||||
|
list.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.extras += log.secondaryItemAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.sort((a,b) => {
|
||||||
|
if (a.target === b.target) {
|
||||||
|
return a.item.name.localeCompare(b.item.name);
|
||||||
|
} else {
|
||||||
|
return b.target - a.target;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="ItemProgress">
|
||||||
|
{#each list as entry (entry.item.id)}
|
||||||
|
<div class="entry">
|
||||||
|
<div class="icon">
|
||||||
|
<Icon name={entry.item.icon} />
|
||||||
|
</div>
|
||||||
|
<div class="name">
|
||||||
|
{entry.item.name}
|
||||||
|
</div>
|
||||||
|
{#if entry.target !== 0}
|
||||||
|
<div class="amount">
|
||||||
|
<span>{entry.amount}</span>
|
||||||
|
<span> / </span>
|
||||||
|
<span>{entry.target}</span>
|
||||||
|
{#if entry.extras > 0}
|
||||||
|
<span class="extras">+ {entry.extras}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{:else}
|
||||||
|
<div class="extras">
|
||||||
|
×{entry.extras}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.ItemProgress {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
div.ItemProgress div.entry {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
div.ItemProgress div.entry div {
|
||||||
|
padding: 0.1em 0.25em;
|
||||||
|
}
|
||||||
|
div.ItemProgress div.entry .name {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
div.ItemProgress div.entry .icon {
|
||||||
|
padding: 0.20em;
|
||||||
|
}
|
||||||
|
div.ItemProgress div.entry .extras {
|
||||||
|
color: #484;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,6 +7,7 @@ import stuffLogClient from "../clients/stufflog";
|
|||||||
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 Icon from "./Icon.svelte";
|
||||||
|
import ItemProgress from "./ItemProgress.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";
|
||||||
@@ -120,6 +121,8 @@ import stuffLogClient from "../clients/stufflog";
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if showAllOptions}
|
{#if showAllOptions}
|
||||||
|
<ItemProgress project={project} />
|
||||||
|
|
||||||
<OptionRow>
|
<OptionRow>
|
||||||
<Option open={mdAddTask}>Add Task</Option>
|
<Option open={mdAddTask}>Add Task</Option>
|
||||||
<Option open={mdLinkTask}>Link Task</Option>
|
<Option open={mdLinkTask}>Link Task</Option>
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ export interface LogFilter {
|
|||||||
projectGroupIds?: string[]
|
projectGroupIds?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LogWithSecondaryItem extends Log {
|
||||||
|
secondaryItem?: Item
|
||||||
|
}
|
||||||
|
|
||||||
export interface LogResult extends Log {
|
export interface LogResult extends Log {
|
||||||
task: TaskWithProject
|
task: TaskWithProject
|
||||||
item: Item
|
item: Item
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { IconName } from "../external/icons";
|
import type { IconName } from "../external/icons";
|
||||||
import type Item from "./item";
|
import type Item from "./item";
|
||||||
import type Log from "./log";
|
import type { LogWithSecondaryItem } from "./log";
|
||||||
import type Project from "./project";
|
import type Project from "./project";
|
||||||
|
|
||||||
export default interface Task {
|
export default interface Task {
|
||||||
@@ -23,7 +23,7 @@ export interface TaskWithProject extends Task {
|
|||||||
|
|
||||||
export interface TaskResult extends Task {
|
export interface TaskResult extends Task {
|
||||||
item: Item
|
item: Item
|
||||||
logs: Log[]
|
logs: LogWithSecondaryItem[]
|
||||||
completedAmount: number
|
completedAmount: number
|
||||||
project?: Project
|
project?: Project
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user