Conversation
…d stop Stopping wrote the interval with whatever had been typed at start, which for most people was nothing, so the time log filled up with unnamed hours. Both stop routes now take an optional description and billable flag and apply each only when it was sent, so a client that stops with an empty body still keeps what the start recorded. Starting gains the same billable override, and starting the task the clock is already on stops being a conflict: it applies the details it carries and answers the running entry. That is what makes "create this task and start it" correct when auto_start_tasks has already opened the clock on create. A start on a different task is still the 409 the run control turns into "stop that one and start this one", and a mismatched stop is still refused before anything is written.
The store gains the two questions a timer ever asks, held as promises the way the invoicing store holds its number prompt: one dialog mounted in the company layout answers whatever control asked. stopWithPrompt is now the only way a timer is stopped, so the dialog, the discard and the single success message are written once instead of by each of the four callers that used to repeat them; startWithPrompt creates the task first when the answer was a name rather than a task. roundMinutes mirrors Application\Rounding exactly, so the dialog can promise what the entry is about to say: zero stays zero, nearest bills a spell shorter than one increment as a whole one, and down is the one direction that may answer zero for real work.
Save and stop shows the task, the ticking clock and what the entry will read after the company's rounding, with the description and the billable flag prefilled from the running entry. Discard confirms inline, naming the time it is about to throw away, rather than through a browser confirm. Start a timer asks the way people think about it: the project, then the task inside it, and when the search matches nothing the typed text becomes "create this task and start", so a name in someone's head does not have to become a form first. Both are mounted beside the invoice number dialog rather than by each control that opens one, and neither is hidden on any path: a clock running while someone is in the settings still has to be stoppable there. The launcher steps aside while either is open, because a floating button over a modal backdrop reads as something still to be pressed.
The chip, the launcher, a task row and the "stop and start" chain all go through stopWithPrompt now, and the running rows of a task's time log grow a stop of their own, so the log is no longer the one place a running entry cannot be closed. Another member's running row still only says so. The launcher's idle click opens the start dialog, which takes its inline search panel and its separate discard with it: the panel now only has the one job it is good at, saying what is on the clock and offering the task and the stop beside it.
Carries the timer dialogs, the prompt-driven store and the call sites that go through it.
…orner The idle launcher was sized by padding around its icon, so it rendered wider than tall; it is now a fixed 56px circle, and only grows into a pill while a timer runs and the elapsed time is shown. It also sits closer to the corner so it overlaps less content.
Contributor
Author
|
Superseded by #14, which carries this stack consolidated into three commits on top of main. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stopping a timer used to write the interval immediately, with whatever had been
typed at start, which for most people was nothing: the header chip and the
floating launcher stopped on one click and rows, cards, the task page and the
time log had no way to describe the time at all. Starting from the floating
circle offered a bare task search that only worked for someone who already knew
the task existed. Both ends are proper dialogs now.
Save and stop
Every stop control opens the same dialog: the header chip, the launcher, a task
row, a card, the task page and the time log, whose running rows grow a stop of
their own. It shows the task, the ticking elapsed time and what the entry will
read after the company's rounding, with the description and the billable flag
prefilled from the running entry. Discard confirms inline, naming the time it is
about to throw away, instead of through a browser confirm. Cancel leaves the
clock running and writes nothing.
"Stop and start" on another row runs the same dialog for the time being left
behind, and starts the new task only when that time was saved.
Start a timer
The floating circle's idle click asks the way people think about it: the
project, then the task inside it, and when the search matches nothing the typed
text becomes "Create task ... and start". The description and the billable flag
come along, prefilled from the task. The launcher's inline search panel and its
separate discard go with it; the running panel keeps what it is good at, saying
what is on the clock with the task and the stop beside it.
Backend
Both stop routes take an optional description and billable flag, applied only
when sent, so a client that stops with an empty body still keeps what the start
recorded. Both start routes take the billable override, and starting the task
the clock is already on stops being a conflict: it applies the details and
answers the running entry, which is what makes "create this task and start it"
correct when
auto_start_taskshas already opened the clock on create. A starton a different task is still a 409, and a mismatched stop is still refused
before anything is written.
support/time.tsgainsroundMinutes, mirroringApplication\Roundingexactly, so the dialog's preview is the number the entry gets.
No schema change.
Verification
vendor/bin/pint,composer run lint,composer run test: 328 tests, 1376assertions (314 before, 14 new covering description and billable at stop, the
billable override at start, the idempotent same-task start and the mismatch
that changes nothing).
pnpm run lint,pnpm exec tsc --noEmit,pnpm run build(one
window.__invoiceshelf_vue, no barevueimports).project and a task; stop from the chip with an edited description and billable
off, landing on the time-log row; "Create task ... and start" both with
auto_start_tasksoff and on (one entry either way, the description applied);stop from a row with cancel and with discard; stop from the time log; the
"stop and start" chain; the dialog on a settings page. Console clean.
https://claude.ai/code/session_01DCf36XDKprZifej8dc2r1E