Skip to content

Commit 8316449

Browse files
authored
feat: allow longer comments (#38)
1 parent 51c4a6d commit 8316449

File tree

21 files changed

+713
-287
lines changed

21 files changed

+713
-287
lines changed

.github/workflows/back-compat-pr.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@ jobs:
4141
rm hours_head
4242
- name: Run last version
4343
run: |
44-
/var/tmp/hours_main --dbpath=/var/tmp/throwaway-1.db report 3d -p
45-
/var/tmp/hours_main --dbpath=/var/tmp/throwaway-2.db gen -y
44+
/var/tmp/hours_main --dbpath=/var/tmp/throwaway-empty.db report 3d -p
45+
/var/tmp/hours_main --dbpath=/var/tmp/throwaway-with-data.db gen -y
4646
- name: Run current version
4747
run: |
48-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-1.db report 3d -p
49-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db report 3d -p
50-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db log 3d -p
51-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db stats 3d -p
48+
echo "empty"
49+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db report 3d -p
50+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db log 3d -p
51+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db stats 3d -p
52+
echo "with data"
53+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db report 3d -p
54+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db log 3d -p
55+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db stats 3d -p

.github/workflows/back-compat.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ jobs:
3939
rm hours_head
4040
- name: Run last version
4141
run: |
42-
/var/tmp/hours_prev --dbpath=/var/tmp/throwaway-1.db report 3d -p
43-
/var/tmp/hours_prev --dbpath=/var/tmp/throwaway-2.db gen -y
42+
/var/tmp/hours_prev --dbpath=/var/tmp/throwaway-empty.db report 3d -p
43+
/var/tmp/hours_prev --dbpath=/var/tmp/throwaway-with-data.db gen -y
4444
- name: Run current version
4545
run: |
46-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-1.db report 3d -p
47-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db report 3d -p
48-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db log 3d -p
49-
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-2.db stats 3d -p
46+
echo "empty"
47+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db report 3d -p
48+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db log 3d -p
49+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-empty.db stats 3d -p
50+
echo "with data"
51+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db report 3d -p
52+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db log 3d -p
53+
/var/tmp/hours_head --dbpath=/var/tmp/throwaway-with-data.db stats 3d -p

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# hours
22

3+
[![Build Workflow Status](https://img.shields.io/github/actions/workflow/status/dhth/hours/build.yml?style=flat-square)](https://github.com/dhth/hours/actions/workflows/build.yml)
4+
[![Vulncheck Workflow Status](https://img.shields.io/github/actions/workflow/status/dhth/hours/vulncheck.yml?style=flat-square&label=vulncheck)](https://github.com/dhth/hours/actions/workflows/vulncheck.yml)
5+
[![Latest Release](https://img.shields.io/github/release/dhth/hours.svg?style=flat-square)](https://github.com/dhth/hours/releases/latest)
6+
[![Commits Since Latest Release](https://img.shields.io/github/commits-since/dhth/hours/latest?style=flat-square)](https://github.com/dhth/hours/releases)
7+
38
`hours` is a no-frills time tracking toolkit for the command line.
49

510
It's designed for users who want basic time tracking for their tasks/projects
@@ -201,7 +206,8 @@ General
201206
3 Switch to Inactive Tasks List View
202207
<tab> Go to next view/form entry
203208
<shift+tab> Go to previous view/form entry
204-
? Show help view
209+
q/<ctrl+c> Go back
210+
? Show help view
205211
206212
General List Controls
207213
@@ -224,6 +230,9 @@ Task List View
224230
225231
Task Logs List View
226232
233+
~ at the end of a task log comment indicates that it has more lines that are not visible in the list view
234+
235+
d Show task log details
227236
<ctrl+d> Delete task log entry
228237
<ctrl+r> Refresh list
229238
@@ -233,7 +242,7 @@ Inactive Task List View
233242
234243
Task Log Entry View
235244
236-
enter Save task log entry
245+
enter/<ctrl+s> Save task log entry
237246
k Move timestamp backwards by one minute
238247
j Move timestamp forwards by one minute
239248
K Move timestamp backwards by five minutes

internal/persistence/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS task_log (
3333
begin_ts TIMESTAMP NOT NULL,
3434
end_ts TIMESTAMP,
3535
secs_spent INTEGER NOT NULL DEFAULT 0,
36-
comment VARCHAR(255),
36+
comment TEXT,
3737
active BOOLEAN NOT NULL,
3838
FOREIGN KEY(task_id) REFERENCES task(id)
3939
);

internal/persistence/queries.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ WHERE active=true;
6767
return err
6868
}
6969

70-
func UpdateActiveTL(db *sql.DB, taskLogID int, taskID int, beginTs, endTs time.Time, secsSpent int, comment *string) error {
70+
func FinishActiveTL(db *sql.DB, taskLogID int, taskID int, beginTs, endTs time.Time, secsSpent int, comment *string) error {
7171
return runInTx(db, func(tx *sql.Tx) error {
7272
stmt, err := tx.Prepare(`
7373
UPDATE task_log

internal/persistence/queries_test.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func TestRepository(t *testing.T) {
8888
require.Nil(t, activeTaskDetailsTwo.CurrentLogComment)
8989
})
9090

91-
t.Run("TestUpdateActiveTL", func(t *testing.T) {
91+
t.Run("TestFinishActiveTL", func(t *testing.T) {
9292
t.Cleanup(func() { cleanupDB(t, testDB) })
9393

9494
// GIVEN
@@ -108,7 +108,7 @@ func TestRepository(t *testing.T) {
108108

109109
// WHEN
110110
comment := "a task log"
111-
err = UpdateActiveTL(testDB, tlID, taskID, beginTS, endTS, numSeconds, &comment)
111+
err = FinishActiveTL(testDB, tlID, taskID, beginTS, endTS, numSeconds, &comment)
112112

113113
// THEN
114114
require.NoError(t, err, "failed to update task log")
@@ -125,6 +125,33 @@ func TestRepository(t *testing.T) {
125125
assert.Equal(t, numSecondsBefore+numSeconds, taskAfter.SecsSpent)
126126
})
127127

128+
t.Run("TestFinishActiveTL can save TL with empty comment", func(t *testing.T) {
129+
t.Cleanup(func() { cleanupDB(t, testDB) })
130+
131+
// GIVEN
132+
referenceTS := time.Now()
133+
seedData := getTestData(referenceTS)
134+
seedDB(t, testDB, seedData)
135+
taskID := 1
136+
numSeconds := 60 * 90
137+
endTS := time.Now()
138+
beginTS := endTS.Add(time.Second * -1 * time.Duration(numSeconds))
139+
tlID, insertErr := InsertNewTL(testDB, taskID, beginTS)
140+
require.NoError(t, insertErr, "failed to insert task log")
141+
142+
// WHEN
143+
err = FinishActiveTL(testDB, tlID, taskID, beginTS, endTS, numSeconds, nil)
144+
145+
// THEN
146+
require.NoError(t, err, "failed to update task log")
147+
148+
taskLog, err := fetchTLByID(testDB, tlID)
149+
require.NoError(t, err, "failed to fetch task log")
150+
151+
assert.Equal(t, numSeconds, taskLog.SecsSpent)
152+
require.Nil(t, taskLog.Comment)
153+
})
154+
128155
t.Run("TestInsertManualTL", func(t *testing.T) {
129156
t.Cleanup(func() { cleanupDB(t, testDB) })
130157

internal/types/date_helpers_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@ func TestParseDateDuration(t *testing.T) {
9393
}
9494

9595
func TestGetTimePeriod(t *testing.T) {
96-
now, err := time.ParseInLocation(string(timeFormat), "2024/06/20 20:00", time.Local)
96+
now, err := time.ParseInLocation(timeFormat, "2024/06/20 20:00", time.Local)
9797
if err != nil {
9898
t.Fatalf("error setting up the test: time is not valid: %s", err)
9999
}
100100

101-
nowME, err := time.ParseInLocation(string(timeFormat), "2024/05/31 20:00", time.Local)
101+
nowME, err := time.ParseInLocation(timeFormat, "2024/05/31 20:00", time.Local)
102102
if err != nil {
103103
t.Fatalf("error setting up the test: time is not valid: %s", err)
104104
}
105105

106-
nowMB, err := time.ParseInLocation(string(timeFormat), "2024/06/01 20:00", time.Local)
106+
nowMB, err := time.ParseInLocation(timeFormat, "2024/06/01 20:00", time.Local)
107107
if err != nil {
108108
t.Fatalf("error setting up the test: time is not valid: %s", err)
109109
}

internal/types/types.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/dustin/go-humanize"
1010
)
1111

12+
const emptyCommentIndicator = "∅"
13+
1214
type Task struct {
1315
ID int
1416
Summary string
@@ -17,8 +19,8 @@ type Task struct {
1719
TrackingActive bool
1820
SecsSpent int
1921
Active bool
20-
TaskTitle string
21-
TaskDesc string
22+
ListTitle string
23+
ListDesc string
2224
}
2325

2426
type TaskLogEntry struct {
@@ -29,8 +31,8 @@ type TaskLogEntry struct {
2931
EndTS time.Time
3032
SecsSpent int
3133
Comment *string
32-
TLTitle string
33-
TLDesc string
34+
ListTitle string
35+
ListDesc string
3436
}
3537

3638
type ActiveTaskDetails struct {
@@ -47,16 +49,16 @@ type TaskReportEntry struct {
4749
SecsSpent int
4850
}
4951

50-
func (t *Task) UpdateTitle() {
52+
func (t *Task) UpdateListTitle() {
5153
var trackingIndicator string
5254
if t.TrackingActive {
5355
trackingIndicator = "⏲ "
5456
}
5557

56-
t.TaskTitle = trackingIndicator + t.Summary
58+
t.ListTitle = trackingIndicator + t.Summary
5759
}
5860

59-
func (t *Task) UpdateDesc() {
61+
func (t *Task) UpdateListDesc() {
6062
var timeSpent string
6163

6264
if t.SecsSpent != 0 {
@@ -66,14 +68,14 @@ func (t *Task) UpdateDesc() {
6668
}
6769
lastUpdated := fmt.Sprintf("last updated: %s", humanize.Time(t.UpdatedAt))
6870

69-
t.TaskDesc = fmt.Sprintf("%s %s", utils.RightPadTrim(lastUpdated, 60, true), timeSpent)
71+
t.ListDesc = fmt.Sprintf("%s %s", utils.RightPadTrim(lastUpdated, 60, true), timeSpent)
7072
}
7173

72-
func (tl *TaskLogEntry) UpdateTitle() {
73-
tl.TLTitle = utils.Trim(tl.GetComment(), 60)
74+
func (tl *TaskLogEntry) UpdateListTitle() {
75+
tl.ListTitle = utils.TrimWithMoreLinesIndicator(tl.GetComment(), 60)
7476
}
7577

76-
func (tl *TaskLogEntry) UpdateDesc() {
78+
func (tl *TaskLogEntry) UpdateListDesc() {
7779
timeSpentStr := HumanizeDuration(tl.SecsSpent)
7880

7981
var timeStr string
@@ -96,35 +98,35 @@ func (tl *TaskLogEntry) UpdateDesc() {
9698
utils.RightPadTrim(durationMsg, 40, true),
9799
timeSpentStr)
98100

99-
tl.TLDesc = fmt.Sprintf("%s %s", utils.RightPadTrim("["+tl.TaskSummary+"]", 60, true), timeStr)
101+
tl.ListDesc = fmt.Sprintf("%s %s", utils.RightPadTrim(tl.TaskSummary, 60, true), timeStr)
100102
}
101103

102104
func (tl *TaskLogEntry) GetComment() string {
103105
if tl.Comment == nil {
104-
return "∅"
106+
return emptyCommentIndicator
105107
}
106108

107109
return *tl.Comment
108110
}
109111

110112
func (t Task) Title() string {
111-
return t.TaskTitle
113+
return t.ListTitle
112114
}
113115

114116
func (t Task) Description() string {
115-
return t.TaskDesc
117+
return t.ListDesc
116118
}
117119

118120
func (t Task) FilterValue() string {
119121
return t.Summary
120122
}
121123

122124
func (tl TaskLogEntry) Title() string {
123-
return tl.TLTitle
125+
return tl.ListTitle
124126
}
125127

126128
func (tl TaskLogEntry) Description() string {
127-
return tl.TLDesc
129+
return tl.ListDesc
128130
}
129131

130132
func (tl TaskLogEntry) FilterValue() string {

internal/ui/cmds.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ LIMIT 1
4949

5050
default:
5151
secsSpent := int(endTs.Sub(beginTs).Seconds())
52-
err := pers.UpdateActiveTL(db, activeTaskLogID, activeTaskID, beginTs, endTs, secsSpent, comment)
52+
err := pers.FinishActiveTL(db, activeTaskLogID, activeTaskID, beginTs, endTs, secsSpent, comment)
5353
if err != nil {
5454
return trackingToggledMsg{err: err}
5555
} else {

internal/ui/generate.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,24 @@ import (
99
pers "github.com/dhth/hours/internal/persistence"
1010
)
1111

12-
const nonEmptyCommentChance = 0.8
12+
const (
13+
nonEmptyCommentChance = 0.8
14+
longCommentChance = 0.3
15+
sampleLongCommentBody = `
16+
17+
This is a sample task log comment. The comment can be used to record
18+
additional information for a task log.
19+
20+
You can include:
21+
- Detailed steps taken during the task
22+
- Observations and notes
23+
- Any issues encountered and how they were resolved
24+
- Future actions or follow-ups required
25+
- References to related tasks or documents
26+
27+
Use this section to ensure all relevant details are captured for each task,
28+
providing a comprehensive log that can be referred to later.`
29+
)
1330

1431
var (
1532
tasks = []string{
@@ -108,8 +125,12 @@ func GenerateData(db *sql.DB, numDays, numTasks uint8) error {
108125
var comment *string
109126
commentStr := fmt.Sprintf("%s %s", verbs[rand.Intn(len(verbs))], nouns[rand.Intn(len(nouns))])
110127
if rand.Float64() < nonEmptyCommentChance {
128+
if rand.Float64() < longCommentChance {
129+
commentStr += sampleLongCommentBody
130+
}
111131
comment = &commentStr
112132
}
133+
113134
_, err = pers.InsertManualTL(db, int(i+1), beginTs, endTs, comment)
114135
if err != nil {
115136
return err

0 commit comments

Comments
 (0)