Allow editing time entry start and end in TUI and web.
Duration is derived from the range so timer sessions can be corrected after the fact. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+43
-21
@@ -88,6 +88,7 @@ type Model struct {
|
||||
timeEntries views.TimeEntriesView
|
||||
timeEntriesTicket string // ticket ID for ModeTimeEntries
|
||||
editingTimeEntry ticket.TimeEntry
|
||||
timeEdit views.TimeEditForm
|
||||
activeTimer *ticket.ActiveTimer
|
||||
spentByID map[string]time.Duration
|
||||
width int
|
||||
@@ -207,8 +208,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch m.mode {
|
||||
case ModeCreate, ModeSearch, ModeTimeManual, ModeTimeEdit:
|
||||
case ModeCreate, ModeSearch, ModeTimeManual:
|
||||
return m.updateInput(msg)
|
||||
case ModeTimeEdit:
|
||||
return m.updateTimeEdit(msg)
|
||||
case ModeEditProject:
|
||||
return m.updateEditProject(msg)
|
||||
case ModeProjects:
|
||||
@@ -238,8 +241,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch m.mode {
|
||||
case ModeProjects, ModeMoveTicket:
|
||||
m.projectList, cmd = m.projectList.Update(msg)
|
||||
case ModeCreate, ModeSearch, ModeTimeManual, ModeTimeEdit:
|
||||
case ModeCreate, ModeSearch, ModeTimeManual:
|
||||
m.input, cmd = m.input.Update(msg)
|
||||
case ModeTimeEdit:
|
||||
cmd = m.timeEdit.Update(msg)
|
||||
case ModeEditProject:
|
||||
cmd = m.projectEdit.Update(msg)
|
||||
}
|
||||
@@ -585,8 +590,6 @@ func (m Model) updateInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
switch {
|
||||
case wasProject:
|
||||
m.mode = ModeProjects
|
||||
case m.mode == ModeTimeEdit:
|
||||
m.mode = ModeTimeEntries
|
||||
default:
|
||||
m.mode = ModeList
|
||||
}
|
||||
@@ -608,16 +611,6 @@ func (m Model) updateInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
|
||||
case key.Matches(msg, m.keys.Enter):
|
||||
value := strings.TrimSpace(m.input.Value())
|
||||
if m.mode == ModeTimeEdit {
|
||||
if err := m.saveEditedTime(value); err != nil {
|
||||
m.setError(err)
|
||||
return m, nil
|
||||
}
|
||||
m.input.Blur()
|
||||
m.mode = ModeTimeEntries
|
||||
m.setStatus("time updated")
|
||||
return m, nil
|
||||
}
|
||||
if m.mode == ModeTimeManual {
|
||||
if err := m.addManualTime(value); err != nil {
|
||||
m.setError(err)
|
||||
@@ -708,10 +701,8 @@ func (m Model) updateTimeEntries(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
m.editingTimeEntry = e
|
||||
m.timeEdit = views.NewTimeEditForm(e, m.width)
|
||||
m.mode = ModeTimeEdit
|
||||
m.input = views.NewTimeManualInput()
|
||||
m.input.SetValue(ticket.FormatDurationHuman(e.Duration))
|
||||
m.input.Focus()
|
||||
return m, textinput.Blink
|
||||
|
||||
case key.Matches(msg, m.keys.Undo):
|
||||
@@ -1717,18 +1708,49 @@ func (m *Model) deleteRemoteWorkItem(e ticket.TimeEntry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Model) saveEditedTime(raw string) error {
|
||||
func (m Model) updateTimeEdit(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.Escape):
|
||||
m.mode = ModeTimeEntries
|
||||
m.clearStatus()
|
||||
return m, nil
|
||||
|
||||
case key.Matches(msg, m.keys.Tab), msg.Type == tea.KeyDown:
|
||||
m.timeEdit.NextField()
|
||||
return m, textinput.Blink
|
||||
|
||||
case key.Matches(msg, m.keys.ShiftTab), msg.Type == tea.KeyUp:
|
||||
m.timeEdit.PrevField()
|
||||
return m, textinput.Blink
|
||||
|
||||
case key.Matches(msg, m.keys.Enter):
|
||||
m.clearStatus()
|
||||
if err := m.saveEditedTime(); err != nil {
|
||||
m.setError(err)
|
||||
return m, nil
|
||||
}
|
||||
m.mode = ModeTimeEntries
|
||||
m.setStatus("time updated")
|
||||
return m, nil
|
||||
}
|
||||
|
||||
cmd := m.timeEdit.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m *Model) saveEditedTime() error {
|
||||
if m.timeStore == nil {
|
||||
return fmt.Errorf("time store not configured")
|
||||
}
|
||||
dur, err := ticket.ParseDurationFlexible(raw)
|
||||
start, end, err := m.timeEdit.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
before := m.editingTimeEntry
|
||||
after := before
|
||||
after.Duration = dur
|
||||
after.End = after.Start.Add(dur)
|
||||
after.Start = start
|
||||
after.End = end
|
||||
after.Duration = end.Sub(start)
|
||||
if err := m.exec.Do(&command.UpdateTimeEntry{
|
||||
Store: m.timeStore,
|
||||
Before: before,
|
||||
|
||||
Reference in New Issue
Block a user