Conversation
The time screens need three things the projects slice does not: a client for the entry, timer and status endpoints, somewhere to keep the running clock, and the session facts a module bundle cannot read from the host stores. The timer is a plain reactive singleton because a module has no Pinia. It recomputes the elapsed seconds from `started_at` on every tick rather than counting up, so a throttled tab, a sleeping laptop and a clock correction all land on the right number at the next tick, and a 409 from `timer/start` is reported and followed by a read rather than treated as a failure. Task names live in their own cache: `TimeEntryResource` carries `task_id` and nothing else, so every timesheet row, the header chip and the entry editor would otherwise show a bare number.
Six small components rather than two large ones, so a failure in any of them leaves the rest of the page standing: the header chip, the floating launcher, the week grid, the managers' table, the entry editor and the status editor. The editor accepts the two ways people describe the same work, a duration or a start and an end, and writes both onto the entry; a duration-only entry is stamped at 09:00 local rather than at midnight, which would land on the previous day for anyone east of UTC. An invoiced entry is shown and never offered for editing, because the money on it belongs to the invoice. The launcher sits above where a chat bubble would be, and hides itself in platform administration, where no company is active.
Everything the slice contributes to the host is declared in one file, so `init.ts` only gains a line: the timesheet page under the module namespace, the header chip, the company layout overlay, the company settings page and the lifecycle wiring. Nothing reads from the network inside the boot callback, because Pinia is not installed yet when it runs; the first read waits for `bootstrap:completed`, and a company switch clears the previous company's timer, task names and settings before asking again. The settings page links to the host's generic module settings form for the four scalar settings rather than mirroring it, which would give a company two places to write the same value, and owns the task status editor, which has no host equivalent. The API still enforces `manage-task-status`, so a member who may not use it is told so instead of seeing a form that refuses to save.
The package ships compiled, so `dist/` is committed with the source change and installs without a build step on the target system. It will be rebuilt when this branch merges with the board work.
`dayOf` and `taskName` were written for callers that ended up using the labelled variants instead. Dead code in a shipped bundle is weight the browser downloads for nothing.
…tracking branch Keeps both registrations in init.ts, takes the richer TaskStatus shape from the board side plus the time side's input type, the time side's fuller TimeEntry types, and rebuilds dist/ from the union.
Registry::registerMenu accepts a priority (lower sorts first inside the group, default 100); the entry now sets 10 so Projects precedes modules that keep the default.
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.
M5, the time-tracking UI, on top of
feat/ui-projects. Backend unchanged: noPHP file is touched and
composer run testis still 229 green.What lands
stores/timer.ts). A plain reactive singleton, because amodule bundle has no Pinia. The elapsed time is recomputed from
started_aton every tick rather than counted up, so a throttled tab, a sleeping laptop
and a clock correction all land on the right number at the next tick. A 409
from
timer/startmeans another tab got there first: it is reported and thereal running entry is read back.
components/TimerChip.vue), throughregisterHeaderActionat priority 30, visible only while an entry runs. Task name,
h:mm:ss, and astop button; the name opens the timesheet.
components/QuickStartOverlay.vue), throughregisterCompanyLayoutOverlay. A floating button above where a chat bubblewould sit, a task search, a description, and stop/discard while running.
Hidden in platform administration.
pages/TimePage.vue) at/admin/modules/tasks-projects/time,meta.abilitytasks-projects:view-own-time. A "My time" week grid with per-day and weektotals, honouring the
week_startsetting, and an "All time" tab with aserver-side table filtered by member, project, date range and billing.
components/TimeEntryModal.vue). A searchable task picker,a date, either a duration (
1:30or1.5) or a start and an end, adescription and a billable switch. Invoiced entries are shown read-only with
the reason; 422 messages land under their fields.
registerCompanySettingsPageat pathtasks-projects. It links to the host's generic module settings form for thefour scalar settings and owns the task status editor: colours, names, the
default and closed flags, add, delete and up/down reorder.
messages/time.ts.Decisions worth reviewing
GET /api/v1/bootstrap,current_user.id. The module cannot read the host user store, and the timeendpoints only narrow to "my time" when asked for a
user_id. It is readonce per company session and kept in
stores/session.ts.members_see_all_time, orwhen a probe for
GET time-entrieswithout auser_idfilter returnssomeone else's row. The API already narrows the list for a caller who may
not see more, so this cannot offer a tab that would come back empty. It can
under-offer: a manager in a company where nobody else has logged time yet
sees only "My time" until someone does.
module's PHP settings schema at
/admin/settings/modules, so the settingspage links there rather than giving a company two places to write the same
value. There is no deep link to one module's form in the host router today,
only the modules index that opens the settings modal.
would land on the previous day for anyone east of UTC. Both timestamps and
the duration are sent, so the server's rounding still decides the stored
minutes.
POST task-statuses/reordera drag would, needs no dependency, and isreachable from a keyboard.
stores/tasks.ts), becauseTimeEntryResourcecarriestask_idand nothing else. Unknown ids arefetched five at a time and a task that cannot be read keeps its id as its
label.
Shared files
init.tsgains one import and one call; everything else lives underregistrations/time.ts,api/time.ts,messages/time.tsand new files, tokeep the merge with the board branch small.
types/task-status.tsis theminimal shape both slices need.
Checks
pnpm run lint,pnpm exec tsc --noEmit,pnpm run build(onewindow.__invoiceshelf_vuedestructuring, no leftoverfrom "vue"),composer run lint,composer run test(229 passing), and both modulevalidators. Not verified in a browser from this worktree: the running stack
serves the sibling checkout.
https://claude.ai/code/session_01DCf36XDKprZifej8dc2r1E