feat: worklog source field, suggestion logic fix, modal form, activity navigation
- Add source column to worklog_entries (migration 014): manual/suggestion/unknown - GetSuggestions now excludes only events linked in worklog_entry_events, not entire nodes — repeated activity same day now produces suggestions - Manual entry form replaced with '+' button + modal dialog - Source display shows correct origin (manual/suggestion/unknown/no-events) - Include-children checkbox hidden when no node selected - Activity events navigate to specific notes/files instead of just case - Expandable row reactivity fixed (journalRows/worklog reassignment)
This commit is contained in:
@@ -176,6 +176,7 @@ type WorklogDTO struct {
|
||||
Details string `json:"details,omitempty"`
|
||||
Approximate bool `json:"approximate"`
|
||||
Billable bool `json:"billable"`
|
||||
Source string `json:"source"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
}
|
||||
|
||||
|
||||
@@ -7,16 +7,31 @@ import (
|
||||
"time"
|
||||
|
||||
"verstak/internal/core/activity"
|
||||
"verstak/internal/core/worklog"
|
||||
syncsvc "verstak/internal/core/sync"
|
||||
)
|
||||
|
||||
// GetSuggestions analyzes today's activity and returns conservative suggestions.
|
||||
// Only events not already linked in worklog_entry_events are considered.
|
||||
func (a *App) GetSuggestions() ([]activity.Suggestion, error) {
|
||||
events, err := a.activity.ListTodayEvents()
|
||||
if err != nil || len(events) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine which event IDs are already accounted for in any worklog entry.
|
||||
accounted := make(map[string]bool)
|
||||
rows, err := a.db.Query(`SELECT DISTINCT event_id FROM worklog_entry_events`)
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var eid string
|
||||
if rows.Scan(&eid) == nil {
|
||||
accounted[eid] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type acc struct {
|
||||
title string
|
||||
kind string
|
||||
@@ -24,6 +39,9 @@ func (a *App) GetSuggestions() ([]activity.Suggestion, error) {
|
||||
}
|
||||
grouped := make(map[string]*acc)
|
||||
for _, e := range events {
|
||||
if accounted[e.ID] {
|
||||
continue
|
||||
}
|
||||
grp, ok := grouped[e.NodeID]
|
||||
if !ok {
|
||||
n, err := a.nodes.GetActive(e.NodeID)
|
||||
@@ -41,11 +59,7 @@ func (a *App) GetSuggestions() ([]activity.Suggestion, error) {
|
||||
|
||||
var suggestions []activity.Suggestion
|
||||
for nodeID, grp := range grouped {
|
||||
if grp.title == "" {
|
||||
continue
|
||||
}
|
||||
hasEntries, err := a.worklog.HasTodayEntries(nodeID)
|
||||
if err != nil || hasEntries {
|
||||
if grp.title == "" || len(grp.events) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -108,7 +122,7 @@ func (a *App) AcceptSuggestionWith(s activity.Suggestion, minutes int, date stri
|
||||
if d == "" {
|
||||
d = time.Now().Format("2006-01-02")
|
||||
}
|
||||
entry, err := a.worklog.AddWithDate(s.NodeID, s.Summary, "", d, minutes, true, false)
|
||||
entry, err := a.worklog.AddWithSource(s.NodeID, s.Summary, "", d, minutes, true, false, worklog.SourceSuggestion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -207,6 +207,7 @@ func entryToDTO(e *worklog.Entry) *WorklogDTO {
|
||||
Details: e.Details,
|
||||
Approximate: e.Approximate,
|
||||
Billable: e.Billable,
|
||||
Source: e.Source,
|
||||
CreatedAt: e.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,8 +16,8 @@
|
||||
background: #13131f;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/main-BbnSy6IG.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-Bh5tqssv.css">
|
||||
<script type="module" crossorigin src="/assets/main-cq32hqy7.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BafVhx43.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user