Browse Source
Move group to backend and change intervals and such to use 05:00 as start of day.
master
0.1.21
Move group to backend and change intervals and such to use 05:00 as start of day.
master
0.1.21
15 changed files with 230 additions and 103 deletions
-
2frontend/src/app.d.ts
-
15frontend/src/lib/clients/sl3.ts
-
7frontend/src/lib/components/contexts/ItemListContext.svelte
-
4frontend/src/lib/components/controls/TimeRangeInput.svelte
-
8frontend/src/lib/models/item.ts
-
71frontend/src/lib/utils/items.ts
-
13frontend/src/lib/utils/timeinterval.ts
-
7frontend/src/routes/[scope=prettyid]/history/[interval].svelte
-
6frontend/src/routes/[scope=prettyid]/overview.svelte
-
6frontend/src/routes/index.svelte
-
9internal/genutils/map.go
-
8models/date.go
-
9ports/httpapi/common.go
-
61ports/httpapi/items.go
-
105usecases/items/groups.go
@ -1,71 +0,0 @@ |
|||||
import type { ItemGroup, ItemGroupReference } from "$lib/models/item"; |
|
||||
import type Item from "$lib/models/item"; |
|
||||
import { formatDate, formatDateTime, formatTime, formatWeekdayDate } from "./date"; |
|
||||
|
|
||||
export interface GroupItemsOptions { |
|
||||
hideCreated?: boolean |
|
||||
hideScheduled?: boolean |
|
||||
hideAcquired?: boolean |
|
||||
} |
|
||||
|
|
||||
export function groupItemOptionsQuery(opts: GroupItemsOptions): string { |
|
||||
return `hideCreated=${opts.hideCreated},hideScheduled=${opts.hideScheduled},hideAcquired=${opts.hideAcquired}`; |
|
||||
} |
|
||||
|
|
||||
export function groupItems(items: Item[], minDate?: string, opts: GroupItemsOptions = {}): ItemGroup[] { |
|
||||
let groups: Record<string, ItemGroup> = {}; |
|
||||
|
|
||||
for (let i = 0; i < items.length; ++i) { |
|
||||
const item = items[i]; |
|
||||
const createKey = formatDate(item.createdTime) |
|
||||
const createSortKey = `${createKey} ${formatTime(item.createdTime)}` |
|
||||
|
|
||||
if (!opts.hideCreated) { |
|
||||
if (!item.acquiredTime || item.acquiredTime >= item.createdTime) { |
|
||||
addItem(groups, createKey, i, createSortKey, item, "created"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (!opts.hideScheduled) { |
|
||||
if (item.scheduledDate) { |
|
||||
addItem(groups, item.scheduledDate, i, `${item.scheduledDate} 23:59:59`, item, "scheduled"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (!opts.hideAcquired) { |
|
||||
if (item.acquiredTime) { |
|
||||
addItem(groups, formatDate(item.acquiredTime), i, formatDateTime(item.acquiredTime), item, "acquired"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return Object.keys(groups).sort((a,b) => ( |
|
||||
b.localeCompare(a) |
|
||||
)).map(k => ({ |
|
||||
...groups[k], |
|
||||
list: groups[k].list.sort((a, b) => { |
|
||||
return b.sortKey.localeCompare(a.sortKey); |
|
||||
}).map(r => ({...r, sortKey: void(0)})), |
|
||||
})).filter(g => minDate == null || g.label > minDate); |
|
||||
} |
|
||||
|
|
||||
function addItem(groups: Record<string, ItemGroup>, key: string, index: number, sortKey: string, item: Item, event: ItemGroupReference["event"]) { |
|
||||
if (groups[key] == null) { |
|
||||
groups[key] = { |
|
||||
label: formatWeekdayDate(sortKey), |
|
||||
list: [], |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const i = groups[key].list.findIndex(r => r.idx === index) |
|
||||
if (i == -1) { |
|
||||
groups[key].list.push({ |
|
||||
idx: index, |
|
||||
event: event, |
|
||||
sortKey: sortKey, |
|
||||
}) |
|
||||
} else { |
|
||||
groups[key].list[i].event = event; |
|
||||
groups[key].list[i].sortKey = sortKey; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,105 @@ |
|||||
|
package items |
||||
|
|
||||
|
import ( |
||||
|
"git.aiterp.net/stufflog3/stufflog3/internal/genutils" |
||||
|
"sort" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type Group struct { |
||||
|
Label string `json:"label,omitempty"` |
||||
|
List []GroupReference `json:"list,omitempty"` |
||||
|
} |
||||
|
|
||||
|
type GroupOptions struct { |
||||
|
HideCreated bool `json:"hideCreated,omitempty"` |
||||
|
HideScheduled bool `json:"hideScheduled,omitempty"` |
||||
|
HideAcquired bool `json:"hideAcquired,omitempty"` |
||||
|
} |
||||
|
|
||||
|
type GroupReference struct { |
||||
|
Index int `json:"idx"` |
||||
|
Event string `json:"event"` |
||||
|
Time string `json:"time"` |
||||
|
|
||||
|
sortKey string |
||||
|
} |
||||
|
|
||||
|
func GenerateGroups(items []Result, opts GroupOptions) []Group { |
||||
|
groups := make(map[string]Group, 16) |
||||
|
|
||||
|
// TODO: Get the scope from somewhere else, if necessary.
|
||||
|
|
||||
|
for i, item := range items { |
||||
|
if !opts.HideCreated && (item.AcquiredTime == nil || item.AcquiredTime.After(item.CreatedTime)) { |
||||
|
addItem(groups, i, "created", item.CreatedTime, tz) |
||||
|
} |
||||
|
if !opts.HideScheduled && item.ScheduledDate != nil { |
||||
|
addItem(groups, i, "scheduled", item.ScheduledDate.WithTimeAndLocation(23, 59, 59, tz), tz) |
||||
|
} |
||||
|
if !opts.HideAcquired && item.AcquiredTime != nil { |
||||
|
addItem(groups, i, "acquired", *item.AcquiredTime, tz) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for _, group := range groups { |
||||
|
sort.Slice(group.List, func(i, j int) bool { |
||||
|
return group.List[j].sortKey < group.List[i].sortKey |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
groupSlice := genutils.MapValues(groups) |
||||
|
sort.Slice(groupSlice, func(i, j int) bool { |
||||
|
return groupSlice[j].Label < groupSlice[i].Label |
||||
|
}) |
||||
|
|
||||
|
return groupSlice |
||||
|
} |
||||
|
|
||||
|
func addItem(groups map[string]Group, index int, event string, eventDate time.Time, tz *time.Location) { |
||||
|
groupDate := eventDate.In(tz).Add(-time.Minute * 300) |
||||
|
eventDate = eventDate.In(tz) |
||||
|
|
||||
|
groupKey := groupDate.Format("2006-01-02") |
||||
|
var sortKey string |
||||
|
if event == "scheduled" { |
||||
|
sortKey = eventDate.Format("2006-01-02") + " 23:59:59.999" |
||||
|
} else { |
||||
|
sortKey = eventDate.Format("2006-01-02 15:04:05") |
||||
|
} |
||||
|
|
||||
|
// Why, Go, must you be so.
|
||||
|
group, ok := groups[groupKey] |
||||
|
if !ok { |
||||
|
group = Group{ |
||||
|
Label: groupDate.Format("2006-01-02 (Monday)"), |
||||
|
List: make([]GroupReference, 0, 16), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for i, ref := range group.List { |
||||
|
if ref.Index == index { |
||||
|
group.List = append(group.List[:i], group.List[i+1:]...) |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
group.List = append(group.List, GroupReference{ |
||||
|
Index: index, |
||||
|
Event: event, |
||||
|
Time: eventDate.Format("15:04"), |
||||
|
sortKey: sortKey, |
||||
|
}) |
||||
|
groups[groupKey] = group |
||||
|
} |
||||
|
|
||||
|
var tz *time.Location |
||||
|
|
||||
|
func init() { |
||||
|
var err error |
||||
|
|
||||
|
tz, err = time.LoadLocation("Europe/Oslo") |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue