feat(ui): panel pin/dock, FLIP animations and workspace management#43
feat(ui): panel pin/dock, FLIP animations and workspace management#43
Conversation
Deletes all sessions, plans, and comments for a workspace in one call.
- Outline and Review panels can be pinned (docked) or floating - FLIP-based expand/minimize animations with backdrop - Workspace cards: direct close, forget action with confirmation - Outline icon changed from Hash to AlignLeft
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughRemoves the macOS app and extensive web app (sources, UI primitives, assets, configs) and adds Tauri backend commands plus frontend flows to forget workspace data and to pin/dock review/outline panels. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Frontend (Tauri)
participant API as Tauri Command Layer
participant DB as SQLite
participant FS as Filesystem (app data)
UI->>API: invoke("forget_workspace_data", workspace_path, workspace_type)
API->>DB: begin transaction
alt workspace_type == "directory"
API->>DB: delete from comments where path LIKE workspace_path/%
API->>DB: delete from file_hashes where file_path LIKE workspace_path/%
API->>DB: delete sessions where workspace_path = workspace_path
DB-->>API: return deleted session IDs
API->>FS: remove plan files for each session ID in app data
else
API->>DB: delete from comments where file_path = workspace_path
API->>DB: delete from file_hashes where file_path = workspace_path
end
API->>DB: commit
DB-->>API: commit result
API-->>UI: return success / error
UI->>FS: unwatches file (if applicable) and removes workspace from client state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (3)
apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx (1)
48-49: Avoid hardcoding translated strings in selectors.These assertions are tightly coupled to Portuguese copy; a locale/default-language change will break tests unrelated to behavior. Prefer role-based queries with stable labels (or mock
tto return keys).Also applies to: 58-60, 70-71
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx` around lines 48 - 49, Tests in OutlineSidebar.test.tsx are using hardcoded Portuguese strings (e.g., screen.getByTitle('Fixar painel')) which will break if locales change; replace those string-based selectors with stable queries like getByRole/getByLabelText (e.g., screen.getByRole('button', { name: /pin-panel|fix-panel|pin/i }) or use aria-labels) or alternatively mock the translation function (mock the i18n/t used in the component to return predictable keys) and update the three occurrences (the getByTitle call at the shown line plus the assertions around 58-60 and 70-71) to use role-based queries or mocked labels instead of literal translated text.apps/tauri/src/components/MarkdownViewer.tsx (1)
376-398: Use shadcnButtonfor these new panel toggles.The new outline/review toggle controls are plain
<button>elements; in this components layer, UI primitives should use shadcn components.🔧 Proposed fix
- {!outlineOpen && headings.length > 0 && ( - <button + {!outlineOpen && headings.length > 0 && ( + <Button + variant="outline" + size="icon" onClick={() => setOutlineOpen(true)} - className="absolute top-3 left-3 z-20 h-8 w-8 flex items-center justify-center rounded-md bg-card border border-border text-muted-foreground hover:text-foreground hover:bg-accent transition-colors shadow-sm" + className="absolute top-3 left-3 z-20 h-8 w-8 text-muted-foreground hover:text-foreground shadow-sm" title={t("outline.title")} > <AlignLeft className="h-4 w-4" /> - </button> + </Button> )}As per coding guidelines, "Use shadcn/ui for all UI primitives; install new components via
npx shadcn@latest add <component>".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/components/MarkdownViewer.tsx` around lines 376 - 398, Replace the plain <button> toggles with the shadcn Button component: import and use Button for the outline toggle (wrapping AlignLeft) and the review toggle (wrapping MessageSquare), keeping the same onClick handlers (setOutlineOpen, and the combined setReviewOpen + review.setIsPanelOpen) and title props; move the badge that shows review.unresolvedCount into Button's content (preserving styling or using Button variants/size) and keep existing className/aria attributes as needed. If Button is not yet added, run npx shadcn@latest add button then update the two elements referenced by setOutlineOpen and the review toggle logic (review.setIsPanelOpen, review.unresolvedCount) to use the shadcn Button API instead of a raw button.apps/tauri/src/App.tsx (1)
20-24: Replace hardcoded overlay/shadow colors with theme variables.The new animation styling introduces hardcoded color values (
rgba(...),bg-black/45), which breaks theme-token consistency.As per coding guidelines, "Use TailwindCSS with HSL CSS variables for theming instead of hardcoded color values".
Also applies to: 223-227
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/App.tsx` around lines 20 - 24, The constants (EXPAND_EASING, MINIMIZE_EASING, DURATION_S, SHADOW) currently embed hardcoded colors (e.g., "rgba(...)" and "bg-black/45"); update the styling to use theme HSL CSS variables/Tailwind tokens instead: replace any rgba(...) overlay values with a CSS variable like var(--overlay-color) or a Tailwind HSL variable (e.g., theme('colors.overlay') / --tw-overlay) and change SHADOW to reference HSL variables for color stops (e.g., "0 30px 90px hsla(var(--shadow-h), var(--shadow-s), var(--shadow-l), 0.55), 0 0 0 0.5px hsla(var(--highlight-h), var(--highlight-s), var(--highlight-l), 0.1)"); also update places flagged (around the 223-227 region) where bg-black/45 is used to use the same theme variable (e.g., bg-[hsla(var(--overlay-h),var(--overlay-s),var(--overlay-l),0.45)] or a named Tailwind token) so all overlay and shadow colors come from theme variables rather than hardcoded rgba values.
🤖 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/tauri/src-tauri/src/comments.rs`:
- Around line 143-149: The two DELETEs in delete_comments_for_file run
separately and can leave stale data if the second fails; wrap both operations in
a single database transaction by creating a Transaction from conn (e.g.,
conn.transaction()), run the two deletes against the transaction (tx.execute
with params![file_path]), map/propagate errors to the same Result<String, ...>
format, and commit the transaction (tx.commit()) so either both deletes succeed
or none are applied.
In `@apps/tauri/src-tauri/src/sessions.rs`:
- Around line 325-334: The directory "forget" branch currently only deletes
sessions/plans (delete_workspace_sessions + delete_plan) but leaves comments and
file_hashes behind; add and call a new function delete_comments_for_workspace in
apps/tauri/src-tauri/src/comments.rs and invoke it from the workspace_type ==
"directory" branch (alongside delete_workspace_sessions and delete_plan) to
purge all comments and file_hashes for files under the workspace; implement
delete_comments_for_workspace to accept the DB connection and workspace_path,
look up all file paths in that workspace and remove their rows from the comments
and file_hashes tables (mirroring the behavior of delete_comments_for_file but
operating on all files in the workspace) and return appropriate Result<> so the
caller can propagate errors.
- Around line 329-331: The loop in the forget flow swallows errors from
crate::plan_file::delete_plan by using let _ = ..., so plan deletion failures
are ignored; change the loop to propagate errors (e.g., replace let _ =
crate::plan_file::delete_plan(&app_data, id); with
crate::plan_file::delete_plan(&app_data, id)? inside the same function so any
filesystem error returns early, or collect results and return an aggregated Err
if any delete_plan call fails), ensuring the surrounding function's signature
returns a compatible Result so the ? operator can be used.
In `@apps/tauri/src/App.tsx`:
- Around line 83-89: The animation timeout assignment in the expand/minimize
flows can leave previous timers active; before calling window.setTimeout to
assign animTimeoutRef.current (used around ANIMATION_DURATION and in functions
like finishExpand and the minimize flow), clear any existing timer by checking
animTimeoutRef.current and calling clearTimeout(animTimeoutRef.current) (and
then nulling it) before reassigning, and likewise clear the timer when the
component unmounts to prevent stale callbacks from calling setAnimPhase,
setFlipTransform, setTransitionEnabled, or touching sourceCard.style.opacity
after the component has changed.
In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 366-370: The HTML returned from render_markdown is being fed
directly into the article via dangerouslySetInnerHTML which can introduce XSS;
sanitize the markup first (e.g., run html through a sanitizeHtml call that
strips <script>, inline event handlers (on*), javascript: and data: URLs, and
unsafe attributes) and use the sanitized string in dangerouslySetInnerHTML
(replace the current html variable with sanitizedHtml), or alternatively enforce
this sanitization in the Rust render_markdown command contract so the value
assigned to dangerouslySetInnerHTML is guaranteed safe; update the code paths
around render_markdown and the article element (articleRef /
dangerouslySetInnerHTML) to use the sanitized output.
- Around line 57-77: The component must listen for window "storage" events and
update outlinePinned and reviewPinned when OUTLINE_PINNED_KEY or
REVIEW_PINNED_KEY change; add a useEffect that registers a storage event handler
which checks event.key (OUTLINE_PINNED_KEY or REVIEW_PINNED_KEY), reads the new
value (localStorage.getItem or event.newValue), converts it to a boolean, and
calls setOutlinePinned or setReviewPinned accordingly, and remove the listener
in the cleanup; reference OUTLINE_PINNED_KEY, REVIEW_PINNED_KEY,
setOutlinePinned, setReviewPinned, and the existing
toggleOutlinePin/toggleReviewPin to keep behavior consistent.
In `@apps/tauri/src/components/OutlineSidebar.tsx`:
- Around line 69-77: The icon-only header action Buttons (the pin toggle and
close buttons rendered when onTogglePin/onClose are provided, using props
pinned, Pin/PinOff and X) lack accessible names; update those <Button> instances
to include aria-label and title attributes (use t(...) for localized labels,
e.g., t(pinned ? 'outline.unpin' : 'outline.pin') for the pin button and
t('outline.close') for the close button) and apply the same change to the other
occurrence of the close button (the one around lines 95-103) so both icon-only
controls have accessible names.
In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Around line 84-87: The confirm action for deleting a workspace in
WorkspaceCard currently calls onForget(workspace.id) without awaiting or
handling errors; update the AlertDialogAction onClick handler to call an async
wrapper that awaits onForget(workspace.id) and catches any rejection (e.g.,
try/catch) to show user feedback (toast/Alert) and prevent unhandled promise
rejections; ensure you reference the existing onForget function and
AlertDialogAction component so the handler replacement is localized to that
confirm button.
---
Nitpick comments:
In `@apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx`:
- Around line 48-49: Tests in OutlineSidebar.test.tsx are using hardcoded
Portuguese strings (e.g., screen.getByTitle('Fixar painel')) which will break if
locales change; replace those string-based selectors with stable queries like
getByRole/getByLabelText (e.g., screen.getByRole('button', { name:
/pin-panel|fix-panel|pin/i }) or use aria-labels) or alternatively mock the
translation function (mock the i18n/t used in the component to return
predictable keys) and update the three occurrences (the getByTitle call at the
shown line plus the assertions around 58-60 and 70-71) to use role-based queries
or mocked labels instead of literal translated text.
In `@apps/tauri/src/App.tsx`:
- Around line 20-24: The constants (EXPAND_EASING, MINIMIZE_EASING, DURATION_S,
SHADOW) currently embed hardcoded colors (e.g., "rgba(...)" and "bg-black/45");
update the styling to use theme HSL CSS variables/Tailwind tokens instead:
replace any rgba(...) overlay values with a CSS variable like
var(--overlay-color) or a Tailwind HSL variable (e.g., theme('colors.overlay') /
--tw-overlay) and change SHADOW to reference HSL variables for color stops
(e.g., "0 30px 90px hsla(var(--shadow-h), var(--shadow-s), var(--shadow-l),
0.55), 0 0 0 0.5px hsla(var(--highlight-h), var(--highlight-s),
var(--highlight-l), 0.1)"); also update places flagged (around the 223-227
region) where bg-black/45 is used to use the same theme variable (e.g.,
bg-[hsla(var(--overlay-h),var(--overlay-s),var(--overlay-l),0.45)] or a named
Tailwind token) so all overlay and shadow colors come from theme variables
rather than hardcoded rgba values.
In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 376-398: Replace the plain <button> toggles with the shadcn Button
component: import and use Button for the outline toggle (wrapping AlignLeft) and
the review toggle (wrapping MessageSquare), keeping the same onClick handlers
(setOutlineOpen, and the combined setReviewOpen + review.setIsPanelOpen) and
title props; move the badge that shows review.unresolvedCount into Button's
content (preserving styling or using Button variants/size) and keep existing
className/aria attributes as needed. If Button is not yet added, run npx
shadcn@latest add button then update the two elements referenced by
setOutlineOpen and the review toggle logic (review.setIsPanelOpen,
review.unresolvedCount) to use the shadcn Button API instead of a raw button.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ec4ca811-d4ca-49b3-98e5-54322b6e907c
⛔ Files ignored due to path filters (5)
apps/macos/Sources/Arandu/Resources/highlight.min.jsis excluded by!**/*.min.jsapps/web/bun.lockbis excluded by!**/bun.lockbapps/web/package-lock.jsonis excluded by!**/package-lock.jsonapps/web/public/favicon.icois excluded by!**/*.icoapps/web/public/placeholder.svgis excluded by!**/*.svg
📒 Files selected for processing (113)
apps/macos/Makefileapps/macos/Sources/Arandu/Info.plistapps/macos/Sources/Arandu/Resources/AppIcon.icnsapps/macos/Sources/Arandu/Resources/highlight-dark.min.cssapps/macos/Sources/Arandu/Resources/highlight-light.min.cssapps/macos/Sources/Arandu/Resources/style.cssapps/macos/Sources/Arandu/main.swiftapps/macos/project.ymlapps/macos/scripts/aranduapps/macos/scripts/install.shapps/tauri/src-tauri/src/comments.rsapps/tauri/src-tauri/src/lib.rsapps/tauri/src-tauri/src/sessions.rsapps/tauri/src/App.tsxapps/tauri/src/__tests__/components/OutlineSidebar.test.tsxapps/tauri/src/__tests__/components/WorkspaceCard.test.tsxapps/tauri/src/components/DirectoryWorkspace.tsxapps/tauri/src/components/HomeScreen.tsxapps/tauri/src/components/MarkdownViewer.tsxapps/tauri/src/components/OutlineSidebar.tsxapps/tauri/src/components/ReviewPanel.tsxapps/tauri/src/components/WorkspaceCard.tsxapps/tauri/src/contexts/AppContext.tsxapps/tauri/src/locales/en.jsonapps/tauri/src/locales/pt-BR.jsonapps/tauri/src/vite-env.d.tsapps/web/.gitignoreapps/web/.lovable/plan.mdapps/web/README.mdapps/web/components.jsonapps/web/eslint.config.jsapps/web/index.htmlapps/web/package.jsonapps/web/postcss.config.jsapps/web/public/robots.txtapps/web/src/App.cssapps/web/src/App.tsxapps/web/src/components/NavLink.tsxapps/web/src/components/arandu/ActivityBar.tsxapps/web/src/components/arandu/AranduLayout.tsxapps/web/src/components/arandu/MarkdownViewer.tsxapps/web/src/components/arandu/PrimarySidebar.tsxapps/web/src/components/arandu/ReviewPanel.tsxapps/web/src/components/arandu/StatusBar.tsxapps/web/src/components/arandu/TabBar.tsxapps/web/src/components/arandu/TitleBar.tsxapps/web/src/components/ui/accordion.tsxapps/web/src/components/ui/alert-dialog.tsxapps/web/src/components/ui/alert.tsxapps/web/src/components/ui/aspect-ratio.tsxapps/web/src/components/ui/avatar.tsxapps/web/src/components/ui/badge.tsxapps/web/src/components/ui/breadcrumb.tsxapps/web/src/components/ui/button.tsxapps/web/src/components/ui/calendar.tsxapps/web/src/components/ui/card.tsxapps/web/src/components/ui/carousel.tsxapps/web/src/components/ui/chart.tsxapps/web/src/components/ui/checkbox.tsxapps/web/src/components/ui/collapsible.tsxapps/web/src/components/ui/command.tsxapps/web/src/components/ui/context-menu.tsxapps/web/src/components/ui/dialog.tsxapps/web/src/components/ui/drawer.tsxapps/web/src/components/ui/dropdown-menu.tsxapps/web/src/components/ui/form.tsxapps/web/src/components/ui/hover-card.tsxapps/web/src/components/ui/input-otp.tsxapps/web/src/components/ui/input.tsxapps/web/src/components/ui/label.tsxapps/web/src/components/ui/menubar.tsxapps/web/src/components/ui/navigation-menu.tsxapps/web/src/components/ui/pagination.tsxapps/web/src/components/ui/popover.tsxapps/web/src/components/ui/progress.tsxapps/web/src/components/ui/radio-group.tsxapps/web/src/components/ui/resizable.tsxapps/web/src/components/ui/scroll-area.tsxapps/web/src/components/ui/select.tsxapps/web/src/components/ui/separator.tsxapps/web/src/components/ui/sheet.tsxapps/web/src/components/ui/sidebar.tsxapps/web/src/components/ui/skeleton.tsxapps/web/src/components/ui/slider.tsxapps/web/src/components/ui/sonner.tsxapps/web/src/components/ui/switch.tsxapps/web/src/components/ui/table.tsxapps/web/src/components/ui/tabs.tsxapps/web/src/components/ui/textarea.tsxapps/web/src/components/ui/toast.tsxapps/web/src/components/ui/toaster.tsxapps/web/src/components/ui/toggle-group.tsxapps/web/src/components/ui/toggle.tsxapps/web/src/components/ui/tooltip.tsxapps/web/src/components/ui/use-toast.tsapps/web/src/hooks/use-mobile.tsxapps/web/src/hooks/use-toast.tsapps/web/src/index.cssapps/web/src/lib/utils.tsapps/web/src/main.tsxapps/web/src/pages/Index.tsxapps/web/src/pages/NotFound.tsxapps/web/src/store/useAranduStore.tsapps/web/src/test/example.test.tsapps/web/src/test/setup.tsapps/web/src/types/arandu.tsapps/web/src/vite-env.d.tsapps/web/tailwind.config.tsapps/web/tsconfig.app.jsonapps/web/tsconfig.jsonapps/web/tsconfig.node.jsonapps/web/vite.config.tsapps/web/vitest.config.ts
💤 Files with no reviewable changes (96)
- apps/web/src/components/ui/aspect-ratio.tsx
- apps/web/src/vite-env.d.ts
- apps/web/src/components/NavLink.tsx
- apps/web/src/index.css
- apps/web/src/components/ui/skeleton.tsx
- apps/web/src/components/ui/toggle-group.tsx
- apps/web/src/components/ui/switch.tsx
- apps/web/src/components/ui/toggle.tsx
- apps/web/src/components/ui/slider.tsx
- apps/web/tsconfig.node.json
- apps/web/package.json
- apps/web/src/components/ui/textarea.tsx
- apps/web/src/pages/Index.tsx
- apps/web/src/components/ui/carousel.tsx
- apps/web/src/components/arandu/AranduLayout.tsx
- apps/web/src/components/ui/calendar.tsx
- apps/web/src/components/arandu/ActivityBar.tsx
- apps/web/src/components/ui/select.tsx
- apps/web/src/components/ui/label.tsx
- apps/web/src/components/ui/input.tsx
- apps/web/src/test/setup.ts
- apps/web/src/components/ui/breadcrumb.tsx
- apps/web/src/components/arandu/ReviewPanel.tsx
- apps/web/src/components/arandu/StatusBar.tsx
- apps/web/src/components/ui/hover-card.tsx
- apps/web/src/components/ui/command.tsx
- apps/web/src/components/ui/drawer.tsx
- apps/macos/scripts/arandu
- apps/web/components.json
- apps/macos/Sources/Arandu/Resources/style.css
- apps/web/index.html
- apps/web/src/components/ui/popover.tsx
- apps/web/README.md
- apps/web/src/components/arandu/TitleBar.tsx
- apps/web/src/App.tsx
- apps/web/src/store/useAranduStore.ts
- apps/web/vite.config.ts
- apps/web/postcss.config.js
- apps/macos/Sources/Arandu/Resources/highlight-light.min.css
- apps/macos/project.yml
- apps/macos/scripts/install.sh
- apps/web/tsconfig.app.json
- apps/macos/Makefile
- apps/web/src/components/ui/navigation-menu.tsx
- apps/web/src/components/ui/form.tsx
- apps/web/src/components/ui/checkbox.tsx
- apps/web/src/hooks/use-mobile.tsx
- apps/web/src/pages/NotFound.tsx
- apps/web/src/components/arandu/MarkdownViewer.tsx
- apps/web/src/components/ui/alert.tsx
- apps/web/src/App.css
- apps/web/src/components/ui/pagination.tsx
- apps/macos/Sources/Arandu/Info.plist
- apps/web/src/lib/utils.ts
- apps/web/src/components/ui/chart.tsx
- apps/web/.lovable/plan.md
- apps/web/vitest.config.ts
- apps/web/src/hooks/use-toast.ts
- apps/macos/Sources/Arandu/Resources/highlight-dark.min.css
- apps/web/src/types/arandu.ts
- apps/web/src/components/ui/progress.tsx
- apps/web/src/components/ui/resizable.tsx
- apps/web/src/components/ui/button.tsx
- apps/web/src/components/ui/input-otp.tsx
- apps/macos/Sources/Arandu/main.swift
- apps/web/src/test/example.test.ts
- apps/web/.gitignore
- apps/web/src/components/ui/scroll-area.tsx
- apps/web/src/components/ui/avatar.tsx
- apps/web/src/components/ui/separator.tsx
- apps/web/tailwind.config.ts
- apps/web/src/components/ui/radio-group.tsx
- apps/web/tsconfig.json
- apps/web/src/components/ui/collapsible.tsx
- apps/web/src/components/ui/table.tsx
- apps/web/src/components/ui/alert-dialog.tsx
- apps/web/src/components/ui/badge.tsx
- apps/web/src/components/ui/accordion.tsx
- apps/web/public/robots.txt
- apps/web/src/components/arandu/PrimarySidebar.tsx
- apps/web/src/components/ui/dropdown-menu.tsx
- apps/web/src/components/ui/context-menu.tsx
- apps/web/src/components/arandu/TabBar.tsx
- apps/web/src/components/ui/tooltip.tsx
- apps/web/src/components/ui/sonner.tsx
- apps/web/src/main.tsx
- apps/web/eslint.config.js
- apps/web/src/components/ui/toaster.tsx
- apps/web/src/components/ui/tabs.tsx
- apps/web/src/components/ui/menubar.tsx
- apps/web/src/components/ui/card.tsx
- apps/web/src/components/ui/sidebar.tsx
- apps/web/src/components/ui/use-toast.ts
- apps/web/src/components/ui/sheet.tsx
- apps/web/src/components/ui/toast.tsx
- apps/web/src/components/ui/dialog.tsx
- Wrap delete_comments_for_file in a transaction - Clear animation timers before reassigning - Add storage event sync for pinned panel state - Add aria-label to OutlineSidebar icon buttons - Handle async forget errors in WorkspaceCard
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
apps/tauri/src/App.tsx (1)
23-24: Use theme tokens instead of hardcoded animation colors.The shadow/backdrop currently hardcode color values, which breaks theme consistency.
🎨 Proposed direction
-const SHADOW = "0 30px 90px rgba(0,0,0,0.55), 0 0 0 0.5px rgba(255,255,255,0.1)"; +const SHADOW = "0 30px 90px hsl(var(--foreground) / 0.45), 0 0 0 0.5px hsl(var(--background) / 0.25)"; @@ - <div - className="absolute inset-0 z-[9] bg-black/45 pointer-events-none" - style={backdropStyle} - /> + <div + className="absolute inset-0 z-[9] pointer-events-none" + style={{ ...backdropStyle, backgroundColor: "hsl(var(--foreground) / 0.45)" }} + />As per coding guidelines, "Use TailwindCSS with HSL CSS variables for theming instead of hardcoded color values".
Also applies to: 229-230
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/App.tsx` around lines 23 - 24, The SHADOW constant currently embeds hardcoded RGBA colors; replace its literal color values with theme token CSS variables (HSL-based) and use those vars in the shadow string (e.g., var(--bg-backdrop), var(--accent-shadow)) so theming follows Tailwind/HSL conventions; update the SHADOW definition and any other occurrences with the same pattern (the other hardcoded shadow/backdrop uses) to reference the new CSS variables and ensure Tailwind or the app's global CSS defines those HSL variables.apps/tauri/src/components/MarkdownViewer.tsx (1)
358-358: Usecn()for conditional class composition.On Line 358, class merging is done with a template literal; this should use
cn()for consistency.♻️ Proposed fix
+import { cn } from "@/lib/utils"; @@ - <div className={`flex flex-row ${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}> + <div className={cn("flex flex-row", isEmbedded ? "h-full" : "flex-1 min-h-0")}>As per coding guidelines, "Use the
cn()utility fromlib/utils.tsfor merging Tailwind CSS classes".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/components/MarkdownViewer.tsx` at line 358, Replace the template-literal class merge in the MarkdownViewer component with the cn() utility: in the JSX where the div currently uses `className={`flex flex-row ${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}`, import and call cn (from lib/utils.ts) and pass the static and conditional classes (e.g., cn('flex flex-row', isEmbedded ? 'h-full' : 'flex-1 min-h-0')); ensure the MarkdownViewer file imports cn if it's not already present.
🤖 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/tauri/src/App.tsx`:
- Around line 57-61: When isExpanding is true but cardRect is missing the
current early return leaves the expand lifecycle half-complete; update the
branch where (!isExpanding || !cardRect) returns so that when isExpanding &&
!cardRect you finalize the expand state by clearing the flip transform and
settling animation flags—for example call setFlipTransform(null) (or undefined),
setTransitionEnabled(false), and setAnimPhase("expanded") (or the appropriate
final phase used elsewhere) so the expand flow never leaves flags out of sync;
reference symbols: isExpanding, cardRect, setFlipTransform,
setTransitionEnabled, setAnimPhase, calcInverseTransform.
In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 79-90: The onStorage handler (onStorage) only updates when
event.newValue != null, so clearing OUTLINE_PINNED_KEY or REVIEW_PINNED_KEY in
another window won't resync; update onStorage to handle event.newValue === null
by treating removal as "false" and calling setOutlinePinned(false) for
OUTLINE_PINNED_KEY and setReviewPinned(false) for REVIEW_PINNED_KEY (while
preserving the existing truthy check for "true" when newValue is present).
- Around line 389-412: Replace the two raw icon-only <button> elements in
MarkdownViewer (the one that calls setOutlineOpen(true) and the one that opens
the review panel via setReviewOpen(true) / review.setIsPanelOpen(true)) with the
shadcn/ui Button component, preserve the onClick handlers and existing className
styling, move the current title values to an aria-label on the new Button, keep
the icon children (AlignLeft and MessageSquare) and the unresolvedCount badge
logic intact, and add the Button import from shadcn/ui at the top of the file.
In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Around line 61-69: The icon-only action Buttons (the one using Unlink inside
the WorkspaceCard component and the similar close/forget button later) only set
title; add an aria-label attribute to each Button so screen readers can identify
them — use the same localized string you pass to title (e.g.,
aria-label={t(`${prefix}.forgetAction`)}) for the Unlink Button and the
corresponding t(...) key for the other icon button; update the Button props in
the JSX where Unlink and the close icon are rendered so both title and
aria-label are present.
---
Nitpick comments:
In `@apps/tauri/src/App.tsx`:
- Around line 23-24: The SHADOW constant currently embeds hardcoded RGBA colors;
replace its literal color values with theme token CSS variables (HSL-based) and
use those vars in the shadow string (e.g., var(--bg-backdrop),
var(--accent-shadow)) so theming follows Tailwind/HSL conventions; update the
SHADOW definition and any other occurrences with the same pattern (the other
hardcoded shadow/backdrop uses) to reference the new CSS variables and ensure
Tailwind or the app's global CSS defines those HSL variables.
In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Line 358: Replace the template-literal class merge in the MarkdownViewer
component with the cn() utility: in the JSX where the div currently uses
`className={`flex flex-row ${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}`,
import and call cn (from lib/utils.ts) and pass the static and conditional
classes (e.g., cn('flex flex-row', isEmbedded ? 'h-full' : 'flex-1 min-h-0'));
ensure the MarkdownViewer file imports cn if it's not already present.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6667d718-f890-4243-92bd-daf5aeb25373
📒 Files selected for processing (5)
apps/tauri/src-tauri/src/comments.rsapps/tauri/src/App.tsxapps/tauri/src/components/MarkdownViewer.tsxapps/tauri/src/components/OutlineSidebar.tsxapps/tauri/src/components/WorkspaceCard.tsx
- Add delete_comments_for_workspace using LIKE prefix match - Call it in the directory forget flow alongside session cleanup - Show forget button for file workspaces too
- Finalize expand state when cardRect is unavailable - Handle storage key removals when syncing pin state - Replace raw buttons with shadcn Button on toggle icons - Add aria-label to all icon-only buttons
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx (1)
59-60: Avoid locale-locked selectors in these tests.Hardcoded
'Fechar'/'Esquecer'makes tests brittle when language config changes. Prefer role-based queries scoped to the dialog and stable accessible names.Also applies to: 79-83, 94-98, 109-110
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx` around lines 59 - 60, Replace locale-locked title selectors like getByTitle('Fechar') / getByTitle('Esquecer') with role-based, accessible queries scoped to the dialog: find the dialog (or the WorkspaceCard component's dialog) using getByRole('dialog') and then use within(dialog).getByRole('button', { name: /close|fechar/i }) or a stable accessible name to click the close/forget buttons; update all occurrences referenced (closeButton, forgetButton, etc.) in WorkspaceCard.test.tsx to use scoped getByRole queries instead of hardcoded titles.
🤖 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/tauri/src-tauri/src/sessions.rs`:
- Around line 323-335: The forget flow currently holds the DB mutex
(db.0.lock()) while performing filesystem work and treats any non-"directory"
workspace_type as a file silently; change it to validate workspace_type
explicitly (accept "directory" and "file" only, returning an error for other
values) and restrict the DB lock scope so you acquire the mutex only for DB
operations: call delete_comments_for_workspace/delete_workspace_sessions or
delete_comments_for_file under the lock, capture the session_ids, then drop the
lock before calling app.path().app_data_dir() and crate::plan_file::delete_plan
for each id; ensure the functions delete_workspace_sessions and
delete_comments_for_workspace/delete_comments_for_file are invoked while holding
conn but filesystem calls happen after releasing conn.
In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx`:
- Around line 16-21: The test mocks for the component's onForget callback are
synchronous (vi.fn()) but the component types and usage expect an async function
returning a Promise; replace the bare vi.fn() mocks used in defaultProps and the
other two test-specific mocks with async-resolving mocks (e.g.,
vi.fn().mockResolvedValue(undefined) or () => Promise.resolve()) so onForget
returns a Promise and callers can safely call .catch(); update the defaultProps
object (workspace: mockWorkspace, onExpand, onClose, onForget) and the other two
test sites where onForget is mocked to use the resolved-Promise form.
In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Line 57: The action controls div in WorkspaceCard uses
"group-hover:opacity-100" so controls remain hidden for keyboard users; update
the visibility classes to also respond to focus by adding focus/focus-within
variants (e.g., add "group-focus-within:opacity-100" and/or
"focus-within:opacity-100" alongside "group-hover:opacity-100") on the same div,
and ensure the wrapper element that has the "group" class can receive focus (or
already contains focusable children) so keyboard focus triggers the
"focus-within" variant.
---
Nitpick comments:
In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx`:
- Around line 59-60: Replace locale-locked title selectors like
getByTitle('Fechar') / getByTitle('Esquecer') with role-based, accessible
queries scoped to the dialog: find the dialog (or the WorkspaceCard component's
dialog) using getByRole('dialog') and then use
within(dialog).getByRole('button', { name: /close|fechar/i }) or a stable
accessible name to click the close/forget buttons; update all occurrences
referenced (closeButton, forgetButton, etc.) in WorkspaceCard.test.tsx to use
scoped getByRole queries instead of hardcoded titles.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b48cbd53-9086-4bab-801e-4358f4b5a8a6
📒 Files selected for processing (4)
apps/tauri/src-tauri/src/comments.rsapps/tauri/src-tauri/src/sessions.rsapps/tauri/src/__tests__/components/WorkspaceCard.test.tsxapps/tauri/src/components/WorkspaceCard.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/tauri/src-tauri/src/comments.rs
- Validate workspace_type and shorten DB lock scope in forget flow - Mock onForget as async to match component contract - Show action controls on keyboard focus via group-focus-within
Summary
apps/macos/andapps/web/directories (all development in Tauri)forget_workspace_dataRust commandHash(#) toAlignLeftfor better UX affordanceemitto Tauri event type declarationsTest plan
cd apps/tauri && npm run buildcompiles without errorsnpm test— all 69 tests passSummary by CodeRabbit
Removed Features
New Features
Bug Fixes / UX
Chores
Tests