Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 45 additions & 18 deletions api/dto/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dto

import (
"fmt"
"strings"
"time"
)

Expand Down Expand Up @@ -103,19 +104,20 @@ type Rate struct {

// TimeEntry DTO
type TimeEntry struct {
ID string `json:"id"`
Billable bool `json:"billable"`
Description string `json:"description"`
HourlyRate Rate `json:"hourlyRate"`
IsLocked bool `json:"isLocked"`
Project *Project `json:"project"`
ProjectID string `json:"projectId"`
Tags []Tag `json:"tags"`
Task *Task `json:"task"`
TimeInterval TimeInterval `json:"timeInterval"`
TotalBillable int64 `json:"totalBillable"`
User *User `json:"user"`
WorkspaceID string `json:"workspaceId"`
ID string `json:"id"`
Billable bool `json:"billable"`
Description string `json:"description"`
HourlyRate Rate `json:"hourlyRate"`
IsLocked bool `json:"isLocked"`
Project *Project `json:"project"`
CustomFields []CustomField `json:"customFieldValues"`
ProjectID string `json:"projectId"`
Tags []Tag `json:"tags"`
Task *Task `json:"task"`
TimeInterval TimeInterval `json:"timeInterval"`
TotalBillable int64 `json:"totalBillable"`
User *User `json:"user"`
WorkspaceID string `json:"workspaceId"`
}

// NewTimeInterval will create a TimeInterval from start and end times
Expand Down Expand Up @@ -199,11 +201,36 @@ func (e Client) GetName() string { return e.Name }

// CustomField DTO
type CustomField struct {
CustomFieldID string `json:"customFieldId"`
Status string `json:"status"`
Name string `json:"name"`
Type string `json:"type"`
Value string `json:"value"`
CustomFieldID string `json:"customFieldId"`
TimeEntryId string `json:"timeEntryId"`
Name string `json:"name"`
Type string `json:"type"`
Value interface{} `json:"value"`
}

// ValueAsString converter for CustomFieldDTO
/*
Custom field `Value` can be either a string or an array of strings.
This function is used to get the value always as string, using the `|` symbol
as separator between each individual string.
*/
func (cf CustomField) ValueAsString() string {
switch v := cf.Value.(type) {
case string:
return v
case []interface{}:
parts := make([]string, len(v))
for i, item := range v {
parts[i] = fmt.Sprint(item)
}
return strings.Join(parts, "|")
case []string:
return strings.Join(v, "|")
case nil:
return ""
default:
return fmt.Sprint(v)
}
}

// Project DTO
Expand Down
3 changes: 3 additions & 0 deletions pkg/cmd/config/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ func NewCmdInit(f cmdutil.Factory) *cobra.Command {
updateFlag(i, config, cmdutil.CONF_SHOW_TASKS,
`Should show task on time entries as a separated column?`,
),
updateFlag(i, config, cmdutil.CONF_SHOW_CUSTOM_FIELDS,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi, i think you will need to add tests to this:

c.ExpectString("show task on time entries")
c.SendLine("")
c.ExpectString("Yes")

you can run make test to see where it fails

`Should show custom fields on time entries as a separated column?`,
),
updateFlag(i, config, cmdutil.CONF_SHOW_CLIENT,
`Should show client on time entries as a separated column?`,
),
Expand Down
5 changes: 5 additions & 0 deletions pkg/cmd/config/init/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func TestInitCmd(t *testing.T) {

setBoolFn(config, cmdutil.CONF_ALLOW_INCOMPLETE, false, false)
setBoolFn(config, cmdutil.CONF_SHOW_TASKS, true, true)
setBoolFn(config, cmdutil.CONF_SHOW_CUSTOM_FIELDS, true, true)
setBoolFn(config, cmdutil.CONF_SHOW_CLIENT, true, true)
setBoolFn(config, cmdutil.CONF_SHOW_TOTAL_DURATION, true, true)
setBoolFn(config, cmdutil.CONF_DESCR_AUTOCOMP, false, true)
Expand Down Expand Up @@ -191,6 +192,10 @@ func TestInitCmd(t *testing.T) {
c.SendLine("")
c.ExpectString("Yes")

c.ExpectString("show custom fields")
c.SendLine("")
c.ExpectString("Yes")

c.ExpectString("show client on time entries")
c.SendLine("")
c.ExpectString("Yes")
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/config/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func NewCmdList(f cmdutil.Factory) *cobra.Command {
interactive: true
no-closing: false
show-task: false
show-custom-fields: false
show-total-duration: true
token: Yamdas569
user:
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/config/set/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func NewCmdSet(
$ %[1]s token "Yamdas569"
$ %[1]s workweek-days monday,tuesday,wednesday,thursday,friday
$ %[1]s show-task true
$ %[1]s show-custom-fields true
$ %[1]s user.id 4564d5a6s4d54a5s4dasd5
`, "clockify-cli config set"),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down
6 changes: 3 additions & 3 deletions pkg/cmd/time-entry/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ func NewCmdReport(f cmdutil.Factory) *cobra.Command {

# csv format output
$ %[1]s --csv
id,description,project.id,project.name,task.id,task.name,start,end,duration,user.id,user.email,user.name,tags...
62b87a9785815e619d7ce02e,Example for today,621948458cb9606d934ebb1c,Clockify Cli,62b87a7e984dba2c0669724d,Report Command,2022-06-26 12:25:56,2022-06-26 12:26:47,0:00:51,5c6bf21db079873a55facc08,[email protected],John Due,Development (62ae28b72518aa18da2acb49)
62b87abb85815e619d7ce034,Example for today (second one),621948458cb9606d934ebb1c,Clockify Cli,62b87a7e984dba2c0669724d,Report Command,2022-06-26 12:26:47,2022-06-26 13:00:00,0:33:13,5c6bf21db079873a55facc08,[email protected],John Due,Development (62ae28b72518aa18da2acb49)
id,description,project.id,project.name,task.id,task.name,start,end,duration,user.id,user.email,user.name,tags...,customFields...
62b87a9785815e619d7ce02e,Example for today,621948458cb9606d934ebb1c,Clockify Cli,62b87a7e984dba2c0669724d,Report Command,2022-06-26 12:25:56,2022-06-26 12:26:47,0:00:51,5c6bf21db079873a55facc08,[email protected],John Due,Development (62ae28b72518aa18da2acb49),Example custom field(5e1147fe8c526f38930d57b8)=value
62b87abb85815e619d7ce034,Example for today (second one),621948458cb9606d934ebb1c,Clockify Cli,62b87a7e984dba2c0669724d,Report Command,2022-06-26 12:26:47,2022-06-26 13:00:00,0:33:13,5c6bf21db079873a55facc08,[email protected],John Due,Development (62ae28b72518aa18da2acb49), Example custom field(5e1147fe8c526f38930d57b8)=value
`, "clockify-cli report", "`",
timehlp.FullTimeFormat,
timehlp.OnlyTimeFormat,
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/time-entry/util/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ func PrintTimeEntries(
opts = opts.WithShowTasks()
}

if config.GetBool(cmdutil.CONF_SHOW_CUSTOM_FIELDS) {
opts = opts.WithShowCustomFields()
}

if config.GetBool(cmdutil.CONF_SHOW_CLIENT) {
opts = opts.WithShowClients()
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cmdutil/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
CONF_TOKEN = "token"
CONF_ALLOW_INCOMPLETE = "allow-incomplete"
CONF_SHOW_TASKS = "show-task"
CONF_SHOW_CUSTOM_FIELDS = "show-custom-fields"
CONF_SHOW_CLIENT = "show-client"
CONF_DESCR_AUTOCOMP = "description-autocomplete"
CONF_DESCR_AUTOCOMP_DAYS = "description-autocomplete-days"
Expand Down
8 changes: 6 additions & 2 deletions pkg/output/time-entry/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package timeentry
import (
"encoding/csv"
"io"
"strings"
"time"

"github.com/lucassabreu/clockify-cli/api/dto"
Expand All @@ -26,6 +27,7 @@ func TimeEntriesCSVPrint(timeEntries []dto.TimeEntry, out io.Writer) error {
"user.email",
"user.name",
"tags...",
"customFields...",
}); err != nil {
return err
}
Expand Down Expand Up @@ -74,8 +76,10 @@ func TimeEntriesCSVPrint(timeEntries []dto.TimeEntry, out io.Writer) error {
te.User.Name,
}

if err := w.Write(append(
arr, tagsToStringSlice(te.Tags)...)); err != nil {
arr = append(arr, strings.Join(tagsToStringSlice(te.Tags), ";"))
arr = append(arr, strings.Join(customFieldsToStringSlice(te.CustomFields), ";"))

if err := w.Write(arr); err != nil {
return err
}
}
Expand Down
29 changes: 29 additions & 0 deletions pkg/output/time-entry/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
// entries
type TimeEntryOutputOptions struct {
ShowTasks bool
ShowCustomFields bool
ShowClients bool
ShowTotalDuration bool
TimeFormat string
Expand All @@ -46,6 +47,7 @@ func NewTimeEntryOutputOptions() TimeEntryOutputOptions {
return TimeEntryOutputOptions{
TimeFormat: TimeFormatSimple,
ShowTasks: false,
ShowCustomFields: false,
ShowClients: false,
ShowTotalDuration: false,
}
Expand All @@ -65,6 +67,12 @@ func (teo TimeEntryOutputOptions) WithShowTasks() TimeEntryOutputOptions {
return teo
}

// WithShowCustomFields shows a new column with the custom fields of the time entry
func (teo TimeEntryOutputOptions) WithShowCustomFields() TimeEntryOutputOptions {
teo.ShowCustomFields = true
return teo
}

// WithShowCliens shows a new column with the client of the time entry
func (teo TimeEntryOutputOptions) WithShowClients() TimeEntryOutputOptions {
teo.ShowClients = true
Expand Down Expand Up @@ -96,6 +104,10 @@ func TimeEntriesPrint(

header = append(header, "Description", "Tags")

if options.ShowCustomFields {
header = append(header, "Custom Fields")
}

tw.SetHeader(header)
tw.SetRowLine(true)
if width, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil {
Expand Down Expand Up @@ -152,6 +164,13 @@ func TimeEntriesPrint(
strings.Join(tagsToStringSlice(t.Tags), "\n"),
)

if options.ShowCustomFields {
line = append(
line,
strings.Join(customFieldsToStringSlice(t.CustomFields), "\n"),
)
}

tw.Rich(line, colors)
}

Expand Down Expand Up @@ -181,3 +200,13 @@ func tagsToStringSlice(tags []dto.Tag) []string {
func durationToString(d time.Duration) string {
return dto.Duration{Duration: d}.HumanString()
}

func customFieldsToStringSlice(customFields []dto.CustomField) []string {
s := make([]string, len(customFields))

for i, cf := range customFields {
s[i] = fmt.Sprintf("%s(%s)=%s", cf.Name, cf.CustomFieldID, cf.ValueAsString())
}

return s
}
30 changes: 23 additions & 7 deletions pkg/output/time-entry/markdown.gotmpl.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,20 @@
{{- $tags = "No Tags" -}}
{{- end -}}

{{- $pad := maxLength .Description $project $tags $bil -}}
{{- $customFields := "" -}}
{{- $hasCustomFields := false -}}
{{- with .CustomFields -}}
{{- range $index, $element := . -}}
{{- $value := $element.ValueAsString -}}
{{- if ne $value "" -}}
{{- if ne $index 0 }}{{ $customFields = concat $customFields ", " }}{{ end -}}
{{- $customFields = concat $customFields $element.Name ": " $value -}}
{{- $hasCustomFields = true -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{- $pad := maxLength .Description $project $tags $customFields $bil -}}

## _Time Entry_: {{ .ID }}

Expand All @@ -35,9 +48,12 @@ Start Time: _{{ formatTimeWS .TimeInterval.Start }}_ 🗓 Today
{{- .TimeInterval.Start.Format " 01/02/2006" }}
{{- end }}

| | {{ pad "" $pad }} |
|---------------|-{{ repeatString "-" $pad }}-|
| _Description_ | {{ pad .Description $pad }} |
| _Project_ | {{ pad $project $pad }} |
| _Tags_ | {{ pad $tags $pad }} |
| _Billable_ | {{ pad $bil $pad }} |
| | {{ pad "" $pad }} |
|-----------------|-{{ repeatString "-" $pad }}-|
| _Description_ | {{ pad .Description $pad }} |
| _Project_ | {{ pad $project $pad }} |
| _Tags_ | {{ pad $tags $pad }} |
| _Billable_ | {{ pad $bil $pad }} |
{{- if $hasCustomFields }}
| _Custom Fields_ | {{ pad $customFields $pad }} |
{{- end }}
Loading
Loading