Commit Graph
5020 Commits
Author SHA1 Message Date
Claude eeeae037da feat(storage): make version list mocks adapt to bucket policy
- Remove the 'Restoring is non-destructive' admonition from the
  bottom of the Versions tab
- Refactor getMockObjectVersions to accept the bucket's current
  cap and expiryDays and adapt its output so version-list labels
  are always consistent with the policy:
    * Never returns a version older than the retention window
      (no 'Past Nd limit' surprises when the user set fewer days)
    * Never returns more noncurrent versions than the cap
      (no '#3 of 2' when the user tightened the cap)
- Anchor all version timestamps to the real clock via
  daysAgoFromNow so the mock stays fresh regardless of when the
  prototype is opened, instead of drifting away from the fixed
  BASE_DATE
- Wire useObjectVersionsQuery to look up the bucket's protection
  and pass it into the mock on every fetch, so policy edits from
  the bucket modal reflect in the panel next time it opens

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 14:40:45 +00:00
Claude b3d683628e feat(storage): add per-version expiry indicators to version history panel
Show expiration policy context directly in the Versions tab:
- Cap badge and retention badge in the header section
- Combined mode indicator (both/either) when both policies are set
- At-cap and nearing-cap warnings
- Per-version VersionExpiryIndicator showing days remaining and
  cap position (#N of M) with warning colors based on combined
  and/or policy logic
- Pre-computed noncurrent indices for efficient lookup
- Versioning-suspended admonition banner

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 14:21:44 +00:00
Claude 93ee4b82b8 fix(storage): validate expiration inputs inline on change, simplify error
- Call trigger() after each field.onChange so zod validation runs
  immediately as the user types, surfacing errors via FormMessage
- Simplify the S3 cap error message to 'Cannot exceed 100 versions'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 14:05:54 +00:00
Claude 54c9f84cb3 fix(storage): enforce S3 max 100 versions via zod, remove native HTML validation
- Add S3_MAX_NONCURRENT_VERSIONS constant (100) and enforce it in
  superRefineBucketProtection independently of plan limits
- Remove HTML min attributes from both inputs so only Supabase inline
  errors (FormMessage via FormItemLayout) appear — no browser tooltips
- Plan-specific bounds still enforced as before; the S3 cap is checked
  first with a distinct error message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 13:53:56 +00:00
Claude 57b359af4e fix(storage): rewrite explainer examples in active voice with full sentences
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 13:05:10 +00:00
Claude 690f6dabdf fix(storage): improve explainer examples for both/either scenarios
- 'both' mode: show a second example where one condition isn't met,
  making it clear the version is kept because both must be exceeded
- 'either' mode: show two examples — one where only the version cap
  is exceeded, one where only the age limit is exceeded — to
  illustrate that either condition alone triggers deletion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 12:44:58 +00:00
Claude 6c5622c4a5 fix(storage): simplify explainer examples to +1 above the set values
- Days only: show a version at days+1 (deleted) vs days-1 (kept)
- Versions only: show versions+1 total, oldest one gets deleted
- Both conditions: show versions+1 at days+1, explain the and/or logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 12:16:27 +00:00
Claude f2713c4214 fix(storage): use 'versions' suffix and show explainer for single conditions
- Change InputGroupText suffix from 'max' to 'versions' on the retained
  noncurrent versions input
- Show 'See how this works' explainer when either expiration field has a
  value, not only when both are set
- Add context-specific explainer text for days-only, versions-only, and
  both-conditions cases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 11:04:12 +00:00
Claude b9b8a7cb12 refactor(storage): use InputGroup design system pattern for expiration inputs
- Replace custom raw <input> elements with FormItemLayout + InputGroup +
  FormInputGroupInput + InputGroupAddon pattern from the design system
- Use layout='flex-row-reverse' for label-left, input-right alignment
- Both version_expiry_days and max_noncurrent_versions default to empty
  (no prefill on toggle)
- Add warning Admonition when no expiration policy is configured to
  alert about ongoing storage costs
- Remove unused useFormState import and prefill logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 10:53:41 +00:00
Claude 98e9e12a05 Redesign expiration policy section with sentence builder and inline toggle
Replace the standard form-field layout with the design-handoff UI:

- Sentence builder paragraph that adapts to which fields are filled
  (both empty → 'retained indefinitely', one filled → describes that
  condition, both filled → sentence with inline toggle)
- Inline [both | either] pill toggle embedded in the sentence text
  when both conditions are set (maps to ExpirationMode 'and' / 'or')
- Compact number inputs with suffix labels ('days' / 'max'),
  right-aligned text, and em-dash placeholder
- Collapsible 'See how this works' section with a dynamic example
  that uses the actual input values and updates on toggle
- Both fields are now optional — empty means 'no limit' for that
  condition. Validation only checks min/max when a value is provided.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 10:27:06 +00:00
Claude 6e8a01d7cb Use solid HSL colors for tree connector lines to avoid overlap artifacts
Replace bg-border-stronger (oklch with alpha) with solid hsl values:
- Light mode: hsl(0 0% 80%) — neutral mid-gray
- Dark mode: hsl(0 0% 30%) — neutral mid-gray

This prevents the accentuated color at the intersection where
the vertical and horizontal lines overlap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-11 10:06:22 +00:00
Claude c20faa7ff7 Move expand/collapse to header bar, dim tree lines, increase gap
- Lift expandedVersionIds state to DeletedFilesContext (shared between
  DeletedFilesList and FileExplorerHeader)
- Move 'Expand all' / 'Collapse all' buttons from the table header into
  the FileExplorerHeader top bar with outline button variant
- Change tree-connector line color from bg-foreground-muted to
  bg-border-stronger for a subtler appearance
- Increase gap between horizontal tree branch and version title text
  (pl-[22px] → pl-[36px], w-[11px] → w-[8px])
- Apply same tree line changes to standalone Trash page (TrashList)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 14:59:12 +00:00
Claude 889146ee06 fix(storage): stronger tree lines, gap before text, text expand/collapse buttons
- Tree connector lines use bg-foreground-muted instead of bg-border for
  better visibility
- Horizontal branch shortened from w-[15px] to w-[11px], creating a 4px
  gap between the line end and the version text (text still aligns with
  parent name)
- Replaced the icon-only expand/collapse toggle in the table header with
  two separate text buttons: 'Expand all' and 'Collapse all', separated
  by a dot divider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 14:35:06 +00:00
Claude cd47cebb5a feat(storage): tree-line connector for nested version rows
Replace CornerDownRight icon with CSS tree-connector lines for nested
version rows. Each version draws:
- A vertical line from the top border to the junction point (center)
- A horizontal branch from the junction to the version text
- For non-last versions, the vertical line continues to the bottom
  border, connecting seamlessly with the next row
- For the last version, the vertical line stops at the junction (└ shape)

Lines are positioned at left-[23px] to align with the parent row's
chevron center (16px cell padding + 7px icon center). Version text
starts at pl-[22px] to align with the parent row's name text.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 13:21:01 +00:00
Claude 4b3960cbc4 feat(storage): deleted files table — version selection, preview, mutations, expand/collapse all
- Version rows are now selectable via checkboxes for batch multi-selection,
  using composite keys (objectId::versionId) in the shared selection state
- Clicking a version row opens the preview panel with version-specific
  metadata (version ID, action, created date, size) and a 'no preview
  available' placeholder
- Aligned CornerDownRight icon with parent row chevron and version text
  with parent name text (both use gap-x-2 and size-14 icons)
- Added expand/collapse all toggle button in the table header top right
  (ChevronsUpDown / ChevronsDownUp icons)
- Restore and delete actions on version rows now perform real client-side
  effects: version-level mock store mutations + query cache invalidation
- Removed the Expires column from both DeletedFilesList and TrashList
- Extended DeletedFilesContext with selectedDeletedVersion state
- Added version-level mutation functions to protection-mocks.ts
- Added useTrashVersionRestoreMutation and useTrashVersionDeleteMutation
  hooks to bucket-trash-query.ts
- Updated Trash page (standalone) with version-level mutation wiring

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 12:55:51 +00:00
Claude 7c2b5bbce3 feat(storage): versioning hints, version URLs, nested deleted versions
- PreviewPane: add Info hint below Delete button when versioning is
  active, explaining that deleting soft-deletes the object and all
  versions and they can be restored from the deleted versions view
- VersionHistory: add Get URL (Copy) icon button on every version row
  alongside existing Download/Restore/Delete actions
- DeletedFilesList & TrashList: implement collapsible nested grouping
  for noncurrent versions under parent objects with ChevronRight/Down
  expand toggle, version count badge, and per-version Restore/Delete
  actions on hover
- protection-mocks: expand mock data from 8 to 12 trash objects with
  richer version histories (up to 6 noncurrent versions per object)
  to properly showcase the nested deleted versions UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 12:02:09 +00:00
Claude 3a0530d2d7 Add AND/OR expiration toggle, move deleted-versions toggle into header, update terminology
Task A: Add ExpirationMode (and/or) toggle between retention-days and
max-versions fields in bucket settings. 'and' = single S3 lifecycle policy
(both conditions must be met), 'or' = two independent rules (either triggers).
Wired into form schema, create/edit bucket modals, and mock store.

Task B: Move 'Show deleted versions' toggle from breadcrumb bar into the
file explorer table header, right of the search input. Switch is on the left
of the label text.

Task C: Add noncurrent version rows beneath each deleted object in TrashList.
Nested rows have left indentation with a CornerDownRight icon and lighter
background. Added DeletedObjectVersion interface and mock data to
protection-mocks.ts. Updated all user-facing terminology from 'files' to
'versions' across Trash, TrashList, TrashSelectionBar, DeletedFilesList,
DeletedFilesHeaderSelection, DeletedFilePreviewPane, and bucket page tabs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-07 11:03:16 +00:00
Claude 7ed23e9c43 Fix restore action placement, model versioning-suspended as a third state
- Reverted the timeline row's Restore action back to its icon-only
  text-variant button — the ask to make Restore a default-variant
  button was about the "Back to latest" action in the version
  preview banner, not the per-row action in the Versions tab
- The version preview banner's action is now labeled Restore, styled
  as a default-variant button, and actually restores the previewed
  version as current (instead of just clearing the preview)
- Versioning can no longer be turned fully "off" on a bucket that's
  ever had it enabled — it moves to a new suspended state instead,
  matching how bucket versioning actually behaves. Suspending only
  stops new noncurrent versions from being created; nothing already
  retained is deleted, so the destructive typed-confirmation flow for
  disabling versioning is gone
- Added `hasVersioningHistory` (enabled OR suspended) alongside the
  existing `isBucketVersioned` (enabled only) and repointed every
  surface that manages or warns about retained version/trash data to
  the former, since a suspended bucket can still be sitting on plenty
  of it
- Bucket list "Versioning" column, plan-downgrade admonition, and the
  Versions tab now all reflect the three states (Enabled / Suspended /
  never enabled)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 14:11:37 +00:00
Claude a86c1b593f Gate versions tab per bucket, refine version preview/history UI
- Versions tab in file preview now only shows when the current bucket
  has object versioning enabled, instead of the global feature flag
- Renamed the current-version badge from Latest to Current
- Previewing-version banner now puts the version date on its own line
- Restore action is now a labeled default-variant button instead of
  an icon-only text button
- Hover-underline moved from the timeline dot to the version date, and
  the currently-previewed version is now highlighted by coloring its
  date text and dot to match the brand color

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 12:51:10 +00:00
Claude a719509724 model full versioning journey: usage chart, edge cases, cap indicator
Usage breakdown & chart:
- Split "Object versions" into "Noncurrent versions" and "Soft-deleted files"
  in the Storage Size breakdown, in the mock data model, and in the chart's
  stacked bars.
- Wire the mock retention series into the Storage Size chart itself so the
  daily bars actually visualize the live / noncurrent / soft-deleted split,
  not just the inline breakdown.

Edge cases:
- Tightening retention (fewer days or fewer versions than the bucket already
  has) shows an inline admonition in the edit modal explaining that some
  retained data will be permanently expired on save.
- EmptyBucketModal: when the bucket is versioned, the destructive banner
  copy and an extra warning admonition call out that emptying also purges
  every noncurrent version and soft-deleted file.
- DeleteBucketModal: appends a note that all versions and soft-deleted files
  will be lost, when the bucket is versioned.
- Plan downgrade auto-disable-and-purge: on the buckets list, an effect
  detects when the org plan no longer supports versioning and invokes a new
  purgeVersioningOnPlanDowngrade() helper that flips every enabled bucket in
  the mock store back to disabled and clears the shared trash store, then
  shows a warning admonition listing the affected buckets.
- Public bucket + versioning: inline admonition in the modal explains that
  public buckets expose every version by default and points to an RLS-based
  mitigation (filter storage.objects by an isCurrent metadata flag).

Version cap indicator:
- In VersionHistory, show a `{count} / {cap} noncurrent` badge when a cap is
  configured, with contextual copy at ≥80% and at cap explaining that older
  versions auto-expire on the next overwrite.

Copy:
- Reword "Noncurrent version retention" and "Max noncurrent versions"
  descriptions to be concise/factual instead of using "this many" phrasing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 11:01:42 +00:00
Claude 2b5a4f4a3e require typed confirmation to disable versioning; show retained-data usage
- Disabling object versioning on a bucket that already has it enabled now
  requires typing the bucket name in a destructive TextConfirmModal,
  warning that every noncurrent version and soft-deleted file will be
  permanently deleted once saved. New buckets (never had versioning) skip
  this since there's nothing to lose. An inline Admonition also reflects
  the staged, not-yet-saved change in the form.
- Resume a (snapshot-free, adapted for this branch's object-level-only
  scope) version of the org Usage page's Storage Size breakdown: a
  Live objects vs Object versions split, a "retained recovery data"
  warning, and a per-bucket breakdown of retained bytes. Backed by a new
  mock retention-usage query (data/storage/protection/storage-retention-usage-query.ts),
  rendered via the Storage Size category's additionalInfo slot in
  /org/[slug]/usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 10:14:11 +00:00
Claude e7cf4d8143 remove left border/padding on revealed object versioning fields
Applies to both the "Create new bucket" and "Edit bucket" modals since
they share BucketDataProtectionFields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 10:02:22 +00:00
Claude 0528e7a5f1 prefill versioning defaults on enable; overlay deleted-file preview panel
- Prefill "Noncurrent version retention" and "Max noncurrent versions"
  with the plan's default values when the Object versioning switch is
  turned on (only if the fields are still empty), so users can save
  immediately instead of starting from a blank input.
- In the deleted files view, render the preview panel as an absolutely
  positioned overlay over the rows instead of a flex sibling that
  shrinks the table. Rows keep their full width and stay horizontally
  scrollable underneath the panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 09:27:05 +00:00
Claude b44b13f4fa polish bucket versioning UI and gate deleted files toggle
- Show an "Enabled" badge instead of "object-level" text under the
  buckets list "Versioning" column, since only object-level versioning
  exists in this scope.
- Tighten vertical padding on deleted files table rows (px-4 py-2
  instead of the default p-4).
- Only show the "Show deleted files" toggle for buckets with versioning
  enabled; move the Switch to the right of its label.
- Move isShowingDeleted from local useState to a nuqs query param
  (?deletedFiles=true) so the deleted files view is linkable/bookmarkable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 09:12:06 +00:00
Claude 30eb897d9d fix ButtonTooltip crash and resume table row UI for deleted files list
- Fix "Cannot read properties of undefined (reading 'content')" crash:
  the snapshot-removal pass dropped the required `tooltip` prop from two
  ButtonTooltip calls (TrashList's per-row delete, Trash's "Delete all
  permanently"). Swap both to plain Button since no dynamic tooltip is
  needed there.
- Rework DeletedFilesList (the "Show deleted files" switch view, now
  the default buckets page) from stacked card rows into a proper single-line
  Table matching the Files/Deleted files tab's TrashList row styling and
  column headers (Object, Original location, Deleted, Size, Expires).
- Add per-row Restore/Delete permanently actions that only reveal on row
  hover, alongside the existing multiselect checkbox and click-to-preview
  behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 08:50:09 +00:00
Claude b0582e496b remove "held by a snapshot" concept
Snapshots aren't implemented in this branch yet, so drop the
heldBySnapshot field from TrashObject/ObjectVersion mocks and all
related UI: disabled states, tooltips, badges, and copy across the
deleted files list/preview, version history, and bulk trash actions.
Delete-all/permanent-delete mutations now act on every selected/listed
item unconditionally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 08:31:32 +00:00
Claude fecea6bf06 mock client-side mutations for bucket versioning + deleted files
- Bucket versioning: create/edit bucket modals now write to an in-memory
  mock store (setMockBucketProtection) on save, so the buckets list
  "Versioning" column reflects the change immediately. Resets on page
  refresh since it's plain module state (no real API yet).
- Deleted files: restore/permanent-delete mutations now actually mutate
  the trash mock store instead of no-op delaying, so the deleted files
  list updates after restoring or hard-deleting items.
- Added 5 more dummy trash entries (8 total) with varied held/expiry
  states.
- Changed all "Delete permanently"/"Delete all permanently" trigger
  buttons to the `danger` Button variant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-06 08:12:18 +00:00
Claude 1514526241 tighten version history item spacing, swap hover bg for icon underline
- Reduce per-item bottom padding from pb-8 to pb-4
- Remove the hover/selected background on each version row entirely;
  instead underline the timeline dot on hover to signal interactivity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-05 17:22:25 +00:00
Claude 7b1dd94c79 use zod schema validation for object-versioning fields, not manual setError
- Move min/max/required validation for version_expiry_days and
  max_noncurrent_versions into a shared superRefine (BucketDataProtectionFields.schema.ts),
  called from each modal's own superRefine, instead of imperative
  validateVersioningFields() + form.setError() calls in onSubmit. Errors
  now surface the same way as the rest of the form (FormItemLayout/FormMessage),
  matching Studio's established form-error convention.
- Switch the fields to the '' empty-sentinel + z.coerce.number() union
  pattern (per the react-hook-form skill) instead of z.string().optional(),
  keeping inputs fully controlled without special-casing undefined.
- Build each modal's schema dynamically via useMemo(() => schema(planLimits), ...)
  since the versioning bounds depend on the async-loaded org plan.
- Replace destructured useFormContext().watch() with useWatch({ control, name })
  in BucketDataProtectionFields, avoiding the ratcheted no-use-watch lint warning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-05 15:55:16 +00:00
Claude 889ab611a6 make versioning number inputs deletable, enforce plan-based limits
- Move versioning fields (retention days, max noncurrent versions) from
  local useState into the parent form via react-hook-form + zod, fixing
  the bug where clearing an input forced it back to "0" and blocked
  typing a fresh single digit
- Show a validation error on submit if versioning is enabled but a
  field is left empty
- Gate object versioning by org billing plan: disable the toggle and
  show an upgrade prompt on the Free plan (which also doesn't support
  lifecycle policy management); enforce plan-specific min/max ranges
  for retention days and max versions on Pro/Team/Enterprise
- Add getVersioningPlanLimits() + validateVersioningFields() helpers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-05 13:28:40 +00:00
Claude 3f308fc266 add Versioning column to buckets list table
Shows "object-level" for buckets with versioning enabled, "-" otherwise,
based on the existing isBucketVersioned() mock helper. Snapshots-level
versioning will be added in a future iteration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-05 09:27:08 +00:00
Claude 54897d41b0 move batch actions to header, use FormItemLayout for versioning fields
Deleted files batch actions:
- Move Restore/Delete permanently buttons into the StorageExplorer header
  row (same position as the normal file selection bar)
- Show "X items selected" text on the far left, actions on the far right
- Update select-all row to show "Select/Unselect all X files" label

Bucket versioning fields:
- Use FormItemLayout with flex-row-reverse layout for retention and max
  versions fields (label left, input right)
- Use InputGroup with InputGroupAddon for unit suffixes ("days", "versions")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-04 15:47:09 +00:00
Claude 0d67829db2 tighten deleted file preview pane: less gap, sticky action footer
- Reduce vertical gap between detail fields from space-y-6 to space-y-3
- Make Restore/Delete permanently actions sticky at the bottom with a
  border-t separator, only the preview + details area scrolls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-04 14:56:29 +00:00
Claude d798b1df0b refine bucketsV2: move toggle to breadcrumbs, add multiselect, keep search visible
- Move "Show deleted files" toggle from StorageExplorer header to
  page-level breadcrumbs as a Switch control, left of Policies button
- Add checkbox multiselect for deleted files with bulk Restore/Delete
  permanently actions and shift-click range selection
- Keep search input visible when showing deleted files, with contextual
  placeholder text
- Add file preview thumbnail to deleted file preview pane
- Change "Delete permanently" button to default variant (matching Restore)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-04 14:30:00 +00:00
Claude 978d61948f feat(studio): add bucketsV2 view with integrated deleted files toggle
Add an alternative bucket view at /storage/files/bucketsV2/[bucketId]
that replaces the separate Files/Deleted files tabs with a unified
StorageExplorer. A "Deleted files" toggle button in the header's
actions bar (left of Navigate) switches between live files and
soft-deleted items inline.

When showing deleted files:
- The file listing is replaced with a DeletedFilesList showing all
  soft-deleted objects with name, size, deletion time, and origin
- Clicking a deleted item opens a dedicated DeletedFilePreviewPane
  with Original location, Deleted at, Deleted by, Size, Expires,
  and Restore / Delete permanently actions
- Upload, search, view options, and folder creation are hidden

The existing bucket page is unchanged (wrapped in DeletedFilesProvider
with enabled=false). The bucketsV2 route is navigable only via URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-04 14:02:42 +00:00
Claude ca875d2e0d feat(studio): add bucket versioning, object versions, and deleted files prototype
Scoped-down storage protection prototype with three features:
- Bucket-level versioning policy (retention days, max versions) in create/edit modals
- Object version history in the file preview pane with restore/delete actions
- Per-bucket deleted files (trash) view with bulk selection, restore, and permanent delete

All data is mock-backed behind the STORAGE_PROTECTION_ENABLED feature flag.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-08-03 16:58:25 +00:00
Joshen Lim a0cec24f49 Remove references to fly (#48648)
## Context

As per PR title - should not have any visual nor functional change 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Changes**
- Standardized infrastructure, region, and database configuration around
AWS-based environments.
- Removed Fly.io-specific region and provider options from project
creation, instance sizing, and infrastructure settings.
- Enabled disk validation, spend-cap eligibility, backup restoration,
and extension setup consistently across supported projects.
- Updated billing and region displays to use the applicable AWS
configuration.
- **Bug Fixes**
- Corrected project-specific restrictions that could incorrectly hide
configuration and billing controls.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 21:14:50 +07:00
Joshen Lim 8e3e14f198 Joshen/fe 4064 add a toast callout for feature preview (#48645)
## Context

Adds a banner toast for the database connections feature preview

<img width="315" height="322" alt="image"
src="https://github.com/user-attachments/assets/8caaab88-10a0-4a06-b678-25fc9c44dd81"
/>

## Other changes

As the observability page currently has a number of banner toasts
(metrics API, unified logs, index advisor for query performance), am
opting to REMOVE the metrics API's banner toast by virtue of how long
its been around for. Mainly to prevent over stacking of banner toasts as
it can be annoying.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a dismissible Database Connections banner with SQL examples and
a link to its feature preview.
  * Banner dismissal and CTA interactions are now tracked.
  * Dismissed banners can reappear when reintroduced.

* **Bug Fixes**
  * Banners are hidden after the feature is enabled or dismissed.
  * Improved banner handling to prevent duplicate active banners.

* **Changes**
* Replaced the Metrics API banner with the Database Connections banner.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 21:02:19 +07:00
Joshen Lim 9006e33f11 Add categories for feature previews (#48641)
## Context

Given that our number of feature previews have been expanding, am opting
to group them into categories for easier understanding of the context of
each feature preview.

Ideally we're able to tag all feature previews into categories (or add
more categories), but leaving the unclassified ones under "others" for
now

<img width="936" height="661" alt="image"
src="https://github.com/user-attachments/assets/b48bd9a2-fe33-4cb0-9288-1cd9c8264da0"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Feature previews are now organized into expandable categories.
  * Observability and database previews are grouped for easier browsing.
  * Uncategorized previews remain available under an “Others” section.
* Existing feature selection options and sorting behavior are preserved.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 17:30:09 +07:00
Danny White 76257f164b fix(studio): align storage row icon weight (#48480)
## What kind of change does this PR introduce?

Bug fix stacked on #48478.

## What is the current behavior?

Storage Explorer renders the custom closed-folder icon at `1.5` but
leaves the Lucide open-folder icon at its default `2`. The duplicated
file-picker implementation also uses a different set of stroke-width
overrides.

## What is the new behavior?

A shared `StorageRowIcon` renders loading, open and closed folder,
image, audio, video and generic file icons at `1.5` across Storage
Explorer, row editing and the bucket file picker.

Test by comparing open and closed folders and file-type rows in Storage
Explorer and the bucket file picker.

| Before | After |
| --- | --- |
| <img width="524" height="336" alt="CleanShot 2026-08-03 at 18 38
06@2x"
src="https://github.com/user-attachments/assets/15eb8b9f-69fc-4eee-8428-d7ec26dce8dc"
/> | <img width="522" height="328" alt="CleanShot 2026-08-03 at 18 39
20@2x"
src="https://github.com/user-attachments/assets/17b7dddd-8d36-421c-8356-c9c1bd7456e8"
/> |
| _Thicker image and file icon compared to folder icon_ | _Every icon
has the same stroke thickness_ |

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Standardized file, folder, media, and loading icons across storage
views.
* Improved visual consistency with unified icon sizing, styling, and
stroke width.

* **Tests**
* Added coverage for loading, folder, media, and generic file icon
states.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 19:37:54 +10:00
Joshen Lim fc69c45985 Bring database connections to feature preview (#48638)
## Context

As per PR title - brings Database Connections into feature preview
Should be working for both hosted + self-host/local

Also adjusts existing feature previews to remove "New"
- Platform webhooks
- Temporary database access

<img width="600" alt="image"
src="https://github.com/user-attachments/assets/b18ae8ca-ce0b-4649-975c-e70749a87dcd"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a Database Connections preview highlighting live activity, query
blocking detection, session termination, and AI-assisted summaries.
* Added access to project-specific observability connections from the
preview.
* Added a Database Connections entry to the observability menu when
enabled.

* **Improvements**
* Updated feature previews and labels, including changes to “new” status
indicators.
  * Added controls to manage Database Connections preview visibility.

* **Bug Fixes**
* Improved blocker detection so results respect the selected role
filters.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 16:48:59 +08:00
Alaister YoungandAlaister Young 3f5ac679e0 fix(studio): redirect to feature preview route after enabling (#48637)
Enabling a feature preview that has a route (e.g. Column-level
privileges) closed the modal but never navigated to the feature's page
on the TanStack runtime (local + staging). The modal closed itself via a
nuqs query-param update *and* called `router.push` — the queued nuqs
flush navigates to the pathname it captured before the push, landing
after the redirect and reverting it. The Next runtime was unaffected
because the stock nuqs pages adapter patches the URL shallowly via the
history API instead of navigating.

**Changed:**

- When the enabled preview has a `getRoute`, skip the explicit
`toggleFeaturePreviewModal(false)` — `router.push(route)` navigates
without the `featurePreviewModal` param, which is what closes the modal.
One URL update instead of two racing ones; works on both runtimes.
- Previews without a route keep the explicit close (unchanged behavior).

## To test

- On a project page, open Feature Previews (avatar menu), select
**Column-level privileges**, click **Enable feature** → modal closes and
you land on `/project/{ref}/database/column-privileges` with the "We've
taken you to where you can try it out." toast (no bounce back to the
previous page)
- Repeat with **Disable Advisor rules** → lands on
`/project/{ref}/advisors/rules/security`
- Enable a preview without a route (e.g. **PG Delta Diff**) → modal
closes, stays on the current page, "It's now active across the
dashboard." toast
- Disable a preview → modal stays open, "disabled" toast, no navigation
- Verified locally on the TanStack runtime; worth a quick click-through
on the Vercel preview (Next runtime) too

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved feature activation navigation to prevent conflicting URL
updates.
* Non-route features continue to close the preview modal and display the
activation confirmation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-08-03 15:39:48 +07:00
Danny White 73c9dbfa52 fix(studio): standardise custom icon weight (#48478)
## What kind of change does this PR introduce?

Bug fix and internal tooling update. Resolves FE-3472.

## What is the current behavior?

Custom Studio icons use inconsistent source stroke widths, and some
child-level styling prevents component props from overriding them. Mixed
custom and Lucide icon sets can therefore appear uneven.

## What is the new behavior?

Custom stroke icons use a root-level `stroke-width="1.5"`; fill-only
logos use `stroke="none"`. The build validates that contract and
regenerated components preserve existing exports and props.

Studio applies the same `1.5` weight across Reports categories and uses
one shared destination icon mapping in the replication selector,
destination rows and diagram.

| Before | After |
| --- | --- |
| <img width="418" height="516" alt="56398"
src="https://github.com/user-attachments/assets/6afa7042-e6be-40e7-9911-af2f61238c9d"
/> | <img width="390" height="550" alt="CleanShot 2026-07-30 at 17 12
37@2x"
src="https://github.com/user-attachments/assets/870f49cf-c8fa-40db-8be8-2eb5f264ff4a"
/> |
| <img width="510" height="734" alt="CleanShot 2026-07-30 at 17 19
28@2x"
src="https://github.com/user-attachments/assets/a5b2c088-dcd2-4907-976b-5820794d06e3"
/> | <img width="554" height="742" alt="CleanShot 2026-07-30 at 17 16
06@2x"
src="https://github.com/user-attachments/assets/ed3a77c4-5d94-4ca7-b9e4-1403b725a981"
/> |


## Testing

At 100% zoom, compare custom and Lucide icon weight in:

- Reports: **Add your first chart** and **Add block**
- Database > Replication: the destination selector, destination rows and
replication diagram
- Command menu (`⌘K`): **Search Database Tables**, **Search RLS
Policies**, **Search Edge Functions** and **Search Storage**
- Authentication > Users: right-click a user row and compare the
context-menu icons
- Database > Schema Visualizer: open a table node overflow menu
- A paused project: **Export your data > Download backups**

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added consistent destination icons across replication panels, rows,
and diagrams.
  * Updated instance health and metric icons for clearer identification.
* Standardized icon stroke weight and reduced default icon stroke
thickness.

* **Documentation**
* Clarified custom icon requirements, default properties, and validation
guidance.

* **Bug Fixes**
* Improved consistency of icon rendering across replication destinations
and reports.

* **Tests**
* Added coverage for icon SVG validation and replication destination
icon rendering.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 17:48:50 +10:00
Joshen Lim 2c53ca4a79 Support listing and reading custom reports from Assistant (#48530)
## Context

This is pre-requisite work for adding support to managing custom reports
from the Assistant. Planning to break this into a number of PRs, briefly
- Adding read support for custom reports
- Adding write support for custom reports
- Adding run support for custom reports
  - Should be able to infer data from the results then

This PR starts with adding support for listing and reading custom
reports from the Assistant

## Other changes involved
- Updates setting up of the home page report to have better title and
description
- Swaps the variant of the ToggleGroup in the SQL block for custom
reports as the default variant blends into the background color of the
PopoverContent

## To test
- [ ] Assistant should be able to list custom reports + read its
contents
<img width="428" height="755" alt="image"
src="https://github.com/user-attachments/assets/6a15b660-c0ee-4a06-984c-87eff3943eec"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added AI-assisted tools to list reports and retrieve report details,
including chart counts, layouts, configurations, and SQL-backed chart
information.
  - Added clearer empty-state messaging when no snippets are available.

- **Improvements**
- New homepage reports now use the name “Homepage Report” and include a
descriptive project-home summary.
  - Updated query controls with refreshed visual styling.
  - Improved content requests to support additional request context.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 13:59:50 +07:00
Danny White e7796315d2 fix sheets stealing focus (#48521)
## What kind of change does this PR introduce?

Bug fix. Resolves DEPR-539.

## What is the current behavior?

When a focused child unmounts, Radix can move focus to the Sheet wrapper
and break the expected tab order. Several callsites suppress the
wrapper's tabindex individually.

## What is the new behavior?

Sheet still focuses its first interactive child when opened, but the
wrapper itself is no longer focusable by default. Callers can opt in
with an explicit `tabIndex` when needed.

## Additional context

### Testing

Compare this Studio experience on both this branch and `master`:

1. Open any project with an Edge Function.
2. Go to **Edge Functions**, open the function, then click **Test**.
3. Under **Headers**, click **Add Headers**. Click the first header key
input, then Tab slowly through the header inputs and remove buttons.

On `master`, focus can jump to the whole Sheet. On this branch, focus
stays on the controls in order.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved keyboard focus behavior across sheets and panels.
* Sheets now focus the first available interactive element when opened,
without adding unnecessary focus targets.
* Preserved support for programmatic focus and prevented focus from
unexpectedly moving to the sheet when focused content is removed.
* Updated authentication, integrations, connection, logging, storage,
and other sheet interfaces consistently.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-03 10:01:47 +10:00
Danny WhiteandJoshen Lim 7a77760a10 fix(studio): confirm before discarding dirty replication destination forms (#48522)
## What kind of change does this PR introduce?

Bug fix (dirty form dismissal for Replication destination sheets), plus
small docs/skill updates so agents pick up the existing modality
pattern.

## What is the current behavior?

Closing the Add/Edit destination sheet (Cancel, Escape, or backdrop)
discards in-progress form state with no confirm. Same for the nested
Create publication sheet.

## What is the new behavior?

Dirty closes go through `useConfirmOnClose` +
`DiscardChangesConfirmationDialog`, matching other Studio sheets.
Successful submit still closes without prompting.

Also: skills + `forms.mdx` now point at Modality “Dirty form dismissal”.

| After |
| --- |
| <img width="1024" height="759" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/6f568a2a-c76b-442a-b592-d638bb36adc4"
/> |

### How to test

1. Studio → Database → Replication → **Add destination** (any pipelines
type with access).
2. Change a field so the form is dirty.
3. Try Cancel, Escape, and backdrop click → discard dialog appears;
**Keep editing** stays open; **Discard changes** closes.
4. Submit successfully with a valid config → sheet closes with no
discard dialog.
5. Repeat for **Edit destination** from a destination row menu.
6. Optional: Add destination → create a new publication from the
publication picker → dirty that nested sheet and dismiss the same way.
7. Optional: Add destination → Read Replica → change region → dismiss →
discard dialog; deploy still closes without prompting.

## Additional context

Sheet owns the close guard; forms report dirty via a ref because RHF
lives in the child. Nested `NewPublicationPanel` wires the guard
locally.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added unsaved-changes tracking to replication destination and
publication forms.
- Added confirmation prompts before closing forms with unsaved changes
via Cancel, Escape, or backdrop dismissal.
- Forms now reset appropriately after successful submission or confirmed
dismissal.

- **Documentation**
- Updated form and UI pattern guidance to document dirty-form dismissal
behavior for sheets and dialogs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-03 10:00:41 +10:00
Danny White eef0f57309 fix(studio): clarify Storage columns keyboard focus and selection (#48222)
## What kind of change does this PR introduce?

Accessibility / UX fix
([DEPR-630](https://linear.app/supabase/issue/DEPR-630)).

## What is the current behavior?

In Storage **As columns** view, keyboard select is unclear: the checkbox
stays hidden until hover, so Tab/Space selection is hard to see. The row
actions (three dots) menu also shows a browser default blue outline on
Tab.

## What is the new behavior?

Same icon/checkbox swap as list/hover, but also on keyboard focus:
- Checkbox replaces the icon on hover, `:focus-within`, and when
selected (no layout shift)
- Checkbox becomes visible when focused via keyboard (without needing
hover)
- Row gets an inset outline while the checkbox is focused
- Folders have no checkbox (non-focusable spacer only)
- Row actions trigger uses `focus-ring` instead of the browser blue
outline

| Before | After |
| --- | --- |
| <img width="1046" height="362" alt="CleanShot 2026-07-31 at 14 37
47@2x"
src="https://github.com/user-attachments/assets/9b827627-17e6-49a6-87a3-1253b4cef1da"
/> | <img width="1046" height="390" alt="CleanShot 2026-07-31 at 14 37
13@2x"
src="https://github.com/user-attachments/assets/2fd2b426-a8e2-4fda-b1ba-4df728b7b2f1"
/> |
| _Checkbox focussed but not visually shown_ | _Checkbox focussed and
visually shown_ |

## To test

1. Open the **Studio preview** for this PR.
2. Go to **Storage → Files** → open a bucket with several files.
3. Set view to **As columns**.
4. Tab until a **file** checkbox is focused.

**Expect:**
- Icon is replaced by the checkbox (same slot; neighbouring row icons
should not look shifted)
- Checkbox visible without hovering
- Row shows an inset outline

5. Press **Space** to select. Checkbox stays in the icon slot; selection
background applies.
6. Hover another file. Same icon to checkbox swap as before.
7. Tab to the three-dot actions control on a row. Expect the shared
focus ring (not a blue browser outline); the menu icon should become
visible.
8. Folders: no checkbox in the tab order; click icon/name still opens
the folder.
9. Smoke **As list**. Same swap behaviour.

## Additional context

From Kemal's DEPR-621 review.
2026-08-03 09:59:19 +10:00
Danny White f7454cf94e feat(studio): oauth impersonation warning on authorize (#48162)
## What kind of change does this PR introduce?

Feature + docs. Stacked on #48161 (logo contract /
[DEPR-604](https://linear.app/supabase/issue/DEPR-604/define-connect-logo-asset-and-variant-contract)).

## What is the current behavior?

After #48161, curated logos only resolve from allowlisted `redirect_uri`
hosts. A requester can still present a trusted partner **name** (e.g.
Claude) while redirecting to an unrelated remote host; the UI shows
Supabase alone but does not call out the mismatch.

## What is the new behavior?

- Shows a caution admonition when the requester name looks like a
trusted partner (Claude, Cursor, ChatGPT/OpenAI, Perplexity) but
`redirect_uri` is a **remote** host outside that partner's allowlist.
- Skips localhost / loopback redirects for the caution (common for local
MCP clients); those still get curated logos when the name matches a
trusted partner.
- Highlights the footer redirect URL in warning colour when the caution
is shown.
- Documents the behaviour in the Connect interstitials pattern.

### To test

Real MCP clients (Claude, Cursor, etc.) only send users to
**production** `/authorize`, so you cannot drive a local or preview
Studio build from those tools. Use a Network override instead:

1. Start Studio and sign in (`pnpm dev:studio`, or use the [Vercel
preview](https://studio-staging-git-danny-oauth-impersonation-warning-supabase.vercel.app/)).
2. Open `/dashboard/authorize?auth_id=foo` (any `auth_id` is fine; the
real response may 404) ([Vercel
preview](https://studio-staging-git-danny-oauth-impersonation-warning-supabase.vercel.app/dashboard/authorize?auth_id=foo)).
3. DevTools → **Network** → find `GET
…/platform/oauth/authorizations/foo` (or whatever id you used).
4. Right-click → **Override content** (enable Local Overrides / pick a
folder if prompted).
5. Paste one of the payloads below (status **200**), save, then reload
the authorize page.
6. Keep `expires_at` in the future so the request does not look expired.

#### Impersonation caution (trusted name + remote non-allowlisted
redirect)

Expect:

- Supabase alone (no curated Claude mark)
- Caution: “Redirect does not match this app name”
- Footer redirect URL in warning colour

```json
{
  "name": "Claude",
  "website": "https://claude.ai",
  "icon": null,
  "domain": "claude.ai",
  "redirect_uri": "https://evil.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Claude Supabase"
src="https://github.com/user-attachments/assets/e6eee016-5710-41ba-9925-87511e009e22"
/> |

#### Localhost MCP: no caution

Expect curated Claude + Supabase pair (name match + loopback), **no**
caution, normal footer colour. Local MCP clients often use loopback
redirects.

```json
{
  "name": "Claude",
  "website": "https://claude.ai",
  "icon": null,
  "domain": "claude.ai",
  "redirect_uri": "http://127.0.0.1:42813/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Claude Supabase"
src="https://github.com/user-attachments/assets/79f36865-3c8e-43e5-9490-24288efc74aa"
/> |

#### Legitimate curated partner: no caution

Expect curated Cursor + Supabase pair, no admonition, normal footer
colour.

```json
{
  "name": "Cursor",
  "website": "https://cursor.com",
  "icon": null,
  "domain": "cursor.com",
  "redirect_uri": "https://cursor.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="56164"
src="https://github.com/user-attachments/assets/412333a3-a74f-42eb-9f63-d56b6a26bf91"
/> |

#### Unrelated name + remote redirect: no caution

Expect Supabase alone (no icon), no admonition.

```json
{
  "name": "Acme Tools",
  "website": "https://evil.com",
  "icon": null,
  "domain": "evil.com",
  "redirect_uri": "https://evil.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Acme Tools Supabase"
src="https://github.com/user-attachments/assets/dab24817-5c26-4aa1-a447-796c4af5868b"
/> |

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Added an OAuth caution when a requester name matches a known partner
but uses an unapproved remote redirect host.
- Improved trusted partner logo selection for localhost/loopback
redirects while preserving safe fallbacks for untrusted redirects.

- **Documentation**
- Updated Connect interstitial guidance for redirect mismatches and
localhost/loopback behavior.

- **Tests**
- Expanded coverage for caution visibility, messaging, localhost logo
pairing, and trusted redirect scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-02 23:57:27 +00:00
Danny WhiteandJoshen Lim 2b26da360e show API and AWS authorization errors inline (#48471)
## What kind of change does this PR introduce?

Bug fix and design-system update.

## What is the current behavior?

API authorisation and AWS Marketplace action failures use transient
toasts. The inline action-error treatment introduced for organisation
invitations is implemented locally.

## What is the new behavior?

Action failures remain visible below their actions and clear on retry or
organisation change.

This PR adds a shared `InterstitialActionError` component, updates the
connect-interstitial guidance and demo to use it, and retroactively
applies it to `OrganizationInvite`.

Mutation errors are read directly from their mutation hooks rather than
copied into component state.

| Before | After |
| --- | --- |
| <img width="1024" height="759" alt="Authorize API Access Supabase"
src="https://github.com/user-attachments/assets/9520aff3-496d-44b1-b5b5-02b331872e32"
/> | <img width="1024" height="759" alt="Authorize API Access Supabase"
src="https://github.com/user-attachments/assets/2d09e337-573a-45b5-80ac-7c546ed1401d"
/> |
| <img width="1024" height="759" alt="Link AWS Marketplace Supabase"
src="https://github.com/user-attachments/assets/bb1a4581-0399-432a-8037-d84ab15ecc4b"
/> | <img width="1024" height="759" alt="Link AWS Marketplace Supabase"
src="https://github.com/user-attachments/assets/f9d43cd9-c661-42ed-91c0-e45ccb9c19f5"
/> |

_Note since taking that AWS screenshot: the error message now replaces
the prior footer text. I.e. “Learn more about billing through AWS.” is
now gone when an error message is present._

## To test

### AWS Marketplace

For a visual check with local Studio running:

1. In
`apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.tsx`,
immediately before `if (!buyerId)`, temporarily add:
   ```tsx
   return (
     <AwsMarketplaceInterstitial>
       <div className="flex flex-col gap-5">
         <InterstitialAccountRow displayName="reviewer@example.com" />
         <OrganizationSelector
           organizations={[
             {
               name: 'Example Organization',
               slug: 'example-organization',
               plan: { id: 'pro', name: 'Pro' },
             } as Organization,
           ]}
           selectedSlug="example-organization"
           disabled
           onSelect={() => undefined}
         />
         <div className="flex flex-col gap-5">
           <div className="flex flex-col gap-2">
             <Button variant="primary" block>
               Link organization
             </Button>
<InterstitialActionError error="Failed to link organization: Test error"
/>
           </div>
<p className="text-center text-xs text-foreground-lighter text-balance">
<InlineLink href={`${DOCS_URL}/guides/platform/aws-marketplace`}>
               Learn more
             </InlineLink>{' '}
             about billing through AWS.
           </p>
         </div>
       </div>
     </AwsMarketplaceInterstitial>
   )
   ```
2. Open `http://localhost:8082/aws-marketplace-onboarding?buyer_id=test`
while signed in.
3. Confirm the error appears below **Link organization** with a divider.

Remove the temporary return before committing anything.

### API authorization

For a visual check with local Studio running:

1. In
`apps/studio/components/interfaces/ApiAuthorization/ApiAuthorization.Valid.tsx`,
immediately before `if (isLoading)`, temporarily add:
   ```tsx
   return (
     <ApiAuthorizationMainView
       approvalState="indeterminate"
       form={form}
       requester={{
         name: 'Test App',
         website: 'https://example.com',
         icon: null,
         domain: 'example.com',
         scopes: [],
         expires_at: '2099-01-01T00:00:00.000Z',
         approved_at: null,
         registration_type: 'static',
       }}
       organizations={{
         _tag: 'success',
         organizations: [
{ name: 'Example Organization', slug: 'example-organization' } as
Organization,
         ],
       }}
       requestedOrganizationSlug={undefined}
       actionError="Failed to authorize request: Test error"
       onOrganizationChange={() => undefined}
       onApprove={() => undefined}
       onDecline={() => undefined}
     />
   )
   ```
2. Open `http://localhost:8082/authorize?auth_id=test` while signed in.
3. Confirm the error appears below the authorisation actions with a
divider.

Remove the temporary return before committing anything.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added consistent inline error messaging for authorization,
organization invitations, and AWS Marketplace onboarding.
* Error messages now appear within the relevant interstitial and replace
supporting footer content until resolved.
  * Retry and action buttons remain available after failed operations.
* **Bug Fixes**
* AWS Marketplace linking failures no longer trigger toast
notifications.
  * Billing guidance is hidden while an onboarding error is displayed.
* **Tests**
* Added coverage for authorization, cancellation, and AWS Marketplace
failure states.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-08-03 09:43:23 +10:00
Charis ec64135f9d perf(pg-meta): scope column privileges query to a single table (#48553)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Performance improvement

## What is the current behavior?

The column privileges page in Studio only ever renders one table, but
the underlying query still `aclexplode`s every column in the whole
schema and filters the result client-side.

## What is the new behavior?

Adds a scoped SQL path that prunes `pg_class`/`pg_namespace` to the
requested schema+table before exploding ACLs, gated behind the
`pgMetaScopedIntrospection` flag, with a plan-guard test asserting
`pg_class`/`pg_attribute` stay index-driven. Studio's query hook and
cache keys now thread the selected table through so column-privilege
invalidation and cold-load races are scoped correctly, and the page
fetches per-table instead of per-schema.

## Additional context

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Column privileges are now scoped to the selected schema and table for
more accurate results.
* Changing schemas automatically updates the table selection and
refreshes the displayed privileges.
* Privilege updates now refresh only the relevant schema, table, and
column data.
* Loading states are handled more accurately when no table is selected.

* **Bug Fixes**
* Improved consistency between scoped and unscoped column privilege
results, including table-, column-, and grant-option privileges.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-31 15:26:37 -04:00