Skip to content

fix(interface): wire Space Settings and fix space switcher dropdown - #3078

Open
gprot42 wants to merge 4 commits into
spacedriveapp:mainfrom
gprot42:fix/space-switcher-settings
Open

fix(interface): wire Space Settings and fix space switcher dropdown#3078
gprot42 wants to merge 4 commits into
spacedriveapp:mainfrom
gprot42:fix/space-switcher-settings

Conversation

@gprot42

@gprot42 gprot42 commented Jul 8, 2026

Copy link
Copy Markdown

Summary

The All Devices space switcher dropdown was unreadable on Tauri's transparent window. Space Settings had no handler, and opening New Space from the dropdown broke Radix focus.

Changes

  • Opaque !bg-sidebar-box background on the dropdown menu
  • CSS override for sidebar dropdowns in apps/tauri/src/index.css
  • Wire Space Settings to a new SpaceSettingsModal (spaces.update)
  • Close dropdown before opening dialogs (Radix focus trap fix)
  • Shared color/icon presets for Create Space and Space Settings

Test plan

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@gprot42, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 880b1552-0e00-46e9-9322-0130dad75cd6

📥 Commits

Reviewing files that changed from the base of the PR and between 2801014 and 0cb0279.

📒 Files selected for processing (12)
  • apps/tauri/src/index.css
  • apps/tauri/src/stubs/debug.ts
  • apps/tauri/src/stubs/spacebot-api-client.ts
  • apps/tauri/vite.config.ts
  • packages/interface/src/Settings/pages/AdvancedSettings.tsx
  • packages/interface/src/Settings/pages/ServicesSettings.tsx
  • packages/interface/src/components/SpacesSidebar/AddGroupModal.tsx
  • packages/interface/src/components/SpacesSidebar/CreateSpaceModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx
  • packages/interface/src/components/SpacesSidebar/spacePresets.ts
  • packages/interface/src/routes/settings/index.tsx

Walkthrough

Adds a space settings dialog and shared presets, threads sort order through explorer state, queries, and views, and updates Tauri aliases, stubs, and overlay styling. A CLI directory listing call and a core test fixture now pass an explicit directory sort direction.

Changes

Space settings feature

Layer / File(s) Summary
Shared preset constants
packages/interface/src/components/SpacesSidebar/spacePresets.ts, .../CreateSpaceModal.tsx
Adds exported preset color and icon arrays and updates the create-space modal to import them.
Space settings dialog
.../SpaceSettingsModal.tsx
Adds the space settings dialog hook, mutation flow, local form state, and dialog UI for editing name, color, and icon.
SpaceSwitcher dropdown
.../SpaceSwitcher.tsx
Controls dropdown open state, defers dialog opening until after menu close, and updates menu item selection handling and disablement.

Explorer sort order flow

