Skip to content

feat(aurora-portal): swift objects list with file browser interface#593

Merged
mark-karnaukh-extern-sap merged 27 commits intomainfrom
mark-swift-objects-file-browser-interface
Mar 25, 2026
Merged

feat(aurora-portal): swift objects list with file browser interface#593
mark-karnaukh-extern-sap merged 27 commits intomainfrom
mark-swift-objects-file-browser-interface

Conversation

@mark-karnaukh-extern-sap
Copy link
Contributor

@mark-karnaukh-extern-sap mark-karnaukh-extern-sap commented Mar 17, 2026

Object Storage — Swift Object Browser

Implements the Swift object browser for the Aurora Portal. Users can now open a container, browse its contents in a familiar folder-like structure, and navigate through nested prefixes using a breadcrumb trail — with smooth performance even for containers holding thousands of objects.

Related tasks

  • object-storage-ui: ObjectBrowser - File browser interface with folder navigation
  • object-storage-ui: Breadcrumb - Navigation breadcrumb component for folder structures

What's included

Object browser — clicking a container name opens a file browser view listing its folders and objects at the current prefix level. Folders and files are visually distinct. Clicking a folder navigates into it; the list updates to show only that folder's contents.

Breadcrumb navigation — a breadcrumb trail above the list always reflects the current location. Each segment is clickable and jumps directly to that prefix level. The container name acts as the root; the deepest open folder is shown as the non-interactive active segment.

URL-based prefix state — the current folder path is stored in the URL as a search param, so deep links, browser back/forward, and page reloads all work correctly.

Virtual scrolling — the object list uses TanStack Virtual, consistent with the existing container list, so containers with 1000+ objects remain performant.

Sort and search — objects can be sorted by name, last modified, or size. The default view preserves the API order. A search field filters by name within the current prefix level.

URL-persisted sort and search — sort column, sort direction, and search term are stored in the URL search params for both the container list and object browser. Deep links, browser back/forward, and page reloads all restore the exact sort and filter state.

Container name links — container names in the container list now link directly to the object browser.

Long name handling — long container and object names are truncated with an ellipsis; the full name is shown on hover.

Component organisation — Swift container and object components are now grouped into dedicated Containers/ and Objects/ subdirectories, and the object list is split into focused single-responsibility components, mirroring the existing container list structure.


Also fixed

  • Infinite re-render loop in ManageContainerAccessModal caused by a mutation object reference in a useEffect dependency array
  • Empty-name pseudo-folder rows appearing for leading-slash filenames (e.g. /Aurora_gold.png) and self-referencing directory entries when listing inside a prefix

Screenshots

Container list — clickable names

Container names now link directly to the object browser

image

Object browser — root level (andreas-pfau)

Folders and files listed at the container root; breadcrumb shows container name as active

image

Object browser — inside a folder (test/)

Breadcrumb updates; only objects at the current prefix level are shown

image

Object browser — deep nesting

Multi-level breadcrumb with clickable intermediate segments

image

Object browser — large container (--progress_segments)

Virtual scrolling handles containers with many objects without performance degradation

image

Checklist

  • I have performed a self-review of my code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have made corresponding changes to the documentation (if applicable).
  • My changes generate no new warnings or errors.

Summary by CodeRabbit

  • New Features

    • Introduced dedicated storage container management interface with integrated search and sort options
    • Added file/object browser with breadcrumb navigation for hierarchical folder exploration
    • Enabled URL-based state preservation for search terms and sorting preferences
  • Refactor

    • Improved storage navigation structure for enhanced user experience

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 453fdef6-1c79-437d-99fd-5cce1772dac0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR restructures object storage routing from a generic splat-based path to explicit container and object-browsing routes, adds new UI components for Swift object storage browsing with breadcrumb navigation and virtualized tables, and implements service availability validation with intelligent fallback redirects.

Changes

Cohort / File(s) Summary
Route Structure & Type Definitions
apps/aurora-portal/src/client/routeTree.gen.ts
Removed generic splat route /storage/$provider/$ and added two explicit routes: /storage/$provider/containers/ for listing containers and /storage/$provider/containers/$containerName/objects/$ for browsing container objects. Updated all route type unions and mappings accordingly.
Containers Index Route
apps/aurora-portal/src/client/routes/.../storage/$provider/containers/index.tsx, index.test.tsx
Updated route path from splat-based to explicit containers path. Modified checkServiceAvailability to remove _splat parameter handling. Changed component render from SwiftObjectStorage to SwiftContainers. Added comprehensive test coverage for service availability logic across various availability scenarios.
Objects Route
apps/aurora-portal/src/client/routes/.../storage/$provider/containers/$containerName/objects/$.tsx, $.test.tsx
Added new route file for browsing container objects with search parameter validation, service availability checks, and provider-specific rendering. Tests verify redirect behavior for invalid/missing providers and unavailable services.
Container Components
apps/aurora-portal/src/client/routes/.../-components/Swift/Containers/ContainerTableView.tsx, ContainerTableView.test.tsx, ManageContainerAccessModal.tsx, index.tsx, index.test.tsx
Renamed ContainerListView to ContainerTableView and integrated routing via useParams and Link. Updated container name cells to render as clickable navigation links. Added router mocks to tests. Fixed dependency array in modal component to prevent unnecessary effect re-runs.
Objects Components - Navigation & Table
apps/aurora-portal/src/client/routes/.../-components/Swift/Objects/ObjectsFileNavigation.tsx, ObjectsFileNavigation.test.tsx, ObjectsTableView.tsx, ObjectsTableView.test.tsx
Added ObjectsFileNavigation breadcrumb component for prefix-based navigation with support for intermediate and active segment interactions. Added ObjectsTableView virtualized table component with sorting, filtering, empty states, and footer counts. Comprehensive test coverage for both components.
Objects Main Component
apps/aurora-portal/src/client/routes/.../-components/Swift/Objects/index.tsx, index.test.tsx
Added new SwiftObjects component with tRPC query integration, prefix encoding/decoding, row building logic with folder/object differentiation, search and sort functionality. Tests cover loading, error, data display, and search interaction scenarios.
Dependencies
apps/aurora-portal/package.json
Added react-icons dependency (^5.6.0) for breadcrumb and table UI icons.

