Skip to content

feat: sunsetting legacy editor#4908

Open
doc-han wants to merge 11 commits into
mainfrom
sunset-legacy-editor
Open

feat: sunsetting legacy editor#4908
doc-han wants to merge 11 commits into
mainfrom
sunset-legacy-editor

Conversation

@doc-han

@doc-han doc-han commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Description

This PR sunsets the legacy editor

Closes #4402

Validation steps

Manual QA — Legacy editor sunset

Redirects

  • /projects/:id/w/:wid/legacy redirects to the collaborative editor
  • /projects/:id/w/new/legacy redirects to the new-workflow flow
  • Legacy URL with query params still loads (no 404/error)

Legacy users

  • A user previously on the legacy editor now lands on the collaborative editor
  • No "switch to legacy editor" control anywhere
  • No legacy deprecation warning shown

Collaborative editor (regression)

  • Open existing workflow (diagram, nodes, edges render)
  • Create workflow (template + from scratch), save works
  • Add/edit/delete job, trigger, edge — persists after reload
  • Real-time sync works across two browsers
  • Job editor (Monaco) edits save
  • Manual run: pick input, run, see result on canvas
  • Credentials modal works
  • Webhook auth modal works

AI Assistant

  • Panel opens
  • Job code mode returns a streamed answer
  • Workflow template mode generates/edits a workflow
  • Chat history loads + paginates
  • Disclaimer prompt works for a new user
  • Retry a failed message

Additional notes for the reviewer

  1. (Is there anything else the reviewer should know or look out for?)

AI Usage

Please disclose whether you've used AI anywhere in this PR (it's cool, we just
want to know!):

  • I have used Claude Code
  • I have used another model
  • I have not used AI

You can read more details in our
Responsible AI Policy

Pre-submission checklist

  • I have performed an AI review of my code (we recommend using /review
    with Claude Code)
  • I have implemented and tested all related authorization policies.
    (e.g., :owner, :admin, :editor, :viewer)
  • I have updated the changelog.
  • I have ticked a box in "AI usage" in this PR

@github-project-automation github-project-automation Bot moved this to New Issues in Core Jun 29, 2026
@doc-han doc-han marked this pull request as ready for review July 2, 2026 07:42
@doc-han doc-han requested review from elias-ba and lmac-1 July 2, 2026 07:42
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Security Review ✅

  • S0 (project scoping): LegacyRedirectController (lib/lightning_web/controllers/legacy_redirect_controller.ex:15-21) only issues a local redirect and reads no project data; the redirect target WorkflowLive.Collaborate still enforces :project_scope via on_mount.
  • S1 (authorization): N/A — the only new endpoint is a redirect gated by [:browser, :require_authenticated_user] (lib/lightning_web/router.ex:146,261-262); authorization continues to be enforced at the redirect target, and the removed switch_to_legacy_editor handler is dead code with no policy surface.
  • S2 (audit trail): N/A — the migration (priv/repo/migrations/20260629143825_clear_prefer_legacy_editor.exs) drops a per-user UI preference key, not a project/instance configuration resource that requires an audit entry.

@lmac-1

lmac-1 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

@doc-han I am blocking out some time today to go through this 🙏🏻

@lmac-1 lmac-1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @doc-han, looking good! The deleted Elixir modules have zero dangling references, so that's great.

But assets/js/editor - the legacy editor directory - isn't touched at all in this PR, because the collaborative editor still depends on two files in it. We should resolve this now:

  1. Copy magic-completion.ts and es5.min.dts.js into the collaborative editor and repoint the imports. CollaborativeMonaco.tsx and loadDTS.ts currently import both files from assets/js/editor
  2. Extract DEFAULT_TEXT out of assets/js/editor/Editor.tsx. This is currently used by usePlaceholders.ts import that one constant. Pull it into a small shared constants file so Editor.tsx has n remaining importers either.
  3. Once 1 and 2 are done, delete assets/js/editor entirely, including lib/es5.dts.js and lib/es5.min.dts.js
  4. Delete the dead .job-editor-panel CSS in assets/css/app.css as the only component using it was already removed
  5. Add a new CHANGELOG.md entry. It belongs in a "Removed" entry and should mention that we are removing the user-facing setting (prefer_legacy_editor) and retires public URLs (/w/:id/legacy, /w/new/legacy)

By the way, I still haven't done manual testing, but happy to do some after these points are addressed :)

@github-project-automation github-project-automation Bot moved this from New Issues to In review in Core Jul 3, 2026

@elias-ba elias-ba left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @doc-han, really clean sunset - I went digging for the scary stuff (dangling refs to the deleted modules, whether the collaborative editor and its AI still stand on their own) and it all holds up nicely 🙌 I'm building on @lmac-1's review rather than repeating it, so I've skipped the changelog + the assets/js/editor cleanup since she's got those covered.

A couple of extra things from me:

  • Deep links - left an inline on the redirect controller. Old ?a=<run> bookmarks won't follow the run anymore. More a question than a blocker.

  • A test I think we lost by accident - deleting the legacy trigger_test.exs also took the only coverage of the passwordless / SSO webhook-secret reveal in WebhookAuthMethodFormComponent, and that component is still alive (mounted in collaborate.ex and project settings). The surviving SSO tests are for reauth/profile, not the webhook reveal. Since it's a secret-disclosure path, could we port those 1-2 tests onto the surviving component ?

  • A bit more dead code to sweep while we're in here - on top of Lucy's list: workflow_live/components.ex still has workflow_diagram/1 (renders phx-hook="WorkflowDiagram", a hook that isn't registered anymore), plus create_job_panel/1 and panel/1 with no callers, and ui_metrics.ex only logged events the deleted JS used to emit. editorUrlConversion.ts also has no prod caller now - though if we reuse it for the deep-link thing above, it earns its keep 🙂

Nothing blocking from my side once Lucy's points land. Thanks for taking this one on, it's a big one 💪

Comment on lines +23 to +33
defp redirect_preserving_query(conn, base_path) do
target =
case conn.query_string do
"" -> base_path
query -> base_path <> "?" <> query
end

conn
|> redirect(to: target)
|> halt()
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @doc-han, nice and tidy PR 🙏 One thing I bumped into here: we forward the raw query string, but the old editor and the collaborative one use different param names. So an old bookmarked run link like /w/:id/legacy?a=<run_id>&m=history redirects to /w/:id?a=<run_id>..., and the collaborative editor only reads run= (see collaborate.ex handle_params), so the run isn't followed - the user just lands on a blank editor. Funny thing is we already have this exact mapping in assets/js/utils/editorUrlConversion.ts (a -> run, s -> job/trigger/edge, m -> panel), it's just client-side. Do you think it's worth mapping at least a -> run here so shared run links keep working ? Not a blocker, more a question.

@elias-ba

elias-ba commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Hey @doc-han, went back for a second, deeper pass now that the shape's settled and a few more things surfaced. Building on what I left above rather than repeating it 🙂

  • One crash I'd want to guard before merge - removing the switch_to_legacy_editor handler from workflow_channel.ex is right, but the channel has no catch-all handle_in. The button that sends that event actually lives in the collaborative editor's Header.tsx, so in the deploy window a tab still on the old JS can click it and hit the new server with an event that matches no clause. That raises a FunctionClauseError and the channel process goes down, so the user's live session drops and has to reconnect. A tiny catch-all handle_in that just replies with an error would stop stale tabs from knocking sessions over.

  • On the deep-link point I raised above - turns out we already have the remapping built: Helpers.collaborative_editor_url/2 (with its @param_mappings / convert_param helpers) does exactly the legacy→collaborative param translation, but its only caller in edit.ex got removed here, so it's now orphaned (just doctests + helpers_test.exs touch it). So it's a clean either/or: wire it into the redirect to actually keep the old ?a/s/m links working, or delete it with the rest. Right now it's the worst of both - dead but still maintained 🙂

  • Small one - clear_prefer_legacy_editor.exs only defines up/0, so a mix ecto.rollback would abort on it. Totally fine for the data clear to be one-way, but a def down, do: :ok keeps it from breaking a rollback if it ever rides along in a batch.

Still nothing blocking beyond that channel guard, and even that's a couple of lines. Thanks again for taking this one on 💪

@doc-han doc-han requested a review from lmac-1 July 7, 2026 10:06
@doc-han

doc-han commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

@elias-ba on your last review.

One crash I'd want to guard before merge
This is a crash I don't think we have to guard against. we have very few users still on this old editor and we surely wouldn't have this crash. I wouldn't want to keep code that tries to handle a use case for a button that has been removed but based on the assumption that someone has that button on their screen before it was removed. I've never seen us consider such a use-case for all the features we've built so far.

On the deep-link point I raised above
There's a limit to the deep linking we can do given we're throwing away the old editor. The old editor had s param to determine a selection. this selection could be a job, trigger or edge but with the new editor we clearly have job, trigger and edge as params on their own. to handle this redirect, we'll need the socket assigns from legacy editor to pick the type of the s parameter. I believe we can go ahead without this redirect as it's not a crazy breaking error. Also once again, very few users on legacy.

Small one
Updated to change and also uses execute/2 with an empty down query. This allows a rollback without error. 👍🏽

@doc-han doc-han requested a review from elias-ba July 8, 2026 08:32

@lmac-1 lmac-1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @doc-han! Thanks for addressing my feedback and for updating the changelog. I've also done some of the manual testing in the PR description and it's looking good.

@elias-ba elias-ba left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @doc-han, this one was a big lift and it came out really clean 🙌🏽. Thanks for working through all the earlier feedback, the a → run remap, the ported webhook-secret tests, the migration rollback and the dead-code sweep are all sorted. Approving 👏🏽

While I was in here I did one more deep pass just for dead code the sweep might've stepped around, and found three leftovers. None block this and none are bugs, so genuinely your call whether to fold them in while the context is fresh or spin up a quick follow-up:

  • An orphaned legacy LiveView, RunLive.RunViewerLive - its only mount was WorkflowLive.JobView (deleted here) via live_render, and the collaborative editor already has its own React run viewer, so the whole module is dead now. This is the one I'd most like to see go, since an orphaned legacy view slightly undercuts the clean sunset.
  • A dead cluster in WorkflowLive.Helpers - you removed collaborative_editor_url/2, but the rest of its legacy URL/param family went out with edit.ex too: build_url/2 plus the *_params / param / query_param builders, and broadcast_updated_params. I traced it and they only reference each other now, none of the live functions touch them. subscribe_to_params_update dies together with the RunViewerLive above.
  • A few now-orphaned test helpers in workflow_live_helpers.ex (editor_element and friends) that lost their callers when the legacy tests went. Lowest priority of the three, and that file's a mix so it wants a per-function look rather than a blanket delete.

Really nice work taking this one on man, thanks again 💪🏽

@stuartc

stuartc commented Jul 8, 2026

Copy link
Copy Markdown
Member

1. Legacy deep-link params silently dropped — correctness (possibly intentional)

lib/lightning_web/controllers/legacy_redirect_controller.ex:42 (root cause also at line 39)

The redirect only remaps arun. The old deep-link params s (selected step) and m (mode/panel) are forwarded verbatim, but the collaborative editor reads job/trigger/edge/panel, not s/m, so it ignores them.

Failure scenario: a saved bookmark like /projects/X/w/wf-1/legacy?s=job-abc&m=expand lands the user on the bare canvas — no node selected, no editor panel open — instead of the specific job expanded. Notably m=expandpanel=editor needs no selection context and could be translated cleanly even where step-ID mapping is hard.

Caveat: the controller's own moduledoc says this is intentional, so this is a product call rather than an outright bug. If any fidelity is worth keeping, m=expandpanel=editor is the cheap win.

2. Default job-body string now duplicated — cleanup

assets/js/workflow-store/constants.ts:1

The new shared DEFAULT_TEXT constant is only adopted by usePlaceholders. The collaborative editor's createWorkflowStore.ts (~line 912) still hardcodes the identical default-job-body string literal instead of importing it.

Failure scenario: two sources of truth. A future edit to the "Job Writing Guide" starter comment updates one creation path (auto-layout placeholders) but not the other (Yjs-backed createWorkflowStore), so new workflows get different starter code depending on which path created the job.

3. Dead URL-conversion module left behind — cleanup

assets/js/utils/editorUrlConversion.ts:58

After this branch removed buildClassicalEditorUrl (its only caller was the deleted "switch to legacy" header button), the remaining exports collaborativeToClassicalParams and classicalToCollaborativeParams have no non-test importer anywhere in assets/js. That's ~200 lines of module plus a 232-line Vitest suite (editorUrlConversion.test.ts) that only exercise each other — on a branch whose whole purpose is retiring this plumbing.

Ties into #1: classicalToCollaborativeParams is exactly the translation that would fix the dropped s/m params. So it's either "delete as dead" (accept the redirect limitation) or "wire it into the redirect controller" — not both.

4. Router comment contradicts the controller — cleanup

lib/lightning_web/router.ex:259

The added comment claims "the raw query string is forwarded as-is", but the controller does remap arun (and says so in its own moduledoc). The two comments describing the same behaviour disagree.

Failure scenario: a maintainer trusting the router comment assumes no param rewriting happens, so when debugging why a legacy a param becomes run they look in the wrong place.


Recommendation

  • #2 — fix unconditionally: import DEFAULT_TEXT in createWorkflowStore.ts.
  • Generic webapp setup #1 / Run #3 / Create audit records for jobs & credentials #4 — pick one branch of the decision:
    • Keep fidelity: wire classicalToCollaborativeParams into legacy_redirect_controller, at minimum m=expandpanel=editor; update the router comment and moduledoc to match.
    • Drop fidelity (simpler, fits the sunset intent): delete editorUrlConversion.ts + its test suite, and correct the router comment / moduledoc to state plainly that s/m are dropped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

Sunsetting Legacy Editor

4 participants