Plan-First Clock Flow: Gates, Drafts, RichEditor Composer, and SuperChat Feed (Milestones 1–7)#446
Draft
Dharp02 wants to merge 16 commits into
Draft
Plan-First Clock Flow: Gates, Drafts, RichEditor Composer, and SuperChat Feed (Milestones 1–7)#446Dharp02 wants to merge 16 commits into
Dharp02 wants to merge 16 commits into
Conversation
Milestone 1 of the plan-first clock flow: teams.updateSettings method, settings on the public team shape, teamApi.updateSettings, and a Switch in the Team Settings modal (admins only, default off).
…yPost hook Milestone 2 of the plan-first clock flow: posts can carry a client-local YYYY-MM-DD postDate, huddle.updatePost stamps wrapUpAt when wrapUp is passed, and huddle.getMyPostForDate + useDailyPost expose today's post.
Milestone 3 of the plan-first clock flow:
- clock.stop throws Meteor.Error('plan-required') when the team setting
is on and today's post has no wrap-up; accepts an optional client-local
localDate so 'today' matches the user's timezone
- ClockPage disables Clock In without today's post and Clock Out without
a wrap-up, with inline messages linking to Huddle
- useClockToggle surfaces plan-required refusals inline instead of alert
- wormhole exposure for teams.updateSettings + huddle.getMyPostForDate
- integration tests: meteor-backend/tests/plan-gate.test.ts (9 passing)
⏳ Preview Build In ProgressDocker image is building — this takes a few minutes (Meteor bundle compilation happens at image-build time, not container start time). A new comment will appear here when the preview is ready or if the build fails. |
The clock-page gate now embeds the same HuddleComposer used on the Huddle tab (PlanComposer wrapper): plan mode creates today's post, wrap-up mode appends a wrap-up and stamps wrapUpAt — no navigation needed. Gates now target the active session's team, not the selected team, so clock-out feedback shows even after switching teams. Extracted shared avatar helpers and toPostAttachment to remove duplication.
…page - useDailyPost now subscribes to the huddlePosts.byTeam publication, so the clock-in/clock-out gates flip in realtime on post create/edit/ delete — no reload and no manual refetch events needed - the mobile bottom-nav clock FAB navigates to the clock page instead of toggling directly, so the gates and inline composer are always visible - dropped the now-unneeded huddle:refetch window events
Centralize the gate in useClockToggle (planGate: planMissing/ wrapUpMissing/todayPost, realtime via useDailyPost) so all clock entry points agree: - clockIn() refuses while today's plan is missing and reports success - bottom-nav FAB shows a dimmed 'plan required'/'wrap-up required' state on any page (dashboard included) while still opening the clock page where the inline composer lives - Work/Tickets clock-in prompts surface the gate instead of silently clocking in without a plan - ClockPage now consumes the shared planGate instead of computing its own
… remove PlanComposer
… shift Milestone 4 (added by request): posts accept draft: true (author-only, date-less, status: 'draft'); the feed, publication/change stream, and both clock gates only see published posts. huddle.publishPost stamps the client-local postDate + clears status (arriving in the feed as a realtime added), huddle.getMyLatestDraft fetches the newest draft. Clock page composer gets Save/Update draft and 'Publish plan and clock in'. Plan doc updated: drafts promoted from out-of-scope to Milestone 4, milestones renumbered, design-iteration notes recorded.
…0.6.1 (file:vendor/ui) Dependency prerequisite for the RichEditor/SuperChat milestones. The library is built locally from the vendor/ui submodule; postinstall runs scripts/ensure-ui-build.mjs so a fresh clone self-heals (no-op when dist/ exists, SKIP_UI_BUILD=1 to opt out), plus a manual setup:ui script. Smoke-tested: typecheck, lint, 76 unit tests, production build, and runtime render all clean on 0.6.1.
Milestone 5: the Huddle composer now uses RichEditor from @mieweb/ui/kerebron (WYSIWYG ProseMirror, markdown in/out) — the manual markdown toolbar and preview tabs are gone. @kerebron/* peer deps installed; a small Vite plugin serves @kerebron/wasm assets at /kerebron-wasm in dev and copies them into dist on build; kerebron.css imported in styles.css. When today's post exists the composer opens it for editing (remounted via key) and submit updates instead of creating. Mentions become removable chips below the editor.
Milestone 6: huddle posts map onto a SuperChatConversation (one participant per author, one message per post; image attachments embedded as markdown, others as links, ticket title as an inline tag) rendered with <SuperChat order='desc' readOnly virtualized> and code/image/ mermaid render plugins. Self-authored messages are editable inline via onMessageEdited → huddle.updatePost. A chat/cards toggle keeps the classic card view for per-post comments and likes (SuperChat has no per-message threads — deliberately not force-fit).
Three product changes by request: 1. Per-session gate (was once-per-day): posts carry clockEventId; clock.start links the plan post to the new session (planPostId), clock.stop gates on that session's post. Every clock-in needs a fresh plan; a 2nd clock-in the same day needs its own. New huddle.getMyPostForSession + useSessionPost hook; useClockToggle exposes sessionPost. Recovery path (createPost accepts clockEventId + wrapUp) so a session can never get stuck. Huddle-tab composer now always creates a new post. 2. Drafts tab: Feed/Drafts toggle on the Huddle page + DraftsPanel for creating/editing/publishing/deleting multiple drafts. New huddle.getMyDrafts; publishPost accepts clockEventId. 3. Bigger editor: RichEditor min-h-52 + larger text; clock-page textarea rows=10/min-h-52. Team Settings copy updated to per-session. Tests updated (15 backend integration, 76 unit). In-browser verified: two independent sessions, two feed posts, drafts created and hidden from the feed.
…k-outside collapse - Shared MarkdownEditor wrapper: a capturing mousedown handler preventDefaults clicks on the Kerebron toolbar/menu (.kb-custom-menu__wrapper) so the editor keeps its selection — toolbar buttons (Toggle bold/italic/etc.) now apply to the selected text instead of no-oping. Also handles Cmd/Ctrl+Enter submit. - Clock page now uses the same Kerebron RichEditor (was a plain textarea); remounts via key to clear after posting and re-seed when a draft loads. - Huddle composer collapses on click-outside when empty, freeing up feed space; typed content is preserved (never collapses with content). Verified in-browser: toolbar bold via mouse, clock-page plan/wrap-up flow through the rich editor, and click-outside collapse.
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.
Overview
The plan-first clock flow (clock-post-simple-plan.md): write today's plan as a Huddle post → clock in → add a wrap-up to that same post → clock out. Gated per team by one setting, off by default — with the setting off, everything behaves exactly as today.
Now covers Milestones 1–7 plus the vendor/ui dependency prerequisite. Only the Yjs live-sync stretch (M8) and a final manual in-browser pass of the new editor/feed remain.
Milestone 1 — Team setting
settings.requirePlanForClockon the team doc (absent =false), admin-onlyteams.updateSettings,Switchin the Team Settings modalMilestone 2 — Today's post
postDate(client-localYYYY-MM-DD) on posts,wrapUp→wrapUpAt,huddle.getMyPostForDate, realtimeuseDailyPosthookMilestone 3 — Gates (+ design iteration)
clock.stopthrowsplan-requireduntil it has a wrap-up (client-locallocalDatefor timezone correctness)useClockToggle.planGate, realtime via thehuddlePosts.byTeamDDP publication — every surface agrees: clock page, bottom-nav FAB (dimmed "plan required" state, navigates to the clock page), Work/Tickets clock-in promptsMilestone 4 — Drafts
draft: trueposts: author-only, date-less,status: 'draft'; excluded from feed, publication/change stream, and both gateshuddle.publishPoststampspostDate+ clears status (arrives in the feed as a realtimeadded);huddle.getMyLatestDraftDependency prerequisite — vendor/ui submodule
mieweb/uivendored as a git submodule atvendor/ui;"@mieweb/ui": "file:vendor/ui"(0.2.4 → 0.6.1, no breaking changes found across the 40 imported components)postinstallrunsscripts/ensure-ui-build.mjsso fresh clones self-heal (no-op when built,SKIP_UI_BUILD=1to skip);npm run setup:uifor manual buildsMilestone 5 — Composer → RichEditor (Kerebron)
RichEditorfrom@mieweb/ui/kerebron(WYSIWYG ProseMirror, markdown in/out);@kerebron/*peer deps installed; wasm grammars served at/kerebron-wasmvia a small inline Vite plugin (dev middleware + dist copy)key) and submit updates instead of creatingMilestone 6 — Feed → SuperChat panel
SuperChatConversation; feed renders<SuperChat order="desc" readOnly virtualized>with code/image/mermaid render pluginsonMessageEdited→huddle.updatePostMilestone 7 — Verify
meteor-backend/tests/plan-gate.test.ts: 14 integration tests (gates + drafts); full backend integration suite 137/137Out of Scope (for Now)
mieweb/uiPR adding anextensionsprop toRichEditortest:all)