feat: closeable info alerts on Sequence Properties (session-only)#13
Merged
PaulNewling merged 12 commits intoMay 29, 2026
Merged
Conversation
PlAlert on the Main tab now renders a close button. Dismissals live in a local ref<Set<string>> — not persisted; resets when the block UI unmounts (project close, app reload, multi-client independent). Hairpin- safe: the only write is from PlAlert's close-button emit (user gesture). Minimal-change variant of the persisted-dismissal approach (paulnewling/fix/dismissable-info-messages). Useful when you want "acknowledged for this session, fresh on reopen" semantics and don't want to extend BlockData or add a migration step.
There was a problem hiding this comment.
Code Review
This pull request introduces a session-only dismissal mechanism for info-message alerts in MainPage.vue by using a ref and computed property. A review comment correctly identifies that defining the state within <script setup> causes it to reset upon component unmounting; it is recommended to move this state to a module-level scope to ensure persistence across tab navigation.
CI flags the 2.5.29 pin as outdated. Build is clean against the new major version; no workflow code touched on this branch so the bump is catalog-only.
In Vue, refs declared inside <script setup> are component-instance state. Switching between block sections (Main, Property Relationships, Property Distribution) unmounts MainPage and resets the dismissals. Hoisting the ref to a module-level singleton in app.ts makes dismissals survive in-block route changes; still resets on project close / app reload / switching to another block. Addresses gemini-code-assist review comment.
Earlier comment said dismissals reset on "switching to another block and back", which is wrong. Block UIs are LRU-cached (limit 4) in the desktop app's WebContentsMap, so the JS context survives brief navigation away. Actual reset triggers: project close (cleanCachedBlockViews on deleteProjectOverview), block reload (LoadBlockFrontend with recreate), LRU eviction once the cache exceeds 4 entries, or app restart.
Dismissals are now tied to the currently-firing advisory set. When the workflow stops emitting a previously-dismissed string (re-run with a different input, advisory naturally goes away), it drops from the set. A future re-fire of the same string shows fresh — no carry-over. Implemented as watch(outputs.info.messages → local ref). Output → local Vue ref is the sanctioned pattern in hairpin.md (state lives in the JS context, not BlockData). No multi-client interleave risk. Closes the stickiness gap on this branch — dismissals follow the firing rather than persisting indefinitely.
Collaborator
Author
Collaborator
Author
CI's require-latest preflight rejects the prior pins. Build clean against the tengo-builder major bump (3 → 4); no workflow source touched on this branch, catalog change only.
CI's changeset-coverage check requires entries for any package whose catalog deps changed. .workflow picks up the tengo-builder bump, .model picks up the block-tools bump. Both are patch (no runtime change).
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
Info-message alerts on the Main tab now have a close button. Dismissals follow the firing: hidden while the message is in the workflow output, surface fresh if the workflow stops emitting it and later re-emits.
Why
Workflow advisories (
vhh(),peptidesShortInstability(),partialChainMissingFullChain(), etc.) render on every Main view with no way to acknowledge. For inputs that legitimately fire an advisory across many runs, users re-see the same banner on every navigation. This PR adds the close affordance and ties dismissal to the firing so a different input that re-fires the same string shows fresh instead of staying silently suppressed.How
State lives in a module-scope
ref<Set<string>>inapp.ts:dismissInfoMessage(m)adds to the set.visibleInfoMessagescomputed filtersoutputs.info?.messagesby the set.watch(() => outputs.info?.messages, ...)prunes the set to the intersection with the current output on every re-emit.Hairpin-safe: writes are user gestures and output → local-ref, both sanctioned by
harnesses/block-dev/hairpin.md. NoBlockDatachange, no migration.Lifetime
Dismissals live as long as the block UI's JS context.
PR #12 prototyped a server-persisted alternative — closed because it gave "dismissed once, dismissed forever" semantics across all future workflow runs that re-emitted the string.
Test plan
pnpm build:devcleanGreptile Summary
This PR adds a close button to info-message alerts on the Main tab, with session-only dismissal semantics. Dismissed entries are stored in a module-scope
ref<Set<string>>inapp.tsand automatically pruned to the intersection of currently-firing messages on each output change, so a message that stops being emitted and later re-fires will show fresh rather than staying silently suppressed.dismissedInfoMessagessingleton and the pruningwatchinapp.tsare well-encapsulated; the prune condition (filtered.length !== current.size) is correct and avoids spurious reactive writes.MainPage.vueswitches thev-forkey from array index to message text (a correctness improvement) and derivesvisibleInfoMessagesvia a simple computed filter against the dismissed set.pnpm-workspace.yaml/pnpm-lock.yamlinclude incidental dependency bumps (@platforma-sdk/block-tools2.8.1→2.9.2,@platforma-sdk/tengo-builder2.5.29→3.0.5); the build is verified clean in the test plan.Confidence Score: 5/5
Safe to merge — changes are UI-only, touch no BlockData schema, and the reactive prune logic is correct and well-tested.
The feature is confined to a module-scope Vue ref and a computed filter; no server state is modified. The prune watch correctly intersects dismissed entries with currently-firing messages and avoids spurious writes via the length-vs-size guard. The @update:model-value handler behaviour was already flagged in a prior review thread. Dependency bumps are incidental and the build was verified clean.
No files require special attention.
Important Files Changed
dismissedInfoMessagesref and a watch insidesdkPluginthat prunes dismissed entries to the intersection with currently-firing messages; logic is correct and well-documented.visibleInfoMessagescomputed anddismissInfoMessagefunction; switchesv-forkey from index to message text; wirescloseableprop and close event onPlAlert.@platforma-sdk/block-tools2.8.1→2.9.2 and@platforma-sdk/tengo-builder2.5.29→3.0.5 (major version change); incidental to the main feature, build verified in test plan.Sequence Diagram
sequenceDiagram participant WF as Workflow Output participant Watch as watch (app.ts) participant DIM as dismissedInfoMessages (ref<Set>) participant Comp as visibleInfoMessages (computed) participant UI as PlAlert (MainPage.vue) participant User as User WF->>Watch: outputs.info.messages changes Watch->>DIM: prune to intersection with fired set DIM-->>Comp: reactive update WF-->>Comp: reactive update Comp->>UI: render only non-dismissed messages User->>UI: clicks close button UI->>Comp: "@update:model-value emitted" Comp->>DIM: dismissInfoMessage(message) → new Set + message DIM-->>Comp: reactive update Comp->>UI: message removed from visibleInfoMessages Note over Watch,DIM: On next output change where message is absent,<br/>entry is pruned → future re-fire shows freshReviews (3): Last reviewed commit: "docs: tighten changeset body" | Re-trigger Greptile