Skip to content

Commit 5651148

Browse files
authored
feat: config show-client (#266)
1 parent 2db3d8a commit 5651148

File tree

8 files changed

+96
-51
lines changed

8 files changed

+96
-51
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
## [Unreleased]
1313

14+
### Added
15+
- new config `show-client` that sets the reports/output of time entries to show its client, if exists
16+
1417
## [v0.50.1] - 2024-05-25
1518

1619
### Fixed

pkg/cmd/config/config.go

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ var validParameters = cmdcompl.ValidArgsMap{
2525
"missing required values",
2626
cmdutil.CONF_SHOW_TASKS: "should show an extra column with the task " +
2727
"description",
28+
cmdutil.CONF_SHOW_CLIENT: "should show an extra column with the client " +
29+
"description",
2830
cmdutil.CONF_DESCR_AUTOCOMP: "autocomplete description looking at " +
2931
"recent time entries",
3032
cmdutil.CONF_DESCR_AUTOCOMP_DAYS: "how many days should be considered " +

pkg/cmd/config/init/init.go

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ func NewCmdInit(f cmdutil.Factory) *cobra.Command {
140140
return err
141141
}
142142

143+
if err := updateFlag(i, config, cmdutil.CONF_SHOW_CLIENT,
144+
`Should show client on time entries as a separated column?`,
145+
); err != nil {
146+
return err
147+
}
148+
143149
if err := updateFlag(i, config, cmdutil.CONF_SHOW_TOTAL_DURATION,
144150
`Should show a line with the sum of `+
145151
`the time entries duration?`,

pkg/cmd/config/init/init_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func TestInitCmd(t *testing.T) {
9898

9999
setBoolFn(config, cmdutil.CONF_ALLOW_INCOMPLETE, false, false)
100100
setBoolFn(config, cmdutil.CONF_SHOW_TASKS, true, true)
101+
setBoolFn(config, cmdutil.CONF_SHOW_CLIENT, true, true)
101102
setBoolFn(config, cmdutil.CONF_SHOW_TOTAL_DURATION, true, true)
102103
setBoolFn(config, cmdutil.CONF_DESCR_AUTOCOMP, false, true)
103104

@@ -180,6 +181,10 @@ func TestInitCmd(t *testing.T) {
180181
c.SendLine("")
181182
c.ExpectString("Yes")
182183

184+
c.ExpectString("show client on time entries")
185+
c.SendLine("")
186+
c.ExpectString("Yes")
187+
183188
c.ExpectString("sum of the time entries duration?")
184189
c.SendLine("yes")
185190
c.ExpectString("Yes")

pkg/cmd/config/set/set_test.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"bytes"
55
"testing"
66

7+
"github.com/lucassabreu/clockify-cli/internal/mocks"
78
"github.com/lucassabreu/clockify-cli/pkg/cmd/config/set"
89
"github.com/lucassabreu/clockify-cli/pkg/cmdcompl"
910
"github.com/lucassabreu/clockify-cli/pkg/cmdutil"
10-
"github.com/lucassabreu/clockify-cli/internal/mocks"
1111
"github.com/stretchr/testify/assert"
1212
)
1313

@@ -77,6 +77,18 @@ func TestSetCmdRun(t *testing.T) {
7777
return c
7878
},
7979
},
80+
tc{
81+
name: "set show client",
82+
args: []string{cmdutil.CONF_SHOW_CLIENT, "true"},
83+
config: func(t *testing.T) cmdutil.Config {
84+
c := mocks.NewMockConfig(t)
85+
c.On("SetString", cmdutil.CONF_SHOW_CLIENT,
86+
"true").
87+
Return(nil).Once()
88+
c.On("Save").Once().Return(nil)
89+
return c
90+
},
91+
},
8092
}
8193

8294
for _, tc := range ts {

pkg/cmd/time-entry/util/report.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,21 @@ func PrintTimeEntries(
119119
case of.DurationFormatted:
120120
return output.TimeEntriesTotalDurationOnlyFormatted(tes, out)
121121
default:
122-
opts := []output.TimeEntryOutputOpt{
123-
output.WithTimeFormat(of.TimeFormat)}
122+
opts := output.NewTimeEntryOutputOptions().
123+
WithTimeFormat(of.TimeFormat)
124124

125125
if config.GetBool(cmdutil.CONF_SHOW_TASKS) {
126-
opts = append(opts, output.WithShowTasks())
126+
opts = opts.WithShowTasks()
127+
}
128+
129+
if config.GetBool(cmdutil.CONF_SHOW_CLIENT) {
130+
opts = opts.WithShowClients()
127131
}
128132

129133
if config.GetBool(cmdutil.CONF_SHOW_TOTAL_DURATION) {
130-
opts = append(opts, output.WithTotalDuration())
134+
opts = opts.WithTotalDuration()
131135
}
132136

133-
return output.TimeEntriesPrint(opts...)(tes, out)
137+
return output.TimeEntriesPrint(opts)(tes, out)
134138
}
135139
}

pkg/cmdutil/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
CONF_TOKEN = "token"
2121
CONF_ALLOW_INCOMPLETE = "allow-incomplete"
2222
CONF_SHOW_TASKS = "show-task"
23+
CONF_SHOW_CLIENT = "show-client"
2324
CONF_DESCR_AUTOCOMP = "description-autocomplete"
2425
CONF_DESCR_AUTOCOMP_DAYS = "description-autocomplete-days"
2526
CONF_SHOW_TOTAL_DURATION = "show-total-duration"

pkg/output/time-entry/default.go

+57-45
Original file line numberDiff line numberDiff line change
@@ -36,67 +36,66 @@ const (
3636
// entries
3737
type TimeEntryOutputOptions struct {
3838
ShowTasks bool
39+
ShowClients bool
3940
ShowTotalDuration bool
4041
TimeFormat string
4142
}
4243

43-
// WithTimeFormat sets the date-time output format
44-
func WithTimeFormat(format string) TimeEntryOutputOpt {
45-
return func(teo *TimeEntryOutputOptions) error {
46-
teo.TimeFormat = format
47-
return nil
44+
// NewTimeEntryOutputOptions creates a default TimeEntryOutputOptions
45+
func NewTimeEntryOutputOptions() TimeEntryOutputOptions {
46+
return TimeEntryOutputOptions{
47+
TimeFormat: TimeFormatSimple,
48+
ShowTasks: false,
49+
ShowClients: false,
50+
ShowTotalDuration: false,
4851
}
4952
}
5053

54+
// WithTimeFormat sets the date-time output format
55+
func (teo TimeEntryOutputOptions) WithTimeFormat(
56+
format string) TimeEntryOutputOptions {
57+
teo.TimeFormat = format
58+
return teo
59+
60+
}
61+
5162
// WithShowTasks shows a new column with the task of the time entry
52-
func WithShowTasks() TimeEntryOutputOpt {
53-
return func(teoo *TimeEntryOutputOptions) error {
54-
teoo.ShowTasks = true
55-
return nil
56-
}
63+
func (teo TimeEntryOutputOptions) WithShowTasks() TimeEntryOutputOptions {
64+
teo.ShowTasks = true
65+
return teo
66+
}
67+
68+
// WithShowCliens shows a new column with the client of the time entry
69+
func (teo TimeEntryOutputOptions) WithShowClients() TimeEntryOutputOptions {
70+
teo.ShowClients = true
71+
return teo
5772
}
5873

5974
// WithTotalDuration shows a footer with the sum of the durations of the time
6075
// entries
61-
func WithTotalDuration() TimeEntryOutputOpt {
62-
return func(teoo *TimeEntryOutputOptions) error {
63-
teoo.ShowTotalDuration = true
64-
return nil
65-
}
76+
func (teo TimeEntryOutputOptions) WithTotalDuration() TimeEntryOutputOptions {
77+
teo.ShowTotalDuration = true
78+
return teo
6679
}
6780

68-
// TimeEntryOutputOpt allows the setting of TimeEntryOutputOptions values
69-
type TimeEntryOutputOpt func(*TimeEntryOutputOptions) error
70-
7181
// TimeEntriesPrint will print more details
72-
func TimeEntriesPrint(opts ...TimeEntryOutputOpt) func([]dto.TimeEntry, io.Writer) error {
73-
options := &TimeEntryOutputOptions{
74-
TimeFormat: TimeFormatSimple,
75-
ShowTasks: false,
76-
ShowTotalDuration: false,
77-
}
78-
79-
for _, o := range opts {
80-
err := o(options)
81-
if err != nil {
82-
return func(te []dto.TimeEntry, w io.Writer) error { return err }
83-
}
84-
}
85-
82+
func TimeEntriesPrint(
83+
options TimeEntryOutputOptions) func([]dto.TimeEntry, io.Writer) error {
8684
return func(timeEntries []dto.TimeEntry, w io.Writer) error {
8785
tw := tablewriter.NewWriter(w)
88-
taskColumn := 6
8986
projectColumn := 4
90-
header := []string{"ID", "Start", "End", "Dur",
91-
"Project", "Description", "Tags"}
87+
header := []string{"ID", "Start", "End", "Dur", "Project"}
88+
9289
if options.ShowTasks {
93-
header = append(
94-
header[:taskColumn],
95-
header[taskColumn-1:]...,
96-
)
97-
header[taskColumn] = "Task"
90+
header = append(header, "Client")
9891
}
9992

93+
if options.ShowTasks {
94+
header = append(header, "Task")
95+
}
96+
97+
header = append(header, "Description", "Tags")
98+
10099
tw.SetHeader(header)
101100
tw.SetRowLine(true)
102101
if width, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil {
@@ -124,18 +123,31 @@ func TimeEntriesPrint(opts ...TimeEntryOutputOpt) func([]dto.TimeEntry, io.Write
124123
end.In(time.Local).Format(options.TimeFormat),
125124
durationToString(end.Sub(t.TimeInterval.Start)),
126125
projectName,
127-
t.Description,
128-
strings.Join(tagsToStringSlice(t.Tags), "\n"),
126+
}
127+
128+
if options.ShowClients {
129+
client := ""
130+
if t.Project.ClientName != "" {
131+
colors[len(line)] = colors[projectColumn]
132+
client = t.Project.ClientName
133+
}
134+
line = append(line, client)
129135
}
130136

131137
if options.ShowTasks {
132-
line = append(line[:taskColumn], line[taskColumn-1:]...)
133-
line[taskColumn] = ""
138+
task := ""
134139
if t.Task != nil {
135-
line[taskColumn] = fmt.Sprintf("%s (%s)", t.Task.Name, t.Task.ID)
140+
task = fmt.Sprintf("%s (%s)", t.Task.Name, t.Task.ID)
136141
}
142+
line = append(line, task)
137143
}
138144

145+
line = append(
146+
line,
147+
t.Description,
148+
strings.Join(tagsToStringSlice(t.Tags), "\n"),
149+
)
150+
139151
tw.Rich(line, colors)
140152
}
141153

0 commit comments

Comments
 (0)