feat(frontend): mark the public version and open what a listing advertises - #7860
Closed
yangzhang75 wants to merge 7 commits into
Closed
feat(frontend): mark the public version and open what a listing advertises#7860yangzhang75 wants to merge 7 commits into
yangzhang75 wants to merge 7 commits into
Conversation
A public workflow follows the author's latest content today: every save reaches the Hub immediately. Pinning a version as the public copy needs somewhere to keep that copy, which is what these columns are. `is_public` stays the on/off switch. `published_content` is the pin: NULL means the workflow follows the author's latest, which is what every workflow does today, so the migration changes nothing anyone can see. `published_name` and `published_description` travel with it because a pin has to hold everything on show, and `workflow_version` stores no metadata at all -- only content deltas. `published_version_id` names the version row holding that copy, so the revision panel can mark it and the author can restore it. The copy is materialized rather than replayed from `workflow_version` because those rows are reverse JSON-Patch deltas: serving a pinned workflow would mean folding every newer patch back from the author's current content on each public read, and a computed value is something the fulltext index cannot cover. A CHECK constraint makes "private but pinned" unrepresentable, and a PGroonga index mirrors the latest-content one so public search can match the frozen copy. Adding columns changes the arity of the generated positional constructor, so the three copy-producing paths (clone, duplicate, restore-a-version) now build their POJO with setters -- which is also what stops a later column from silently shifting a null into the wrong field. Part of apache#7828.
A public workflow follows the author's latest content, as publishing has
always done. This adds the other state: the author pins the version they
have now, and the public copy stops moving until they pin again.
`is_public` stays the on/off switch; `published_content` is the pin, NULL
while following. `WorkflowPublishService` owns the two states, and three
endpoints expose them: POST and DELETE `/workflow/pin/{wid}` to pin and
unpin, GET `/workflow/publish-status/{wid}` for what the author is shown.
Publishing and unpublishing move through the same service, so unpublishing
drops the pin rather than leaving a private workflow carrying one.
Two paths are narrowed so a pin can hold. A save wrote the whole row back,
so a publish landing while a save was in flight was silently rolled back,
and a request body could set the publish columns itself; saves now write
only name, description and content. Creating a workflow clears the publish
columns for the same reason.
Nothing reads the pinned copy yet: every workflow is in the following
state it is in today, and nothing on screen changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With a version pinned, a workflow has two copies: the author's working copy and the frozen one on public show. This routes every read that serves a viewer without granted access through the frozen copy, and freezes the name and description with the graph. `WorkflowPublishService.publicCopyOf` returns the three fields as a group, so a surface cannot pick up the published graph under a title the author has not published; `WorkflowAccessResource.hasGrantedAccess` is the seam that decides which copy a caller gets. Granted access -- owner, shared, project member -- keeps tracking the author's latest, because sharing is not publishing. Name and description freeze because they are as public as the graph: if only the graph froze, a report about a title could be answered by editing the title while the pinned copy still advertised it. Routed through it: opening a workflow, the hub's read, Clone, Duplicate, `/workflow_name`, `/workflow_description` and the size a listing shows. A workflow that follows the author's latest -- every workflow today -- is served exactly what it is served now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Search and the listings it feeds were reading the author's live columns, which for a pinned workflow is the one copy the public cannot open. A draft would turn up in a public search under a title nobody has seen, and the card would advertise a name the detail page does not show. Each filter is now applied to whichever copy the caller may see: `onVisibleCopy` builds the same filter twice -- over the live columns for rows the caller was granted access to, over the frozen ones for rows they reach only because the workflow is public -- and ORs the two. A disjunction over bare columns rather than a CASE, so each side stays eligible for its own fulltext index. Unpinned public rows fall back to the live columns, so a following workflow searches exactly as it does now. Listings carry two more things from the same query: the frozen name and description to show a viewer without granted access, and whether the copy on show is behind the author's working copy. `constructWhereClause` takes `includePublic` for this; the other builders accept and ignore it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The author can pin a version, and their working copy then moves on. This gives them a way back to what the public is seeing: pinning leaves an anchor in the revision history they already use, and the panel marks it as the one currently public, so restoring the published version is the restore they already know. The anchor is a version row whose delta is the identity patch, so replaying it returns exactly what was pinned however many edits pile up after. An existing row cannot stand in: a version row replays to the content as it was *before* the change it records. Pinning content that is already the pinned one reuses its anchor rather than adding a twin, and the read that decides takes a row lock so two pins racing cannot both insert. Two consequences the anchor forces: - It must not start the version panel's aggregation window. It lands seconds after the save it freezes, and the panel folds close-together versions into the newest, which would hide the author's own save behind a row they never made. - The revision history is now readable only with granted access, or while nothing is pinned. Replaying a version folds deltas back from the author's current content, so listing versions of a pinned workflow would hand a public viewer the very edits the pin is holding back. `publish-status` carries the pinned version's date, read from the version row so the dialog and the panel print one value rather than two clocks'. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The share dialog said whether a workflow was public and nothing about which copy the public was getting. With pinning that is now a choice, so the dialog carries it: a two-option control -- Follow latest, or Pinned -- under the Public tile, plus a line naming the pinned version by the date it went public. Follow latest is the default and is exactly what publishing does today. Pinning freezes the version the author has now; while a pin is in place and their working copy has moved on, the panel says so and offers Update to current, which is the only way those edits reach the public. The panel re-reads its state when a save lands rather than on a timer: `WorkflowPersistService` now emits on persist, rename and re-describe, which is what makes "your edits are not public yet" appear as soon as the autosave lands rather than the next time the dialog is opened. Publishing returns the state it produced, so the panel does not have to ask again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tises Two places outside the share dialog have to agree with the pin. The versions panel marks the version the Hub is serving, as a quiet second line under its timestamp. That row is also how an author who has moved on gets the published copy back: it is already in the panel, so restoring it is the restore they already know. The panel re-reads when the share dialog closes, since that is where the pin can have moved and the panel is covered until then. Hub entries open what they advertise. A hub card shows the public copy, so an author whose working copy has moved on behind a pin now lands on the published preview -- what they just saw, and where Clone gives them a copy of it -- rather than in their editor showing something else. Their own listings are untouched: there the entry is their workflow, and it opens the editor as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Automated Reviewer SuggestionsBased on the
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7860 +/- ##
============================================
+ Coverage 91.87% 91.88% +0.01%
- Complexity 4510 4515 +5
============================================
Files 1173 1174 +1
Lines 47350 47347 -3
Branches 5306 5312 +6
============================================
+ Hits 43502 43505 +3
+ Misses 2204 2191 -13
- Partials 1644 1651 +7
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 425 | 0.259 | 22,419/31,155/31,155 us | 🔴 +149.4% / 🔴 +116.6% |
| 🔴 | bs=100 sw=10 sl=64 | 938 | 0.572 | 104,062/148,806/148,806 us | 🔴 +98.0% / 🔴 +49.5% |
| 🔴 | bs=1000 sw=10 sl=64 | 1,103 | 0.673 | 911,596/982,161/982,161 us | 🔴 +35.0% / ⚪ within ±5% |
Baseline details
Latest main b7c33b0 from 2026-08-22T12:41:18.215Z
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 425 tuples/sec | 1,070 tuples/sec | 833.79 tuples/sec | -60.3% | -49.0% |
| bs=10 sw=10 sl=64 | MB/s | 0.259 MB/s | 0.653 MB/s | 0.509 MB/s | -60.3% | -49.1% |
| bs=10 sw=10 sl=64 | p50 | 22,419 us | 8,990 us | 11,864 us | +149.4% | +89.0% |
| bs=10 sw=10 sl=64 | p95 | 31,155 us | 12,633 us | 14,381 us | +146.6% | +116.6% |
| bs=10 sw=10 sl=64 | p99 | 31,155 us | 13,861 us | 18,035 us | +124.8% | +72.7% |
| bs=100 sw=10 sl=64 | throughput | 938 tuples/sec | 1,420 tuples/sec | 1,083 tuples/sec | -33.9% | -13.4% |
| bs=100 sw=10 sl=64 | MB/s | 0.572 MB/s | 0.867 MB/s | 0.661 MB/s | -34.0% | -13.5% |
| bs=100 sw=10 sl=64 | p50 | 104,062 us | 69,686 us | 93,077 us | +49.3% | +11.8% |
| bs=100 sw=10 sl=64 | p95 | 148,806 us | 75,137 us | 99,553 us | +98.0% | +49.5% |
| bs=100 sw=10 sl=64 | p99 | 148,806 us | 89,601 us | 108,604 us | +66.1% | +37.0% |
| bs=1000 sw=10 sl=64 | throughput | 1,103 tuples/sec | 1,455 tuples/sec | 1,119 tuples/sec | -24.2% | -1.4% |
| bs=1000 sw=10 sl=64 | MB/s | 0.673 MB/s | 0.888 MB/s | 0.683 MB/s | -24.2% | -1.4% |
| bs=1000 sw=10 sl=64 | p50 | 911,596 us | 685,976 us | 909,247 us | +32.9% | +0.3% |
| bs=1000 sw=10 sl=64 | p95 | 982,161 us | 727,444 us | 952,561 us | +35.0% | +3.1% |
| bs=1000 sw=10 sl=64 | p99 | 982,161 us | 767,738 us | 985,186 us | +27.9% | -0.3% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,470.62,200,128000,425,0.259,22419.36,31155.16,31155.16
1,100,10,64,20,2132.81,2000,1280000,938,0.572,104061.54,148805.75,148805.75
2,1000,10,64,20,18131.17,20000,12800000,1103,0.673,911595.71,982160.98,982160.98
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.
Part of #7828, and the last PR in the series. Stacked on #7859 — the review here is the last commit,
feat(frontend): mark the public version and open what a listing advertises.Two places outside the share dialog have to agree with the pin.
The versions panel marks the version the Hub is serving
A quiet second line under its timestamp — the panel is 230px wide, so horizontal room is scarce while vertical room is free. That row is also how an author who has moved on gets the published copy back: it is already in the panel, so restoring it is the restore they already know.
It re-reads when the share dialog closes, since that is where the pin can have moved and the panel is covered until then. The dialog announces rather than reaching down into the panel, which keeps the dependency one-way.
A hub entry opens what it advertises
A hub card shows the public copy. Clicking it took the author into their editor, so the workflow they had just seen described one way opened another. An author whose working copy has moved on behind a pin now lands on the published preview — what they just saw, and where Clone gives them a copy of it.
Their own listings are untouched: under Your Work the entry is their workflow, and it opens the editor as before.
Tests
+9 frontend cases: the routing rule in both the list and the card view, and the versions panel showing the mark, re-reading when told to, and leaving unmarked rows alone.