mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
fix(webapp): a project URL by name opens the project (BEA-140) (#180)
Two personas guessed /wiki independently — the project name is what the
sidebar shows them, and the id (4c400e3f-…) never appears in the UI as
something to copy. Both got a page that argued with itself: the correct
project's chrome, breadcrumb and full file tree, with a body reading
"Project not found. This project doesn't exist, or you're no longer a
member." One of them owned the project.
Both halves land in the same place, and the net effect is one conditional
removed. `projectMissing` becomes an early return:
- A first segment that names exactly one of your projects, matched
case-insensitively on the DECODED segment (route.project is the
still-encoded slice, so a name with a space would never have
matched), redirects to /<id> with the rest of the URL — path, view,
target, filters, version — carried along. Exactly one: ProjectDB
names are scoped per organization, so a viewer in two orgs can hold
two projects called "wiki", and the not-found page is the honest
answer there.
- Anything else renders the not-found body in a shell with NO tree —
the same shape the `!current` branch already uses — so no other
project's files sit beside a body denying the one that was asked
for. The copy names the segment and drops the "no longer a member"
claim, which was told to readers who may never have been members.
The `current` fallback chain is untouched: "Back to <project>" still
points at it. With the early return in place, none of the four redirects
below can be reached on a missing project, so the `if (!projectMissing)`
wrapper is gone and its reason now lives in the return.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1868228d29
commit
52156f1b21
@@ -54,6 +54,7 @@ classDiagram
|
||||
+historyFilterQuery(filters) / hasHistoryFilters
|
||||
+urlForPath(path, projectId, version)
|
||||
+urlForView(view, projectId, target, filters) / encodePath / decodePath
|
||||
+projectByName(projects, seg) id, only when exactly one name matches
|
||||
}
|
||||
class nav {
|
||||
+navigate(url)
|
||||
@@ -62,6 +63,7 @@ classDiagram
|
||||
+Redirect
|
||||
}
|
||||
note for router "Two lookups on peer-authored path segments are now prototype-safe and one is throw-safe: legacyView() goes through Object.hasOwn, because LEGACY_VIEWS['constructor'] is truthy and turned a folder of that name into a view whose name was a FUNCTION; decodePath falls back to the raw segment instead of letting decodeURIComponent throw URIError out of a useMemo during render. Same shape as ProjectIcon's PROJECT_ICONS lookup in shell.tsx"
|
||||
note for router "projectByName is what makes /wiki reach the project called wiki: the id never appears in the UI as something to copy, so a hand-typed first segment is the NAME the sidebar shows. It decodes the segment (route.project is the still-encoded slice) and returns an id only on EXACTLY one case-insensitive match — ProjectDB names are scoped per organization, so a viewer in two orgs can hold two projects named wiki and guessing between them is worse than the not-found page (BEA-140)"
|
||||
note for nav "nav.ts + router.ts — deliberately NOT a router library (react-router v7 startTransition left stale views); History-API path routing, slashes literal, every user-facing page owns a URL path. A version is not a view route (the first segment after the project id is reserved for view names) — it rides as ?v=, so useLocationPath must snapshot the search too or the URL changes and nothing re-renders"
|
||||
|
||||
class api {
|
||||
|
||||
Reference in New Issue
Block a user