Sequence Diagram

sequenceDiagram
    actor User
    participant Router
    participant ContainersRoute as Containers Route
    participant ObjectsRoute as Objects Route
    participant API as tRPC API
    participant UI as UI Components

    User->>Router: Navigate to /storage/$provider/containers/
    Router->>ContainersRoute: Load containers route
    ContainersRoute->>API: Check service availability
    API-->>ContainersRoute: Available services
    ContainersRoute->>UI: Render SwiftContainers
    UI-->>User: Display container list

    User->>UI: Click container name
    UI->>Router: Navigate to /storage/$provider/containers/$containerName/objects/
    
    Router->>ObjectsRoute: Load objects route
    ObjectsRoute->>API: Check service availability
    API-->>ObjectsRoute: Available services
    ObjectsRoute->>API: listObjects query (container, prefix)
    API-->>ObjectsRoute: Object summaries
    
    ObjectsRoute->>UI: Render SwiftObjects
    UI->>UI: Build rows (folders + objects)
    UI-->>User: Display breadcrumbs + objects table

    User->>UI: Click folder in table
    UI->>Router: Update search params with new prefix
    Router->>API: Re-query with new prefix
    API-->>ObjectsRoute: Filtered object summaries
    UI-->>User: Update breadcrumbs + table content
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • Issue #557: The addition of ObjectsFileNavigation breadcrumb component directly implements the breadcrumb functionality for object-storage prefix navigation that was requested in this issue.

Possibly related PRs

  • PR #584: Inverse relationship—the retrieved PR introduces the /storage/$provider/$ splat route structure that this PR removes and replaces with explicit /containers/ and /objects/$ routes.

Suggested labels

enhancement, aurora-portal, object storage

Suggested reviewers

  • andypf
  • vlad-schur-external-sap
  • KirylSAP

Poem

🐰 Hops through the storage with glee,
Breadcrumbs now guide where objects be,
No more splats in the routing tree,
Folders and files arranged so neat,
Navigation's a hop, a skip, a treat! 🗂️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: adding a Swift objects list with a file browser interface, which aligns with the substantial changes to the storage routing and UI components.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering purpose, changes, related tasks, detailed feature descriptions, bug fixes, and supporting screenshots.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@mark-karnaukh-extern-sap mark-karnaukh-extern-sap force-pushed the mark-swift-objects-file-browser-interface branch from 10a7163 to 1fce367 Compare March 19, 2026 16:24
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ManageContainerAccessModal.tsx (1)

205-212: ⚠️ Potential issue | 🟡 Minor

Reset showPreview in the external-close path too.

When the modal is closed via parent state (isOpen = false) instead of handleClose, showPreview is not cleared. On reopen, preview state can be stale.

Proposed patch
  useEffect(() => {
    if (!isOpen) {
      setReadAcl("")
      setWriteAcl("")
      setPublicRead(false)
+      setShowPreview(false)
      resetMutationRef.current()
    }
  }, [isOpen])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ManageContainerAccessModal.tsx
around lines 205 - 212, The useEffect that clears state when the modal is closed
via parent (useEffect with dependency [isOpen]) misses resetting the preview
flag, causing stale previews on reopen; update that effect to also reset the
preview state by invoking the showPreview state setter (e.g., call
setShowPreview(false) or equivalent) alongside setReadAcl, setWriteAcl,
setPublicRead, and resetMutationRef.current(), so both external-close
(useEffect) and handleClose paths clear showPreview consistently.
🧹 Nitpick comments (3)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx (1)

107-113: Unused project variable in StorageDashboard.

The project variable extracted from useParams is only used for a truthy check but never used for its actual value. Consider renaming to clarify intent or removing if not needed.

💡 Suggested clarification

If you only need to check if project exists:

 function StorageDashboard() {
-  const { project, provider } = useParams({
+  const { hasProject, provider } = useParams({
     from: "/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/",
     select: (params) => {
-      return { project: params.projectId, provider: params.provider }
+      return { hasProject: Boolean(params.projectId), provider: params.provider }
     },
   })

Or simply use projectId consistently if you might need the value later.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/index.tsx
around lines 107 - 113, The destructured variable project from the useParams
call in StorageDashboard is unused except for a truthy check; update the
useParams usage to either rename project to something like hasProject (if you
only need existence) or remove it and check for provider/projectId existence
directly, or replace it with projectId to use the actual value consistently;
locate the useParams call in StorageDashboard and adjust the select return or
subsequent checks so there is no unused variable left.
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerTableView.test.tsx (1)

15-41: Router mock is duplicated across test files.

This router mock is identical to the one in ContainerList.test.tsx. Consider extracting it to a shared test utility to reduce duplication and ensure consistency.

💡 Suggested shared mock location

Create a shared test utility, e.g., src/client/test-utils/routerMocks.ts:

import { vi } from "vitest"
import React from "react"

export const mockTanStackRouter = () => {
  vi.mock("@tanstack/react-router", async () => {
    const actual = await vi.importActual("@tanstack/react-router")
    return {
      ...actual,
      useParams: vi.fn(() => ({
        accountId: "test-account",
        projectId: "test-project",
        provider: "swift",
      })),
      Link: vi.fn(({ children, to, ...props }) => (
        <a href={to} {...props}>{children}</a>
      )),
    }
  })
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerTableView.test.tsx
around lines 15 - 41, Extract the duplicated router mock from
ContainerTableView.test.tsx (and ContainerList.test.tsx) into a shared test
utility function (e.g., mockTanStackRouter) and export it from a new module
(suggested name routerMocks or test-utils/routerMocks); move the vi.mock
implementation there and ensure it returns the same mocked useParams and Link as
the original, then replace the in-file vi.mock calls in both tests with an
import of mockTanStackRouter and a call to it at the top of each test file so
both tests reuse the single shared mock implementation.
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.test.tsx (1)

7-25: Same redirect mock pattern duplicated across test files.

This redirect mock is identical to the one in $.test.tsx. Consider extracting to a shared test utility.

💡 Suggested shared mock
// src/client/test-utils/redirectMock.ts
export const createRedirectMock = () => 
  vi.fn((args) => {
    if (args.href) {
      throw new Error(`Redirect to: ${args.href}`)
    }
    let resolvedPath: string = args.to
    if (args.params) {
      for (const [key, value] of Object.entries(args.params as Record<string, string>)) {
        resolvedPath = resolvedPath.replace(`$${key}`, value ?? "")
      }
    }
    throw new Error(`Redirect to: ${resolvedPath}`)
  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/index.test.tsx
around lines 7 - 25, Extract the duplicated redirect mock into a shared test
utility (e.g. export createRedirectMock from src/client/test-utils/redirectMock)
and replace the inline mock in the vi.mock("@tanstack/react-router") blocks with
an import of that helper; update the vi.mock return to spread the actual module
and set redirect: createRedirectMock(), keeping the same behavior of checking
args.href, interpolating args.params into args.to, and throwing the "Redirect
to: ..." Error so tests that assert thrown messages keep working (refer to the
existing vi.mock in the test and the suggested createRedirectMock helper name).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ObjectList.tsx:
- Around line 287-293: Replace the template-literal interpolation inside the
<Trans> component so i18n extraction works: in the error-handling branch of
ObjectList (the block that checks `if (error)`), remove `{error.message}` from
the literal and pass the runtime message to <Trans> via a values prop or as a
child placeholder (e.g., use a message key like "Error Loading Objects:
{message}" and pass `{ message: error.message }` to the <Trans> component) so
translation extraction tools can pick up the static string while still rendering
the dynamic `error.message`.
- Around line 26-36: The current encodePrefix/decodePrefix use btoa/atob which
throw on non-Latin-1 input; update encodePrefix to first UTF-8 encode the string
(TextEncoder -> Uint8Array) and then base64-encode that byte buffer (convert
bytes to a binary string and btoa it), and update decodePrefix to atob the
base64 into a binary string, convert that to a Uint8Array and decode it with
TextDecoder to produce the original Unicode string; keep the existing undefined
check and wrap both functions' operations in try/catch to return empty string on
failure, referencing the functions encodePrefix and decodePrefix.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$.tsx:
- Around line 101-114: The loader and beforeLoad both call
trpcClient.auth.getAvailableServices, causing duplicate network requests;
refactor so loader fetches availableServices once and beforeLoad reuses it: have
loader return availableServices (keeping client) and modify beforeLoad to accept
or read that loader data instead of calling trpcClient again, then pass the
returned availableServices into checkServiceAvailability(availableServices,
params) (use the loader-returned availableServices and params in beforeLoad
rather than invoking trpcClient.auth.getAvailableServices twice).
- Around line 98-100: The notFoundComponent currently returns plain English
text; wrap the string in the Lingui translation component (e.g., replace
<p>Storage container not found</p> with <p><Trans>Storage container not
found</Trans></p>) and add the necessary import for Trans if missing so the
container 404 copy is localized; the change targets the notFoundComponent
returned JSX in the route component.
- Around line 92-97: The errorComponent currently renders raw error.message for
Error instances, leaking internals; update the errorComponent to always render
the shared app error UI (use ErrorComponent / the app ErrorBoundary/ErrorBoundry
recovery component) instead of returning error.message so both Error and
non-Error cases display the unified error page. Locate the errorComponent in the
route (symbol: errorComponent) and replace the conditional branch that returns
<div>{error.message}</div> with a call to the shared error UI (e.g., return
<ErrorComponent error={error} />) so all errors go through the same recovery UX.
- Around line 127-139: The setPageTitle calls are being invoked directly in the
component body (via Route.useRouteContext() -> setPageTitle) which triggers
document/title updates on every render; move this logic into a useEffect so it
only runs when the computed pageTitle changes. Compute pageTitle from provider
(using useLingui()'s t for "Object Storage" vs "Storage Overview") and then call
setPageTitle inside a useEffect with [pageTitle, setPageTitle] as dependencies,
leaving the rest of the render logic unchanged.
- Around line 144-149: The ErrorBoundary wrapping SwiftObjects doesn't include
resetKeys, so once SwiftObjects throws the fallback remains until a full reload;
extract the prefix search param and add resetKeys={[project, provider,
containerName, prefix]} to the ErrorBoundary component (referencing
ErrorBoundary and SwiftObjects) so the boundary resets when any of project,
provider, containerName or prefix change.

---

Outside diff comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ManageContainerAccessModal.tsx:
- Around line 205-212: The useEffect that clears state when the modal is closed
via parent (useEffect with dependency [isOpen]) misses resetting the preview
flag, causing stale previews on reopen; update that effect to also reset the
preview state by invoking the showPreview state setter (e.g., call
setShowPreview(false) or equivalent) alongside setReadAcl, setWriteAcl,
setPublicRead, and resetMutationRef.current(), so both external-close
(useEffect) and handleClose paths clear showPreview consistently.

---

Nitpick comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerTableView.test.tsx:
- Around line 15-41: Extract the duplicated router mock from
ContainerTableView.test.tsx (and ContainerList.test.tsx) into a shared test
utility function (e.g., mockTanStackRouter) and export it from a new module
(suggested name routerMocks or test-utils/routerMocks); move the vi.mock
implementation there and ensure it returns the same mocked useParams and Link as
the original, then replace the in-file vi.mock calls in both tests with an
import of mockTanStackRouter and a call to it at the top of each test file so
both tests reuse the single shared mock implementation.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/index.test.tsx:
- Around line 7-25: Extract the duplicated redirect mock into a shared test
utility (e.g. export createRedirectMock from src/client/test-utils/redirectMock)
and replace the inline mock in the vi.mock("@tanstack/react-router") blocks with
an import of that helper; update the vi.mock return to spread the actual module
and set redirect: createRedirectMock(), keeping the same behavior of checking
args.href, interpolating args.params into args.to, and throwing the "Redirect
to: ..." Error so tests that assert thrown messages keep working (refer to the
existing vi.mock in the test and the suggested createRedirectMock helper name).

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/index.tsx:
- Around line 107-113: The destructured variable project from the useParams call
in StorageDashboard is unused except for a truthy check; update the useParams
usage to either rename project to something like hasProject (if you only need
existence) or remove it and check for provider/projectId existence directly, or
replace it with projectId to use the actual value consistently; locate the
useParams call in StorageDashboard and adjust the select return or subsequent
checks so there is no unused variable left.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 246f3106-e12c-46a4-afcf-a75b6467d2e0

📥 Commits

Reviewing files that changed from the base of the PR and between 30ef99a and cc8e660.

📒 Files selected for processing (11)
  • apps/aurora-portal/src/client/routeTree.gen.ts
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerList.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerList.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerTableView.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ContainerTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ManageContainerAccessModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/SwiftObjectStorage/ObjectList.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx (2)

16-23: ⚠️ Potential issue | 🟡 Minor

Unicode prefixes can break with btoa/atob.

On Line 16 and Line 22, direct btoa/atob is not UTF-8 safe; non‑Latin-1 folder names can fail encoding/decoding.

Proposed fix
-const encodePrefix = (prefix: string): string => btoa(prefix)
+const encodePrefix = (prefix: string): string => {
+  const bytes = new TextEncoder().encode(prefix)
+  let bin = ""
+  bytes.forEach((b) => (bin += String.fromCharCode(b)))
+  return btoa(bin)
+}

 const decodePrefix = (encoded: string | undefined): string => {
   if (!encoded) return ""
   try {
-    return atob(encoded)
+    const bin = atob(encoded)
+    const bytes = Uint8Array.from(bin, (ch) => ch.charCodeAt(0))
+    return new TextDecoder().decode(bytes)
   } catch {
     return ""
   }
 }
Does the browser btoa()/atob() API support Unicode input directly, and what is the recommended UTF-8 safe encoding pattern?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
around lines 16 - 23, The current encodePrefix/decodePrefix use btoa/atob which
break on Unicode; update encodePrefix to UTF-8 encode the string (use
TextEncoder to get bytes, convert bytes to a binary string, then base64-encode
that) and update decodePrefix to base64-decode to a binary string (via atob),
convert that binary string to a Uint8Array and UTF-8 decode with TextDecoder,
preserving non‑Latin-1 characters; modify the functions named encodePrefix and
decodePrefix accordingly so all callers keep the same signatures.

231-231: ⚠️ Potential issue | 🟡 Minor

Use Lingui-compatible interpolation in <Trans> for extraction.

On Line 231, interpolating error.message directly as {error.message} in <Trans> is the pattern already flagged by lint and can break extraction semantics.

Proposed fix
-        <Trans>Error Loading Objects: {error.message}</Trans>
+        <Trans id="swift.objects.errorLoading" message="Error Loading Objects: {message}" values={{ message: error.message }} />
In Lingui v5, what is the recommended pattern for passing dynamic values into `<Trans>` so message extraction works correctly?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
at line 231, Replace the direct JSX interpolation inside <Trans> with Lingui's
values interpolation: change the fragment that currently renders <Trans>Error
Loading Objects: {error.message}</Trans> to use a named placeholder like <Trans
values={{ errorMessage: error.message }}>Error Loading Objects:
{errorMessage}</Trans>; this keeps extraction working and avoids direct
{error.message} inside the <Trans> content in the Swift Objects component
(index.tsx).
🧹 Nitpick comments (1)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx (1)

39-65: Consider centralizing the TanStack router mock used in Swift container tests.

This mock pattern is effectively duplicated in apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.test.tsx (Line 15-42). A shared test helper would reduce drift risk when route params evolve.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx
around lines 39 - 65, Extract the duplicated vi.mock of "@tanstack/react-router"
(the useParams and Link mocks) into a single test helper module that exports a
setup function (e.g., setupTanstackRouterMock) or the mock implementation
itself; replace the inline mocks in index.test.tsx and
ContainerTableView.test.tsx with an import and call to that helper. Ensure the
helper uses vi.importActual to spread the real module, defines useParams and
Link the same way, and exports any types or utilities needed by tests so both
tests import the same centralized mock and avoid duplication.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx:
- Around line 71-72: The footer currently uses visibleCount derived from
rowVirtualizer.getVirtualItems().length which reflects the virtualization window
rather than the total filtered dataset; replace visibleCount with the actual
dataset count (e.g., objects.length or filteredObjects.length used for
rendering) when composing the “Showing X of Y items” text, or alternatively
change the label to explicitly say “Showing X visible items” if you intend to
report mounted rows; update the usages around visibleCount and the footer render
block (referenced where rowVirtualizer.getVirtualItems() is called and the
footer lines ~167-169) to ensure the count represents dataset size not
virtualized window.
- Line 138: The folder-row button in ObjectsTableView (the element with
className containing "flex min-w-0 items-center gap-2 text-left hover:underline
focus:outline-none") currently removes the focus indicator; remove
"focus:outline-none" and instead add keyboard-visible focus styles like
"focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-indigo-500"
(or your design system's equivalent) so keyboard users retain a visible focus
state while keeping hover behavior intact.
- Around line 39-44: The formatDate helper (formatDate) currently assumes new
Date(dateString) will throw on bad input, but it returns an Invalid Date and
toLocaleString() yields "Invalid Date"; change formatDate to create the Date,
test its validity with isNaN(date.getTime()) (or Number.isNaN) and return t`N/A`
for invalid dates, otherwise return date.toLocaleString(); apply the same
validity-check fix to the second occurrence referenced at line 155 (likely the
other date formatting helper or inlined usage) so both places return t`N/A`
instead of "Invalid Date".

---

Duplicate comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx:
- Around line 16-23: The current encodePrefix/decodePrefix use btoa/atob which
break on Unicode; update encodePrefix to UTF-8 encode the string (use
TextEncoder to get bytes, convert bytes to a binary string, then base64-encode
that) and update decodePrefix to base64-decode to a binary string (via atob),
convert that binary string to a Uint8Array and UTF-8 decode with TextDecoder,
preserving non‑Latin-1 characters; modify the functions named encodePrefix and
decodePrefix accordingly so all callers keep the same signatures.
- Line 231: Replace the direct JSX interpolation inside <Trans> with Lingui's
values interpolation: change the fragment that currently renders <Trans>Error
Loading Objects: {error.message}</Trans> to use a named placeholder like <Trans
values={{ errorMessage: error.message }}>Error Loading Objects:
{errorMessage}</Trans>; this keeps extraction working and avoids direct
{error.message} inside the <Trans> content in the Swift Objects component
(index.tsx).

---

Nitpick comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx:
- Around line 39-65: Extract the duplicated vi.mock of "@tanstack/react-router"
(the useParams and Link mocks) into a single test helper module that exports a
setup function (e.g., setupTanstackRouterMock) or the mock implementation
itself; replace the inline mocks in index.test.tsx and
ContainerTableView.test.tsx with an import and call to that helper. Ensure the
helper uses vi.importActual to spread the real module, defines useParams and
Link the same way, and exports any types or utilities needed by tests so both
tests import the same centralized mock and avoid duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5822c4ba-55bd-4043-966b-b940780bfb17

📥 Commits

Reviewing files that changed from the base of the PR and between cc8e660 and 1cae840.

📒 Files selected for processing (23)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerLimitsTooltip.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerLimitsTooltip.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerToastNotifications.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerToastNotifications.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/CreateContainerModal.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/CreateContainerModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/DeleteContainerModal.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/DeleteContainerModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/EditContainerMetadataModal.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/EditContainerMetadataModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/EmptyContainerModal.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/EmptyContainerModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ManageContainerAccessModal.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ManageContainerAccessModal.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx (2)

1-1: Unnecessary React import with new JSX transform.

Same as the previous file - this import is not needed with React 19's JSX transform.

Suggested fix
-import React from "react"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx
at line 1, Remove the unnecessary top-level import "import React from 'react'"
from the ObjectsTableView.test.tsx test file because React 19's automatic JSX
transform makes it redundant; update the file by deleting the import statement
(ensure no JSX pragma or direct use of the React identifier remains in
ObjectsTableView.test.tsx and run tests to confirm).

186-196: Footer assertions may be fragile due to Lingui Trans interpolation.

The tests assert /4 items/i and /2 items/i, but the component renders <Trans>Showing {visibleCount} of {allCount} items</Trans>. Depending on how Lingui handles the translation in test mode, the text may render differently. If tests become flaky, consider asserting on the full pattern or using a more specific query.

More robust assertion approach
   describe("Footer", () => {
     test("shows item count in footer", () => {
       renderView()
-      expect(screen.getByText(/Showing/i)).toBeInTheDocument()
-      expect(screen.getByText(/4 items/i)).toBeInTheDocument()
+      expect(screen.getByText(/Showing 4 of 4 items/i)).toBeInTheDocument()
     })
 
     test("footer total matches rows length", () => {
       renderView({ rows: [makeObject("a.txt"), makeObject("b.txt")] })
-      expect(screen.getByText(/2 items/i)).toBeInTheDocument()
+      expect(screen.getByText(/Showing 2 of 2 items/i)).toBeInTheDocument()
     })
   })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx
around lines 186 - 196, The footer tests in ObjectsTableView.test.tsx are
asserting on partial text like /4 items/i which can break due to Lingui <Trans>
interpolation; update the tests (the test cases that call renderView and
makeObject) to assert the full localized pattern instead—e.g., use a regex that
matches "Showing {visibleCount} of {allCount} items" such as
/Showing\s+\d+\s+of\s+\d+\s+items/i or
screen.getByText(/Showing.*of.*items/i)—so the assertions target the complete
rendered sentence rather than only the trailing "X items".
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx (3)

73-77: Mutable trpcState pattern works but consider factory function for isolation.

The mutable trpcState object is reassigned in beforeEach, which works but can be error-prone if tests run in parallel or if a test forgets to reset state. A factory function pattern would provide better isolation.

Alternative approach using factory
-let trpcState = {
-  objects: mockObjects as ObjectSummary[] | undefined,
-  isLoading: false,
-  error: null as { message: string } | null,
-}
+const createTrpcState = () => ({
+  objects: mockObjects as ObjectSummary[] | undefined,
+  isLoading: false,
+  error: null as { message: string } | null,
+})
+
+let trpcState = createTrpcState()

Then in beforeEach:

-    trpcState = { objects: mockObjects, isLoading: false, error: null }
+    trpcState = createTrpcState()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx
around lines 73 - 77, Replace the mutable shared trpcState object with a factory
function that returns a fresh state for each test to ensure isolation: create a
function (e.g., makeTrpcState or createTrpcState) that returns the object
currently assigned to trpcState (including objects: mockObjects as
ObjectSummary[] | undefined, isLoading: false, error: null) and call that
factory inside beforeEach to reassign a new local trpcState for each test;
update any references to trpcState in the test file (including beforeEach and
tests using mockObjects) so they use the freshly created instance instead of a
shared mutable variable.

31-42: Relative mock path is fragile and may break on file moves.

The mock path "../../../$provider/containers/$containerName/objects/$" is deeply nested and tightly coupled to the current file location. Consider using a path alias (e.g., @/client/routes/...) if the project supports it, or document this dependency clearly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx
around lines 31 - 42, The relative mock path string
"../../../$provider/containers/$containerName/objects/$" is fragile; update the
vi.mock call to reference a stable path alias (for example use
"@/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$")
or add a module name mapping in your test config (Vitest/Jest) and use that
alias in the vi.mock invocation; ensure the mocked export shape (Route,
useSearch, useParams) remains unchanged so tests still stub Route.useParams and
Route.useSearch correctly.

1-1: Unnecessary React import with new JSX transform.

With the new JSX transform (React 17+), explicit import React from "react" is not required for JSX. Since this project uses React 19.1.0, this import can be removed.

Suggested fix
-import React from "react"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx
at line 1, Remove the unnecessary top-level import statement `import React from
"react"` from the test file `index.test.tsx` (the Swift Objects test) — the
project uses the new JSX transform (React 17+ / React 19.1.0) so JSX works
without importing React; simply delete that import line to clean up the file.
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx (1)

1-1: Unnecessary React import with new JSX transform.

Same as previous files - this import can be removed with React 19's JSX transform.

Suggested fix
-import React from "react"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx
at line 1, Remove the unnecessary top-level "import React from \"react\"" in
ObjectsFileNavigation.test.tsx (the import statement at the top of the file)
since the project uses the new JSX transform; delete that import line and run
the tests to confirm no other code in the file relies on the React identifier
(leave other imports and the test code untouched).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx:
- Around line 105-114: The test "last segment is active and does not call
onPrefixClick when clicked" currently only checks that onPrefixClick wasn't
called with "a/b/c/"; update the assertion to ensure onPrefixClick was not
called at all (e.g., use expect(onPrefixClick).not.toHaveBeenCalled() or
expect(onPrefixClick).toHaveBeenCalledTimes(0)) after rendering via renderNav
and clicking the "c" element (cEl) so any accidental calls with other args are
caught; keep the rest of the test (userEvent.setup, renderNav, finding cEl)
unchanged.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx:
- Around line 159-163: The test title is inconsistent with its assertion: change
the test description string in ObjectsTableView.test.tsx (the test that calls
renderView with makeObject and checks getByTestId("object-row-file.txt")) to
reflect the actual expected symbol "—" (e.g., "renders — for missing
last_modified on objects") so the name matches the assertion and component
behavior.

---

Nitpick comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx:
- Around line 73-77: Replace the mutable shared trpcState object with a factory
function that returns a fresh state for each test to ensure isolation: create a
function (e.g., makeTrpcState or createTrpcState) that returns the object
currently assigned to trpcState (including objects: mockObjects as
ObjectSummary[] | undefined, isLoading: false, error: null) and call that
factory inside beforeEach to reassign a new local trpcState for each test;
update any references to trpcState in the test file (including beforeEach and
tests using mockObjects) so they use the freshly created instance instead of a
shared mutable variable.
- Around line 31-42: The relative mock path string
"../../../$provider/containers/$containerName/objects/$" is fragile; update the
vi.mock call to reference a stable path alias (for example use
"@/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/$")
or add a module name mapping in your test config (Vitest/Jest) and use that
alias in the vi.mock invocation; ensure the mocked export shape (Route,
useSearch, useParams) remains unchanged so tests still stub Route.useParams and
Route.useSearch correctly.
- Line 1: Remove the unnecessary top-level import statement `import React from
"react"` from the test file `index.test.tsx` (the Swift Objects test) — the
project uses the new JSX transform (React 17+ / React 19.1.0) so JSX works
without importing React; simply delete that import line to clean up the file.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx:
- Line 1: Remove the unnecessary top-level "import React from \"react\"" in
ObjectsFileNavigation.test.tsx (the import statement at the top of the file)
since the project uses the new JSX transform; delete that import line and run
the tests to confirm no other code in the file relies on the React identifier
(leave other imports and the test code untouched).

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx:
- Line 1: Remove the unnecessary top-level import "import React from 'react'"
from the ObjectsTableView.test.tsx test file because React 19's automatic JSX
transform makes it redundant; update the file by deleting the import statement
(ensure no JSX pragma or direct use of the React identifier remains in
ObjectsTableView.test.tsx and run tests to confirm).
- Around line 186-196: The footer tests in ObjectsTableView.test.tsx are
asserting on partial text like /4 items/i which can break due to Lingui <Trans>
interpolation; update the tests (the test cases that call renderView and
makeObject) to assert the full localized pattern instead—e.g., use a regex that
matches "Showing {visibleCount} of {allCount} items" such as
/Showing\s+\d+\s+of\s+\d+\s+items/i or
screen.getByText(/Showing.*of.*items/i)—so the assertions target the complete
rendered sentence rather than only the trailing "X items".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a84fae78-3dfe-4da3-8fdf-ea016c7f4dee

📥 Commits

Reviewing files that changed from the base of the PR and between 1cae840 and c3d2466.

📒 Files selected for processing (3)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx

@mark-karnaukh-extern-sap mark-karnaukh-extern-sap marked this pull request as ready for review March 23, 2026 12:18
@mark-karnaukh-extern-sap mark-karnaukh-extern-sap requested a review from a team as a code owner March 23, 2026 12:18
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx (1)

234-238: ⚠️ Potential issue | 🟡 Minor

Use a plain variable placeholder inside <Trans> instead of error.message access.

Line 237 still uses property access interpolation inside <Trans>, which is the same lint/i18n extraction issue flagged earlier.

💡 Proposed fix
   // Handle error state
   if (error) {
+    const message = error.message
     return (
       <Stack className="fixed inset-0" distribution="center" alignment="center" direction="vertical">
-        <Trans>Error Loading Objects: {error.message}</Trans>
+        <Trans>Error Loading Objects: {message}</Trans>
       </Stack>
     )
   }

Use this read-only check to find the same pattern elsewhere:

#!/bin/bash
rg -nP --type=tsx '<Trans[^>]*>[^<]*\{[A-Za-z_$][\w$]*\.[^}]+\}[^<]*</Trans>'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
around lines 234 - 238, The <Trans> element currently interpolates a property
access ({error.message}) which breaks i18n extraction; extract the message into
a local plain variable (e.g., const errorMessage = error?.message ?? '') before
the JSX and then use that variable inside <Trans> (e.g., <Trans>Error Loading
Objects: {errorMessage}</Trans>), replacing the direct property access; target
the JSX block using the <Trans> element and the error variable to apply this
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx:
- Around line 234-238: The <Trans> element currently interpolates a property
access ({error.message}) which breaks i18n extraction; extract the message into
a local plain variable (e.g., const errorMessage = error?.message ?? '') before
the JSX and then use that variable inside <Trans> (e.g., <Trans>Error Loading
Objects: {errorMessage}</Trans>), replacing the direct property access; target
the JSX block using the <Trans> element and the error variable to apply this
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a8758d4-caee-436c-b6ad-df114c1a224f

📥 Commits

Reviewing files that changed from the base of the PR and between c3d2466 and 64df23e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • apps/aurora-portal/package.json
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/aurora-portal/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx (1)

177-205: Memoize row derivation to avoid repeated O(n log n) work per render.

buildRows + filter + sort are recomputed on every render. For large containers, this can become a visible UI cost even with virtualization.

⚙️ Proposed refactor
-import { useState, startTransition } from "react"
+import { useMemo, useState, startTransition } from "react"
...
-  const allRows = buildRows((objects ?? []) as ObjectSummary[], currentPrefix)
-
-  const filteredRows = allRows.filter((row) => row.displayName.toLowerCase().includes(searchTerm.toLowerCase().trim()))
-
-  const sortedRows = !sortSettings.sortBy
-    ? filteredRows
-    : [...filteredRows].sort((a, b) => {
+  const sortedRows = useMemo(() => {
+    const allRows = buildRows((objects ?? []) as ObjectSummary[], currentPrefix)
+    const filteredRows = allRows.filter((row) =>
+      row.displayName.toLowerCase().includes(searchTerm.toLowerCase().trim())
+    )
+
+    if (!sortSettings.sortBy) return filteredRows
+
+    return [...filteredRows].sort((a, b) => {
         let comparison = 0
         switch (sortSettings.sortBy) {
           case "name":
             comparison = a.displayName.localeCompare(b.displayName)
             break
...
         }
         return sortSettings.sortDirection === "desc" ? -comparison : comparison
       })
+  }, [objects, currentPrefix, searchTerm, sortSettings.sortBy, sortSettings.sortDirection])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
around lines 177 - 205, The rows (buildRows -> filteredRows -> sortedRows) are
recomputed every render causing O(n log n) work; wrap the entire derivation
(call to buildRows, the search filter using searchTerm, and the sorting using
sortSettings) in a useMemo that depends on [objects, currentPrefix, searchTerm,
sortSettings] (or the specific keys within sortSettings) so the expensive
computation only runs when inputs change; update references to use the memoized
value instead of recomputing inline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx:
- Around line 213-219: handleSortChange currently normalizes newSort.sortBy
using lossy .toString(), which can yield unsupported keys (e.g., "0" or
"name,bytes") and cause the switch in the sort application logic to no-op;
update handleSortChange to explicitly normalize newSort.sortBy into one of the
supported string keys before calling setSortSettings (use type-safe checks: if
sortBy is a string and is one of the allowed keys use it, if it's a number map
it to the corresponding allowed key, if it's an array pick the first allowed
element or join/map to a canonical key, otherwise default to "name"), and ensure
the SortSettings passed into setSortSettings uses that normalized value instead
of newSort.sortBy?.toString().

---

Nitpick comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx:
- Around line 177-205: The rows (buildRows -> filteredRows -> sortedRows) are
recomputed every render causing O(n log n) work; wrap the entire derivation
(call to buildRows, the search filter using searchTerm, and the sorting using
sortSettings) in a useMemo that depends on [objects, currentPrefix, searchTerm,
sortSettings] (or the specific keys within sortSettings) so the expensive
computation only runs when inputs change; update references to use the memoized
value instead of recomputing inline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62b4cd10-8044-4fd6-88e3-f2d17f337de9

📥 Commits

Reviewing files that changed from the base of the PR and between 64df23e and ed5bb80.

📒 Files selected for processing (1)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/index.tsx (1)

121-125: Consider defensive handling for availableServices.

Line 124 uses non-null assertion (availableServices!) after optional chaining on line 123. If trpcClient is undefined (or if the query returns undefined unexpectedly), this assertion would pass an invalid value to checkServiceAvailability, potentially causing a runtime error within that function when accessing availableServices.reduce(...).

Since beforeLoad runs before the component mounts, a silent failure here could be confusing to debug.

🛡️ Proposed defensive check
 beforeLoad: async ({ context, params }) => {
   const { trpcClient } = context
   const availableServices = await trpcClient?.auth.getAvailableServices.query()
+  if (!availableServices) {
+    throw redirect({
+      to: "/accounts/$accountId/projects",
+      params: { accountId: params.accountId },
+    })
+  }
-  checkServiceAvailability(availableServices!, params)
+  checkServiceAvailability(availableServices, params)
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/index.tsx
around lines 121 - 125, beforeLoad is calling
trpcClient?.auth.getAvailableServices.query() and then force-unwrapping
availableServices with availableServices! when passing to
checkServiceAvailability, which can cause a runtime error if trpcClient is
undefined or the query returns undefined; update beforeLoad to defensively
handle unavailable services by checking trpcClient and availableServices before
calling checkServiceAvailability (e.g., if trpcClient is missing abort/return
early or throw a meaningful Error, and if availableServices is undefined pass an
empty array or handle the error path), referencing the beforeLoad handler, the
trpcClient variable, availableServices, and the checkServiceAvailability(...)
call so the call site safely handles undefined results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/aurora-portal/src/client/routes/_auth/accounts/`$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/index.tsx:
- Around line 121-125: beforeLoad is calling
trpcClient?.auth.getAvailableServices.query() and then force-unwrapping
availableServices with availableServices! when passing to
checkServiceAvailability, which can cause a runtime error if trpcClient is
undefined or the query returns undefined; update beforeLoad to defensively
handle unavailable services by checking trpcClient and availableServices before
calling checkServiceAvailability (e.g., if trpcClient is missing abort/return
early or throw a meaningful Error, and if availableServices is undefined pass an
empty array or handle the error path), referencing the beforeLoad handler, the
trpcClient variable, availableServices, and the checkServiceAvailability(...)
call so the call site safely handles undefined results.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 41561a31-d90b-4d0a-847a-12941a4fb1fd

📥 Commits

Reviewing files that changed from the base of the PR and between 64df23e and 1801ec7.

📒 Files selected for processing (12)
  • apps/aurora-portal/src/client/routeTree.gen.ts
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/$containerName/objects/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/index.test.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/ContainerTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Containers/index.test.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/$provider/containers/index.tsx
  • apps/aurora-portal/src/client/routes/_auth/accounts/$accountId/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.test.tsx

@mark-karnaukh-extern-sap mark-karnaukh-extern-sap merged commit 9341300 into main Mar 25, 2026
19 checks passed
@mark-karnaukh-extern-sap mark-karnaukh-extern-sap deleted the mark-swift-objects-file-browser-interface branch March 25, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

3 participants