Skip to content

Commit efed7fe

Browse files
Merge pull request #3 from DylanDevelops/ravel/prototype-data-management
[add] `stats`, `log`, `export` + CSV and JSON Data Exports
2 parents c234dbb + 0b11f1a commit efed7fe

7 files changed

Lines changed: 714 additions & 0 deletions

File tree

cmd/export.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"time"
8+
9+
"github.com/DylanDevelops/tmpo/internal/export"
10+
"github.com/DylanDevelops/tmpo/internal/storage"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var (
15+
exportFormat string
16+
exportOutput string
17+
exportProject string
18+
exportToday bool
19+
exportWeek bool
20+
)
21+
22+
var exportCmd = &cobra.Command{
23+
Use: "export",
24+
Short: "Export time entries",
25+
Long: `Export time tracking data to different formats.`,
26+
Run: func(cmd *cobra.Command, args []string) {
27+
db, err := storage.Initialize()
28+
if err != nil {
29+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
30+
31+
os.Exit(1)
32+
}
33+
34+
defer db.Close()
35+
36+
var entries []*storage.TimeEntry
37+
38+
if exportToday {
39+
start := time.Now().Truncate(24 * time.Hour)
40+
end := start.Add(24 * time.Hour)
41+
entries, err = db.GetEntriesByDateRange(start, end)
42+
} else if exportWeek {
43+
now := time.Now()
44+
weekday := int(now.Weekday())
45+
if weekday == 0 {
46+
weekday = 7 // sunday
47+
}
48+
49+
start := now.AddDate(0, 0, -weekday+1).Truncate(24 * time.Hour)
50+
end := start.AddDate(0, 0, 7)
51+
entries, err = db.GetEntriesByDateRange(start, end)
52+
} else if exportProject != "" {
53+
entries, err = db.GetEntriesByProject(exportProject)
54+
} else {
55+
entries, err = db.GetEntries(0) // all
56+
}
57+
58+
if err != nil {
59+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
60+
61+
os.Exit(1)
62+
}
63+
64+
if len(entries) == 0 {
65+
fmt.Println("No entries to export.")
66+
67+
os.Exit(0)
68+
}
69+
70+
filename := exportOutput
71+
if filename == "" {
72+
timestamp := time.Now().Format("2006-01-02")
73+
ext := "csv"
74+
75+
if exportFormat == "json" {
76+
ext = "json"
77+
}
78+
79+
filename = fmt.Sprintf("tmpo-export-%s.%s", timestamp, ext)
80+
}
81+
82+
if exportFormat == "csv" && filepath.Ext(filename) != ".csv" {
83+
filename += ".csv"
84+
} else if exportFormat == "json" && filepath.Ext(filename) != ".json" {
85+
filename += ".json"
86+
}
87+
88+
switch exportFormat {
89+
case "csv":
90+
err = export.ToCSV(entries, filename)
91+
case "json":
92+
err = export.ToJson(entries, filename)
93+
default:
94+
fmt.Fprintf(os.Stderr, "Error: Unknown format '%s'. Use 'csv' or 'json'\n", exportFormat)
95+
96+
os.Exit(1)
97+
}
98+
99+
if err != nil {
100+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
101+
102+
os.Exit(1)
103+
}
104+
105+
fmt.Printf("[tmpo] Exported %d entries to %s\n", len(entries), filename)
106+
},
107+
}
108+
109+
func init() {
110+
rootCmd.AddCommand(exportCmd)
111+
112+
exportCmd.Flags().StringVarP(&exportFormat, "format", "f", "csv", "Export format (csv or json)")
113+
exportCmd.Flags().StringVarP(&exportOutput, "output", "o", "", "Output filename")
114+
exportCmd.Flags().StringVarP(&exportProject, "project", "p", "", "Filter by project")
115+
exportCmd.Flags().BoolVarP(&exportToday, "today", "t", false, "Export today's entries")
116+
exportCmd.Flags().BoolVarP(&exportWeek, "week", "w", false, "Export this week's entries")
117+
}

cmd/log.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"time"
7+
8+
"github.com/DylanDevelops/tmpo/internal/storage"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var (
13+
logLimit int
14+
logProject string
15+
logToday bool
16+
logWeek bool
17+
)
18+
19+
var logCmd = &cobra.Command{
20+
Use: "log",
21+
Short: "View time tracking history",
22+
Long: `Display past time tracking entries with optional filtering.`,
23+
Run: func(cmd *cobra.Command, args []string) {
24+
db, err := storage.Initialize()
25+
26+
if err != nil {
27+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
28+
os.Exit(1)
29+
}
30+
31+
defer db.Close()
32+
33+
var entries []*storage.TimeEntry
34+
35+
if logToday {
36+
start := time.Now().Truncate(24 * time.Hour)
37+
end := start.Add(24 * time.Hour)
38+
entries, err = db.GetEntriesByDateRange(start, end)
39+
} else if logWeek {
40+
now := time.Now()
41+
weekday := int(now.Weekday())
42+
if weekday == 0 {
43+
weekday = 7 // sunday
44+
}
45+
46+
start := now.AddDate(0, 0, -weekday+1).Truncate(24 * time.Hour)
47+
end := start.AddDate(0, 0, 7)
48+
entries, err = db.GetEntriesByDateRange(start, end)
49+
} else if logProject != "" {
50+
entries, err = db.GetEntriesByProject(logProject)
51+
} else {
52+
entries, err = db.GetEntries(logLimit)
53+
}
54+
55+
if err != nil {
56+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
57+
os.Exit(1)
58+
}
59+
60+
if len(entries) == 0 {
61+
fmt.Println("No time entries found.")
62+
63+
return
64+
}
65+
66+
fmt.Printf("\n[tmpo] Time Entries (%d total)\n\n", len(entries))
67+
68+
var totalDuration time.Duration
69+
currentDate := ""
70+
71+
for _, entry := range entries {
72+
entryDate := entry.StartTime.Format("Mon, Jan 2, 2006")
73+
if entryDate != currentDate {
74+
if currentDate != "" {
75+
fmt.Println()
76+
}
77+
78+
fmt.Printf("─── %s ───\n", entryDate)
79+
currentDate = entryDate
80+
}
81+
82+
duration := entry.Duration()
83+
totalDuration += duration
84+
85+
timeRange := entry.StartTime.Format("3:04 PM")
86+
if entry.EndTime != nil {
87+
timeRange += " - " + entry.EndTime.Format("3:04 PM")
88+
} else {
89+
timeRange += " - (running)"
90+
}
91+
92+
fmt.Printf(" %s %-20s %s\n", timeRange, entry.ProjectName, formatDuration(duration))
93+
if entry.Description != "" {
94+
fmt.Printf(" └─ %s\n", entry.Description)
95+
}
96+
}
97+
98+
fmt.Printf("\n─────────────────────────────────────────\n")
99+
fmt.Printf("Total Time: %s\n", formatDuration(totalDuration))
100+
},
101+
}
102+
103+
func init() {
104+
rootCmd.AddCommand(logCmd)
105+
106+
logCmd.Flags().IntVarP(&logLimit, "limit", "l", 10, "Number of entries to show")
107+
logCmd.Flags().StringVarP(&logProject, "project", "p", "", "Filter by project name")
108+
logCmd.Flags().BoolVarP(&logToday, "today", "t", false, "Show today's entries")
109+
logCmd.Flags().BoolVarP(&logWeek, "week", "w", false, "Show this week's entries")
110+
}

0 commit comments

Comments
 (0)