Layer / File(s) Summary
Sort order contract
packages/interface/src/routes/explorer/sortUtils.ts, packages/interface/src/components/TabManager/TabManagerContext.tsx, core/src/ops/files/query/directory_listing.rs, core/tests/normalized_cache_fixtures_test.rs
Adds shared sort types and helpers, extends tab state with persisted sort order, and initializes directory listing inputs with an explicit sort direction.
Core directory sorting
core/src/ops/files/query/directory_listing.rs
Uses the new sort-direction input in indexed queries and in-memory sorting, including the default-direction helper and direction reversal logic.
Explorer sort context
packages/interface/src/routes/explorer/context.tsx
Re-exports sort order, derives the active sort order from tab state, and adds sort toggling and column-sort handlers to the explorer context.
Explorer views
packages/interface/src/routes/explorer/ExplorerView.tsx, .../hooks/useExplorerFiles.ts, .../hooks/useExplorerKeyboard.ts, .../views/*
Wires explorer views to the new sort order, passes sort direction into directory listing queries, updates client-side directory sorting, and adds the storage action in the top bar.
CLI directory listing input
apps/cli/src/domains/file/mod.rs
Sets an explicit sort_direction on the directory listing query input.

Tauri compatibility updates

Layer / File(s) Summary
Vite aliases and stubs
apps/tauri/vite.config.ts, apps/tauri/src/stubs/*
Adds Bun-based CommonJS resolution, aliases the spacebot API client to a local stub when absent, and wires debug and interop package aliases into Vite.
Tauri CSS overlay
apps/tauri/src/index.css
Extends Tailwind source scanning and adds overlay, dialog, menu, and sidebar styling for the transparent Tauri window.

Estimated code review effort: 4 (Complex) | ~60 minutes

Poem

I’m a rabbit with a sorting wand,
I hop through files and dialogs grand.
Presets shine, and menus glide,
Sort order flips from side to side.
Tauri blurs, then clears the view —
hop, save, sort, and scurry through 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers summary, changes, and test plan, but it omits the required 'Closes #(issue)' reference. Add a 'Closes #' line per the template, and create or reference the issue if one does not exist.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main interface change: wiring Space Settings and fixing the space switcher dropdown.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx (1)

19-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an explicit interface for component props.

Inline type { id: number; space: Space } should be an explicit interface per coding guidelines. As per coding guidelines, "Use explicit TypeScript interfaces for component props instead of implicit types."

♻️ Proposed refactor
-function SpaceSettingsDialog(props: { id: number; space: Space }) {
+interface SpaceSettingsDialogProps {
+	id: number;
+	space: Space;
+}
+
+function SpaceSettingsDialog(props: SpaceSettingsDialogProps) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx` at
line 19, The SpaceSettingsDialog component is using an inline props type instead
of an explicit interface. Define a named interface for the component props (for
example, alongside SpaceSettingsDialog) and update the component signature to
use that interface so the props shape is explicit and consistent with the coding
guidelines.

Source: Coding guidelines

packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx (1)

76-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename these dialog helpers to drop the use prefix. They’re plain dialog factories, so the hook-like name is misleading when they’re passed through menu callbacks. createSpaceDialog / createSpaceSettingsDialog would be clearer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx` around
lines 76 - 92, Rename the dialog factory helpers referenced in SpaceSwitcher so
they no longer use the hook-like `use` prefix; update the menu callbacks to call
`createSpaceDialog` and `createSpaceSettingsDialog` instead of
`useCreateSpaceDialog` and `useSpaceSettingsDialog`. Make sure the corresponding
helper exports/imports and any other call sites are updated consistently so the
names reflect that these are plain dialog factories, not React hooks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx`:
- Around line 30-40: The `onSubmit` handler in `SpaceSettingsModal` currently
awaits `updateSpace.mutateAsync` without surfacing failures, so rejected
`spaces.update` requests leave the dialog open with no user feedback. Wrap the
`mutateAsync` call in a try-catch inside `onSubmit`, keep `dialog.state.open =
false` only on success, and use an existing UI feedback path in this component
(toast, inline form error, or similar) to show the caught error message to the
user.

---

Nitpick comments:
In `@packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx`:
- Line 19: The SpaceSettingsDialog component is using an inline props type
instead of an explicit interface. Define a named interface for the component
props (for example, alongside SpaceSettingsDialog) and update the component
signature to use that interface so the props shape is explicit and consistent
with the coding guidelines.

In `@packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx`:
- Around line 76-92: Rename the dialog factory helpers referenced in
SpaceSwitcher so they no longer use the hook-like `use` prefix; update the menu
callbacks to call `createSpaceDialog` and `createSpaceSettingsDialog` instead of
`useCreateSpaceDialog` and `useSpaceSettingsDialog`. Make sure the corresponding
helper exports/imports and any other call sites are updated consistently so the
names reflect that these are plain dialog factories, not React hooks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b7d25112-f575-49ee-a22c-87edc595fc27

📥 Commits

Reviewing files that changed from the base of the PR and between 60369e9 and ef0597f.

📒 Files selected for processing (4)
  • packages/interface/src/components/SpacesSidebar/CreateSpaceModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx
  • packages/interface/src/components/SpacesSidebar/spacePresets.ts

Comment on lines +30 to +40
const onSubmit = form.handleSubmit(async (data) => {
if (!data.name?.trim()) return;

await updateSpace.mutateAsync({
space_id: props.space.id,
name: data.name.trim(),
icon: selectedIcon,
color: selectedColor,
});
dialog.state.open = false;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add error handling for the spaces.update mutation.

If mutateAsync rejects, handleSubmit catches the error but it's never surfaced to the user — the dialog stays open with no feedback. Wrap the mutation in a try-catch and display the error (toast, inline message, or form error state).

🛡️ Proposed fix
 const onSubmit = form.handleSubmit(async (data) => {
 	if (!data.name?.trim()) return;

-	await updateSpace.mutateAsync({
-		space_id: props.space.id,
-		name: data.name.trim(),
-		icon: selectedIcon,
-		color: selectedColor,
-	});
-	dialog.state.open = false;
+	try {
+		await updateSpace.mutateAsync({
+			space_id: props.space.id,
+			name: data.name.trim(),
+			icon: selectedIcon,
+			color: selectedColor,
+		});
+		dialog.state.open = false;
+	} catch (error) {
+		console.error('Failed to update space:', error);
+		// Surface error to user via toast, inline message, or form error state
+	}
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx`
around lines 30 - 40, The `onSubmit` handler in `SpaceSettingsModal` currently
awaits `updateSpace.mutateAsync` without surfacing failures, so rejected
`spaces.update` requests leave the dialog open with no user feedback. Wrap the
`mutateAsync` call in a try-catch inside `onSubmit`, keep `dialog.state.open =
false` only on success, and use an existing UI feedback path in this component
(toast, inline form error, or similar) to show the caught error message to the
user.

@gprot42
gprot42 force-pushed the fix/space-switcher-settings branch from ef0597f to 2801014 Compare July 8, 2026 17:38
@gprot42
gprot42 force-pushed the fix/space-switcher-settings branch from 2801014 to 654b15b Compare July 8, 2026 17:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts (1)

47-61: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add folders_first to the directory listing query for keyboard navigation consistency.

The query now includes sort_direction but omits folders_first. When the user has "folders first" enabled, the displayed files (from useExplorerFiles) have directories first, but this keyboard navigation query returns files without that ordering. Arrow key navigation and "select all" will operate on a different file order than what's displayed.

💚 Proposed fix
 				sort_by: sortBy as DirectorySortBy,
 				sort_direction: toSortDirection(sortOrder),
+				folders_first: viewSettings.foldersFirst,
 			}
 			: null!,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts` around
lines 47 - 61, The directory listing query in useExplorerKeyboard’s
useNormalizedQuery input is missing the folders-first ordering flag, so keyboard
navigation can diverge from the file order shown by useExplorerFiles. Update the
query payload to pass the same folders-first setting used elsewhere when
building the directory listing request, alongside sort_by and sort_direction, so
arrow-key navigation and select-all operate on the displayed order.
🧹 Nitpick comments (2)
packages/interface/src/routes/explorer/views/KnowledgeView.tsx (1)

85-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent sortBy casting between KnowledgeView and useExplorerFiles.

useExplorerFiles.ts casts sortBy as DirectorySortBy before passing it to the directory listing query, but KnowledgeView.tsx passes sortBy directly without a cast. If SortBy (DirectorySortBy | MediaSortBy) includes values outside DirectorySortBy, this is a type safety gap. Align both call sites to use the same approach.

As per coding guidelines, packages/interface/**/*.{tsx,ts} should use auto-generated types from Rust and never manually redefine or cast backend types — verify whether the cast is needed or the query input accepts the broader SortBy type.

♻️ Suggested alignment
 				sort_by: sortBy,
+```

If the cast is needed (as in `useExplorerFiles.ts`):

```diff
-				sort_by: sortBy,
+				sort_by: sortBy as DirectorySortBy,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/routes/explorer/views/KnowledgeView.tsx` around lines
85 - 98, Align KnowledgeView with useExplorerFiles by checking the type expected
by the files.directory_listing query input and avoiding an unsafe mismatch
between SortBy and DirectorySortBy. In KnowledgeView.tsx, use the same typing
approach as useExplorerFiles.ts: either accept the broader query type if the
Rust-generated schema supports it, or narrow sortBy through the existing
DirectorySortBy-safe path before passing it to useNormalizedQuery. Keep the fix
local to KnowledgeView and preserve the shared sortBy/toSortDirection flow.

Source: Coding guidelines

packages/interface/src/routes/explorer/ExplorerView.tsx (1)

152-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Type SortMenu to accept ViewMode directly
ExplorerView still passes viewMode as any into both SortMenuPanel and SortMenu. SortMenu only branches on "media" vs everything else, so it can take the shared ViewMode type (or a shared alias) instead of suppressing type checking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/interface/src/routes/explorer/ExplorerView.tsx` around lines 152 -
156, ExplorerView is still forcing a type cast when passing viewMode into
SortMenu, which hides the real type mismatch. Update SortMenu to accept the
shared ViewMode type (or a common alias) directly, and adjust its props and any
internal branching so it handles the existing media vs non-media cases without
requiring viewMode as any. Then remove the cast in ExplorerView and keep the
SortMenuPanel/SortMenu call sites typed consistently.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts`:
- Around line 47-61: The directory listing query in useExplorerKeyboard’s
useNormalizedQuery input is missing the folders-first ordering flag, so keyboard
navigation can diverge from the file order shown by useExplorerFiles. Update the
query payload to pass the same folders-first setting used elsewhere when
building the directory listing request, alongside sort_by and sort_direction, so
arrow-key navigation and select-all operate on the displayed order.

---

Nitpick comments:
In `@packages/interface/src/routes/explorer/ExplorerView.tsx`:
- Around line 152-156: ExplorerView is still forcing a type cast when passing
viewMode into SortMenu, which hides the real type mismatch. Update SortMenu to
accept the shared ViewMode type (or a common alias) directly, and adjust its
props and any internal branching so it handles the existing media vs non-media
cases without requiring viewMode as any. Then remove the cast in ExplorerView
and keep the SortMenuPanel/SortMenu call sites typed consistently.

In `@packages/interface/src/routes/explorer/views/KnowledgeView.tsx`:
- Around line 85-98: Align KnowledgeView with useExplorerFiles by checking the
type expected by the files.directory_listing query input and avoiding an unsafe
mismatch between SortBy and DirectorySortBy. In KnowledgeView.tsx, use the same
typing approach as useExplorerFiles.ts: either accept the broader query type if
the Rust-generated schema supports it, or narrow sortBy through the existing
DirectorySortBy-safe path before passing it to useNormalizedQuery. Keep the fix
local to KnowledgeView and preserve the shared sortBy/toSortDirection flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 712a62ed-a8d4-4a25-9249-1502f6688699

📥 Commits

Reviewing files that changed from the base of the PR and between ef0597f and 2801014.

⛔ Files ignored due to path filters (1)
  • packages/ts-client/src/generated/types.ts is excluded by !**/generated/**, !**/generated/**
📒 Files selected for processing (22)
  • apps/cli/src/domains/file/mod.rs
  • apps/tauri/src/index.css
  • apps/tauri/src/stubs/debug.ts
  • apps/tauri/src/stubs/spacebot-api-client.ts
  • apps/tauri/vite.config.ts
  • core/src/ops/files/query/directory_listing.rs
  • core/tests/normalized_cache_fixtures_test.rs
  • packages/interface/src/components/SpacesSidebar/CreateSpaceModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx
  • packages/interface/src/components/SpacesSidebar/spacePresets.ts
  • packages/interface/src/components/TabManager/TabManagerContext.tsx
  • packages/interface/src/routes/explorer/ExplorerView.tsx
  • packages/interface/src/routes/explorer/context.tsx
  • packages/interface/src/routes/explorer/hooks/useExplorerFiles.ts
  • packages/interface/src/routes/explorer/hooks/useExplorerKeyboard.ts
  • packages/interface/src/routes/explorer/sortUtils.ts
  • packages/interface/src/routes/explorer/views/ColumnView/Column.tsx
  • packages/interface/src/routes/explorer/views/ColumnView/ColumnView.tsx
  • packages/interface/src/routes/explorer/views/KnowledgeView.tsx
  • packages/interface/src/routes/explorer/views/ListView/ListView.tsx
  • packages/interface/src/routes/explorer/views/SizeView/SizeView.tsx
✅ Files skipped from review due to trivial changes (4)
  • packages/interface/src/components/SpacesSidebar/spacePresets.ts
  • apps/tauri/src/stubs/debug.ts
  • packages/interface/src/routes/explorer/views/SizeView/SizeView.tsx
  • apps/cli/src/domains/file/mod.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/interface/src/components/SpacesSidebar/SpaceSettingsModal.tsx
  • packages/interface/src/components/SpacesSidebar/CreateSpaceModal.tsx
  • packages/interface/src/components/SpacesSidebar/SpaceSwitcher.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant