Add the Meeting Tasks prototype: carried-over next actions for sync pages - #25
Draft
mattakamatsu wants to merge 3 commits into
Draft
mattakamatsu wants to merge 3 commits into
mattakamatsu wants to merge 3 commits into
Conversation
…ages Ports dg-team's roam/render meeting-tasks component into an installable extension. The roam/render code block becomes a short shim that hands the extension an element to render into, so existing invocations and templates keep working. Addresses the performance review of the roam/render version: - Reads use data.async.* and run after the widget renders, not during Roam's render. - Widgets on the same page share one set of reads. - Four list-bound Datalog queries (full attribute scans in DataScript) become pull_many calls; the meeting and task scans start from reverse references. On Sync / All Hands a widget went from 1.6-2.0 s of blocking work to about 390 ms after render. - The collapsed section is read and rendered only when opened, and block references in item text are read in one batch. - TypeScript modules separate reads (roam.ts), rules (model.ts, text.ts) and display (view.tsx). Output matches the old component on all 20 widgets on the three dg-team sync pages, apart from the fixes listed in the CHANGELOG. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Roam prototype previewsThe preview deployment is ready. Paste a URL below into Load Developer Extensions from URL in Roam: |
Behavior, from comparing with the three akamatsulab widgets: - Meeting mode reads only meetings dated before the host meeting, so a task carried from last meeting into this one stays under "From last meeting", and "older open items" no longer lists this meeting's tasks. - "Last meeting" skips meetings whose next-actions header has no tasks. - The "From last meeting" date links to the meeting. - Items within a meeting follow outline order, not edit time. - A wrapper such as `((uid)) --> by Friday` keeps its note on screen. - "Proposed next step" wording, the ℹ️ tooltip variant, a list of anchors, and cleaner item text (components, labelled refs, mailto links). Simplify pass (reuse, simplification, efficiency, altitude reviews): - Reverse-reference reads compare entity ids and pull only the blocks on the page (3-6x cheaper for .sticky, ~30% for DONE, measured). - Meetings are read two levels deep; only header subtrees in full. - Headers are found once; one ref-chain reader serves wrappers and display text; one latest-meeting rule; one marker definition. - A Roam re-render with unchanged args no longer redraws the widget; expired shared reads are dropped; the sweep runs only while mounted. - Rows memoize display text and skip rendering when unchanged. - `meeting` never forced anything, so the flag is now just `page`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
What this adds
prototypes/roam-meeting-tasks: the meeting-tasks widget on dg-team's sync pages, moved out of aroam/rendercode block and into an installable extension. A widget shows the next actions carried over from past meetings, and the other open tasks on the page. Inside a meeting block it shows the previous meeting's next actions instead.Widgets are still placed with
{{roam/render: ((uid))}}. Roam has no API for registering an inline component, so the code block those invocations point at will hold a short shim (src/shim.ts) that hands the extension an empty element to render into. Existing invocations and templates keep working; only the code block's content changes.Why
A teammate's review found the widget was freezing meeting pages. The old component ran nine synchronous Datalog queries while Roam rendered the page. Measured on
Sync / All Hands(26,728 blocks), each widget blocked for 1.6 to 2.0 s, and a page mounts several widgets. The review asked for::in $ [?mu ...]) are nowpull_manycalls. DataScript answers those queries by scanning the whole attribute, so each took 230 to 360 ms regardless of result size; together they now take about 70 ms. The meeting and TODO/DONE scans start from the.sticky,TODO, andDONEpages' reverse references.data.async.*and run after the widget renders. The page paints first and the widget shows "Loading tasks…" until its reads finish.const/let, and one module per concern:roam.ts(every graph read and write),model.tsandtext.ts(pure rules),view.tsx(React). Each widget has its own React root, so checkbox state is ordinary component state instead of DOM patching.Behavior changes
Behavior is kept on purpose. Output was compared with the old component on all 20 widgets on the three dg-team sync pages: the same items in both sections, the same counts, and the same footers. The differences are fixes:
((uid))).meetingmode outside a meeting shows page mode instead of throwing.Not done here (needs a decision)
roam/jsloader block and replacing the content of code blockz4qOLRka7with the shim. Anyone who does not load the extension then sees a one-line note instead of each widget.{{roam/render}}avoids editing 26 blocks and 5 templates. An extension-owned{{meeting-tasks}}component would drop the shim but needs that migration.roam/renderversion could not. That adds a pull watch per page, so it works against this PR's goal and is left out.roam/rendercomponents with a different header anchor and person scoping) are not ported.0.2.0: fixes from the matsulab widgets, and a simplify pass
The three akamatsulab
roam/renderwidgets were compared with this extension. Items that are safe for dg-team were folded in:((uid)) --> by Fridaykeeps its note on screen and still writes to the wrapped task.ℹ️tooltip variant, a list of anchors, and cleaner item text.Left for a product decision: person scoping across pages, checkboxes on unmarked bullets, and matsulab's three-level group headers.
A four-angle review (reuse, simplification, efficiency, altitude) then led to these changes:
.sticky133-201 ms down to 23-37 ms, DONE 42-69 ms down to 29-53 ms.Skipped: moving the capability check, failure report, style injection and vitest alias into the extension-base template (outside this prototype; fourth copy across prototypes), moving the legacy-alias source check into the repo validator, and roamjs-components'
roamAlphaAPItypes (they typepull_manyids as uid pairs, and the entity-id reads need plain ids).Checked on the published 0.2.0 preview:
sandbox-discourse-graphs, with the shim in a realroam/renderblock: the extension loaded after the widgets rendered and picked them up; checking a box wrote to the wrapped source block and updated both widgets without entering edit mode; the collapsed section loaded on first open; shift-click opened the sidebar; navigating away and back remounted cleanly.Verification
pnpm testat the root passes. The prototype has 67 vitest cases: the old component's 34-check offline harness ported check for check, string rules, the shim evaluated the way Roam evaluates aroam/renderblock (including loading the extension after the widget rendered), a source guard against default imports fromroamjs-componentsand the legacyroamAlphaAPIaliases, and a built-bundle check that runsonloadwithextensionAPIundefined. Each of three key cases was confirmed to fail when its behavior is broken on purpose.pnpm typecheck(opt-in, strict),pnpm build,pnpm prepare:artifacts, and a frozen-lockfile install succeed.roam/renderfunction as a component with props{ args }, andwindow.Reactis 18.2, so each widget gets acreateRootroot.Notes for the reviewer
roamjs-components' React peer for the other prototypes inpnpm-lock.yamlfrom 17.0.2 to 18.2.0. Every prototype's tests pass.missingCapabilityandreportLoadFailureinsrc/index.tsfollow roam-inbox's copies; they are a candidate for the extension-base template.🤖 Generated with Claude Code