docs(storybook): story the object browser — file tree, breadcrumbs, and object detail - #521
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Claude finished @alukach's task in 1m 23s —— View job Reviewing PR #521
✅ No blocking issues — safe to merge. Traced the pieces this PR depends on to confirm the story fixtures actually match production behavior:
No correctness, security, or best-practice issues found in the diff. Simplify (ponytail): none — 💰 Estimated review cost: $0.43 · 1m23s · 25 turns |
`logging.ts` ends with a debug line whose `context` was `__filename` -- a CommonJS global -- and that line runs on import. Any browser bundle reaching this module threw `ReferenceError: __filename is not defined` before rendering anything. The field is a debug label naming where the log came from, so a literal does the job. This is the actual cause of the render failures worked around in #514, #517 and #520. I had attributed them to server actions dragging the AWS SDK into the browser; the actions were only one of several routes to this module, and the barrels were others. Confirmed by disabling every sb.mock() and rebuilding: DataConnectionForm renders in full without any of them. Worth considering separately: an ESLint rule banning __filename and __dirname outside scripts/ would have caught this, and would catch the next one. tsc clean · jest 65 suites / 567 tests · next lint 0 errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
Five stories for DirectoryList: the root of a product, one directory down, an empty prefix, awkward names, and 250 rows through the virtualizer. Every one of them otherwise needs real objects behind the data proxy to look at. The real S3CredentialsProvider and UploadProvider wrap each story through a decorator, because the rows read upload progress from context. They are the real providers, not stubs, and no credential is ever minted -- nothing here uploads -- so no `credentials` mock is needed. I added one, found it unused, and removed it again. Stacked on the __filename fix, which is what made any of this renderable. tsc clean · jest 65 suites / 567 tests · next lint 0 errors · storybook build succeeds. Stories opened and confirmed rendering, including the 4 TB / 1 B size formatting and the truncated 100-character filename. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
alukach
force-pushed
the
stories/object-browser
branch
from
August 28, 2026 00:46
0c87565 to
6f9bed9
Compare
alukach
added a commit
that referenced
this pull request
Aug 28, 2026
`src/lib/logging.ts` ends with a module-scope debug call:
```ts
LOGGER.debug("Loaded Config", { operation: "config", context: __filename, ... });
```
`__filename` is a **CommonJS global**, and this line runs on import. Any
browser bundle that reached this module threw `ReferenceError:
__filename is not defined` before rendering a single element.
The field is just a debug label naming where the log came from, so a
literal does the job. One line.
## This is the cause of the crashes worked around in #514, #517 and #520
I had attributed those to server actions dragging the AWS SDK into the
browser. **That was wrong.** The actions were only one of several routes
to `logging.ts`; the `@/lib` and `@/components/core` barrels were
others. The AWS SDK was never the problem.
Verified rather than assumed: with **every** `sb.mock()` disabled,
`DataConnectionForm` renders in full.
## What that means for the mocks already merged
They still earn their place — a story submitting a form would otherwise
invoke a real server action, and `searchAccounts` returning fixtures is
the only way the account picker's suggestion list draws. But *"these
components cannot render without mocks"* was not a true reason, and the
mock list can likely be trimmed. That deserves its own change rather
than being folded in here.
## Worth considering separately
An ESLint rule banning `__filename` / `__dirname` outside `scripts/`
would have caught this, and would catch the next one.
## Verification
`tsc` clean · jest 65 suites / 567 tests · `next lint` 0 errors.
The Storybook stories that this unblocks are stacked in #521.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
BreadcrumbNav gets six stories. The one worth having is Truncated: past four segments it collapses to the first two, an ellipsis, and the last two, and a real product rarely hands you a path that deep on demand. Also the rule that the current directory is plain text while the same segment becomes a link once a file sits below it. DirectoryList gets a Browsable story that actually navigates. In the app a directory is a <Link> and the server re-fetches the listing for the new URL; Storybook has neither, so clicks went nowhere and each story was a single frozen level. This holds the prefix in state, derives the listing from one fixture tree, and intercepts clicks on links into the product. That is a stand-in for the routing rather than the routing itself, and the story says so -- but going down and back up with the breadcrumb keeping pace is the thing worth reviewing, and it is reviewable now. Verified in a browser rather than assumed: root -> recordings -> 2019 shows the two recordings, the breadcrumb walks back up through recordings to root, and clicking a file leaves the listing alone. The first attempt failed on a slash -- a row's href ends in "/" where a breadcrumb's does not -- which the guard now normalises away. tsc clean · jest 65 suites / 567 tests · next lint 0 errors · storybook build succeeds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
…il view Browsable becomes Default and moves to the top of the file, since a listing you cannot move around in is half the component. The two static stories it supersedes are gone: its opening state was the old Default, and one click reaches what InADirectory showed. Empty, AwkwardNames and Virtualized stay -- those are states navigation cannot reach. ObjectSummary gets six stories. Its two conditional rows are the point, and both are awkward to arrange in the app: Cloud URI appears only with a resolved connection and takes a different shape per provider -- s3:// on S3, an HTTPS blob URL on Azure, absent on GCS -- and Checksum appears only when the object carries a sha256, bringing the verifier with it. Confirmed all three provider branches render as described, including GCS having no Cloud URI row at all rather than an empty one. Also sets NEXT_PUBLIC_S3_ENDPOINT for the Storybook build. CONFIG reads it with no fallback, so every Source URL rendered as "undefined/cascadia-research/..." -- which on a published page reads as a bug in the product rather than a gap in the environment. It goes through a vite `define`: Storybook's own `env` does not reach it, because the Next builder inlines NEXT_PUBLIC_* at build time from the real environment. tsc clean · jest 65 suites / 567 tests · next lint 0 errors · storybook build succeeds. Default verified still navigating after the promotion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
Storybook title-cases an export name to label the story, which turned OnS3 into "On S 3". An explicit `name` fixes the label; the story id stays as it was, so existing links keep working. Azure and Google Cloud get one too, for consistency rather than because they were broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE
alukach
added a commit
that referenced
this pull request
Aug 28, 2026
Two conflicts, both in stories main had also touched: - InviteMemberForm: main dropped the product-scoped story and its fixture (it rendered identically to the org one), so take main's side. - ProductCreationForm: main gave the archive connection an owner so it filters on owner change (#522); keep that and rename it to miskatonic. Main also added stories that carried the old names — the object browser (#521) and BreadcrumbNav — so the same mapping is applied to them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Stories for the object browser — the file tree, the breadcrumbs above it, and the detail panel for a single object. 16 stories across three components.
The
__filenamefix that made any of this renderable went in separately as #524, which has merged; this PR is stories plus one Storybook config line.DirectoryList— and it browsesDefault is navigable. In the app a directory is a
<Link>and the server re-fetches the listing for the new URL. Storybook has neither a server nor a real router, so clicks went nowhere and every story was one frozen level.Defaultnow holds the prefix in state, derives each listing from a single fixture tree, and intercepts clicks on links into this product. That is a stand-in for the routing, not the routing itself — the story says so — but it makes the thing you'd actually want to check reviewable.Verified in a browser rather than assumed:
root→recordings→2019shows the two recordings;recordingstoroot;The remaining three cover states navigation cannot reach: Empty (an empty prefix, not an empty product), AwkwardNames (a 100-character filename beside a 1-byte and a 4-terabyte file), and Virtualized (250 rows, past
MAX_VISIBLE_ITEMS).The two static stories an earlier revision had are gone — the browsable one opens on what
Defaultshowed, and one click reaches whatInADirectoryshowed.BreadcrumbNavSix stories. The one that earns its place is Truncated: past four segments the path collapses to the first two, an ellipsis, and the last two, and a real product rarely hands you a path that deep on demand. Also the rule that the current directory renders as plain text but the same segment becomes a link once a
fileNamesits below it.ObjectSummary— the object detail viewSix stories. Its two conditional rows are the point, and both are awkward to arrange in the app:
s3://bucket/…on S3, anhttps://account.blob.core.windows.net/…URL on Azure, and no row at all on GCS. All three confirmed in a browser.sha256, and brings the verifier with it. That verifier is live — pressing it fetches the object, which fails here. The button and its states are what the story shows, not a passing check.One config line, and why it is needed
CONFIG.storage.endpointreadsNEXT_PUBLIC_S3_ENDPOINTwith no fallback, so every Source URL rendered asundefined/cascadia-research/…. On a published page that reads as a bug in the product rather than a gap in the environment.It goes through a Vite
definerather than Storybook's ownenv: the Next builder inlinesNEXT_PUBLIC_*at build time from the real environment and never consultsenv. I tried that first and the value stayedundefined.Providers, not stubs
The real
S3CredentialsProviderandUploadProviderwrap theDirectoryListstories through a decorator, because the rows read upload progress from context.No
credentialsmock. Nothing here uploads, so no credential is ever minted. I added the mock, found it unused, and removed it.Verification
tscclean · jest 65 suites / 567 tests ·next lint0 errors ·storybook buildsucceeds.🤖 Generated with Claude Code
https://claude.ai/code/session_011mnsg8m1dXZ5z5ig5xMtkE