Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add flag to set the timezone on reports #253

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- new config `lang` to allow setting the number format to be used when printing
- support to using client's name or id for autocompletion on bash
- new config `timezone` to allow setting which timezone to use when reporting the time of a time entry

## [v0.52.0] - 2024-06-02

Expand Down
7 changes: 7 additions & 0 deletions cmd/clockify-cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ func bindViper(rootCmd *cobra.Command) error {
}
}

if flag := cmd.Flags().Lookup("tz"); flag != nil {
if err := bind(flag, cmdutil.CONF_TIMEZONE,
"TIMEZONE"); err != nil {
return err
}
}

return nil
}

Expand Down
82 changes: 82 additions & 0 deletions internal/mocks/mock_Config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 29 additions & 12 deletions internal/mocks/simple_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mocks

import (
"time"

"github.com/lucassabreu/clockify-cli/pkg/cmdutil"
"golang.org/x/text/language"
)
Expand All @@ -24,18 +26,7 @@ type SimpleConfig struct {
AllowArchivedTags bool
SearchProjectWithClientsName bool
LanguageTag language.Tag
}

// IsSearchProjectWithClientsName defines if the project name for ID should
// include the client's name
func (s *SimpleConfig) IsSearchProjectWithClientsName() bool {
return s.SearchProjectWithClientsName
}

// InteractivePageSize sets how many items are shown when prompting
// projects
func (s *SimpleConfig) InteractivePageSize() int {
return s.InteractivePageSizeNumber
TimeZoneLoc *time.Location
}

func (d *SimpleConfig) GetBool(n string) bool {
Expand Down Expand Up @@ -147,6 +138,32 @@ func (d *SimpleConfig) LogLevel() string {
return d.LogLevelValue
}

// TimeZone which time zone to use for showing date & time
func (s *SimpleConfig) TimeZone() *time.Location {
if s.TimeZoneLoc == nil {
s.TimeZoneLoc = time.UTC
}

return s.TimeZoneLoc
}

// SetTimeZone changes the timezone used for dates
func (s *SimpleConfig) SetTimeZone(loc *time.Location) {
s.TimeZoneLoc = loc
}

// IsSearchProjectWithClientsName defines if the project name for ID should
// include the client's name
func (s *SimpleConfig) IsSearchProjectWithClientsName() bool {
return s.SearchProjectWithClientsName
}

// InteractivePageSize sets how many items are shown when prompting
// projects
func (s *SimpleConfig) InteractivePageSize() int {
return s.InteractivePageSizeNumber
}

func (*SimpleConfig) Save() error {
panic("should not call")
}
3 changes: 3 additions & 0 deletions pkg/cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ var validParameters = cmdcompl.ValidArgsMap{
cmdutil.CONF_LOG_LEVEL: "how much logs should be shown values: " +
"none , error , info and debug",
cmdutil.CONF_ALLOW_ARCHIVED_TAGS: "should allow and suggest archived tags",
cmdutil.CONF_LANGUAGE: "which language to use for number " +
"formatting",
cmdutil.CONF_TIMEZONE: "which timezone to use to input/output time",
}

// NewCmdConfig represents the config command
Expand Down
82 changes: 55 additions & 27 deletions pkg/cmd/config/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package init
import (
"fmt"
"strings"
"time"

"github.com/lucassabreu/clockify-cli/api"
"github.com/lucassabreu/clockify-cli/pkg/cmdutil"
Expand Down Expand Up @@ -110,7 +111,8 @@ func NewCmdInit(f cmdutil.Factory) *cobra.Command {
"Should suggest and allow creating time entries "+
"with archived tags?",
),
func() error { return setLanguage(i, config) },
setLanguage(i, config),
setTimezone(i, config),
); err != nil {
return err
}
Expand All @@ -122,36 +124,62 @@ func NewCmdInit(f cmdutil.Factory) *cobra.Command {
return cmd
}

func setLanguage(i ui.UI, config cmdutil.Config) error {
suggestLanguages := []string{
language.English.String(),
language.German.String(),
language.Afrikaans.String(),
language.Chinese.String(),
language.Portuguese.String(),
func setTimezone(i ui.UI, config cmdutil.Config) func() error {
return func() error {
tzname, err := i.AskForValidText("What is your preferred timezone:",
func(s string) error {
_, err := time.LoadLocation(s)
return err
},
ui.WithHelp("Should be 'Local' to use the systems timezone, UTC "+
"or valid TZ identifier from the IANA TZ database "+
"https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"),
ui.WithDefault(config.TimeZone().String()),
)
if err != nil {
return err
}

tz, _ := time.LoadLocation(tzname)

config.SetTimeZone(tz)

return nil
}
}

lang, err := i.AskForValidText("What is your preferred language:",
func(s string) error {
_, err := language.Parse(s)
func setLanguage(i ui.UI, config cmdutil.Config) func() error {
return func() error {
suggestLanguages := []string{
language.English.String(),
language.German.String(),
language.Afrikaans.String(),
language.Chinese.String(),
language.Portuguese.String(),
}

lang, err := i.AskForValidText("What is your preferred language:",
func(s string) error {
_, err := language.Parse(s)
return err
},
ui.WithHelp("Accepts any IETF language tag "+
"https://en.wikipedia.org/wiki/IETF_language_tag"),
ui.WithSuggestion(func(toComplete string) []string {
return strhlp.Filter(
strhlp.IsSimilar(toComplete),
suggestLanguages,
)
}),
ui.WithDefault(config.Language().String()),
)
if err != nil {
return err
},
ui.WithHelp("Accepts any IETF language tag "+
"https://en.wikipedia.org/wiki/IETF_language_tag"),
ui.WithSuggestion(func(toComplete string) []string {
return strhlp.Filter(
strhlp.IsSimilar(toComplete),
suggestLanguages,
)
}),
ui.WithDefault(config.Language().String()),
)
if err != nil {
return err
}
}

config.SetLanguage(language.MustParse(lang))
return nil
config.SetLanguage(language.MustParse(lang))
return nil
}
}

func setWeekdays(config cmdutil.Config, i ui.UI) (err error) {
Expand Down
10 changes: 10 additions & 0 deletions pkg/cmd/config/init/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ func TestInitCmd(t *testing.T) {
config.EXPECT().Language().Return(language.English)
config.EXPECT().SetLanguage(language.German)

config.EXPECT().TimeZone().Return(time.Local)
config.EXPECT().SetTimeZone(mock.Anything).
Run(func(tz *time.Location) {
assert.Equal(t, tz.String(), "America/Bahia")
})

config.EXPECT().Save().Once().Return(nil)

f.EXPECT().UI().Return(ui.NewUI(in, out, out))
Expand Down Expand Up @@ -209,6 +215,10 @@ func TestInitCmd(t *testing.T) {
c.Send(string(terminal.KeyTab))
c.SendLine(string(terminal.KeyTab))

c.ExpectString("preferred timezone:")
c.SendLine("America/Bahia")
c.ExpectString("America/Bahia")

c.ExpectEOF()
})
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/cmd/config/set/set.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package set

import (
"fmt"
"strings"
"time"

"github.com/MakeNowJust/heredoc"
"github.com/lucassabreu/clockify-cli/pkg/cmdcompl"
"github.com/lucassabreu/clockify-cli/pkg/cmdutil"
"github.com/lucassabreu/clockify-cli/strhlp"
"github.com/spf13/cobra"
"golang.org/x/text/language"
)

// NewCmdSet will update the value of one parameter
Expand Down Expand Up @@ -44,6 +47,22 @@ func NewCmdSet(
ws,
)
config.SetStringSlice(param, ws)
case cmdutil.CONF_LANGUAGE:
lang, err := language.Parse(value)
if err != nil {
return fmt.Errorf(
"%s is not a valid language: %w", value, err)
}

config.SetLanguage(lang)
case cmdutil.CONF_TIMEZONE:
tz, err := time.LoadLocation(value)
if err != nil {
return fmt.Errorf(
"%s is not a valid timezone: %w", value, err)
}

config.SetTimeZone(tz)
default:
config.SetString(param, value)
}
Expand Down
Loading
Loading