Skip to content

refactor(resources): one canonical view per resource, mounted on source/grants/host - #6279

Open
waleedlatif1 wants to merge 3 commits into
stagingfrom
improvement/resource-views-final
Open

refactor(resources): one canonical view per resource, mounted on source/grants/host#6279
waleedlatif1 wants to merge 3 commits into
stagingfrom
improvement/resource-views-final

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Introduce a resource-view architecture: every resource view is mounted on three explicit axes — source (workspace vs share), grants (write/run), and host (page/panel/public) — defined as pure TypeScript in apps/sim/resources/**
  • Collapse the per-surface duplicates into one canonical view per resource kind, so a file/table renders from the same component whether it is a page or an embedded panel
  • Make the security property structural rather than conventional: shareSource.hrefFor always returns null, and a kind with no public route is typed never in ResourceSeedMap, so an anonymous surface cannot construct a workspace URL or address a resource the share does not grant
  • Route URL-state writes through hostOwnsUrl(host) — the single place the "only a page owns the address bar" rule is spelled — so embedded views stop writing nuqs keys into the parent's URL
  • Add scripts/check-resource-views.ts, a ratcheted gate covering wrapper mounts, shadow-named Embedded* components, imports past a barrel, cross-tree imports, unsanctioned props, and 'use client' leaking into the axis modules

Behavior-neutral for users, with three deliberate exceptions:

  • ActionRow's divider referenced var(--divider), which is not defined anywhere — it silently fell back to currentColor. Now var(--border).
  • Removed a 'form' trigger type that was advertised in six registries with nothing producing it. It would have rendered a dead "Form" chip in the Logs filter, a dead trigger option in the workflow editor, and advertised a form trigger to copilot block metadata.
  • Swapped the remaining lucide-react imports to @sim/emcn/icons. lucide-react is no longer in package.json, so two of these files would have failed the build.

Type of Change

  • Refactor (plus three small fixes noted above)

Testing

Typecheck clean, all 15 repo gates pass, biome clean across every changed file, full suite green (18,626 tests).

Not visually verified. Worth a look before merge — the knowledge base page is the highest risk, since its header, toolbar, and table were restructured under ResourceRoot.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…ce/grants/host

Extracts the file and table views out of their route folders into canonical
units under `apps/sim/components/resources/**`, and gives every consumer one way
to mount them. Behavior-neutral: no page, no API route, and no migration is
added or removed, and every default is preserved.

The three axes (`apps/sim/resources/**`, pure TypeScript so a Server Component
can build one during SSR):

- `source` — where the data comes from and by what address, `WorkspaceSource<K> |
  ShareSource<K>` discriminated on `via`. Replaces `workspaceId`, `token`,
  `contentSource`, `isPublic`. `ShareSource` declares `workspaceId?: never`, so a
  share token can no longer be laundered through a workspace-shaped slot.
- `grants` — what this viewer may do: `{ write, run }`. Replaces `canEdit`,
  `canRun`, `canAdmin`, `disableEdit/Insert/Delete`.
- `host` — who owns the URL, the router, the document frame. Replaces
  `embedded`; `hostOwnsUrl(host)` is the single home of the "embedded views do
  not write nuqs keys" rule.

`file` is the only kind with a share seed, because `/f/[token]` is the only
public route that serves one. Every other kind is `never` and cannot be
addressed by a token at all — a compile-time fact rather than a runtime check.

Also in this PR:

- Public share auth (password / email-OTP / SSO) moves out of `app/f/[token]`
  into `components/public-share/**`, behind one page-side gate. Security
  hardening on the way: timing-safe OTP comparison, a per-IP bucket on OTP
  verify separate from the send path, and share tokens removed from logs.
- Log status chrome (`StatusBadge`, `STATUS_CONFIG`, `getDisplayStatus`) moves
  to `components/execution-status/`, shared instead of per-surface.
- `AnchoredContextMenu` and `ActionRow` move to `components/`, which closed a
  real hole: `file-view` is mounted by `app/f/[token]` for anonymous visitors,
  and with no `sideEffects: false` its import of the workspace barrel pulled the
  whole authenticated tree into the public chunk.
- emcn: `ChipPasswordInput`, a shared `ChipChevronDown`, and byte-range /
  untitled-title utilities behind the file preview routes.
- Deployed-chat header now renders the shared `Navbar` in `logoOnly` mode, so a
  public chat wears the same wordmark, geometry, name and "Shared by" credit as
  the shared file page. This drops the GitHub star chip from that header.
- `ActionRow` used `var(--divider)`, which is not a defined token, so its
  dividers fell back to `currentColor`. Now `var(--border)`.

Nothing here advertises a capability it cannot deliver: the `form` trigger type
that arrived with this work drives nothing on its own, so it is not registered in
the Start block's trigger list, the Logs filter, the execute contract, or the
executor's streaming types. It lands with the surface that produces it.

Enforced by `bun run check:resources` (added to CI), which ratchets counters for
wrappers, imports past a unit barrel, cross-tree imports, unsanctioned props,
token-as-workspaceId, and context leaks. The cross-tree counter is re-based to
the current tree: every offender it counts is inherited, and this change strictly
reduces the number.

Verification: apps/sim + 22 packages typecheck, biome clean, 18598 tests pass,
and all 15 repo gates pass including both strict variants.
@waleedlatif1
waleedlatif1 requested a review from a team as a code owner August 5, 2026 03:37
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 5, 2026 4:05am

Request Review

@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR Summary

Cursor Bugbot is generating a summary for commit 001cbb4. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile-apps

@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR consolidates file and table resource rendering around canonical views parameterized by source, grants, and host, while reorganizing shared UI and public-share infrastructure.

  • Adds typed resource axes and canonical resource components for workspace, panel, and public surfaces.
  • Moves shared file, table, chat, public-share, context-menu, and presence components out of route-specific trees.
  • Refactors public file routes, table queries/services, and workspace consumers to use the shared architecture.
  • Adds a CI audit enforcing resource-view boundaries and removes obsolete trigger and icon-library usage.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/resources/source.ts Introduces discriminated workspace/share sources, preventing share sources from carrying workspace identifiers or producing workspace links.
apps/sim/components/resources/file-view/file-view.tsx Consolidates workspace, panel, streaming, and public file rendering into one canonical view driven by source, grants, and host.
apps/sim/app/f/[token]/public-file-view.tsx Mounts the canonical file view with a token-based share source, read-only grants, and public host behavior.
apps/sim/app/api/files/public/[token]/content/route.ts Refactors public content serving while retaining active-share resolution, deployment authentication, rate limiting, and ranged media responses before storage access.
apps/sim/components/resources/table-view/index.ts Establishes shared table-view exports and data contracts used by the workspace table grid.
apps/sim/hooks/queries/tables.ts Updates table query and mutation integration while preserving typed contracts and authoritative cache refresh behavior.
scripts/check-resource-views.ts Adds static enforcement for canonical mounts, import boundaries, axis purity, and prohibited route or permission context access.
.github/workflows/test-build.yml Adds the resource boundary audit to CI and removes the explicit ripgrep installation step.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Workspace[Workspace page] --> WS[Workspace source]
  Panel[Embedded panel] --> WS
  Public[Public share page] --> SS[Share source]
  Permissions[Workspace permissions] --> WG[Workspace grants]
  SharePolicy[Share policy] --> SG[Read-only share grants]
  WS --> View[Canonical resource view]
  SS --> View
  WG --> View
  SG --> View
  PageHost[page host: owns URL] --> View
  PanelHost[panel host: no URL ownership] --> View
  PublicHost[public host: no workspace links] --> View
  View --> File[File content and collaboration]
  View --> Table[Table rendering and editing]
Loading

Reviews (3): Last reviewed commit: "fix(file-view): correct the data-table s..." | Re-trigger Greptile

Navbar's actions slot is not gated by hideBrand, so a whitelabeled public
chat or shared file rendered a Share menu whose drafted post advertised
Sim. Compose the mention from brand.name when brand.isWhitelabeled,
matching the rule the email footer already applies.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile-apps

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c013365. Configure here.

data-table.tsx moved one directory deeper during the migration but kept
its './document-table.css' import. The stylesheet is shared at the
components/ level — both rich-markdown-editor importers already use
'../document-table.css' — so this was the lone stale path. TypeScript
does not resolve bare CSS imports, so only the production build caught it.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile-apps

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 4da3df5. Configure here.

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.

1 participant