simplify ListTodayView: remove fallback table queries, pure activity_events + ListTodayNodes
TodayView now uses only activity_events (source of truth) + ListTodayNodes (ensure changed cases appear). Removed direct queries to nodes (notes) and files tables — those will come from activity_events going forward.
This commit is contained in:
parent
08c9d5dbea
commit
5a1c4c6d7f
Binary file not shown.
|
|
@ -187,83 +187,20 @@ func (a *App) ListNodesBySection(section string) ([]NodeDTO, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTodayView returns a dashboard of today's activity.
|
// ListTodayView returns a dashboard of today's activity.
|
||||||
|
// For MVP this uses activity_events + root nodes changed today.
|
||||||
|
// Future: full Activity/Event Log system will be the single source of truth.
|
||||||
func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
start, end := activity.TodayBoundaries()
|
// Collect events from activity_events, grouped by parent node.
|
||||||
|
|
||||||
// 1. Collect events from activity_events table.
|
|
||||||
aeByParent, err := a.activity.ListTodayEventsByParent()
|
aeByParent, err := a.activity.ListTodayEventsByParent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aeByParent = nil
|
aeByParent = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Query notes created/updated today directly from nodes.
|
// Root nodes that were created/updated today.
|
||||||
type noteRow struct {
|
|
||||||
ID string
|
|
||||||
ParentID string
|
|
||||||
Title string
|
|
||||||
CreatedAt string
|
|
||||||
}
|
|
||||||
var todayNotes []noteRow
|
|
||||||
if r, err := a.db.Query(`SELECT n.id, COALESCE(n.parent_id,''), n.title, n.created_at
|
|
||||||
FROM nodes n
|
|
||||||
WHERE n.deleted_at IS NULL AND n.type='note'
|
|
||||||
AND ((n.created_at >= ?1 AND n.created_at < ?2) OR (n.updated_at >= ?1 AND n.updated_at < ?2))`,
|
|
||||||
start, end); err == nil {
|
|
||||||
for r.Next() {
|
|
||||||
var nr noteRow
|
|
||||||
if err := r.Scan(&nr.ID, &nr.ParentID, &nr.Title, &nr.CreatedAt); err == nil {
|
|
||||||
todayNotes = append(todayNotes, nr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Query files created today from files table.
|
|
||||||
type fileRow struct {
|
|
||||||
ID string
|
|
||||||
NodeID string
|
|
||||||
Filename string
|
|
||||||
ParentID string
|
|
||||||
CreatedAt string
|
|
||||||
}
|
|
||||||
var todayFiles []fileRow
|
|
||||||
if r, err := a.db.Query(`SELECT f.id, f.node_id, f.filename, COALESCE(n.parent_id,''), f.created_at
|
|
||||||
FROM files f
|
|
||||||
JOIN nodes n ON f.node_id = n.id
|
|
||||||
WHERE n.deleted_at IS NULL
|
|
||||||
AND (f.created_at >= ?1 AND f.created_at < ?2)`, start, end); err == nil {
|
|
||||||
for r.Next() {
|
|
||||||
var fr fileRow
|
|
||||||
if err := r.Scan(&fr.ID, &fr.NodeID, &fr.Filename, &fr.ParentID, &fr.CreatedAt); err == nil {
|
|
||||||
todayFiles = append(todayFiles, fr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also include files updated today (but not created today).
|
|
||||||
if r, err := a.db.Query(`SELECT f.id, f.node_id, f.filename, COALESCE(n.parent_id,''), f.updated_at
|
|
||||||
FROM files f
|
|
||||||
JOIN nodes n ON f.node_id = n.id
|
|
||||||
WHERE n.deleted_at IS NULL
|
|
||||||
AND f.updated_at >= ?1 AND f.updated_at < ?2
|
|
||||||
AND f.created_at < ?1`, start, end); err == nil {
|
|
||||||
for r.Next() {
|
|
||||||
var fr fileRow
|
|
||||||
if err := r.Scan(&fr.ID, &fr.NodeID, &fr.Filename, &fr.ParentID, &fr.CreatedAt); err == nil {
|
|
||||||
todayFiles = append(todayFiles, fr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Get root nodes that were created/updated today.
|
|
||||||
todayNodes, _ := a.nodes.ListTodayNodes()
|
todayNodes, _ := a.nodes.ListTodayNodes()
|
||||||
|
|
||||||
// Build caseID → events map from all sources.
|
|
||||||
type rawEvent struct {
|
type rawEvent struct {
|
||||||
NodeID string
|
NodeID string
|
||||||
ParentID string
|
|
||||||
EventType string
|
EventType string
|
||||||
Title string
|
Title string
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
|
|
@ -274,7 +211,6 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
}
|
}
|
||||||
caseMap := make(map[string]*caseInfo)
|
caseMap := make(map[string]*caseInfo)
|
||||||
|
|
||||||
// Helper: ensure case entry exists.
|
|
||||||
ensureCase := func(caseID string) *caseInfo {
|
ensureCase := func(caseID string) *caseInfo {
|
||||||
if ci, ok := caseMap[caseID]; ok {
|
if ci, ok := caseMap[caseID]; ok {
|
||||||
return ci
|
return ci
|
||||||
|
|
@ -293,7 +229,6 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
for _, e := range events {
|
for _, e := range events {
|
||||||
ci.Events = append(ci.Events, rawEvent{
|
ci.Events = append(ci.Events, rawEvent{
|
||||||
NodeID: e.NodeID,
|
NodeID: e.NodeID,
|
||||||
ParentID: pid,
|
|
||||||
EventType: e.EventType,
|
EventType: e.EventType,
|
||||||
Title: e.Title,
|
Title: e.Title,
|
||||||
CreatedAt: e.CreatedAt,
|
CreatedAt: e.CreatedAt,
|
||||||
|
|
@ -301,43 +236,7 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge notes from direct query (avoid duplicates with ae).
|
// Ensure all today's root nodes are present (even without events).
|
||||||
noteSeen := make(map[string]bool)
|
|
||||||
for _, nr := range todayNotes {
|
|
||||||
if noteSeen[nr.ID] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
noteSeen[nr.ID] = true
|
|
||||||
caseID := nr.ParentID
|
|
||||||
ci := ensureCase(caseID)
|
|
||||||
ci.Events = append(ci.Events, rawEvent{
|
|
||||||
NodeID: nr.ID,
|
|
||||||
ParentID: caseID,
|
|
||||||
EventType: activity.TypeNoteCreated,
|
|
||||||
Title: nr.Title,
|
|
||||||
CreatedAt: nr.CreatedAt,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge files.
|
|
||||||
fileSeen := make(map[string]bool)
|
|
||||||
for _, fr := range todayFiles {
|
|
||||||
if fileSeen[fr.ID] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fileSeen[fr.ID] = true
|
|
||||||
caseID := fr.ParentID
|
|
||||||
ci := ensureCase(caseID)
|
|
||||||
ci.Events = append(ci.Events, rawEvent{
|
|
||||||
NodeID: fr.NodeID,
|
|
||||||
ParentID: caseID,
|
|
||||||
EventType: activity.TypeFileAdded,
|
|
||||||
Title: fr.Filename,
|
|
||||||
CreatedAt: fr.CreatedAt,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge today's root nodes (even without events).
|
|
||||||
for _, n := range todayNodes {
|
for _, n := range todayNodes {
|
||||||
_ = ensureCase(n.ID)
|
_ = ensureCase(n.ID)
|
||||||
if ci := caseMap[n.ID]; ci.Node.ID == "" {
|
if ci := caseMap[n.ID]; ci.Node.ID == "" {
|
||||||
|
|
@ -345,7 +244,6 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build final groups and flat timeline.
|
|
||||||
var groups []TodayGroupDTO
|
var groups []TodayGroupDTO
|
||||||
var flatEvents []EventDTO
|
var flatEvents []EventDTO
|
||||||
summary := SummaryDTO{}
|
summary := SummaryDTO{}
|
||||||
|
|
@ -358,17 +256,16 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
|
|
||||||
dtoEvents := make([]EventDTO, 0, len(ci.Events))
|
dtoEvents := make([]EventDTO, 0, len(ci.Events))
|
||||||
for _, re := range ci.Events {
|
for _, re := range ci.Events {
|
||||||
et := re.EventType
|
|
||||||
dtoEvents = append(dtoEvents, EventDTO{
|
dtoEvents = append(dtoEvents, EventDTO{
|
||||||
ID: ci.Node.ID + "/" + re.NodeID,
|
ID: ci.Node.ID + "/" + re.NodeID,
|
||||||
NodeID: re.NodeID,
|
NodeID: re.NodeID,
|
||||||
ParentID: re.ParentID,
|
ParentID: ci.Node.ID,
|
||||||
EventType: et,
|
EventType: re.EventType,
|
||||||
Title: re.Title,
|
Title: re.Title,
|
||||||
Metadata: "{}",
|
Metadata: "{}",
|
||||||
CreatedAt: re.CreatedAt,
|
CreatedAt: re.CreatedAt,
|
||||||
})
|
})
|
||||||
switch et {
|
switch re.EventType {
|
||||||
case activity.TypeNoteCreated, activity.TypeNoteUpdated:
|
case activity.TypeNoteCreated, activity.TypeNoteUpdated:
|
||||||
summary.Notes++
|
summary.Notes++
|
||||||
case activity.TypeFileAdded, activity.TypeFileDeleted, activity.TypeFileRenamed, activity.TypeFileCopied, activity.TypeFileMoved:
|
case activity.TypeFileAdded, activity.TypeFileDeleted, activity.TypeFileRenamed, activity.TypeFileCopied, activity.TypeFileMoved:
|
||||||
|
|
@ -377,13 +274,11 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
last := ci.Node.UpdatedAt.Format(time.RFC3339)
|
last := ci.Node.UpdatedAt.Format(time.RFC3339)
|
||||||
if len(dtoEvents) > 0 {
|
|
||||||
for _, e := range dtoEvents {
|
for _, e := range dtoEvents {
|
||||||
if e.CreatedAt > last {
|
if e.CreatedAt > last {
|
||||||
last = e.CreatedAt
|
last = e.CreatedAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
groups = append(groups, TodayGroupDTO{
|
groups = append(groups, TodayGroupDTO{
|
||||||
NodeID: ci.Node.ID,
|
NodeID: ci.Node.ID,
|
||||||
|
|
@ -393,24 +288,18 @@ func (a *App) ListTodayView() (*TodayDashboardDTO, error) {
|
||||||
LastActivityAt: last,
|
LastActivityAt: last,
|
||||||
Events: dtoEvents,
|
Events: dtoEvents,
|
||||||
})
|
})
|
||||||
|
|
||||||
flatEvents = append(flatEvents, dtoEvents...)
|
flatEvents = append(flatEvents, dtoEvents...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort groups by lastActivityAt desc.
|
|
||||||
sort.Slice(groups, func(i, j int) bool {
|
sort.Slice(groups, func(i, j int) bool {
|
||||||
return groups[i].LastActivityAt > groups[j].LastActivityAt
|
return groups[i].LastActivityAt > groups[j].LastActivityAt
|
||||||
})
|
})
|
||||||
|
|
||||||
// Sort flat events by createdAt desc.
|
|
||||||
sort.Slice(flatEvents, func(i, j int) bool {
|
sort.Slice(flatEvents, func(i, j int) bool {
|
||||||
return flatEvents[i].CreatedAt > flatEvents[j].CreatedAt
|
return flatEvents[i].CreatedAt > flatEvents[j].CreatedAt
|
||||||
})
|
})
|
||||||
|
|
||||||
dateStr := time.Now().Format("2006-01-02")
|
|
||||||
|
|
||||||
return &TodayDashboardDTO{
|
return &TodayDashboardDTO{
|
||||||
Date: dateStr,
|
Date: time.Now().Format("2006-01-02"),
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
Groups: groups,
|
Groups: groups,
|
||||||
Events: flatEvents,
|
Events: flatEvents,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue