mirror of
https://github.com/RWejlgaard/org.git
synced 2026-09-02 01:15:35 +00:00
feat: add configurable done flag to TODO states
This commit is contained in:
parent
25dd231073
commit
5b10f4e229
2 changed files with 81 additions and 1 deletions
|
|
@ -83,6 +83,7 @@ type TagsConfig struct {
|
||||||
type StateConfig struct {
|
type StateConfig struct {
|
||||||
Name string `toml:"name"`
|
Name string `toml:"name"`
|
||||||
Color string `toml:"color"`
|
Color string `toml:"color"`
|
||||||
|
Done bool `toml:"done,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatesConfig holds TODO state configurations
|
// StatesConfig holds TODO state configurations
|
||||||
|
|
@ -163,7 +164,7 @@ func DefaultConfig() *Config {
|
||||||
{Name: "TODO", Color: "202"},
|
{Name: "TODO", Color: "202"},
|
||||||
{Name: "PROG", Color: "220"},
|
{Name: "PROG", Color: "220"},
|
||||||
{Name: "BLOCK", Color: "196"},
|
{Name: "BLOCK", Color: "196"},
|
||||||
{Name: "DONE", Color: "34"},
|
{Name: "DONE", Color: "34", Done: true},
|
||||||
},
|
},
|
||||||
DefaultNewTaskState: "TODO",
|
DefaultNewTaskState: "TODO",
|
||||||
},
|
},
|
||||||
|
|
@ -393,6 +394,21 @@ func (c *Config) fillDefaults() {
|
||||||
// Note: We don't fill DefaultNewTaskState if States.States is non-empty because
|
// Note: We don't fill DefaultNewTaskState if States.States is non-empty because
|
||||||
// an empty string is a valid intentional value meaning "no default state".
|
// an empty string is a valid intentional value meaning "no default state".
|
||||||
|
|
||||||
|
// Back-compat: if states exist but none is flagged done (config predates the
|
||||||
|
// `done` field), treat the last state as done to preserve prior behavior.
|
||||||
|
if len(c.States.States) > 0 {
|
||||||
|
anyDone := false
|
||||||
|
for _, s := range c.States.States {
|
||||||
|
if s.Done {
|
||||||
|
anyDone = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !anyDone {
|
||||||
|
c.States.States[len(c.States.States)-1].Done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fill UI if zero values
|
// Fill UI if zero values
|
||||||
if c.UI.HelpTextWidth == 0 {
|
if c.UI.HelpTextWidth == 0 {
|
||||||
c.UI.HelpTextWidth = defaults.UI.HelpTextWidth
|
c.UI.HelpTextWidth = defaults.UI.HelpTextWidth
|
||||||
|
|
@ -511,6 +527,19 @@ func (c *Config) GetStateNames() []string {
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsDoneState reports whether the named state is configured as a done state.
|
||||||
|
func (c *Config) IsDoneState(name string) bool {
|
||||||
|
if name == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, state := range c.States.States {
|
||||||
|
if state.Name == name {
|
||||||
|
return state.Done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateKeybinding updates a keybinding in the configuration
|
// UpdateKeybinding updates a keybinding in the configuration
|
||||||
func (c *Config) UpdateKeybinding(action string, keys []string) error {
|
func (c *Config) UpdateKeybinding(action string, keys []string) error {
|
||||||
// Use reflection would be complex, so we handle specific cases
|
// Use reflection would be complex, so we handle specific cases
|
||||||
|
|
|
||||||
51
internal/config/config_test.go
Normal file
51
internal/config/config_test.go
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestIsDoneState(t *testing.T) {
|
||||||
|
c := &Config{States: StatesConfig{States: []StateConfig{
|
||||||
|
{Name: "TODO", Color: "202"},
|
||||||
|
{Name: "DONE", Color: "34", Done: true},
|
||||||
|
{Name: "CANCELLED", Color: "240", Done: true},
|
||||||
|
}}}
|
||||||
|
|
||||||
|
cases := map[string]bool{"TODO": false, "DONE": true, "CANCELLED": true, "": false, "NOPE": false}
|
||||||
|
for name, want := range cases {
|
||||||
|
if got := c.IsDoneState(name); got != want {
|
||||||
|
t.Errorf("IsDoneState(%q) = %v, want %v", name, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFillDefaultsMarksLastStateDoneWhenNoneFlagged(t *testing.T) {
|
||||||
|
c := &Config{States: StatesConfig{States: []StateConfig{
|
||||||
|
{Name: "TODO", Color: "202"},
|
||||||
|
{Name: "DONE", Color: "34"},
|
||||||
|
}}}
|
||||||
|
c.fillDefaults()
|
||||||
|
|
||||||
|
if c.States.States[len(c.States.States)-1].Name != "DONE" {
|
||||||
|
t.Fatalf("states reordered unexpectedly")
|
||||||
|
}
|
||||||
|
if !c.States.States[len(c.States.States)-1].Done {
|
||||||
|
t.Error("expected last state (DONE) to be flagged Done after migration")
|
||||||
|
}
|
||||||
|
if c.States.States[0].Done {
|
||||||
|
t.Error("expected first state (TODO) to remain not-done")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFillDefaultsLeavesExplicitDoneFlagsAlone(t *testing.T) {
|
||||||
|
c := &Config{States: StatesConfig{States: []StateConfig{
|
||||||
|
{Name: "DONE", Color: "34", Done: true},
|
||||||
|
{Name: "TODO", Color: "202"},
|
||||||
|
}}}
|
||||||
|
c.fillDefaults()
|
||||||
|
|
||||||
|
if c.States.States[0].Name != "DONE" || !c.States.States[0].Done {
|
||||||
|
t.Error("explicit done flag on DONE should be preserved")
|
||||||
|
}
|
||||||
|
if c.States.States[1].Done {
|
||||||
|
t.Error("last state (TODO) must NOT be auto-flagged when a done state already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue