Skip to content

fix(project-management): address a project by its id, not its name (#1363) - #1377

Merged
Victor-w-Madeira merged 1 commit into
mainfrom
fix/issue-1363-project-sidebar-addressed-by-id
Aug 8, 2026
Merged

fix(project-management): address a project by its id, not its name (#1363)#1377
Victor-w-Madeira merged 1 commit into
mainfrom
fix/issue-1363-project-sidebar-addressed-by-id

Conversation

@Victor-w-Madeira

Copy link
Copy Markdown
Collaborator

Closes #1363.

Problem

Seven @stable tests across four specs hard-failed on the 2026-08-07 daily (run 31163810520) with one shape: a project the backend confirms exists (POST /api/v1/projects201) never resolves in the home sidebar. Every one failed on all three attempts, across both shards and worker indices 2–17, outside the run's 108 s outage window — so not environmental. They were quarantined manually at triage (@stable removed and test.fixme added).

Upstream 23f91d8587 (fix(authz): support scoped project visibility, langflow-ai/langflow#14429) re-keyed both testids from the project name to its id, on the release-1.12.0 line the nightly is cut from:

- data-testid={`sidebar-nav-${item.name}`}
+ data-testid={`sidebar-nav-${item.id}`}
- "more-options-button" + `_${convertTestName(item?.name ?? "")}`
+ data-testid={`more-options-button_${item.id}`}

Verdict: internal rename of an automation hook — NOT a product regression

Read from the live DOM on 1.12.0.dev20, not inferred from the commit:

entry   data-testid="sidebar-nav-<uuid>"           id="sidebar-nav-<uuid>"
kebab   data-testid="more-options-button_<uuid>"   aria-label="Options for <name>"
wrapper data-project-id="<uuid>"

The name is still the entry's text and the kebab's accessible name, so nothing a user or a screen reader perceives was lost — data-testid is a test hook, not a product contract. Keying on the id is also the more correct choice under the change that introduced it: visibility is now per-principal, and a project name is not unique across principals while its id is. No REGRESSIONS.md row is owed and no upstream ticket is filed. Full reasoning recorded on the issue.

Ruled out rather than assumed: the ProjectRenamePermission wrapper the same commit adds is children(can(projectId, "write")) — it always renders its child, and canRename only guards onDoubleClick. Both projects render live.

Fix

Addressing lives in one place — tests/helpers/ui/project-sidebar.ts — matching both spellings as a single locator.

That is not a hedge. main still renders the name-derived testid, and manual.yml dispatches the @stable set against 1.11.x release candidates before every sign-off — pinning the id alone would trade seven tests red on the nightly for seven red on the lane that signs releases off. The two branches can never both match: an entry carries exactly one testid, and a project's name is never another project's uuid. The name branch carries its own deletion trigger, and it is the only place that spells it.

Rejected: editing each spec in place. The issue's own directive puts the fix in the shared layer, and addressing by the id the create response already returns removes the #1023 ambiguity instead of trading one name for another.

Consumers updated: MainPage (deleteProject / clickProject / uploadFlowByDragDrop), createProjectThroughSidebar / renameProjectThroughSidebar, cleanOldFolders, the four quarantined specs, and the two latent ones.

Second defect, riding on the first

cleanOldFolders drove the kebab through the name-derived testid, so from dev20 on it deleted nothing and merely timed out on a click — the mechanism behind the New ProjectNew Project (5) accumulation the daily's retries recorded inside a single test. It now sweeps through the REST API: this is teardown of the previous run and must not depend on the UI state the test it precedes is about to assert on, the argument removeLeftoverRenamedProject already makes in the same file.

Measured on 1.12.0.dev20: 3 New Project* projects seeded via POST /api/v1/projects/, spec run once — 0 of 3 survived.

One observable had to change

The id-derived testid does not change with a rename, so asserting on it would pass whether the rename committed or not. renameProjectThroughSidebar now asserts the entry's text, and returns the project under its new name (which is what later assertions must address it by on 1.11.x, where the testid does change).

Scope notes

  • Quarantine lifted on all 7 tests — test.fixme removed and @stable restored.
  • The two specs carrying the same addressing but no @stable, hence latently broken and invisible to the daily, are fixed here as the issue requires: folder-drag-drop-flow.spec.ts, flow-navigation-between-folders.spec.ts.
  • The @destructive loop kept its assertions; its isVisible() fallback to more-options-button_*.first() is gone — it could delete a folder other than the one it had just hovered. The #1008 known-defect declaration still fires.
  • No assertion was weakened anywhere; every changed line is addressing, not verdict.
  • Out of scope, filed separately: mcp-server-starter-projects leaks one flow and one project per run, hidden by the next run's cleanup #1376mcp-server-starter-projects leaks one flow and one project per run, masked by the next run's cleanOldFolders. A cleanup defect, not an addressing one.

Covered tests

# Test What it validates
1 creates, renames and deletes an empty project folder via the UI entry visible after create; entry text becomes the new unique name; Project deleted successfully; entry gone
2 deleting a folder that contains a flow removes the flow with it flow listed inside the folder; after the UI delete, GET /api/v1/flows/{id}404
3 deleting a folder should update the folder list immediately entry gone within 10 s (no stale data) and add-project-button still functional
4 deleting one folder should not affect other folders alpha gone, beta still visible and clickable, mainpage_title renders
5 creating a new folder after deletion should work correctly the second folder's entry appears — no stale-cache collision between a deletion and the next creation
6 deleting every folder lands on the empty project screen (@destructive) folderCount === 0, sidebar empty message, new_project_btn_empty_page; the #1008 422 still fires as declared
7 user should be able to select flows … bulk actions all 3 checkboxes checked, download toast, listing equals exactly the 3 created names
8 user must be able to see starter projects for mcp servers lf-starter_project count 1; lf-new_project / lf-new_project_1 appear; lf-renamed_project appears then count 0 after delete
9 navigating between two folders scopes the listing to each folder's flows mutual exclusion — folder A shows flow A and toHaveCount(0) of flow B, and vice versa
10 folder listing shows flows correctly via UI the folder appears in the sidebar and clicking it lists its flow

Unit coverage (npm run test:units)

project-sidebar.test.ts asserts by selection, not string equality — each case compiles the selector and runs it against a data-testid: it matches the id spelling (nightly) and the name spelling (main/1.11.x); the kebab matches the id and the slugified name and not the raw one; matching is exact, so New Project does not match New Project (3); a name carrying " or \ still yields a well-formed selector.

clean-old-folders.test.ts pins the sweep's end state, not its calls: it deletes every New Project* and nothing else, deletes by id and never through the sidebar, reads both response shapes, does not throw on a failed list, does not abort on one undeletable leftover, and does not sweep a name that merely contains "New Project".

Validation (nightly 1.12.0.dev20, --workers=1 --retries=0)

  • npm run typecheck ✅ · npm run lint ✅ (0 errors) · npm run test:units ✅ 531/531 · npm run test:scripts ✅ 795/795
  • 5 clean runs of the six specs, 11 passed each (~39 s); @destructive green isolated (1 passed)
  • --trace=on ✅ — ran normally (23 s), no sign of the Simple Agent-family hang
  • Zero 🚨 Backend Error attributable to this change. Two advisory entries appear, both from mcp-server-starter-projects test 2, which this PR does not touch and which reproduces them on main: the 409 Server already exists. is that test's own assertion, and the intermittent 500 on DELETE /api/v1/flows/ is sqlite3.OperationalError: database is locked in the cascade delete — the already-filed [Daily #962] api-folders DELETE returns 500 instead of 204 (recurrent) #965/LE-2020 contention class, read from the container's traceback.
  • Orphan check: flows and projects counted via GET /api/v1/flows/?get_all=true and GET /api/v1/projects/ before and after a clean run — 0 delta for all five project-management specs. The +1/+1 on the MCP spec is pre-existing and filed as mcp-server-starter-projects leaks one flow and one project per run, hidden by the next run's cleanup #1376.

Force-fail — executed, one mutation per test in scope

Mutation Result
A — drop the id branch from both selector builders (i.e. the pre-#1363 addressing) 9 of 9 UI tests failed (1–5, 7–10); the two API-only tests and the untouched siblings passed
B — drop the name branch unit 516, 517, 520 failed — the 1.11.x half is guarded, not decorative
CcleanOldFolders filter matches nothing unit 109, 110, 111, 113 failed
DrenameProjectThroughSidebar stops filling the input (no rename happens) tests 1, 4, 5 failed on toContainText; tests 2 and 3, which do not rename, passed — this is what proves the new observable detects a rename that did not commit
E — mutate flow.folder_id and numberOfErrors the two untouched tests inside touched files failed
F@destructive kebab pointed at a non-existent id TimeoutError: locator.click. It needed its own mutation: A does not break it, because it derives the suffix from the DOM and is therefore spelling-agnostic by construction

Revert proven: grep FF_MUTATION over tests/ returns 0, followed by a final green run.

Dependencies

None — pure UI plus REST. No LLM, no provider key. Parallel-safe: every test addresses only projects it created, and cleanup is id-scoped.

🤖 Generated with Claude Code

…1363)

Upstream 23f91d8587 ("fix(authz): support scoped project visibility", #14429)
re-keyed the home sidebar's testids from the project NAME to its ID, on the
release-1.12.0 line the nightly is cut from:

  sidebar-nav-${item.name}                          -> sidebar-nav-${item.id}
  more-options-button_${convertTestName(item.name)} -> more-options-button_${item.id}

Seven @stable tests across four specs hard-failed on the 2026-08-07 daily and
were quarantined at triage. This lifts that quarantine.

Verdict: an internal rename of an automation hook, not a product regression.
Measured live on 1.12.0.dev20 — the name is still the entry's text and the
kebab's accessible name (aria-label="Options for <name>"), so nothing a user or
a screen reader observes was lost, and no REGRESSIONS.md row is owed. The entry
is not gated away by the ProjectRenamePermission wrapper the same commit adds:
it always renders its child, canRename only guards onDoubleClick.

Addressing now lives in one place, helpers/ui/project-sidebar.ts, matching BOTH
spellings as a single locator. Not a hedge: main still renders the name-derived
testid and manual.yml dispatches the @stable set against 1.11.x release
candidates before every sign-off, so pinning the id alone would trade seven
tests red on the nightly for seven red on the lane that signs releases off. The
two can never both match — an entry carries exactly one testid, and a project's
name is never another project's uuid. The name branch carries its deletion
trigger.

Second defect, riding on the first: cleanOldFolders drove the kebab through the
name-derived testid, so it had been deleting NOTHING and merely timing out on a
click — the mechanism behind the New Project -> New Project (5) accumulation the
daily's retries recorded inside one test. It now sweeps through the REST API,
because it is teardown of the PREVIOUS run and must not depend on the UI state
the test it precedes is about to assert on (the argument
removeLeftoverRenamedProject already makes in the same file). Measured: 3
seeded New Project* projects, 0 survived.

The rename assertion had to change observable. The id-derived testid does not
change with a rename, so asserting on it would pass whether the rename committed
or not; the entry's TEXT is asserted instead.

Also fixed: the two specs carrying the same addressing that were latently broken
and invisible to the daily for want of @stable (folder-drag-drop-flow,
flow-navigation-between-folders), and the @destructive loop's isVisible()
fallback, which could delete a folder other than the one it had just hovered.

Unit-covered: the selector builders (both spellings, exact matching, escaping)
and the cleanup sweep.
Copilot AI lite review requested due to automatic review settings August 8, 2026 06:38

Copilot AI 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.

Pull request overview

Updates the e2e suite’s project-sidebar addressing to be resilient to upstream Langflow changing data-testid keys from project nameproject id (release-1.12.0 line), restoring quarantined @stable coverage and hardening cleanup.

Changes:

  • Introduce a shared ProjectRef-based sidebar locator helper that matches both id- and name-derived testid spellings.
  • Refactor affected specs + MainPage helpers to address projects via { id, name } instead of name-only selectors; restore @stable and remove test.fixme.
  • Move cleanOldFolders from UI-driven deletion to REST API deletion and add unit coverage for the new selector/cleanup behaviors.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/tests-automations/regression/mcp/server/mcp-server-starter-projects.spec.ts Unquarantines the spec and switches folder CRUD interactions to id/name-aware sidebar helpers.
tests/tests-automations/regression/core-functionality/project-management/folder-drag-drop-flow.spec.ts Uses projectSidebarEntry with { id, name } to find/click the folder reliably.
tests/tests-automations/regression/core-functionality/project-management/folder-deletion-integrity.spec.ts Restores @stable tests and replaces name-derived sidebar/kebab selectors with shared helpers.
tests/tests-automations/regression/core-functionality/project-management/folder-crud.spec.ts Refactors create/rename/delete assertions to use ProjectRef and text-based rename verification.
tests/tests-automations/regression/core-functionality/project-management/flow-navigation-between-folders.spec.ts Updates sidebar addressing for both folders to use { id, name } refs.
tests/tests-automations/regression/core-functionality/project-management/bulk-actions.spec.ts Switches sidebar click to the id/name-aware entry locator and restores @stable.
tests/pages/MainPage.ts Changes project helpers (deleteProject, clickProject, uploadFlowByDragDrop) to accept ProjectRef.
tests/helpers/ui/project-sidebar.ts Adds centralized selector builders + locators + openProjectOptions supporting both upstream spellings.
tests/helpers/ui/project-sidebar.test.ts Adds unit tests validating selector matching semantics (id vs name/slug, exactness, escaping).
tests/helpers/flows/create-project-through-sidebar.ts Returns ProjectRef and updates rename helper to return the renamed ProjectRef with a stronger observable.
tests/helpers/filesystem/clean-old-folders.ts Reworks cleanup to delete New Project* folders via REST API (id-scoped) instead of sidebar UI.
tests/helpers/filesystem/clean-old-folders.test.ts Adds unit tests for the API-based cleanup behavior and safety properties.
docs/mcp/server/mcp-server-starter-projects.md Documents the new sidebar addressing helper and updates validation metadata.
docs/core-functionality/project-management/folder-deletion-integrity.md Updates spec doc steps/dependencies to reflect id/name-aware sidebar addressing.
docs/core-functionality/project-management/folder-crud.md Updates rename observable and external dependency notes for the new addressing scheme.
docs/core-functionality/project-management/flow-navigation-between-folders.md Updates validation/dependency text to reflect the new project-sidebar addressing.
docs/core-functionality/project-management/bulk-actions.md Updates validation metadata and sidebar addressing dependency description.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Victor-w-Madeira
Victor-w-Madeira merged commit 05ed9ad into main Aug 8, 2026
7 of 8 checks passed
@Victor-w-Madeira
Victor-w-Madeira deleted the fix/issue-1363-project-sidebar-addressed-by-id branch August 8, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Daily #1361] project sidebar — every project is addressed by name, but the entry no longer carries a name-derived testid (7 tests, 4 specs)

2 participants