Add spreadsheet UI, frontend and backend with monorepo setup#11
Conversation
WalkthroughThis change introduces the foundational structure for a full-stack monorepo application named "Wafflebase", organized with a Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend (React)
participant Backend (NestJS)
participant Database (Prisma/SQLite)
User->>Frontend (React): Visit /login
Frontend (React)->>Backend (NestJS): GET /auth/me (check session)
Backend (NestJS)-->>Frontend (React): 401 Unauthorized
Frontend (React)->>User: Show login form
User->>Frontend (React): Click "Login with GitHub"
Frontend (React)->>Backend (NestJS): GET /auth/github
Backend (NestJS)->>GitHub: OAuth redirect
GitHub->>Backend (NestJS): OAuth callback
Backend (NestJS)->>Database (Prisma/SQLite): Find or create user
Database (Prisma/SQLite)-->>Backend (NestJS): User record
Backend (NestJS)->>Frontend (React): Set session cookie, redirect to dashboard
User->>Frontend (React): View documents
Frontend (React)->>Backend (NestJS): GET /documents/
Backend (NestJS)->>Database (Prisma/SQLite): Query documents by user
Database (Prisma/SQLite)-->>Backend (NestJS): Documents list
Backend (NestJS)-->>Frontend (React): Documents data
Frontend (React)->>User: Render document list
User->>Frontend (React): Open document
Frontend (React)->>Backend (NestJS): GET /documents/:id
Backend (NestJS)->>Database (Prisma/SQLite): Fetch document, check ownership
Database (Prisma/SQLite)-->>Backend (NestJS): Document data
Backend (NestJS)-->>Frontend (React): Document data
Frontend (React)->>Sheet (Spreadsheet): initialize(container, { theme })
Sheet (Spreadsheet)->>Frontend (React): Spreadsheet instance
Frontend (React)->>User: Render spreadsheet UI
Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
8ec029b to
b6f057b
Compare
There was a problem hiding this comment.
Actionable comments posted: 26
🧹 Nitpick comments (55)
packages/frontend/README.md (1)
1-2: Clear and Consistent Frontend README
This README provides a concise header that clearly identifies the frontend package. As the project evolves, consider expanding this file with additional details (e.g., setup instructions, usage, dependencies) to further enhance clarity for new developers.packages/backend/README.md (1)
1-2: Straightforward Backend README
The backend README is minimal yet effective in stating the package title. Similar to the frontend README, you might eventually want to include further documentation (e.g., build instructions, API details) to assist with onboarding or maintenance.packages/frontend/src/types/users.ts (1)
1-6: User type definition looks good, but consider adding JSDoc documentation.The User type definition is clear and includes all the necessary basic fields for user representation. However, adding JSDoc documentation would improve developer experience by providing context and field descriptions.
Consider adding documentation like this:
+/** + * Represents a user in the system. + */ export type User = { + /** Authentication provider (e.g., 'github', 'google') */ authProvider: string; + /** User's display name */ username: string; + /** User's email address */ email: string; + /** URL to the user's profile image */ avatar: string; };packages/backend/src/auth/jwt-auth.guard.ts (1)
4-9: Remove unnecessary constructor.The constructor doesn't add any functionality beyond calling the parent constructor, making it redundant.
@Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { - constructor() { - super(); - } }🧰 Tools
🪛 Biome (1.9.4)
[error] 6-8: This constructor is unnecessary.
Unsafe fix: Remove the unnecessary constructor.
(lint/complexity/noUselessConstructor)
packages/frontend/components.json (1)
1-21: Component configuration file is clear and descriptive.
The JSON file properly defines schema validation, UI styling preferences, Tailwind configuration, and convenient alias mappings for components, utilities, and hooks. One minor note: if a specific Tailwind configuration file is available, consider updating the"config"field instead of leaving it as an empty string. This is an optional enhancement.packages/backend/src/auth/github-auth.guard.ts (1)
6-15: Add error handling in the canActivate method.There's no error handling for potential issues when accessing the request or session. If the session middleware isn't properly configured, this could cause runtime errors.
async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); + try { const returnTo = request.query.returnTo; if (returnTo) { request.session.returnTo = returnTo; } return (await super.canActivate(context)) as boolean; + } catch (error) { + console.error('Error in GitHubAuthGuard:', error); + throw error; + } }packages/backend/src/auth/auth.module.ts (1)
11-11: Consider removing redundant ConfigModule.forRoot() call.The
ConfigModule.forRoot()call may be redundant if it's already called in the root AppModule, which is the typical pattern in NestJS applications.@Module({ imports: [ - ConfigModule.forRoot(), JwtModule.registerAsync({ imports: [ConfigModule], // ...Ensure this is only called once, typically in the
AppModule.packages/frontend/src/PublicRoute.tsx (3)
6-14: Add documentation for the PublicRoute component.The component lacks documentation describing its purpose and behavior. Adding a JSDoc comment would improve maintainability.
+ /** + * PublicRoute component restricts authenticated users from accessing routes like login + * If user is authenticated, redirects to home page + * If loading, displays a loader + * If not authenticated, renders the child routes via Outlet + */ export const PublicRoute = (): ReactElement => { const { me, isLoading } = useMe();
9-11: Consider adding a timeout for loading state.The loading state could potentially continue indefinitely if there's a network issue without raising an error. Consider adding a timeout.
You could enhance the
useMehook to include a timeout mechanism, or add a local timeout in this component:export const PublicRoute = (): ReactElement => { const { me, isLoading } = useMe(); + const [isTimedOut, setIsTimedOut] = useState(false); + + useEffect(() => { + const timer = setTimeout(() => { + if (isLoading) { + setIsTimedOut(true); + } + }, 10000); // 10 seconds timeout + + return () => clearTimeout(timer); + }, [isLoading]); + + if (isTimedOut) { + return <div>Failed to authenticate. Please try again later.</div>; + } if (isLoading) { return <Loader />; } return me ? <Navigate to="/" /> : <Outlet />; };
13-13: Store the intended destination for redirecting after login.Currently, if a user is redirected to login from a protected route, they always go to the home page after login. Consider storing and using the original destination.
- return me ? <Navigate to="/" /> : <Outlet />; + // Use location from react-router to capture the intended location + const location = useLocation(); + // Store the location the user tried to visit for later redirect + const from = location.state?.from?.pathname || "/"; + + return me ? <Navigate to={from} /> : <Outlet />;This would require updating the protected routes to pass the current location when redirecting to login.
packages/frontend/src/app/login/page.tsx (1)
10-15: Update placeholder logo link.The logo link is currently set to "#", which doesn't navigate anywhere. Consider setting it to a valid route such as the home page.
- <a href="#" className="flex items-center gap-2 font-medium"> + <a href="/" className="flex items-center gap-2 font-medium">packages/sheet/src/store/local.ts (1)
7-9: Consider adding documentation about storage behavior change.The change from DuckDB to in-memory storage represents a significant behavioral change. Consider adding a comment documenting this change and its implications, especially regarding data persistence.
export async function createStore(key: string): Promise<LocalStore> { + // Uses in-memory storage that doesn't persist across page reloads const store = new MemStore(); return new LocalStore(store); }packages/frontend/src/api/auth.ts (1)
3-20: Improve error handling and add return valueThe logout function effectively handles the logout process and provides user feedback through toast notifications. Consider these improvements:
- Improve error message display by using
error.messageorString(error)instead of concatenating with the error object directly- Return a boolean or status to inform callers whether the logout was successful
- Add a check for the environment variable's existence before using it
-export async function logout() { +export async function logout(): Promise<boolean> { try { + const apiUrl = import.meta.env.VITE_BACKEND_API_URL; + if (!apiUrl) { + toast.error("Backend API URL is not configured"); + return false; + } const response = await fetch( - `${import.meta.env.VITE_BACKEND_API_URL}/auth/logout`, + `${apiUrl}/auth/logout`, { method: "POST", credentials: "include", } ); if (response.ok) { toast.success("Logged out successfully"); + return true; } else { toast.error("Failed to log out"); + return false; } } catch (error) { - toast.error("Error during logout:" + error); + toast.error(`Error during logout: ${error instanceof Error ? error.message : String(error)}`); + return false; } }packages/frontend/src/components/ui/card.tsx (1)
5-16: Consider adding appropriate ARIA roles for improved accessibilityThe Card component looks well implemented using the composition pattern. For better accessibility, consider adding appropriate ARIA roles like
role="region"or more specific roles depending on the card's purpose.<div data-slot="card" + role="region" + aria-labelledby="card-title" className={cn( "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className )} {...props} />packages/backend/src/auth/jwt.strategy.ts (1)
21-27: Add type definition for JWT payload and consider additional validationThe validation method could be improved with proper typing and additional checks:
- async validate(payload: any) { + async validate(payload: { sub: string; username: string; email: string }) { + // You could add additional validation here, such as: + // - Check if the user still exists in the database + // - Verify user permissions/roles + // - Check if the user is not banned/suspended return { id: payload.sub, username: payload.username, email: payload.email, }; }packages/frontend/src/components/ui/separator.tsx (1)
14-14: Consider adding documentation for the data-slot attributeThe
data-slot="separator-root"attribute is used for component targeting, but its purpose might not be immediately clear to other developers.packages/backend/package.json (1)
69-85: Consider configuring Jest coverage thresholdsThe Jest configuration correctly sets up testing for TypeScript files and collects coverage information. For stricter quality control, consider adding coverage thresholds.
"jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "rootDir": "src", "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, "collectCoverageFrom": [ "**/*.(t|j)s" ], "coverageDirectory": "../coverage", - "testEnvironment": "node" + "testEnvironment": "node", + "coverageThreshold": { + "global": { + "statements": 80, + "branches": 70, + "functions": 80, + "lines": 80 + } + } }packages/frontend/tsconfig.node.json (2)
5-5: Consider being more specific with the lib arrayWhile ["ES2023"] will work, you may want to explicitly include other libraries you'll need like "DOM" if your code will run in a browser environment.
23-23: Check if you need additional files in the include arrayCurrently, you're only including
vite.config.ts. If you have other Node-specific TypeScript files that should use this configuration (like build scripts), you might want to include them here as well.🧰 Tools
🪛 Biome (1.9.4)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-24: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
packages/frontend/src/components/ui/skeleton.tsx (2)
7-7: Consider extracting default styles to a variableFor better maintainability, you might want to extract the default class string to a constant.
+const defaultClasses = "bg-accent animate-pulse rounded-md" function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="skeleton" - className={cn("bg-accent animate-pulse rounded-md", className)} + className={cn(defaultClasses, className)} {...props} /> ) }
3-11: Consider adding aria attributes for better accessibilityFor better accessibility, consider adding appropriate ARIA attributes to indicate this is a loading state.
function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="skeleton" + aria-hidden="true" + role="status" className={cn("bg-accent animate-pulse rounded-md", className)} {...props} /> ) }packages/frontend/src/components/loader.tsx (2)
3-13: Consider making the component more configurableThe component could be more flexible by accepting props to customize the text and size.
-export const Loader = () => { +export const Loader = ({ + text = "Loading...", + size = "default", +}: { + text?: string; + size?: "small" | "default" | "large"; +}) => { + const sizeClasses = { + small: "h-4 w-4", + default: "h-8 w-8", + large: "h-12 w-12" + }; return ( <div className="flex flex-col items-center justify-center min-h-[300px]" aria-live="polite" > - <Loader2 className="h-8 w-8 animate-spin text-primary" /> - <p className="mt-4 text-sm text-muted-foreground">Loading...</p> + <Loader2 className={`${sizeClasses[size]} animate-spin text-primary`} /> + <p className="mt-4 text-sm text-muted-foreground">{text}</p> </div> ); };
6-6: Consider making the min-height configurableThe fixed
min-h-[300px]might not be suitable for all contexts. Consider making this configurable.- className="flex flex-col items-center justify-center min-h-[300px]" + className={`flex flex-col items-center justify-center ${className || "min-h-[300px]"}`}packages/backend/eslint.config.mjs (1)
20-20: Consider updating the ECMAScript version.The ECMAScript version is set to 5, which is quite outdated compared to your TypeScript target of ES2023 in the project's tsconfig.json. This mismatch might lead to inconsistent linting behavior.
- ecmaVersion: 5, + ecmaVersion: 2023,packages/frontend/src/components/login-form.tsx (3)
13-15: Fix incomplete text in the login description.The text "Wafflebase with your GitHub account" appears to be incomplete and should probably read "Login to Wafflebase with your GitHub account" or similar.
- <p className="text-balance text-sm text-muted-foreground"> - Wafflebase with your GitHub account. - </p> + <p className="text-balance text-sm text-muted-foreground"> + Login to Wafflebase with your GitHub account. + </p>
20-23: Consider making the return URL configurable.The return URL after authentication is hardcoded to "/dashboard". Consider making this configurable to support different redirect paths depending on the context.
- <Link - to={`${ - import.meta.env.VITE_BACKEND_API_URL - }/auth/github?returnTo=${encodeURIComponent("/dashboard")}`} - rel="noopener noreferrer" - > + <Link + to={`${ + import.meta.env.VITE_BACKEND_API_URL + }/auth/github?returnTo=${encodeURIComponent(props.returnTo || "/dashboard")}`} + rel="noopener noreferrer" + >This would require updating the component props:
type LoginFormProps = React.ComponentPropsWithoutRef<"form"> & { returnTo?: string; }; export function LoginForm({ className, returnTo, ...props }: LoginFormProps) { // ... }
25-31: Add accessibility attributes to the GitHub icon.The SVG icon for GitHub is missing accessibility attributes such as
aria-labelandrole, which can impact screen reader users.- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" role="img" className="mr-2 h-4 w-4">packages/backend/tsconfig.json (1)
8-8: Consider adding esModuleInterop setting.The configuration includes
allowSyntheticDefaultImports, but commonlyesModuleInteropis also enabled to ensure complete interoperability with CommonJS modules."allowSyntheticDefaultImports": true, + "esModuleInterop": true,packages/frontend/src/components/ui/input.tsx (1)
5-19: Well-structured Input component with comprehensive stylingThe Input component follows best practices for React components:
- Props are properly typed using React.ComponentProps
- Destructuring props and spreading remaining ones to the input element
- Using the
cnutility to merge classNames effectively- Comprehensive styling for various states (focus, invalid, disabled)
Consider adding ARIA attributes for improved accessibility, especially when dealing with validation states:
<input type={type} data-slot="input" + aria-invalid={props['aria-invalid'] || undefined} className={cn( "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className )} {...props} />packages/frontend/src/components/nav-secondary.tsx (2)
14-23: Well-typed props interface for navigation itemsThe props are properly typed, accepting an array of items with title, URL, and icon properties, as well as inheriting props from SidebarGroup.
Consider adding a unique identifier for each item to improve stability when mapping:
items: { + id: string title: string url: string icon: Icon }[]
24-42: Structured navigation implementation with potential key improvementThe component has a clear structure with nested sidebar components and correctly maps over the items array to create navigation elements.
Using the title as a key might lead to issues if titles aren't unique. Consider updating the key usage if you implement the id property:
-<SidebarMenuItem key={item.title}> +<SidebarMenuItem key={item.id || item.title}>Also, for improved accessibility, consider adding an aria-label to the links:
-<a href={item.url}> +<a href={item.url} aria-label={`Navigate to ${item.title}`}>packages/backend/src/auth/auth.service.ts (1)
12-27: Token generation implementation looks solid but missing expiration settingsThe
AuthServiceimplementation follows NestJS best practices with proper dependency injection and a clean method for token creation. The JWT payload contains essential information.However, no token expiration is specified, which could lead to tokens that never expire. Consider adding expiration configuration to enhance security.
return { - token: this.jwtService.sign(payload), + token: this.jwtService.sign(payload, { expiresIn: '1h' }), };packages/backend/src/auth/github.strategy.ts (1)
8-15: Configuration looks good but non-null assertions could be riskyThe strategy configuration is well-structured, but using non-null assertions (
!) for configuration values assumes these environment variables will always be set, which might cause runtime errors if they're missing.Consider adding validation or fallback handling for missing configuration values.
super({ - clientID: configService.get('GITHUB_CLIENT_ID')!, - clientSecret: configService.get('GITHUB_CLIENT_SECRET')!, - callbackURL: configService.get('GITHUB_CALLBACK_URL')!, + clientID: configService.getOrThrow('GITHUB_CLIENT_ID'), + clientSecret: configService.getOrThrow('GITHUB_CLIENT_SECRET'), + callbackURL: configService.getOrThrow('GITHUB_CALLBACK_URL'), scope: ['user:email'], });packages/frontend/package.json (1)
6-11: Build script looks good but consider adding test scriptThe build script properly runs TypeScript compilation before Vite build. However, unlike the sheet package, there's no test script defined. Consider adding test scripts for consistency across packages.
"scripts": { "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview" + "test": "vitest --run", + "test:watch": "vitest --watch" },package.json (1)
1-15: Consider enhancing the package.json configuration.While the basic pnpm monorepo setup is good, the package.json would benefit from additional information and improved script definitions:
- The description field is empty - adding a meaningful description would improve documentation
- The scripts only define package targets but don't specify operations to perform on them
- Missing standard fields like
repository,homepage, and potentiallyworkspacesconfigurationConsider enhancing the configuration with something like:
{ "name": "wafflebase", "version": "1.0.0", - "description": "", + "description": "WaffleBase - A spreadsheet-like application", "main": "index.js", "scripts": { "frontend": "pnpm --filter @wafflebase/frontend", "backend": "pnpm --filter @wafflebase/backend", - "sheet": "pnpm --filter @wafflebase/sheet" + "sheet": "pnpm --filter @wafflebase/sheet", + "dev": "pnpm -r run dev", + "build": "pnpm -r run build", + "test": "pnpm -r run test" }, "keywords": [], "author": "", "license": "ISC", - "packageManager": "[email protected]" + "packageManager": "[email protected]", + "repository": { + "type": "git", + "url": "https://github.com/wafflebase/wafflebase.git" + } }packages/frontend/src/app/dashboard/data.json (1)
1-614: Consider representing numeric values as numbers rather than strings.The
targetandlimitproperties are represented as strings (e.g.,"18","5") throughout the JSON file. If these values are intended to be used in calculations or comparisons, they should be numeric types rather than strings to avoid type coercion issues.{ "id": 1, "header": "Cover page", "type": "Cover page", "status": "In Process", - "target": "18", - "limit": "5", + "target": 18, + "limit": 5, "reviewer": "Eddie Lake" },packages/frontend/src/components/nav-user.tsx (2)
33-33: Remove debug console.log statementThere's a console.log statement that should be removed before deploying to production.
- console.log("user", user);
44-53: Refactor duplicate user information display to reduce code repetitionThe user information layout (avatar, username, email) is duplicated between the dropdown trigger button and the dropdown content. Consider extracting this into a reusable component to adhere to the DRY principle.
+ // Create a component at the top of the file or in a separate file + function UserInfo({ user }: { user: User }) { + return ( + <div className="flex items-center gap-2"> + <Avatar className="h-8 w-8 rounded-lg"> + <AvatarImage src={user.avatar} alt={user.username} /> + <AvatarFallback className="rounded-lg"> + {user.username.slice(0, 2).toUpperCase()} + </AvatarFallback> + </Avatar> + <div className="grid flex-1 text-left text-sm leading-tight"> + <span className="truncate font-medium">{user.username}</span> + <span className="text-muted-foreground truncate text-xs"> + {user.email} + </span> + </div> + </div> + ); + }Then use this component in both places.
Also applies to: 65-74
packages/frontend/src/components/app-sidebar.tsx (2)
96-101: Consider showing a skeleton loader instead of null during loading.Returning
nullduring loading can cause UI flickering when the component mounts. A skeleton loader would provide a smoother user experience.export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) { const { me, isLoading } = useMe(); if (isLoading) { - return null; + return ( + <Sidebar collapsible="offcanvas" {...props}> + <SidebarHeader> + {/* Header content */} + </SidebarHeader> + <SidebarContent> + {/* Loading skeleton */} + </SidebarContent> + <SidebarFooter> + {/* Loading skeleton */} + </SidebarFooter> + </Sidebar> + ); }
26-94: Extract navigation data to a separate configuration file.The navigation data is currently embedded in the component file. For better maintainability and separation of concerns, consider moving this data to a dedicated configuration file.
- const data = { - navMain: [ - // ... data ... - ], - navClouds: [ - // ... data ... - ], - navSecondary: [ - // ... data ... - ], - };Create a new file
src/config/navigation.ts:import { IconCamera, IconFileAi, IconFileDescription, IconFolder, IconSettings, IconUsers, } from "@tabler/icons-react"; export const navigationConfig = { navMain: [ // ... same data ... ], navClouds: [ // ... same data ... ], navSecondary: [ // ... same data ... ], };Then import it in the component:
import { navigationConfig } from "@/config/navigation";And use it:
<NavMain items={navigationConfig.navMain} />packages/frontend/src/components/ui/tabs.tsx (1)
42-44: Refactor long className string using class-variance-authority.The TabsTrigger component has a very long className string which makes it hard to read and maintain. Consider using class-variance-authority (cva) to organize these classes, similar to the pattern used in the Button component.
+ const tabsTriggerVariants = cva( + "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + // Add variants if needed + }, + defaultVariants: { + // Default variants if needed + }, + } + ); function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) { return ( <TabsPrimitive.Trigger data-slot="tabs-trigger" - className={cn( - "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", - className - )} + className={cn(tabsTriggerVariants(), className)} {...props} /> ); }packages/frontend/src/hooks/useMe.ts (2)
6-6: Remove Korean comments for consistency.There are Korean comments throughout the code. For an open-source project, maintaining English-only comments ensures better collaboration across different contributors.
- const [isLoading, setIsLoading] = useState(true); // 로딩 상태 추가 + const [isLoading, setIsLoading] = useState(true); // Loading state - setIsLoading(true); // 로딩 시작 + setIsLoading(true); // Start loading - setIsLoading(false); // 로딩 종료 + setIsLoading(false); // End loading - return { me: user, isLoading }; // 로딩 상태와 사용자 정보 반환 + return { me: user, isLoading }; // Return loading state and user informationAlso applies to: 17-17, 35-35, 41-41
19-25: Add error handling for network failures and handle API rate limits.The current implementation logs errors but doesn't provide a way to retry requests or handle specific error cases like rate limiting. Consider adding more robust error handling.
try { const res = await fetch( `${import.meta.env.VITE_BACKEND_API_URL}/auth/me`, { method: "GET", credentials: "include", + // Add timeout to prevent infinite loading in case of network issues + signal: AbortSignal.timeout(10000), // 10 second timeout } ); if (res.ok) { setUser(await res.json()); + } else if (res.status === 429) { + // Handle rate limiting + console.warn("Rate limited. Retrying in 5 seconds..."); + setTimeout(fetchUser, 5000); } else { + console.error(`Failed to fetch user: ${res.status} ${res.statusText}`); setUser(null); }packages/frontend/src/components/ui/toggle-group.tsx (1)
41-69: ToggleGroupItem handles context correctlyThe component properly consumes context values with fallbacks to its own props, which is a good pattern.
One minor improvement: consider destructuring
variantandsizefrom context in one step for cleaner code.- const context = React.useContext(ToggleGroupContext) + const { variant: contextVariant, size: contextSize } = React.useContext(ToggleGroupContext) return ( <ToggleGroupPrimitive.Item data-slot="toggle-group-item" - data-variant={context.variant || variant} - data-size={context.size || size} + data-variant={contextVariant || variant} + data-size={contextSize || size} className={cn( toggleVariants({ - variant: context.variant || variant, - size: context.size || size, + variant: contextVariant || variant, + size: contextSize || size, }), "min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l", className )} {...props} > {children} </ToggleGroupPrimitive.Item> )packages/frontend/src/components/ui/tooltip.tsx (2)
6-17: Consider increasing default delay durationA delay duration of 0 means tooltips appear immediately, which can lead to tooltip flicker when users move their cursor across the UI. Consider increasing the default delay to a small value like 300ms.
function TooltipProvider({ - delayDuration = 0, + delayDuration = 300, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>) { return ( <TooltipPrimitive.Provider data-slot="tooltip-provider" delayDuration={delayDuration} {...props} /> ) }
35-57: TooltipContent has comprehensive animationsThe component includes a rich set of animations for different states and positions using Tailwind's animation utilities.
One suggestion: consider making the
sideOffsetslightly larger to give more space between the trigger and the tooltip content:function TooltipContent({ className, - sideOffset = 0, + sideOffset = 4, children, ...props }: React.ComponentProps<typeof TooltipPrimitive.Content>) {packages/frontend/src/components/theme-provider.tsx (2)
33-49: Handle system theme changes dynamically.
Currently, the code checks the system preference on mount but does not react to future OS theme changes.You could attach a
matchMedialistener to reapply the "dark"/"light" class if the user’s system theme changes.
59-63: Avoid spreading extra props into the Provider unless necessary.
{...props}can lead to unintentional overrides or confusion.Inline usage of the required props can be more predictable if no additional props are expected.
packages/frontend/src/components/data-table.tsx (1)
201-245: Form submissions do not update table data.
onSubmittriggers a toast but does not reflect the new target/limit values in your local state, leading to potential discrepancies.You may want to store submitted values in the local state or pass them to an API, ensuring the table re-renders with the updated data.
packages/frontend/src/components/ui/table.tsx (1)
68-79: Optional: consider adding scope for TableHead cells.While your
<th>elements are styled correctly, you might consider usingscope="col"orscope="row"for improved accessibility, particularly for assistive technologies.packages/frontend/src/components/ui/chart.tsx (1)
35-68: ChartContainer is well-designed.Providing a unique
chartIdfor each chart ensures styles and references are properly scoped. The heavy inline class usage is acceptable, though you could consider factoring out some styles if it grows too large.packages/frontend/src/components/ui/sidebar.tsx (4)
28-29: Consider storing UI preferences in localStorage or similar.
While using cookies to store the open/closed state can be convenient, localStorage might be simpler and less risky from a security perspective. If you decide to stick with cookies, consider attributes likeSameSiteorHttpOnlyif needed for your application.
91-110: Prevent potential collisions with global keyboard shortcuts.
Using meta/ctrl+b might conflict with popular shortcuts (e.g., bold text in some contexts). Ensure that this shortcut does not interfere with user text editing or other features. You could allow customization or create a user setting for advanced users.
256-280: Enhance accessibility with labeling.
TheSidebarTriggerincludes a visually hidden label, which is great. Also consideraria-expandedoraria-controlsto inform screen readers about sidebar state.
282-305: Improve resize handle discoverability.
TheSidebarRailuses a hover-based approach to show a drag handle. Consider providing a more explicit visual indicator or a persistent affordance for better discoverability, especially on touch devices.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
frontend/package-lock.jsonis excluded by!**/package-lock.jsonpackages/frontend/public/vite.svgis excluded by!**/*.svgpackages/sheet/public/maltese.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (82)
.github/workflows/ci.yml(1 hunks).gitignore(1 hunks)frontend/src/store/duckdb/duckdb.ts(0 hunks)package.json(1 hunks)packages/backend/.gitignore(1 hunks)packages/backend/.prettierrc(1 hunks)packages/backend/README.md(1 hunks)packages/backend/eslint.config.mjs(1 hunks)packages/backend/nest-cli.json(1 hunks)packages/backend/package.json(1 hunks)packages/backend/src/app.module.ts(1 hunks)packages/backend/src/auth/auth.controller.ts(1 hunks)packages/backend/src/auth/auth.module.ts(1 hunks)packages/backend/src/auth/auth.service.ts(1 hunks)packages/backend/src/auth/github-auth.guard.ts(1 hunks)packages/backend/src/auth/github.strategy.ts(1 hunks)packages/backend/src/auth/jwt-auth.guard.ts(1 hunks)packages/backend/src/auth/jwt.strategy.ts(1 hunks)packages/backend/src/main.ts(1 hunks)packages/backend/test/app.e2e-spec.ts(1 hunks)packages/backend/test/jest-e2e.json(1 hunks)packages/backend/tsconfig.build.json(1 hunks)packages/backend/tsconfig.json(1 hunks)packages/frontend/.gitignore(1 hunks)packages/frontend/README.md(1 hunks)packages/frontend/components.json(1 hunks)packages/frontend/eslint.config.js(1 hunks)packages/frontend/index.html(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/frontend/src/PrivateRoute.tsx(1 hunks)packages/frontend/src/PublicRoute.tsx(1 hunks)packages/frontend/src/api/auth.ts(1 hunks)packages/frontend/src/app/dashboard/data.json(1 hunks)packages/frontend/src/app/dashboard/page.tsx(1 hunks)packages/frontend/src/app/login/page.tsx(1 hunks)packages/frontend/src/components/app-sidebar.tsx(1 hunks)packages/frontend/src/components/data-table.tsx(1 hunks)packages/frontend/src/components/loader.tsx(1 hunks)packages/frontend/src/components/login-form.tsx(1 hunks)packages/frontend/src/components/nav-documents.tsx(1 hunks)packages/frontend/src/components/nav-main.tsx(1 hunks)packages/frontend/src/components/nav-secondary.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/components/site-header.tsx(1 hunks)packages/frontend/src/components/theme-provider.tsx(1 hunks)packages/frontend/src/components/ui/avatar.tsx(1 hunks)packages/frontend/src/components/ui/badge.tsx(1 hunks)packages/frontend/src/components/ui/breadcrumb.tsx(1 hunks)packages/frontend/src/components/ui/button.tsx(1 hunks)packages/frontend/src/components/ui/card.tsx(1 hunks)packages/frontend/src/components/ui/chart.tsx(1 hunks)packages/frontend/src/components/ui/checkbox.tsx(1 hunks)packages/frontend/src/components/ui/drawer.tsx(1 hunks)packages/frontend/src/components/ui/dropdown-menu.tsx(1 hunks)packages/frontend/src/components/ui/input.tsx(1 hunks)packages/frontend/src/components/ui/label.tsx(1 hunks)packages/frontend/src/components/ui/select.tsx(1 hunks)packages/frontend/src/components/ui/separator.tsx(1 hunks)packages/frontend/src/components/ui/sheet.tsx(1 hunks)packages/frontend/src/components/ui/sidebar.tsx(1 hunks)packages/frontend/src/components/ui/skeleton.tsx(1 hunks)packages/frontend/src/components/ui/sonner.tsx(1 hunks)packages/frontend/src/components/ui/table.tsx(1 hunks)packages/frontend/src/components/ui/tabs.tsx(1 hunks)packages/frontend/src/components/ui/toggle-group.tsx(1 hunks)packages/frontend/src/components/ui/toggle.tsx(1 hunks)packages/frontend/src/components/ui/tooltip.tsx(1 hunks)packages/frontend/src/hooks/use-mobile.ts(1 hunks)packages/frontend/src/hooks/useMe.ts(1 hunks)packages/frontend/src/index.css(1 hunks)packages/frontend/src/lib/utils.ts(1 hunks)packages/frontend/src/main.tsx(1 hunks)packages/frontend/src/types/users.ts(1 hunks)packages/frontend/tsconfig.app.json(1 hunks)packages/frontend/tsconfig.json(1 hunks)packages/frontend/tsconfig.node.json(1 hunks)packages/frontend/vite.config.ts(1 hunks)packages/sheet/package.json(1 hunks)packages/sheet/src/store/local.ts(1 hunks)packages/sheet/src/vite-env.d.ts(1 hunks)pnpm-workspace.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- frontend/src/store/duckdb/duckdb.ts
🧰 Additional context used
🧬 Code Graph Analysis (33)
packages/frontend/src/PublicRoute.tsx (2)
packages/frontend/src/hooks/useMe.ts (1)
useMe(4-42)packages/frontend/src/components/loader.tsx (1)
Loader(3-13)
packages/frontend/src/app/login/page.tsx (1)
packages/frontend/src/components/login-form.tsx (1)
LoginForm(5-37)
packages/frontend/src/components/ui/label.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/App.tsx (3)
packages/frontend/src/components/theme-provider.tsx (1)
ThemeProvider(23-64)packages/frontend/src/PublicRoute.tsx (1)
PublicRoute(6-14)packages/frontend/src/PrivateRoute.tsx (1)
PrivateRoute(6-14)
packages/frontend/src/components/ui/sonner.tsx (1)
packages/frontend/src/components/theme-provider.tsx (1)
useTheme(66-73)
packages/frontend/src/PrivateRoute.tsx (2)
packages/frontend/src/hooks/useMe.ts (1)
useMe(4-42)packages/frontend/src/components/loader.tsx (1)
Loader(3-13)
packages/frontend/src/app/dashboard/page.tsx (4)
packages/frontend/src/components/ui/sidebar.tsx (2)
SidebarProvider(721-721)SidebarInset(711-711)packages/frontend/src/components/app-sidebar.tsx (1)
AppSidebar(96-129)packages/frontend/src/components/site-header.tsx (1)
SiteHeader(4-17)packages/frontend/src/components/data-table.tsx (1)
DataTable(332-621)
packages/frontend/src/components/ui/button.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/avatar.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/nav-user.tsx (3)
packages/frontend/src/components/ui/sidebar.tsx (4)
useSidebar(725-725)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)packages/frontend/src/components/ui/dropdown-menu.tsx (7)
DropdownMenu(242-242)DropdownMenuTrigger(244-244)DropdownMenuContent(245-245)DropdownMenuLabel(247-247)DropdownMenuSeparator(252-252)DropdownMenuGroup(246-246)DropdownMenuItem(248-248)packages/frontend/src/components/ui/avatar.tsx (3)
Avatar(53-53)AvatarImage(53-53)AvatarFallback(53-53)
packages/frontend/src/components/ui/checkbox.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/toggle.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/badge.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/toggle-group.tsx (2)
packages/frontend/src/components/ui/toggle.tsx (1)
toggleVariants(47-47)packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/nav-secondary.tsx (1)
packages/frontend/src/components/ui/sidebar.tsx (5)
SidebarGroup(705-705)SidebarGroupContent(707-707)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)
packages/frontend/src/components/nav-main.tsx (1)
packages/frontend/src/components/ui/sidebar.tsx (5)
SidebarGroup(705-705)SidebarGroupContent(707-707)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)
packages/frontend/src/components/ui/tooltip.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/app-sidebar.tsx (5)
packages/frontend/src/components/ui/sidebar.tsx (7)
Sidebar(702-702)SidebarHeader(709-709)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)SidebarContent(703-703)SidebarFooter(704-704)packages/frontend/src/hooks/useMe.ts (1)
useMe(4-42)packages/frontend/src/components/nav-main.tsx (1)
NavMain(11-47)packages/frontend/src/components/nav-secondary.tsx (1)
NavSecondary(14-42)packages/frontend/src/components/nav-user.tsx (1)
NavUser(26-94)
packages/frontend/src/components/ui/skeleton.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/breadcrumb.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/card.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/separator.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/data-table.tsx (13)
packages/frontend/src/components/ui/button.tsx (1)
Button(62-62)packages/frontend/src/components/ui/checkbox.tsx (1)
Checkbox(30-30)packages/frontend/src/components/ui/badge.tsx (1)
Badge(46-46)packages/frontend/src/components/ui/label.tsx (1)
Label(24-24)packages/frontend/src/components/ui/input.tsx (1)
Input(21-21)packages/frontend/src/components/ui/select.tsx (5)
Select(175-175)SelectTrigger(183-183)SelectValue(184-184)SelectContent(176-176)SelectItem(178-178)packages/frontend/src/components/ui/dropdown-menu.tsx (6)
DropdownMenu(242-242)DropdownMenuTrigger(244-244)DropdownMenuContent(245-245)DropdownMenuItem(248-248)DropdownMenuSeparator(252-252)DropdownMenuCheckboxItem(249-249)packages/frontend/src/components/ui/table.tsx (6)
TableRow(113-113)TableCell(114-114)Table(108-108)TableHeader(109-109)TableHead(112-112)TableBody(110-110)packages/frontend/src/components/ui/tabs.tsx (4)
Tabs(64-64)TabsList(64-64)TabsTrigger(64-64)TabsContent(64-64)packages/frontend/src/components/ui/chart.tsx (4)
ChartConfig(9-17)ChartContainer(345-345)ChartTooltip(346-346)ChartTooltipContent(347-347)packages/frontend/src/hooks/use-mobile.ts (1)
useIsMobile(5-19)packages/frontend/src/components/ui/drawer.tsx (8)
Drawer(120-120)DrawerTrigger(123-123)DrawerContent(125-125)DrawerHeader(126-126)DrawerTitle(128-128)DrawerDescription(129-129)DrawerFooter(127-127)DrawerClose(124-124)packages/frontend/src/components/ui/separator.tsx (1)
Separator(26-26)
packages/sheet/src/store/local.ts (1)
packages/sheet/src/store/memory/memory.ts (1)
MemStore(14-122)
packages/frontend/src/components/ui/chart.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/tabs.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/input.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/select.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/drawer.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/nav-documents.tsx (2)
packages/frontend/src/components/ui/sidebar.tsx (7)
useSidebar(725-725)SidebarGroup(705-705)SidebarGroupLabel(708-708)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)SidebarMenuAction(713-713)packages/frontend/src/components/ui/dropdown-menu.tsx (5)
DropdownMenu(242-242)DropdownMenuTrigger(244-244)DropdownMenuContent(245-245)DropdownMenuItem(248-248)DropdownMenuSeparator(252-252)
packages/frontend/src/components/ui/sheet.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
packages/frontend/src/components/ui/sidebar.tsx (8)
packages/frontend/src/hooks/use-mobile.ts (1)
useIsMobile(5-19)packages/frontend/src/components/ui/tooltip.tsx (4)
TooltipProvider(59-59)TooltipContent(59-59)Tooltip(59-59)TooltipTrigger(59-59)packages/frontend/src/lib/utils.ts (1)
cn(4-6)packages/frontend/src/components/ui/sheet.tsx (4)
SheetContent(134-134)SheetHeader(135-135)SheetTitle(137-137)SheetDescription(138-138)packages/frontend/src/components/ui/button.tsx (1)
Button(62-62)packages/frontend/src/components/ui/input.tsx (1)
Input(21-21)packages/frontend/src/components/ui/separator.tsx (1)
Separator(26-26)packages/frontend/src/components/ui/skeleton.tsx (1)
Skeleton(13-13)
packages/frontend/src/components/ui/table.tsx (1)
packages/frontend/src/lib/utils.ts (1)
cn(4-6)
🪛 Biome (1.9.4)
packages/frontend/tsconfig.node.json
[error] 9-9: JSON standard does not allow comments.
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-16: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-16: JSON standard does not allow comments.
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-24: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
packages/backend/src/auth/jwt-auth.guard.ts
[error] 6-8: This constructor is unnecessary.
Unsafe fix: Remove the unnecessary constructor.
(lint/complexity/noUselessConstructor)
packages/backend/src/auth/github.strategy.ts
[error] 23-23: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
packages/frontend/tsconfig.app.json
[error] 10-10: JSON standard does not allow comments.
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 15-15: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 15-15: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 15-15: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 15-15: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-16: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-16: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-16: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: JSON standard does not allow comments.
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-25: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 25-25: JSON standard does not allow comments.
(parse)
[error] 26-26: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 26-26: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 26-26: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 26-26: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-27: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 27-29: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 30-30: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-31: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 31-32: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
packages/frontend/src/components/ui/chart.tsx
[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (136)
.gitignore (1)
1-145: Comprehensive and Well-Organized Gitignore File
The file is well structured and covers a wide range of Node.js–specific artifacts including logs, caches, build outputs, and directories used by various tools (e.g., ESLint, Stylelint, Parcel, and frameworks like Next.js, Nuxt.js, Gatsby). The header comments from toptal’s generator add clarity on its origin.packages/frontend/eslint.config.js (1)
1-29: Solid ESLint Configuration for Frontend
The ESLint configuration effectively integrates recommended settings from both the JavaScript and TypeScript ESLint plugins, and it also properly incorporates rules from react-hooks and react-refresh. The use oftseslint.config(assuming it is a valid helper from thetypescript-eslintpackage or a project-specific abstraction) streamlines the setup. Just ensure that the parser and other environment nuances are appropriately managed by this configuration.packages/sheet/src/vite-env.d.ts (1)
1-2: Correct Vite Type Reference Inclusion
The file correctly includes the reference to Vite’s client types, ensuring appropriate type-checking and autocompletion for Vite-related features in the project. This is essential for a smooth development experience with Vite.packages/backend/.prettierrc (1)
1-4: Prettier configuration follows standard practices.The configuration uses common best practices with single quotes and trailing commas. The minimal configuration keeps things simple while enforcing consistent formatting.
pnpm-workspace.yaml (1)
1-2: PNPM workspace configuration is correctly structured.The workspace configuration properly specifies all packages under the
packages/directory to be included in the monorepo setup, which aligns with the PR objective of adding PNPM configuration to manage packages.packages/backend/nest-cli.json (1)
1-8: NestJS configuration follows recommended project structure.The configuration provides appropriate settings for a NestJS application with proper schema reference, source directory configuration, and compiler options. Setting
deleteOutDirto true is a good practice to ensure clean builds.packages/backend/src/app.module.ts (1)
1-15: LGTM! Standard NestJS module setup.The
AppModuleis correctly structured according to NestJS conventions with proper imports and configuration. Making theConfigModuleglobal is a good practice to ensure configuration is accessible throughout the application.packages/frontend/src/lib/utils.ts (1)
1-6: LGTM! Great utility function for Tailwind CSS class management.The
cnfunction is a common and useful pattern for React projects using Tailwind CSS. It correctly leveragesclsxandtailwind-mergeto handle class name combinations and resolve potential conflicts when classes are conditionally applied.packages/backend/test/jest-e2e.json (1)
1-9: LGTM! Standard Jest E2E test configuration.The configuration correctly sets up the test environment for end-to-end testing with TypeScript support. It follows Jest and NestJS testing conventions with appropriate test file pattern matching.
packages/frontend/src/main.tsx (1)
1-10: Overall, the React entry point is well-structured.
The file correctly imports required modules and usescreateRootto bootstrap the application wrapped inStrictMode, which is a best practice in React 18. The use of the non-null assertion (!) on the DOM element is common in TypeScript React projects, assuming that the element with id"root"is guaranteed to exist.packages/frontend/tsconfig.json (1)
1-13: TypeScript configuration looks good.
The configuration leverages project references by pointing totsconfig.app.jsonandtsconfig.node.json, and the alias mapping using"@/*"for./src/*is clear and useful for module resolution. Just ensure that the referenced files exist and are maintained consistently.packages/backend/tsconfig.build.json (1)
1-4: Backend build configuration is appropriately streamlined.
The file extends from the maintsconfig.jsonand correctly excludes directories and patterns (like test files,node_modules, anddist) to optimize the build process.packages/frontend/vite.config.ts (1)
1-14: Vite configuration is well-formed and optimizes the development environment.
The configuration imports essential plugins, sets up a path alias for cleaner imports, and integrates both React and Tailwind CSS via the respective plugins. Ensure that the Tailwind plugin imported from"@tailwindcss/vite"is the correct (and intended) package for your setup.packages/backend/src/auth/auth.module.ts (1)
14-17: Review JWT token expiration time for your application needs.The JWT token is set to expire after 1 hour. Consider whether this duration is appropriate for your application's security requirements and user experience. Shorter durations enhance security but may frustrate users with frequent re-authentication.
For applications with sensitive data, you might want to:
- Use a shorter expiration (15-30 minutes)
- Implement a refresh token mechanism
- Add token invalidation on user logout
packages/frontend/.gitignore (1)
1-24: Standard .gitignore configuration for frontend development.This is a well-structured .gitignore file that follows best practices for frontend development:
- Covers logs from various package managers (npm, yarn, pnpm, lerna)
- Excludes build artifacts (node_modules, dist, dist-ssr)
- Ignores local configuration files
- Excludes editor-specific files and OS-specific files
The configuration appears to be adapted from a standard Vite template.
packages/frontend/src/components/ui/sonner.tsx (2)
4-21: Good implementation of themed toast component.The Toaster component effectively wraps the Sonner component with theme support and custom styling. The implementation:
- Properly forwards props to the underlying component
- Sets appropriate CSS custom properties for styling
- Handles theme detection with fallback to "system"
5-5:Details
✅ Verification successful
Verify theme context compatibility.
The destructured
themeproperty assumes the theme context has a particular structure. Ensure this is compatible with the actual theme context being used, especially if you switch to the local theme implementation.
🏁 Script executed:
#!/bin/bash # Check if the local useTheme hook returns a compatible interface # Find the ThemeProviderContext definition to understand its structure rg -A 10 "ThemeProviderContext" packages/frontend/src/componentsLength of output: 2033
Theme Context Compatibility Verified
I confirmed that the
useThemehook (defined inpackages/frontend/src/components/theme-provider.tsx) returns a context object that includes thethemeproperty. The fallback value ("system") aligns with the default used in the ThemeProvider. No changes are required at this moment, but please ensure that any local theme implementation maintains this structure.packages/frontend/src/app/login/page.tsx (1)
7-22: Well-structured responsive login layout.The login page uses a responsive grid layout that adapts well to different screen sizes. The component:
- Provides a clean, centered login form on smaller screens
- Adds a background image on larger screens
- Includes proper spacing and alignment
packages/sheet/src/store/local.ts (1)
4-4:Details
❓ Verification inconclusive
Transition from DuckDB to in-memory storage.
The code has been modified to use
MemStoreinstead of a DuckDB-based storage solution. While this simplifies the implementation, be aware of the following implications:
- Data persistence: In-memory stores don't persist data across page reloads
- Memory usage: Large datasets might consume significant memory
- Data migration: No clear path for migrating existing user data
Also applies to: 8-8
🏁 Script executed:
#!/bin/bash # Check for any code that might depend on the persistent nature of DuckDB # Look for code that might be affected by the change to in-memory storage rg -A 3 -B 3 "createStore|LocalStore" --glob "!packages/sheet/src/store/local.ts" packages/Length of output: 3450
Updated Transition Note: Verify In-Memory Store Trade-offs
The storage in
packages/sheet/src/store/local.tshas been updated to import and useMemStore(see lines 4 and 8), replacing the old DuckDB-based implementation. This change has been confirmed by our tests—e.g., in the spreadsheet initialization and store tests—which now create stores viacreateStorethat instantiateMemStore.Please note the following implications of this transition:
- Data Persistence: In-memory storage does not persist data across page reloads.
- Memory Usage: Handling large datasets may increase memory consumption.
- Data Migration: There isn’t a defined mechanism for migrating data from the previous DuckDB storage.
Review these trade-offs to ensure they align with your project’s requirements.
packages/frontend/src/PrivateRoute.tsx (1)
1-14: Well-implemented authentication route protectionThe
PrivateRoutecomponent correctly implements a protected route pattern by checking authentication status with theuseMehook. It properly handles the loading state and redirects unauthenticated users to the login page. The implementation is clean, concise, and follows React best practices.packages/frontend/src/components/ui/label.tsx (1)
1-24: Well-implemented accessible label componentThe
Labelcomponent is well-structured and follows best practices:
- Uses Radix UI primitives for accessibility
- Handles proper styling for different states (disabled, etc.)
- Correctly implements class name merging with the
cnutility- Maintains proper TypeScript typing with appropriate props forwarding
The component effectively handles the accessibility concerns through proper labeling and state management, which is crucial for form elements.
packages/frontend/src/components/site-header.tsx (2)
4-17: Simple and focused header componentThe
SiteHeadercomponent is well-structured, using semantic HTML and proper component composition with theSidebarTriggerandSeparatorcomponents. The layout follows a good pattern for application headers with proper spacing and organization.
6-6:Details
❓ Verification inconclusive
Verify custom CSS syntax in class name
The class name contains unusual syntax that isn't standard Tailwind CSS:
h-(--header-height)And complex selectors:
group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)Consider:
- Confirming that this custom syntax is properly configured in your Tailwind setup
- Extracting complex class combinations into more readable utility classes or variables
🏁 Script executed:
#!/bin/bash # Check if there's a tailwind config that might explain this custom syntax fd -e js -e ts "tailwind.config" -x cat {}Length of output: 44
Action Required: Verify Custom Tailwind CSS Configuration
The class names in question use non-standard syntax such as
h-(--header-height)and the complex selectorgroup-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height). Our initial automated search for a Tailwind configuration file (which might explain this custom setup) didn’t return any results. Please double-check whether a custom configuration exists elsewhere (or if it might be configured in a non-conventional file) to support this syntax. If not, consider extracting these custom combinations into named utility classes or standard Tailwind utilities to improve clarity and maintainability.
- File: packages/frontend/src/components/site-header.tsx, Line: 6
packages/backend/.gitignore (1)
1-56: Well-structured .gitignore file with comprehensive coverageThis is a well-organized .gitignore file that properly excludes all standard files and directories that shouldn't be tracked in a Node.js/NestJS project. The inclusion of pnpm-specific log files (line 10) aligns with the PR's objective of adding pnpm configuration.
packages/frontend/src/components/ui/card.tsx (2)
18-82: Well-implemented component composition patternThe Card subcomponents (CardHeader, CardTitle, etc.) follow a consistent pattern and create a flexible, reusable card system. The use of data-slot attributes provides good styling hooks, and the className merging with the cn utility preserves custom styling capabilities.
84-92: Named exports provide good developer experienceExporting all components individually rather than as a default export makes importing specific components easier and enables tree-shaking.
packages/frontend/src/app/dashboard/page.tsx (1)
1-22: Good implementation of the dashboard page component!This component correctly implements a dashboard layout using sidebar, header, and data table components. The structure follows React best practices with clean JSX hierarchy and proper component composition.
packages/frontend/src/components/ui/separator.tsx (1)
6-24: Well-implemented primitive component with good defaultsThe Separator component is properly constructed using the Radix UI primitive. Good use of destructuring props, default parameters, and conditional class name application with the
cnutility.packages/frontend/src/App.tsx (2)
9-25: Good routing implementation with authentication protectionThe App component correctly sets up the application's routing structure with proper authentication checks through PublicRoute and PrivateRoute components. The use of ThemeProvider ensures consistent theming across the application.
12-12:Details
✅ Verification successful
Verify that the VITE_SYNCUP_BASENAME environment variable is properly set
The router's basename is dynamically set from an environment variable. Ensure this variable is defined in all environments where the application will run.
🏁 Script executed:
#!/bin/bash # Check if the VITE_SYNCUP_BASENAME environment variable is defined in .env files echo "Checking for VITE_SYNCUP_BASENAME in environment files..." fd "\.env.*" packages/frontend -x grep -l "VITE_SYNCUP_BASENAME" {} \; # If not found, suggest adding it if [ $? -ne 0 ]; then echo "Warning: VITE_SYNCUP_BASENAME not found in any .env files." echo "Consider adding it to ensure proper routing in different environments." fiLength of output: 216
Environment variable verified: No changes required
The review comment has been validated. The VITE_SYNCUP_BASENAME variable is present in the relevant .env files, so its usage in the<Router basename={import.meta.env.VITE_SYNCUP_BASENAME}>line is already properly integrated. Please ensure that this variable is also defined in all deployment configurations to maintain consistent routing behavior across environments.packages/backend/package.json (2)
8-21: LGTM: Comprehensive set of NestJS scriptsThe scripts section provides all the necessary commands for development, testing, and production, following NestJS best practices.
22-38:Details
✅ Verification successful
Verify dependency versions for security and compatibility
The package includes several key dependencies for authentication and API functionality. Some packages have specific version requirements to ensure proper functioning.
🏁 Script executed:
#!/bin/bash # Check for any known vulnerabilities in dependencies echo "Checking for potential dependency issues..." # Check for passport-github2 vulnerabilities (it's quite old) echo "Checking passport-github2 (version 0.1.12)..." curl -s "https://registry.npmjs.org/passport-github2" | jq '.time.modified, .homepage, .repository.url' # Check if there are newer NestJS versions available echo "Latest NestJS core version:" curl -s "https://registry.npmjs.org/@nestjs/core" | jq '.["dist-tags"].latest'Length of output: 591
Dependency Versions Verified
- Verified that
passport-github2(version 0.1.12) shows a last modified timestamp from 2022 without any flagged vulnerabilities. However, its older update history may warrant a brief review to confirm ongoing maintenance.- Checked that
@nestjs/core, specified as^11.0.1, is compatible with the latest registry version (11.0.16), ensuring that the caret range will capture relevant patch updates as expected.- All other dependencies appear compliant with security and compatibility requirements.
No further modifications are needed at this time.
packages/frontend/tsconfig.node.json (3)
1-24: TypeScript configuration looks well structuredThis is a good TypeScript configuration for a Node environment, particularly for use with Vite. The configuration appropriately:
- Targets modern JavaScript (ES2022)
- Enables strict type checking
- Configures bundler mode
- Sets up proper linting rules for code quality
The build info file is correctly placed in the node_modules/.tmp directory to avoid cluttering your source code.
🧰 Tools
🪛 Biome (1.9.4)
[error] 9-9: JSON standard does not allow comments.
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-16: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 16-16: JSON standard does not allow comments.
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 22-22: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-24: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
9-14: Good bundler configuration for ViteThe bundler mode configuration is appropriately set up for Vite with TypeScript, enabling features like importing TypeScript files with their extensions and ensuring proper module isolation.
🧰 Tools
🪛 Biome (1.9.4)
[error] 9-9: JSON standard does not allow comments.
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 10-10: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
16-21: Strong linting settings enabledExcellent job enabling strict type checking and additional linting rules like:
noUnusedLocalsandnoUnusedParametersto catch unused codenoFallthroughCasesInSwitchto prevent logic errorsnoUncheckedSideEffectImportsfor better tree-shakingThese will help maintain code quality as the project grows.
🧰 Tools
🪛 Biome (1.9.4)
[error] 16-16: JSON standard does not allow comments.
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 17-17: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
packages/frontend/src/components/ui/skeleton.tsx (2)
1-13: Well-implemented skeleton loading componentThe Skeleton component is cleanly implemented with good use of:
- Props spreading for flexibility
- Class name composition using the
cnutility- Appropriate default styling for a loading placeholder
- Semantic
data-slotattribute for component identificationThis will work well as a loading placeholder throughout the application.
6-6: Good use of data attributes for component identificationUsing
data-slot="skeleton"provides a good semantic identifier for this component, which can be useful for both styling and testing purposes.packages/frontend/index.html (1)
1-13: Standard Vite React TypeScript entry pointThis is a well-structured HTML entry point for a Vite React TypeScript application with all the necessary elements:
- Proper DOCTYPE declaration
- Appropriate meta tags
- Root div for React mounting
- Module script pointing to the main entry point
packages/frontend/src/components/loader.tsx (2)
1-13: Well-implemented loading component with good accessibilityThe Loader component is well structured with:
- Proper use of aria-live for accessibility
- Clear visual loading indicator
- Helpful loading text
- Good use of Tailwind classes for styling
This will provide a good user experience during loading states.
7-7: Good use of aria-live for accessibilityThe
aria-live="polite"attribute is a good accessibility practice, as it will notify screen readers of the loading state without interrupting their current task.packages/backend/eslint.config.mjs (1)
29-33: LGTM! Sensible rule customizations.The rule customizations are appropriate:
- Disabling
no-explicit-anyprovides flexibility when needed- Warning for floating promises and unsafe arguments helps catch common issues while still allowing the code to pass linting
packages/backend/tsconfig.json (1)
1-21: Solid TypeScript configuration for NestJS.The configuration is well-structured for a NestJS application with appropriate strict type checking and modern JavaScript features enabled.
packages/frontend/src/components/ui/input.tsx (2)
1-4: Clean import pattern with well-organized dependenciesThe import structure follows React best practices by importing React and the utility function needed for class name management.
21-22: Appropriate export patternNamed export is used correctly, allowing for clean imports elsewhere in the codebase.
packages/frontend/src/components/ui/avatar.tsx (5)
1-7: Appropriate usage of Next.js directive and importsThe "use client" directive ensures this component works correctly with Next.js RSC. The imports are clean and follow best practices, specifically importing from Radix UI's Avatar primitives.
8-22: Well-structured Avatar component with proper compositionThe Avatar component is implemented following best practices:
- Uses Radix UI primitives as the foundation
- Props are correctly typed using React.ComponentProps
- Styling is applied using the
cnutility- Data attributes provide hooks for testing or styling
24-35: Clean implementation of AvatarImage componentThe AvatarImage component correctly extends the Radix UI primitive with appropriate styling. The aspect-square class ensures the image maintains its aspect ratio.
37-51: Comprehensive AvatarFallback implementationThe AvatarFallback component provides a well-styled fallback for when images aren't available. The styling ensures appropriate contrast and visual consistency.
53-53: Appropriate export pattern for component compositionThe named exports for all three components facilitate the composition pattern, allowing users to import and use them together as needed.
packages/frontend/src/index.css (5)
1-4: Proper CSS framework imports and custom variant definitionThe imports for Tailwind CSS and tw-animate-css are correctly specified. The custom variant for dark mode is well-defined using modern CSS selector syntax.
6-42: Comprehensive theme variable structureThe theme definition establishes a robust system of CSS variables for consistent styling across the application, including variables for radius, colors, and component-specific styling.
44-77: Well-structured light theme color definitionsThe root variables define a comprehensive set of OKLCH color values for the light theme, providing a modern and perceptually uniform color system across the application.
79-111: Comprehensive dark theme implementationThe dark theme overrides maintain consistent variable names while providing appropriate contrast ratios. The color choices ensure readability and accessibility in dark mode.
113-120: Clean base layer stylingThe base layer applies consistent border and outline styles globally and sets appropriate background and text colors for the body element, ensuring a solid foundation for the UI.
packages/frontend/src/components/nav-secondary.tsx (1)
1-13: Appropriate directive and imports for navigation componentThe "use client" directive ensures compatibility with Next.js RSC. The imports are clean and appropriately structured, importing only the necessary components from the sidebar UI library.
packages/backend/src/auth/auth.service.ts (1)
4-10: User interface looks good, but consider validating critical fieldsThe
Userinterface is well-structured with clear type definitions. TheauthProvideris properly restricted to 'github' which matches the strategy being implemented in the system.Consider adding validation for the critical fields to ensure data integrity when creating tokens.
packages/sheet/package.json (2)
2-5: Package name and description updates align well with monorepo structureThe change from "wafflebase" to "@wafflebase/sheet" follows the standard scoped package naming convention, which is ideal for a monorepo setup with pnpm. The added description provides clarity about the package's purpose.
1-30:Details
❓ Verification inconclusive
DuckDB dependencies have been removed
The removal of DuckDB and Apache Arrow dependencies suggests a shift in the data storage strategy, which aligns with the PR description about enhancing package management. Make sure the DuckDB functionality has been properly migrated or replaced in the codebase.
🏁 Script executed:
#!/bin/bash # Check for any remaining DuckDB references in the codebase echo "Checking for remaining DuckDB references:" rg -i "duckdb" --type ts --stats packages/sheet/Length of output: 300
Verified the removal of DuckDB references in packages/sheet
The DuckDB dependency has been successfully removed from the package (no duckdb matches were found in the TypeScript files in packages/sheet and the package.json snippet confirms its absence). Please ensure that any functionality previously reliant on DuckDB (and Apache Arrow) has been fully migrated or replaced elsewhere in the codebase.
- No remaining duckdb references were found in the TS files within packages/sheet.
- Confirm that all features formerly dependent on DuckDB now work with the new data management strategy.
packages/frontend/package.json (2)
12-46: Comprehensive UI component library choicesThe dependency list includes a well-rounded set of modern UI libraries (Radix UI, DND Kit, TanStack, etc.) which should provide a solid foundation for building interactive interfaces. The structured approach using packages like
class-variance-authorityandtailwind-mergesuggests a thoughtful, maintainable UI architecture.
36-38:Details
❓ Verification inconclusive
Using very recent React version
The package is using React 19.0.0 which is a very recent version. Ensure compatibility with other dependencies as some third-party libraries might not have been updated to support React 19 yet.
🌐 Web query:
When was React 19 released and what are the major breaking changes?💡 Result:
React 19 was officially released as stable on December 5, 2024 [4][7]. Prior to this, a beta version was available starting April 25, 2024 [1][6], with Release Candidates (RC) circulating earlier in the year.
Major Breaking Changes in React 19
1. New JSX Transform Requirement
React 19 mandates the new JSX transform, which automatically imports React and optimizes output. The legacyReact.createElementsyntax is no longer supported[5][8][9].2. Legacy API Removals
ReactDOM.renderreplaced byReactDOM.createRoot[5][8]ReactDOM.hydratereplaced byReactDOM.hydrateRoot[5]react-test-rendererdeprecated in favor of React Testing Library[8][9]3. Error Handling Changes
New error reporting methods introduced:
onCaughtErrorfor Error Boundary-caught errorsonUncaughtErrorfor unhandled errorsonRecoverableErrorfor auto-recovered errors[7][9]4. Ref Handling
- Function components now accept
refas a direct prop, eliminatingforwardRef[6][9][10]- Legacy
element.refaccess deprecated in favor ofelement.props.ref[8]5. Strict Mode Updates
- Double-rendering in development now preserves
useMemo/useCallbackresults between renders[8]- Improved simulation of Suspense behavior during mounting[8]
6. Dependency Requirements
- TypeScript types now require
@types/react@^19.0.0[8]- Third-party libraries must update React peer dependencies[6][8]
7. Suspense Hydration
New algorithm skips third-party script injections during hydration mismatches while preserving styles[7][9].These changes aim to improve performance and developer experience but require careful testing during migration. The React team provides codemods and detailed upgrade guidance in their official documentation[7][8].
Citations:
- 1: https://www.codifynext.com/blog/react-19-comprehensive-overview-and-new-features
- 2: https://www.freecodecamp.org/news/new-react-19-features/
- 3: https://eluminoustechnologies.com/blog/react-19/
- 4: https://www.telerik.com/blogs/whats-new-react-19
- 5: https://dev.to/manojspace/react-19-vs-react-18-performance-improvements-and-migration-guide-5h85
- 6: https://dev.to/gladiatorsbattle/react-19-stable-release-whats-new-and-how-to-upgrade-299d
- 7: https://react.dev/blog/2024/12/05/react-19
- 8: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
- 9: https://vercel.com/blog/whats-new-in-react-19
- 10: https://www.wisp.blog/blog/react-191-is-out-heres-what-you-need-to-know
React 19 Usage: Verify Dependency Compatibility
The package now uses React 19.0.0 (stable since December 5, 2024), which introduces several breaking changes (new JSX transform, deprecation of legacy APIs like ReactDOM.render/hydrate, updated error handling, etc.). Please ensure that all third-party libraries—especially those dependent on React internals—are compatible with these changes.
- Location:
packages/frontend/package.json(Lines 36-38)- Snippet:
"react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.5.0",- Action: Double-check that dependent libraries have updated their peer dependencies and support for React 19’s breaking changes.
packages/frontend/src/components/ui/badge.tsx (1)
1-46: Well-structured Badge component following best practices.This Badge component is well-implemented, using the class-variance-authority package for managing style variants and Radix UI's Slot for component composition. The component has:
- Proper TypeScript typing
- Consistent accessibility attributes with
data-slot- Good variant handling with default options
- Flexible rendering with the
asChildpatternThe implementation provides an elegant, reusable UI component that can be used throughout the application.
packages/frontend/src/components/ui/checkbox.tsx (1)
1-30: Well-implemented Checkbox component with accessibility features.This Checkbox component correctly implements:
- Radix UI primitives for accessibility
- Comprehensive styling for various states (checked, unchecked, disabled)
- Proper TypeScript typing
- Consistent use of data-slot attributes for styling hooks
- Clean indicator implementation with appropriate icon sizing
The implementation follows the same pattern as other UI components, maintaining consistency across the design system.
packages/frontend/src/components/ui/toggle.tsx (1)
1-47: Well-structured Toggle component with variant support.Aside from the className issue, this Toggle component is well-implemented with:
- Clean separation of concerns using Radix UI primitives
- Comprehensive variant and size options
- Proper TypeScript typing with VariantProps
- Consistent accessibility with data-slot attributes
- "use client" directive for client-side rendering compatibility
The toggleVariants implementation provides good flexibility for different visual styles and sizes.
packages/frontend/tsconfig.app.json (1)
1-32: TypeScript configuration looks appropriate for a modern React application.The configuration provides a solid foundation with:
- ES2020 target for modern browser compatibility
- Strict type checking enabled for better code quality
- Path aliases using the
@/prefix for cleaner imports- Bundler mode configuration suitable for tools like Vite
- Comprehensive linting options to prevent common issues
The setup is well-structured and follows TypeScript best practices.
🧰 Tools
🪛 Biome (1.9.4)
[error] 10-10: JSON standard does not allow comments.
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 11-11: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 12-12: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 13-13: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 14-14: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 15-15: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 15-15: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 15-15: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 15-15: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 16-16: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 16-16: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 16-16: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 16-18: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 18-18: JSON standard does not allow comments.
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 19-19: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 20-20: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 21-21: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 22-22: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 22-22: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 22-22: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 22-22: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-23: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 23-25: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 25-25: JSON standard does not allow comments.
(parse)
[error] 26-26: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 26-26: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 26-26: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 26-26: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-27: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 27-29: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 30-30: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-31: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
[error] 31-32: End of file expected
Use an array for a sequence of values:
[1, 2](parse)
.github/workflows/ci.yml (3)
18-18: Successfully upgraded Node.js to version 22.xThe upgrade to Node.js version 22.x aligns with the PR objective of improving package management capabilities.
22-40: Good implementation of pnpm setup with efficient cachingThe configuration correctly:
- Sets up pnpm with the latest action version
- Configures Node.js to use pnpm for caching
- Implements a dedicated cache for the pnpm store with proper key generation
- Uses conditional installation to avoid unnecessary work when cache is hit
This follows best practices for pnpm in GitHub Actions workflows.
41-54: Successfully migrated build commands to use pnpmThe build commands have been properly updated to use pnpm's workspace functionality for building frontend, backend, and sheet packages.
packages/frontend/src/components/nav-user.tsx (1)
79-82: Add onClick handler to Account menu itemThe Account menu item doesn't have an onClick handler, making it non-functional. Either implement navigation to the account page or remove this menu item if it's not ready yet.
- <DropdownMenuItem> + <DropdownMenuItem onClick={() => window.location.href = "/account"}>Is there an account page implementation that this should navigate to? If not, consider either implementing one or adding a TODO comment explaining future plans.
packages/frontend/src/components/ui/tabs.tsx (3)
6-17: LGTM! Well-structured tabs root component.The Tabs component is well-structured and correctly implements the Radix UI primitive with good styling and organization.
19-33: LGTM! Well-structured tabs list component.The TabsList component correctly implements the Radix UI primitive with appropriate styling and data attributes.
51-62: LGTM! Well-structured tabs content component.The TabsContent component appropriately implements the Radix UI primitive with good styling.
packages/frontend/src/components/ui/button.tsx (2)
7-36: LGTM! Well-structured button variants.The buttonVariants implementation using class-variance-authority is well organized with comprehensive styling options for different variants and sizes.
38-60: LGTM! Well-implemented Button component.The Button component implementation is solid with good TypeScript types, proper handling of the asChild prop, and correct application of variants.
packages/frontend/src/hooks/useMe.ts (1)
20-20:Details
❓ Verification inconclusive
Verify environment variable availability.
The hook directly accesses
import.meta.env.VITE_BACKEND_API_URL, which might not be available at runtime if not properly configured in the build process.
🏁 Script executed:
#!/bin/bash # Check if the VITE_BACKEND_API_URL environment variable is defined in .env files # Check for .env files echo "Checking for environment variable configurations:" fd "\.env" --type f --exec grep -l "VITE_BACKEND_API_URL" {} \; # Check Vite configuration for environment variable definitions echo -e "\nChecking Vite configuration for environment variables:" fd "vite\.config\.(js|ts)" --type f --exec grep -l "env" {} \;Length of output: 366
Attention: Verify Environment Variable Configuration
The hook in
packages/frontend/src/hooks/useMe.tsaccessesimport.meta.env.VITE_BACKEND_API_URLwithout any clear indication that this variable is defined at build time. Our initial search for its definition in standard.envfiles and Vite configuration files returned no results, so please manually confirm that theVITE_BACKEND_API_URLvariable is provided (whether via a local.env,.env.local, or similar configuration file or through Vite’s configuration). This verification is crucial to prevent potential runtime issues if the variable isn’t properly set.packages/frontend/src/components/nav-main.tsx (1)
11-19: Component props defined correctly with TypeScriptThe component's props are well-defined with proper TypeScript typing, making it clear what data structure is expected.
packages/frontend/src/components/ui/toggle-group.tsx (2)
8-13: Context setup is appropriateThe context is properly set up with default values for the toggle variants.
15-39: Well-structured ToggleGroup componentThe component correctly extends Radix UI's toggle group and provides context to its children.
packages/frontend/src/components/nav-documents.tsx (3)
28-38: Responsive design with useSidebar hookGood use of the
useSidebarhook to determine if the view is mobile and adjust the UI accordingly.
39-42: Group has conditional visibilityThe
group-data-[collapsible=icon]:hiddenclass suggests this group will be hidden when a parent element has thedata-collapsible="icon"attribute. Make sure this behavior is properly documented and tested.
43-81: Document items with dropdown menus are implemented wellThe component maps through items array to create menu entries with associated dropdown menus that adjust positioning based on mobile view. Good implementation of the dropdown menu with proper separation of actions.
packages/frontend/src/components/ui/tooltip.tsx (1)
19-33: Tooltip and TooltipTrigger are well-implementedBoth components correctly wrap the Radix UI primitives and add data attributes for styling and accessibility.
packages/frontend/src/components/theme-provider.tsx (1)
29-31: Consider handling unavailable or restricted localStorage scenarios.
If this component renders in an environment withoutlocalStorage(SSR, private mode, etc.), it may throw an error.Would you like to conditionally check for
window.localStorageavailability before attempting to read or write?packages/frontend/src/components/data-table.tsx (3)
264-264: Verify custom class syntax.
className="w-38 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate"looks like a custom or experimental selector.Confirm that these selectors are recognized by your styling engine or tailwind configuration.
508-511: Check row uniqueness for DnD keys.
Yourdatais mapped byrow.id. If multiple rows share an identicalid, the table could have unstable keys.Ensure all
idfields are unique to avoid drag-and-drop collisions.
643-799: LGTM!
The drawer-based detail view with a chart is well-structured and uses responsive logic viauseIsMobile.packages/backend/src/auth/auth.controller.ts (1)
21-31: Consider adding domain/path configuration for cookies if needed.
Your logout endpoint clears the session cookie but defaults tosameSite: 'lax'. This may be sufficient, but some deployments require a specificdomainorpath.Would you like a domain/path configuration for cross-subdomain usage or out-of-scope?
packages/frontend/src/components/ui/table.tsx (8)
7-20: Well-structured Table component.The use of a wrapping
<div>for horizontal scrolling is a good approach for large, overflowing tables. No issues found regarding logic or accessibility at this time.
22-30: Solid structure for TableHeader.The component succinctly wraps
<thead>with a data attribute for potential testing or styling. Implementation looks good.
32-40: TableBody component is clear.Clean usage of
React.ComponentProps<"tbody">ensuring a valid, flexible container for table rows.
42-53: TableFooter styling is fine.Background and border classes appear consistent with a typical table footer layout. No further comments.
55-66: TableRow transitions are well done.Hover effects and row transitions are properly incorporated. No issues found.
81-92: TableCell component looks solid.The approach is consistent with your other components. No logical or performance concerns.
94-105: Adequate design for TableCaption.Applying a distinct style to the table caption is clear and consistent. Looks good.
107-116: Exports are well-defined.All components are exported together, promoting easy consumption across the codebase.
packages/frontend/src/components/ui/breadcrumb.tsx (8)
7-9: Breadcrumb component is accessible.Using
aria-label="breadcrumb"on the<nav>helps screen readers identify the breadcrumb section. Good implementation.
11-22: BreadcrumbList structure is sound.The usage of
<ol>is semantically correct for breadcrumbs, and the added classes ensure proper styling.
24-32: BreadcrumbItem is straightforward.Inline styling with data attributes is a nice pattern for consistent styling or testing.
34-50: BreadcrumbLink effectively manages anchor vs. Slot usage.The
asChildproperty provides good flexibility. This pattern can help integrate with other components or routing solutions.
52-63: BreadcrumbPage logic is appropriate.Ensuring
aria-current="page"helps assistive technology identify the current page. This is an accessibility best practice.
65-81: BreadcrumbSeparator clearly sets the separator.Conditionally using
<ChevronRight />when children are absent is a neat fallback. No issues found.
83-99: BreadcrumbEllipsis is well-implemented.Using
MoreHorizontalalong with screen-reader text meets accessibility guidelines for hidden elements.
101-109: Exports appear consistent.All components are neatly exported for external usage.
packages/frontend/src/components/ui/chart.tsx (3)
105-247: ChartTooltipContent logic is robust.A well-organized approach that cleanly handles multiple data series, custom labels, icons, and formatting. Looks good for typical Recharts usage.
305-342: getPayloadConfigFromPayload is well-structured.The function safely checks and retrieves extra label or icon config from your chart configuration. No issues discovered.
80-101:Details
✅ Verification successful
Potential XSS concern with dangerouslySetInnerHTML.
Even though you are generating CSS here, please ensure that no untrusted or user-supplied content flows into
dangerouslySetInnerHTML. If there's any remote possibility of unsafe input, sanitize it or consider a different approach to injecting dynamic style rules.To confirm whether any user-supplied content might flow into this prop, run the script below:
🏁 Script executed:
#!/bin/bash # Search for references to ChartStyle and checks if user input merges in. rg "ChartStyle" rg "dangerouslySetInnerHTML"Length of output: 405
Action Required: Confirm Safe Usage of
dangerouslySetInnerHTMLThe analysis shows that the generated CSS in
<ChartStyle>originates from predefined constants (THEMESandcolorConfig) and does not appear to incorporate any user-supplied input. However, please ensure that theidand any parts of the configuration remain exclusively controlled by trusted sources. Future changes should maintain this safeguard to avoid potential XSS risks.
- Verify that the
idand other configuration values come only from safe, validated sources.- Continue to monitor for any refactoring that might inadvertently merge untrusted input into these dynamic style rules.
🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
packages/frontend/src/components/ui/drawer.tsx (5)
1-11: Well-structured wrapper components for Drawer.Good implementation of the root Drawer component using the
vaullibrary. Thedata-slotattribute provides a good way to target these elements in CSS and testing.
12-44: Clean implementation of Drawer primitive components.These wrapper components (DrawerTrigger, DrawerPortal, DrawerClose, DrawerOverlay) follow a consistent pattern, passing through all props and adding appropriate data attributes. The DrawerOverlay especially has good animation handling with conditional classes.
46-71: Comprehensive DrawerContent implementation with directional support.Great job implementing different positioning logic for the drawer (top, bottom, right, left) with appropriate styling for each direction. The use of
data-vaul-drawer-directionattribute to conditionally apply styles is a smart approach.
73-117: Semantic drawer structure components properly implemented.The header, footer, title and description components provide good semantic structure and styling options through className props. This allows for flexible customization while maintaining consistent default styling.
119-130: Complete export of drawer component API.All component exports are organized clearly, making the API easy to use by consumers of this module.
packages/frontend/src/components/ui/select.tsx (7)
1-8: Client-side component setup with proper imports.Good use of the "use client" directive and appropriate imports from Radix UI and Lucide React for icons.
9-26: Clean base Select component wrappers.These primitive wrappers (Select, SelectGroup, SelectValue) follow a consistent pattern with appropriate data attributes for styling and targeting.
27-51: Well-designed SelectTrigger with size variants.Good implementation of the SelectTrigger component with size variants ('sm' and 'default'). The comprehensive className string handles various states and styling needs efficiently.
53-86: Properly structured SelectContent with portal and viewport.The SelectContent component correctly uses a portal for rendering and includes scroll buttons. The conditional styling based on the position is well implemented.
88-136: Clean implementation of select item components.The SelectLabel, SelectItem, and SelectSeparator components follow consistent patterns with good accessibility considerations through data attributes.
138-172: Functional scroll button components.Both scroll button implementations provide good user experience for navigating long select lists with appropriate icons and styling.
174-185: Complete and organized component exports.All components are properly exported, providing a clean API for consumers of this module.
packages/frontend/src/components/ui/sheet.tsx (6)
1-8: Client-side component with proper imports.Good use of the "use client" directive indicating client-side rendering, with appropriate imports from Radix UI Dialog primitives and Lucide React for icons.
9-29: Clean base Sheet component wrappers.These primitive wrappers (Sheet, SheetTrigger, SheetClose, SheetPortal) follow a consistent pattern with appropriate data attributes for styling and targeting.
31-45: Well-implemented SheetOverlay with animations.Good implementation of overlay with fade animations for open/close states. The fixed positioning and z-index ensure proper stacking and visual effects.
47-82: Flexible SheetContent with directional variants.Excellent implementation of the content component with support for different sides (top, right, bottom, left) and appropriate animations for each direction. The close button is well positioned and includes screen reader text for accessibility.
84-128: Semantic structure components with consistent styling.The header, footer, title and description components provide a consistent structure and styling options, following the same pattern as other UI components in the system.
130-139: Complete component exports.All components are properly exported, providing a clean API for consumers of this module.
packages/frontend/src/components/ui/dropdown-menu.tsx (8)
1-13: Client-side component with proper imports.Good use of the "use client" directive and appropriate imports for Radix UI dropdown menu primitives and icons.
15-52: Well-structured portal and content components.The DropdownMenuPortal, DropdownMenuTrigger, and DropdownMenuContent components are implemented correctly, with the content component handling animations and positioning appropriately.
54-83: Flexible DropdownMenuItem with variant support.Good implementation of the menu item with support for different variants (default, destructive) and an inset option. This provides flexibility for different use cases within the same component.
85-144: Well-implemented checkbox and radio components.The checkbox and radio items include proper indicators and state handling. The positioning of the indicators is consistent and provides good visual feedback.
146-177: Consistent support components.The label and separator components follow the same pattern as other components, providing consistent styling and behavior.
179-193: Useful shortcut component for keyboard commands.The DropdownMenuShortcut component provides a nice way to display keyboard shortcuts within menu items, enhancing the usability of the dropdown menu.
195-239: Comprehensive submenu implementation.The submenu components (Sub, SubTrigger, SubContent) provide a complete solution for nested menus, with appropriate styling and indicators.
241-257: Complete component exports.All components are properly exported, providing a clean and comprehensive API for dropdown menu functionality.
packages/frontend/src/components/ui/sidebar.tsx (5)
45-54: Validate correct usage of throw statement in custom hook.
TheuseSidebarhook throws an error if not used within theSidebarProvider. This is fine, but be aware that any code referencinguseSidebaroutside of the provider will cause a runtime crash. Ensure you wrap any usage with<SidebarProvider>.
96-110: Ensure cleanup of event listeners.
You have correctly removed the "keydown" listener on component unmount, which is good. This ensures no memory leaks.
154-206: Thorough responsive logic.
Your approach to gracefully switch between aSheeton mobile and a persistent sidebar on desktop demonstrates solid responsiveness. This improves mobile UX while preserving a full sidebar on bigger screens.
476-496: Review class-variance-authority usage.
YoursidebarMenuButtonVariantsusage is comprehensive. Just ensure that any new variant or size you add is consistent with the existing styling pattern to prevent class bloat.
602-638: Confirm the skeleton loading pattern meets design expectations.
Generating random widths for Skeleton placeholders adds visual variety, which is often beneficial. Make sure your designers are aware of and approve this effect for a consistent loading state experience.
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (5)
packages/frontend/src/components/app-sidebar.tsx (1)
57-57:⚠️ Potential issueAvoid using non-null assertion with potential null values.
Using the non-null assertion operator (
!) withmeassumes it will never be null, which could lead to runtime errors if the API call fails butisLoadingbecomes false.- <NavUser user={me!} /> + {me ? <NavUser user={me} /> : <div>No user data available</div>}packages/frontend/src/hooks/useMe.ts (1)
5-26: 🛠️ Refactor suggestionImplement a caching or revalidation strategy.
The current implementation fetches user data on every mount without any caching. For components that use this hook multiple times, this could lead to unnecessary API calls.
Consider using a data fetching library like SWR or React Query to handle caching, revalidation, and stale data. This would improve performance and reduce API calls.
What are the benefits of using SWR or React Query compared to custom fetch hooks?packages/frontend/src/components/nav-main.tsx (1)
23-43: Add ARIA attributes for better accessibility.The navigation implementation uses Link components correctly with proper URL handling. This addresses a previous issue where navigation items weren't linking to their URLs. Consider enhancing accessibility with ARIA attributes.
<SidebarMenuButton tooltip={item.title} isActive={isActive(item.url)} > - <Link to={item.url} className="flex items-center gap-2"> + <Link + to={item.url} + className="flex items-center gap-2" + aria-current={isActive(item.url) ? "page" : undefined} + > {item.icon && <item.icon />} <span>{item.title}</span> </Link> </SidebarMenuButton>packages/backend/src/auth/github.strategy.ts (1)
23-24: Use optional chaining for safer property access.The current implementation could cause runtime errors if the
emailsorphotosarrays are undefined or empty.Replace the conditional operators with optional chaining:
return { githubId: id, username, - email: emails && emails[0].value, - photo: photos && photos[0].value, + email: emails?.[0]?.value, + photo: photos?.[0]?.value, accessToken, };🧰 Tools
🪛 Biome (1.9.4)
[error] 23-23: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 24-24: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
packages/backend/src/auth/auth.controller.ts (1)
33-55: Handle authentication errors.Currently, there is no error-handling path if GitHub auth fails or the user denies access.
Add a catch-all route or exception handler to avoid redirect loops or silent failures.
🧹 Nitpick comments (5)
packages/frontend/src/components/nav-main.tsx (1)
12-44: Consider handling empty navigation items.The component doesn't handle the case when the
itemsarray is empty. Consider adding a fallback UI or message when there are no navigation items to display.export function NavMain({ items }: { items: Array<NavItem> }) { const location = useLocation(); const isActive = useCallback( (url: string) => { const pathname = location.pathname; return pathname === url || pathname.startsWith(url + "/"); }, [location.pathname] ); return ( <SidebarGroup> <SidebarGroupContent className="flex flex-col gap-2"> <SidebarMenu> + {items.length === 0 ? ( + <div className="px-4 py-2 text-sm text-muted-foreground"> + No navigation items available + </div> + ) : ( {items.map((item) => ( <SidebarMenuItem key={item.title}> <SidebarMenuButton tooltip={item.title} isActive={isActive(item.url)} > <Link to={item.url} className="flex items-center gap-2"> {item.icon && <item.icon />} <span>{item.title}</span> </Link> </SidebarMenuButton> </SidebarMenuItem> ))} + )} </SidebarMenu> </SidebarGroupContent> </SidebarGroup> ); }packages/backend/src/auth/auth.controller.ts (4)
24-28: Consider extracting cookie options to a common configuration.Cookie options are duplicated between the
logoutandgithubAuthCallbackmethods. This could lead to inconsistencies if one location is updated but not the other.Extract the common cookie options to a private method or class property:
+private getCookieOptions() { + return { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + }; +} async logout(@Res() res: Response) { - res.clearCookie('wafflebase_session', { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'lax', - }); + res.clearCookie('wafflebase_session', this.getCookieOptions()); return res.sendStatus(200); }And in the callback method:
res.cookie('wafflebase_session', token, { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'lax', + ...this.getCookieOptions(), maxAge: 3600000, });
35-37: Empty method implementation for GitHub authentication.The
githubAuthmethod has a comment but no implementation. While the AuthGuard will handle the redirect, it's better to be explicit about the expected behavior.@Get('github') @UseGuards(AuthGuard('github')) -async githubAuth() { - // NOTE(hackerwins): Redirect to GitHub for authentication. -} +async githubAuth(@Req() req: Request, @Res() res: Response) { + // This method won't be executed as the AuthGuard redirects to GitHub + // This implementation handles edge cases where the guard somehow doesn't redirect + return res.status(500).json({ error: 'Authentication failed. Please try again.' }); +}
51-51: Consider making session duration configurable.The session cookie
maxAgeis hardcoded to 1 hour (3600000 ms). This should ideally be configurable via environment variables.+// In your ConfigService initialization or module +// SESSION_DURATION=3600000 res.cookie('wafflebase_session', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', - maxAge: 3600000, + maxAge: parseInt(this.configService.get('SESSION_DURATION') || '3600000'), });
15-19: Consider returning a consistent data structure.The
getMeendpoint directly returns the user object from the request. For API consistency, consider standardizing the response format across all endpoints.@Get('me') @UseGuards(JwtAuthGuard) async getMe(@Req() req: Request & { user: User }) { - return req.user; + return { + success: true, + data: req.user, + }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
packages/backend/src/auth/auth.controller.ts(1 hunks)packages/backend/src/auth/auth.service.ts(1 hunks)packages/backend/src/auth/github.strategy.ts(1 hunks)packages/backend/src/auth/jwt.strategy.ts(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/frontend/src/api/auth.ts(1 hunks)packages/frontend/src/app/Layout.tsx(1 hunks)packages/frontend/src/app/documents/page.tsx(1 hunks)packages/frontend/src/app/members/page.tsx(1 hunks)packages/frontend/src/app/settings/page.tsx(1 hunks)packages/frontend/src/components/app-sidebar.tsx(1 hunks)packages/frontend/src/components/login-form.tsx(1 hunks)packages/frontend/src/components/nav-main.tsx(1 hunks)packages/frontend/src/components/nav-secondary.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/components/site-header.tsx(1 hunks)packages/frontend/src/hooks/useMe.ts(1 hunks)packages/frontend/src/types/nav-items.ts(1 hunks)packages/frontend/src/types/users.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- packages/frontend/src/app/documents/page.tsx
- packages/frontend/src/app/members/page.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
- packages/frontend/src/components/site-header.tsx
- packages/backend/src/auth/jwt.strategy.ts
- packages/frontend/src/components/nav-secondary.tsx
- packages/frontend/src/components/nav-user.tsx
- packages/backend/src/auth/auth.service.ts
- packages/frontend/src/components/login-form.tsx
🧰 Additional context used
🧬 Code Graph Analysis (7)
packages/frontend/src/types/users.ts (1)
packages/backend/src/auth/auth.service.ts (1)
User(4-10)
packages/frontend/src/api/auth.ts (3)
packages/backend/src/auth/auth.controller.ts (1)
logout(23-31)packages/backend/src/auth/auth.service.ts (1)
User(4-10)packages/frontend/src/types/users.ts (1)
User(1-6)
packages/frontend/src/components/app-sidebar.tsx (5)
packages/frontend/src/types/nav-items.ts (1)
NavItem(1-5)packages/frontend/src/hooks/useMe.ts (1)
useMe(5-26)packages/frontend/src/components/nav-main.tsx (1)
NavMain(12-44)packages/frontend/src/components/nav-secondary.tsx (1)
NavSecondary(13-37)packages/frontend/src/components/nav-user.tsx (1)
NavUser(26-92)
packages/frontend/src/App.tsx (5)
packages/frontend/src/components/theme-provider.tsx (1)
ThemeProvider(23-64)packages/frontend/src/PublicRoute.tsx (1)
PublicRoute(6-14)packages/frontend/src/PrivateRoute.tsx (1)
PrivateRoute(6-14)packages/frontend/src/app/Layout.tsx (1)
Layout(29-51)packages/frontend/src/app/settings/page.tsx (1)
Settings(1-3)
packages/frontend/src/components/nav-main.tsx (2)
packages/frontend/src/types/nav-items.ts (1)
NavItem(1-5)packages/frontend/src/components/ui/sidebar.tsx (5)
SidebarGroup(705-705)SidebarGroupContent(707-707)SidebarMenu(712-712)SidebarMenuItem(716-716)SidebarMenuButton(715-715)
packages/backend/src/auth/auth.controller.ts (2)
packages/backend/src/auth/auth.service.ts (1)
User(4-10)packages/frontend/src/types/users.ts (1)
User(1-6)
packages/frontend/src/app/Layout.tsx (3)
packages/frontend/src/components/ui/sidebar.tsx (2)
SidebarProvider(721-721)SidebarInset(711-711)packages/frontend/src/components/app-sidebar.tsx (1)
AppSidebar(20-61)packages/frontend/src/components/site-header.tsx (1)
SiteHeader(4-17)
🪛 Biome (1.9.4)
packages/backend/src/auth/github.strategy.ts
[error] 23-23: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 24-24: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (10)
packages/frontend/src/app/settings/page.tsx (1)
1-3: Simple, focused component implementation.This is a straightforward implementation of a Settings page component. The component follows React's functional component pattern and serves as a placeholder for future Settings functionality.
packages/frontend/src/types/users.ts (1)
1-6: Consider aligning with backend User interfaceThe backend User interface in
packages/backend/src/auth/auth.service.tsincludes anidproperty and restrictsauthProviderto 'github', while this implementation has a more generic type without theidfield.Consider updating the User type to match the backend interface:
export type User = { - authProvider: string; + authProvider: 'github'; + id: string; username: string; email: string; photo: string; };packages/frontend/src/types/nav-items.ts (1)
1-5: Well-structured type definition for nav itemsThis type definition for navigation items is clear and provides good type safety for components that use it.
packages/frontend/src/app/Layout.tsx (3)
7-27: Structured navigation items with clear organizationThe navigation items are well-organized into main and secondary categories, each with appropriate properties. The structure aligns well with the NavItem type defined in the nav-items.ts file.
29-35: Effective title determination based on current routeThe code correctly determines the page title by matching the current pathname against navigation items. The fallback to an empty string ensures there are no undefined values when no match is found.
36-51: Well-structured layout implementationThe layout implementation provides a good structure with sidebar and content areas. It uses context providers appropriately and passes the necessary props to child components.
packages/frontend/src/App.tsx (1)
1-35: Well-structured routing setup with proper access control.The App component is well-organized with clear separation between public and private routes. The implementation of
PublicRouteandPrivateRoutewrappers provides good authentication control, while the nested route structure with theLayoutcomponent ensures consistent UI across protected routes.The use of environment variables for the router's basename is a good practice for flexibility across different deployment environments.
packages/frontend/src/api/auth.ts (1)
4-21: Good implementation of logout functionality with proper error handling.The logout function correctly handles both server errors and network exceptions with appropriate user feedback via toast notifications.
packages/frontend/src/components/nav-main.tsx (2)
1-11: Appropriate imports and component dependencies.The component correctly imports React Router's navigation elements and the required UI components from the sidebar library. The imports are well-organized and the component dependencies are properly structured.
12-22: Well-implemented active state detection.The
isActivefunction is correctly implemented usinguseCallbackwith the proper dependency array. The logic accurately determines if a navigation item is active by checking if the current path matches exactly or is a child route.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
packages/frontend/src/api/auth.ts (1)
24-39: Improve error handling in fetchMe functionWhile the function handles basic error cases, there are opportunities to improve the error handling:
- The error message provides minimal information about what went wrong
- There's no specific handling for different HTTP status codes
export async function fetchMe(): Promise<User> { const res = await fetch(`${import.meta.env.VITE_BACKEND_API_URL}/auth/me`, { method: "GET", credentials: "include", }); if (!res.ok) { - throw new Error("Failed to fetch user"); + const errorText = await res.text(); + throw new Error(`Failed to fetch user: ${res.status} ${errorText}`); } return res.json(); }
🧹 Nitpick comments (16)
package.json (2)
12-14: Populate project metadata fields.
The"keywords","author", and other fields such as"repository"or"bugs"are empty or missing. Filling these improves discoverability and integrates better with tooling (e.g., CI, GitHub).
15-15: Reviewpnpmversion pinning.
You’ve locked"packageManager": "[email protected]". Confirm that all contributors use exactly this version, or consider allowing patch updates (e.g.,^10.5.2) to ease maintenance.packages/frontend/src/app/documents/page.tsx (1)
51-72: Consider adding loading state for document creationThe component displays the document list and creation button, but doesn't show any loading indicator while a new document is being created. This might lead to user confusion if the creation takes time.
<Button onClick={handleCreateDocument} className="flex items-center gap-2" + disabled={createDocumentMutation.isPending} > <Plus className="w-4 h-4" /> - New Document + {createDocumentMutation.isPending ? "Creating..." : "New Document"} </Button>packages/frontend/src/api/documents.ts (2)
3-20: Consider enhancing the createDocument functionThe function only accepts a
titlefield in the payload, but theDocumenttype includes other fields likedescription. Consider expanding the payload to match the expected document structure.export async function createDocument(payload: { title: string; + description?: string; }): Promise<Document> { const response = await fetch( `${import.meta.env.VITE_BACKEND_API_URL}/documents`, { method: "POST", headers: { "Content-Type": "application/json", + // Add auth headers if needed + // "Authorization": `Bearer ${getToken()}` }, body: JSON.stringify(payload), } ); if (!response.ok) { - throw new Error("Failed to create document"); + const errorText = await response.text(); + throw new Error(`Failed to create document: ${response.status} ${errorText}`); } - return response.json(); + return await response.json(); }
22-30: Enhance fetchDocuments with better error handlingThe error handling in this function could be improved to include response details for debugging purposes.
export async function fetchDocuments(): Promise<Array<Document>> { const response = await fetch( `${import.meta.env.VITE_BACKEND_API_URL}/documents`, + { + headers: { + // Add auth headers if needed + // "Authorization": `Bearer ${getToken()}` + } + } ); if (!response.ok) { - throw new Error("Failed to fetch documents"); + const errorText = await response.text(); + throw new Error(`Failed to fetch documents: ${response.status} ${errorText}`); } return await response.json(); }packages/backend/src/documents/document.controller.ts (3)
9-18: Remove unused ConfigServiceThe
ConfigServiceis injected in the constructor but not used anywhere in the controller. Consider removing it if it's not needed.-import { ConfigService } from '@nestjs/config'; @Controller('documents') export class DocumentController { constructor( private readonly documentService: DocumentService, - private readonly configService: ConfigService, ) {}
20-29: Improve error handling for ID conversionThe current implementation assumes IDs are always numeric. If the ID format changes in the future (e.g., to UUID), this would break. Consider adding error handling for the ID conversion.
@Get('/:id') async getDocumentById( @Param('id') id: string, ): Promise<DocumentModel | null> { + let numericId: number; + try { + numericId = Number(id); + if (isNaN(numericId)) { + throw new Error('Invalid ID format'); + } + } catch (error) { + throw new NotFoundException(`Invalid document ID format: ${id}`); + } - const doc = await this.documentService.document({ id: Number(id) }); + const doc = await this.documentService.document({ id: numericId }); if (!doc) { throw new NotFoundException(`document not found with id ${id}`); } return doc; }
31-34: Add pagination to document listingThe current implementation fetches all documents without pagination, which could lead to performance issues as the collection grows. Consider adding pagination parameters.
+import { Query } from '@nestjs/common'; @Get('/') async getDocuments( + @Query('skip') skip?: string, + @Query('take') take?: string, ): Promise<DocumentModel[]> { - return this.documentService.documents({}); + const skipNum = skip ? parseInt(skip, 10) : undefined; + const takeNum = take ? parseInt(take, 10) : undefined; + + return this.documentService.documents({ + skip: skipNum, + take: takeNum || 10, // Default limit to avoid large result sets + }); }packages/backend/src/users/user.service.ts (4)
1-3: Fix the import path for PrismaServiceImporting from 'src/database/prisma.service' uses an absolute path, which might cause issues in some build configurations. Use a relative path or configure path aliases.
import { Injectable } from '@nestjs/common'; import { User, Prisma } from '@prisma/client'; -import { PrismaService } from 'src/database/prisma.service'; +import { PrismaService } from '../database/prisma.service';
5-8: Add documentation to the service classAdding JSDoc comments to the class and methods would improve code readability and help other developers understand how to use this service.
+/** + * Service for managing user entities in the database. + * Provides methods for CRUD operations on users. + */ @Injectable() export class UsersService { constructor(private prisma: PrismaService) {}
34-38: Make createUser method signature consistent with updateUserFor consistency with the update method, consider using a params object with a separate data field for the createUser method.
-async createUser(data: Prisma.UserCreateInput): Promise<User> { +async createUser(params: { + data: Prisma.UserCreateInput; +}): Promise<User> { + const { data } = params; return this.prisma.user.create({ data, }); }
51-55: Add existence check before deletionThe current implementation doesn't check if the user exists before deletion, which could lead to cryptic errors. Add a check to provide a clearer error message.
async deleteUser(where: Prisma.UserWhereUniqueInput): Promise<User> { + // Check if user exists + const user = await this.prisma.user.findUnique({ + where, + }); + + if (!user) { + throw new Error(`User not found for deletion`); + } + return this.prisma.user.delete({ where, }); }packages/backend/src/documents/document.service.ts (4)
9-11: Parameter name should bedocumentWhereUniqueInputfor consistency.The parameter name
postWhereUniqueInputappears to be a copy-paste error from a Post service. Rename it todocumentWhereUniqueInputto maintain consistency with the Document entity being operated on.async document( - postWhereUniqueInput: Prisma.DocumentWhereUniqueInput, + documentWhereUniqueInput: Prisma.DocumentWhereUniqueInput, ): Promise<Document | null> {
12-14: Update variable reference to match renamed parameter.After renaming the parameter, update the reference in the where clause to maintain consistency.
return this.prisma.document.findUnique({ - where: postWhereUniqueInput, + where: documentWhereUniqueInput, });
38-38: Remove console.log statement before deploying to production.Console logging should be removed from production code. Consider using a proper logging service if you need to track document creation events.
- console.log('doc', doc);
5-60: Consider implementing pagination metadata for the documents method.The
documentsmethod returns an array of Document objects but doesn't provide pagination metadata (total count, page information, etc.). This information is often useful for frontend UI components like data tables.Consider modifying the return type to include pagination metadata:
async documents(params: { skip?: number; take?: number; cursor?: Prisma.DocumentWhereUniqueInput; where?: Prisma.DocumentWhereInput; orderBy?: Prisma.DocumentOrderByWithRelationInput; }): Promise<{ data: Document[]; count: number; }> { const { skip, take, cursor, where, orderBy } = params; const [data, count] = await Promise.all([ this.prisma.document.findMany({ skip, take, cursor, where, orderBy, }), this.prisma.document.count({ where }), ]); return { data, count }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
packages/backend/prisma/dev.dbis excluded by!**/*.dbpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
package.json(1 hunks)packages/backend/package.json(1 hunks)packages/backend/prisma/migrations/20250419011142_init/migration.sql(1 hunks)packages/backend/prisma/migrations/20250419025308_init/migration.sql(1 hunks)packages/backend/prisma/migrations/migration_lock.toml(1 hunks)packages/backend/prisma/schema.prisma(1 hunks)packages/backend/src/app.module.ts(1 hunks)packages/backend/src/database/prisma.service.ts(1 hunks)packages/backend/src/documents/document.controller.ts(1 hunks)packages/backend/src/documents/document.module.ts(1 hunks)packages/backend/src/documents/document.service.ts(1 hunks)packages/backend/src/users/user.service.ts(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/frontend/src/PrivateRoute.tsx(1 hunks)packages/frontend/src/PublicRoute.tsx(1 hunks)packages/frontend/src/api/auth.ts(1 hunks)packages/frontend/src/api/documents.ts(1 hunks)packages/frontend/src/app/Layout.tsx(1 hunks)packages/frontend/src/app/documents/page.tsx(1 hunks)packages/frontend/src/components/app-sidebar.tsx(1 hunks)packages/frontend/src/components/data-table.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/index.css(1 hunks)packages/frontend/src/types/documents.ts(1 hunks)
✅ Files skipped from review due to trivial changes (7)
- packages/frontend/src/types/documents.ts
- packages/backend/prisma/migrations/migration_lock.toml
- packages/backend/prisma/migrations/20250419011142_init/migration.sql
- packages/backend/src/documents/document.module.ts
- packages/frontend/src/index.css
- packages/frontend/src/app/Layout.tsx
- packages/backend/prisma/schema.prisma
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/backend/src/app.module.ts
- packages/frontend/src/components/nav-user.tsx
- packages/frontend/src/PublicRoute.tsx
- packages/frontend/package.json
- packages/backend/package.json
- packages/frontend/src/components/app-sidebar.tsx
- packages/frontend/src/App.tsx
- packages/frontend/src/components/data-table.tsx
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/backend/src/documents/document.service.ts (3)
packages/backend/src/database/prisma.service.ts (1)
Injectable(4-16)packages/backend/src/users/user.service.ts (1)
Injectable(5-56)packages/frontend/src/types/documents.ts (1)
Document(1-7)
packages/frontend/src/api/auth.ts (2)
packages/backend/src/auth/auth.controller.ts (1)
logout(23-31)packages/frontend/src/types/users.ts (1)
User(1-6)
packages/frontend/src/PrivateRoute.tsx (2)
packages/frontend/src/api/auth.ts (1)
fetchMe(28-39)packages/frontend/src/components/loader.tsx (1)
Loader(3-13)
packages/frontend/src/app/documents/page.tsx (3)
packages/frontend/src/types/documents.ts (1)
Document(1-7)packages/frontend/src/api/documents.ts (2)
fetchDocuments(22-30)createDocument(3-20)packages/frontend/src/components/data-table.tsx (1)
DataTable(102-244)
packages/frontend/src/api/documents.ts (3)
packages/backend/src/documents/document.controller.ts (1)
createDocument(37-41)packages/backend/src/documents/document.service.ts (1)
createDocument(34-40)packages/frontend/src/types/documents.ts (1)
Document(1-7)
packages/backend/src/users/user.service.ts (2)
packages/backend/src/documents/document.service.ts (1)
Injectable(5-60)packages/backend/src/database/prisma.service.ts (1)
Injectable(4-16)
🔇 Additional comments (8)
package.json (1)
16-18: Dev dependency looks good.
Addingconcurrentlyis appropriate for orchestrating parallel processes in thedevscript.packages/backend/src/database/prisma.service.ts (1)
1-16: Well-structured Prisma service implementationThis is a well-implemented service class that properly integrates Prisma with the NestJS lifecycle. The class correctly:
- Extends
PrismaClientfor database operations- Implements
OnModuleInitandOnModuleDestroyinterfaces- Connects to the database when the module initializes
- Disconnects when the module is destroyed
This implementation ensures proper resource management and follows NestJS best practices for database integration.
packages/frontend/src/PrivateRoute.tsx (1)
7-19: Robust authentication route guard implementationThe
PrivateRoutecomponent correctly implements route protection based on authentication status. It:
- Uses React Query to fetch the current user data
- Shows a loading state while authentication is being verified
- Renders child routes only for authenticated users
- Redirects unauthenticated users to the login page
- Disables automatic retries with
retry: falsewhich is appropriate for auth checksThis implementation follows React best practices for protected routes and properly handles the authentication flow.
packages/frontend/src/api/auth.ts (1)
4-22: Well-documented logout functionThe logout implementation is clear and properly documented with JSDoc comments. It correctly:
- Makes a POST request to the logout endpoint
- Includes credentials to ensure cookies are sent
- Throws an error on failure
- Shows a success notification on successful logout
This follows best practices for API interactions.
packages/frontend/src/app/documents/page.tsx (2)
8-33: Well-structured document management implementationThis component correctly implements document fetching and creation using React Query. The code:
- Uses appropriate hooks for querying and mutations
- Properly invalidates the query cache after creating a document
- Handles the document creation flow efficiently
- Provides good separation of concerns between data fetching and UI rendering
This follows modern React and data fetching best practices.
34-49: Good user feedback for loading and error statesThe component provides clear visual feedback to users when documents are loading or when an error occurs. The centered messages with appropriate styling improve the user experience.
packages/backend/prisma/migrations/20250419025308_init/migration.sql (1)
1-21: Migration script looks goodThe migration script correctly removes the
publishedcolumn from theDocumenttable using the SQLite approach of creating a new table, copying data, dropping the old table, and renaming. Foreign key constraints are properly managed with temporary disabling and re-enabling.packages/backend/src/documents/document.service.ts (1)
1-60: The implementation follows NestJS and Prisma best practices.The service is well-structured with appropriate dependency injection and follows a consistent pattern for CRUD operations. The code structure is similar to the UserService implementation, which promotes consistency throughout the application.
- Introduced a new type `Document` in `documents.ts` with fields: id, title, description, createdAt, and updatedAt. - Updated `pnpm-lock.yaml` to include new dependencies and versions: - Added `@prisma/client` and `@tanstack/react-query` with specified versions. - Updated `lucide-react` to version 0.501.0. - Updated `globals` and `typescript` to versions 16.0.0 and 5.8.3 respectively. - Added `concurrently` version 9.1.2 and `esbuild-register` version 3.6.0.
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (5)
packages/frontend/src/app/documents/document-list.tsx (2)
43-115: WrapcolumnsinuseMemoto prevent table‑state resets on every render
columnsis re‑created on each component render, which causes a new table instance to be built every time. This can reset pagination, sorting, and selection state, and it allocates unnecessary memory.- const columns: Array<ColumnDef<Document>> = [ + const columns: Array<ColumnDef<Document>> = React.useMemo( + () => [ /* … column defs … */ - ]; + ], + [deleteDocumentMutation], // memo deps + );
117-126: Add loading/disabled states for document mutationsWhile a mutation is in‑flight users can click buttons multiple times, potentially spamming the backend with identical requests. Disable actions while
isLoadingis true and surface errors fromonError.const createDocumentMutation = useMutation({ mutationFn: async (data: { title: string }) => await createDocument(data), - onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), + onError: (e: unknown) => toast.error(`${e}`), });And for the button:
- <Button - onClick={() => { - createDocumentMutation.mutate({ title: "New Document" }); - }} - className="flex items-center gap-2" - > + <Button + onClick={() => createDocumentMutation.mutate({ title: "New Document" })} + className="flex items-center gap-2" + disabled={createDocumentMutation.isLoading} + >packages/sheet/src/store/local.ts (1)
7-10:createStoreno longer needs to beasyncAfter dropping the DuckDB path the function is fully synchronous. Keeping
asyncunnecessarily wraps the return value inPromise.resolve, adds micro‑task overhead, and may mislead future maintainers.-export async function createStore(): Promise<LocalStore> { - const store = new MemStore(); - return new LocalStore(store); -} +export function createStore(): LocalStore { + const store = new MemStore(); + return new LocalStore(store); +}packages/sheet/src/worksheet/sheet.ts (1)
24-27: Document the reduced row limit (now 700 000) and make it configurableChanging
Dimensions.rowsfrom ~2 billion to 700 000 is a breaking behavioural change for consumers relying on the prior limit. Capture the motivation in code comments and consider surfacing it as a configurable value rather than a constant to maximise flexibility.packages/sheet/src/spreadsheet/worksheet.ts (1)
861-868: Minor style optimisationRepeated calls to
getThemeColorduring every paint tick could allocate strings unnecessarily.
Cache the resolved colors at construction time:private colors = (this.theme === 'light' ? LightTheme : DarkTheme) as const; ... ctx.fillStyle = selected ? this.colors.headerActiveBGColor : this.colors.headerBGColor;This is purely a micro‑optimisation but keeps the hot rendering path lean.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
packages/backend/prisma/dev.dbis excluded by!**/*.dbpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (36)
package.json(1 hunks)packages/backend/package.json(1 hunks)packages/backend/prisma/migrations/20250419011142_init/migration.sql(1 hunks)packages/backend/prisma/migrations/20250419025308_init/migration.sql(1 hunks)packages/backend/prisma/migrations/migration_lock.toml(1 hunks)packages/backend/prisma/schema.prisma(1 hunks)packages/backend/src/app.module.ts(1 hunks)packages/backend/src/database/prisma.service.ts(1 hunks)packages/backend/src/documents/document.controller.ts(1 hunks)packages/backend/src/documents/document.module.ts(1 hunks)packages/backend/src/documents/document.service.ts(1 hunks)packages/backend/src/users/user.service.ts(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/frontend/src/PrivateRoute.tsx(1 hunks)packages/frontend/src/PublicRoute.tsx(1 hunks)packages/frontend/src/api/auth.ts(1 hunks)packages/frontend/src/api/documents.ts(1 hunks)packages/frontend/src/app/Layout.tsx(1 hunks)packages/frontend/src/app/documents/document-detail.tsx(1 hunks)packages/frontend/src/app/documents/document-list.tsx(1 hunks)packages/frontend/src/app/documents/page.tsx(1 hunks)packages/frontend/src/components/app-sidebar.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/index.css(1 hunks)packages/frontend/src/types/documents.ts(1 hunks)packages/frontend/vite.config.ts(1 hunks)packages/sheet/package.json(1 hunks)packages/sheet/src/index.ts(1 hunks)packages/sheet/src/main.ts(1 hunks)packages/sheet/src/spreadsheet/spreadsheet.ts(2 hunks)packages/sheet/src/spreadsheet/worksheet.ts(10 hunks)packages/sheet/src/store/local.ts(1 hunks)packages/sheet/src/worksheet/sheet.ts(2 hunks)packages/sheet/src/worksheet/types.ts(0 hunks)packages/sheet/vite.build.ts(1 hunks)
💤 Files with no reviewable changes (1)
- packages/sheet/src/worksheet/types.ts
✅ Files skipped from review due to trivial changes (5)
- packages/sheet/src/main.ts
- packages/sheet/vite.build.ts
- packages/sheet/src/index.ts
- packages/frontend/src/index.css
- packages/backend/package.json
🚧 Files skipped from review as they are similar to previous changes (23)
- packages/backend/prisma/migrations/migration_lock.toml
- packages/backend/src/app.module.ts
- packages/backend/src/documents/document.module.ts
- packages/frontend/src/PublicRoute.tsx
- packages/frontend/src/app/documents/page.tsx
- packages/backend/src/database/prisma.service.ts
- packages/frontend/vite.config.ts
- packages/frontend/src/api/auth.ts
- packages/frontend/src/PrivateRoute.tsx
- packages/frontend/src/app/Layout.tsx
- packages/frontend/src/components/app-sidebar.tsx
- packages/frontend/src/api/documents.ts
- package.json
- packages/backend/src/users/user.service.ts
- packages/backend/src/documents/document.controller.ts
- packages/backend/prisma/schema.prisma
- packages/frontend/src/App.tsx
- packages/frontend/src/types/documents.ts
- packages/frontend/src/components/nav-user.tsx
- packages/backend/prisma/migrations/20250419025308_init/migration.sql
- packages/backend/prisma/migrations/20250419011142_init/migration.sql
- packages/frontend/package.json
- packages/backend/src/documents/document.service.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
packages/sheet/src/store/local.ts (1)
packages/sheet/src/store/memory/memory.ts (1)
MemStore(14-122)
packages/sheet/src/worksheet/sheet.ts (1)
packages/sheet/src/worksheet/types.ts (1)
Ref(26-29)
packages/frontend/src/app/documents/document-list.tsx (9)
packages/frontend/src/types/documents.ts (1)
Document(1-7)packages/frontend/src/components/ui/checkbox.tsx (1)
Checkbox(30-30)packages/frontend/src/components/ui/dropdown-menu.tsx (4)
DropdownMenu(242-242)DropdownMenuTrigger(244-244)DropdownMenuContent(245-245)DropdownMenuLabel(247-247)packages/frontend/src/components/ui/button.tsx (1)
Button(62-62)packages/backend/src/documents/document.controller.ts (2)
createDocument(38-42)deleteDocument(45-51)packages/backend/src/documents/document.service.ts (2)
createDocument(34-40)deleteDocument(53-59)packages/frontend/src/api/documents.ts (2)
createDocument(4-21)deleteDocument(33-47)packages/frontend/src/components/ui/input.tsx (1)
Input(21-21)packages/frontend/src/components/ui/table.tsx (6)
Table(108-108)TableHeader(109-109)TableRow(113-113)TableHead(112-112)TableBody(110-110)TableCell(114-114)
packages/sheet/src/spreadsheet/worksheet.ts (2)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
Theme(7-7)packages/sheet/src/worksheet/sheet.ts (1)
Sheet(31-439)
🪛 GitHub Actions: Frontend CI
packages/frontend/src/app/documents/document-detail.tsx
[error] 6-6: TypeScript error TS6133: 'id' is declared but its value is never read.
🔇 Additional comments (8)
packages/frontend/src/app/documents/document-detail.tsx (1)
11-38: Simplify mounting logic & ensure cleanup on route changesThe extra
didMountstate adds another render cycle and the effect will not rerun if the document ID changes.
You can rely onuseEffectwith the container ref and (optionally)idas dependencies:- const [didMount, setDidMount] = useState(false); ... - useEffect(() => { - setDidMount(true); - }, []); - - useEffect(() => { - if (!containerRef.current) { - return; - } - async function setupSpreadsheet() { - if (!didMount) { - return; - } - const cleanup = await setup(containerRef.current!, { theme: 'dark' }); - cleanupRef.current = cleanup; - } - setupSpreadsheet(); - return () => { - if (cleanupRef.current) { - cleanupRef.current(); - cleanupRef.current = null; - } - }; - }, [didMount, containerRef]); + useEffect(() => { + if (!containerRef.current) return; + + (async () => { + cleanupRef.current = await setup(containerRef.current, { theme: 'dark' }); + })(); + + return () => { + cleanupRef.current?.(); + cleanupRef.current = null; + }; + }, [containerRef, _id]); // rerun when navigating to a different documentBenefits: one render shorter, easier to reason about, and spreadsheet re‑initialises when navigating between document IDs without unmounting the component.
[ suggest_essential_refactor ]packages/sheet/src/spreadsheet/spreadsheet.ts (1)
19-24: Return type & unnecessaryawait
createStore()is described as synchronous; awaiting a sync function is harmless but misleading and forces the surroundingsetupto stayasync.
Consider:-export async function setup(container: HTMLDivElement, options?: SetupOptions) { - const spreadsheet = new Spreadsheet(container, options); - const store = await createStore(); +export function setup(container: HTMLDivElement, options?: SetupOptions): Promise<() => void> | (() => void) { + const spreadsheet = new Spreadsheet(container, options); + const store = createStore();If
createStoreis indeed synchronous you can remove theasync/awaitpair and return the cleanup function directly; otherwise keep the current form but add an explicit return type (Promise<() => void>).
[ suggest_optional_refactor ]packages/sheet/src/spreadsheet/worksheet.ts (1)
212-218: Type‐safety for theme keys
getThemeColor(key: string)allows any string and may returnundefined, which later gets assigned tostyle.*or canvas colors.
Define a sharedThemeColorKeyinstead:- public getThemeColor(key: string) { + type ThemeColorKey = keyof typeof LightTheme; + + public getThemeColor(key: ThemeColorKey) {This guarantees compile‑time safety when adding new theme colors or refactoring existing ones.
[ suggest_optional_refactor ]packages/sheet/package.json (5)
2-2: Verify scoped package naming across workspaces.You’ve renamed the package to
@wafflebase/sheet. Ensure this matches the entries in your rootpnpm-workspace.yaml(or equivalent), and update any import/require paths in consuming packages to use the new scope.
5-5: Great addition ofdescription.Adding
"description": "Frontend for Wafflebase"improves clarity for consumers and on registry listings.
17-17: Build script switched to custom Vite config.Using
vite --config vite.build.ts buildreflects the new library build setup. This is correct and aligns with the addedvite.build.tsfile.
20-20: Prettier format script added.Including
"format": "prettier --write ."is a good move to keep styling consistent across the package.
28-28: Dev dependency version bumps.You’ve upgraded
prettier,vite,vite-plugin-node-polyfills, andvitestto recent majors. These versions look reasonable, but be sure to run full CI to catch any compatibility issues with your existing codebase.Also applies to: 30-32
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/sheet/src/spreadsheet/worksheet.ts (2)
91-97: Event‐listener registry is solid but could use stricter typingStoring
{ element, type, handler }enables deterministic cleanup – nice!
If you want to tighten the API, consider generics sohandler’s parameter type is derived fromtype(similar to yourK extends keyof …trick below).
537-541: Frequentrender()calls may pile up unresolved async work
render()invokes the asyncpaintSheet()but doesn’t await it.
With rapidscrollorresizeevents, you can spawn overlappingpaintSheet()executions, risking race conditions and unnecessary DOM/canvas work.Consider debouncing with
requestAnimationFrameor tracking a single in‑flight promise:private renderPending?: Promise<void>; private render = () => { if (this.renderPending) { return; } this.renderPending = (async () => { this.paintFormulaBar(); await this.paintSheet(); // now awaited this.paintOverlay(); })().finally(() => { this.renderPending = undefined; }); };This keeps UI responsive while preventing uncontrolled concurrency.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
packages/frontend/src/app/Layout.tsx(1 hunks)packages/frontend/src/app/documents/document-detail.tsx(1 hunks)packages/sheet/package.json(1 hunks)packages/sheet/src/index.ts(1 hunks)packages/sheet/src/spreadsheet/spreadsheet.ts(2 hunks)packages/sheet/src/spreadsheet/worksheet.ts(12 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/sheet/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/frontend/src/app/Layout.tsx
- packages/frontend/src/app/documents/document-detail.tsx
- packages/sheet/package.json
- packages/sheet/src/spreadsheet/spreadsheet.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
Theme(7-7)
🔇 Additional comments (3)
packages/sheet/src/spreadsheet/worksheet.ts (3)
190-199: 👍 Bound handlers solve the previous leakGreat job binding the handlers once and storing them as fields – this directly addresses memory‑leak reports from the earlier review.
214-229: Wrapper adds/removes listeners safelyThe private
addEventListenerhelper andremoveAllEventListenersguarantee balanced add/remove pairs and simplifycleanup(). Well done.
851-865: Nice theme integration in overlay drawingUsing
getThemeColorfor active‑cell and selection visuals centralises styling and simplifies future theme tweaks.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
368-379:⚠️ Potential issueOne remaining event listener leak risk during drag operations.
The
mousemoveandmouseuplisteners are still added directly to the document without using your centralized registry system. Ifcleanup()is called during a drag operation, these listeners won't be removed.- document.addEventListener('mousemove', onMove); - document.addEventListener('mouseup', onUp); + this.addEventListener(document, 'mousemove', onMove); + this.addEventListener(document, 'mouseup', onUp);This was pointed out in a previous review but wasn't fully addressed in this file.
🧹 Nitpick comments (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
15-33: Consider moving theme definitions to a separate file.The theme objects are well-structured, but as the application grows, moving these to a dedicated themes file would improve modularity and make it easier to extend with additional themes.
Consider creating a
themes.tsfile that exports these theme objects and related types/utilities for better organization.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
package.json(1 hunks)packages/backend/src/auth/github.strategy.ts(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/app/Layout.tsx(1 hunks)packages/frontend/src/app/documents/document-detail.tsx(1 hunks)packages/frontend/src/app/documents/document-list.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/components/ui/toggle.tsx(1 hunks)packages/sheet/package.json(1 hunks)packages/sheet/src/index.ts(1 hunks)packages/sheet/src/spreadsheet/spreadsheet.ts(2 hunks)packages/sheet/src/spreadsheet/worksheet.ts(12 hunks)
✅ Files skipped from review due to trivial changes (2)
- packages/sheet/src/index.ts
- packages/frontend/src/components/ui/toggle.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
- packages/backend/src/auth/github.strategy.ts
- packages/frontend/src/components/nav-user.tsx
- packages/frontend/src/app/Layout.tsx
- packages/frontend/src/app/documents/document-list.tsx
- packages/sheet/src/spreadsheet/spreadsheet.ts
- packages/frontend/package.json
- packages/frontend/src/app/documents/document-detail.tsx
- package.json
- packages/sheet/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/sheet/src/spreadsheet/worksheet.ts (1)
packages/sheet/src/spreadsheet/spreadsheet.ts (1)
Theme(7-7)
🔇 Additional comments (9)
packages/sheet/src/spreadsheet/worksheet.ts (9)
7-7: Great implementation of theming support.The addition of theme support with proper typing and constructor parameter is well-implemented. This aligns with the PR's broader goal of enhancing the structure of the codebase.
Also applies to: 77-77, 107-109
15-33: Good implementation of theme objects.The separation into
LightThemeandDarkThemeobjects is clean and maintainable. Each theme consistently provides all necessary color values required by the worksheet.
91-95: Well-designed event listener tracking.This listener tracking array is a clean solution for managing event listeners, making cleanup more reliable and preventing memory leaks.
97-106: Fixed event handler binding issue.You've properly addressed the previous review comments by binding all event handlers once in the constructor and storing them as class properties, ensuring the same references are used for both adding and removing listeners.
Also applies to: 190-199
208-213: Comprehensive cleanup implementation.The
cleanupmethod properly removes all event listeners and clears the container, effectively preventing memory leaks when the component unmounts.
214-229: Well-implemented event listener management system.This centralized approach to tracking and removing event listeners is excellent and ensures no listeners are left behind when the component is destroyed.
282-298: Correctly using the listener tracking system.You're now consistently using the
addEventListenermethod to register all event listeners, which ensures they can be properly cleaned up later.
526-539: Excellent implementation of system theme detection.Your implementation of the
getThemeColormethod properly handles the 'system' theme by checking the user's OS preferences via media query. This addresses the previous review comment perfectly.
858-872: Consistent application of theme colors.You've systematically updated all color references to use the
getThemeColormethod, ensuring consistent theming throughout the component's rendering.Also applies to: 889-895, 907-915
a01840e to
36fb4de
Compare
8b3a5a1 to
e4202cc
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
packages/sheet/src/spreadsheet/worksheet.ts (2)
307-379:⚠️ Potential issuePotential event listener leak during drag operations.
When handling mouse down events, you're attaching document-level event listeners for 'mousemove' and 'mouseup' directly rather than through your central registry.
If
cleanup()is called while a drag operation is in progress (e.g., during component unmount), these listeners won't be removed because they're not tracked in your listener registry.- document.addEventListener('mousemove', onMove); - document.addEventListener('mouseup', onUp); + this.addEventListener(document, 'mousemove', onMove); + this.addEventListener(document, 'mouseup', onUp);You can then remove the explicit
removeEventListenercalls inonUp, or keep them as an extra safety measure.
526-532:⚠️ Potential issueThe
getThemeColormethod doesn't handle the 'system' theme.The union type
Theme = 'light' | 'dark' | 'system'(defined in the spreadsheet file) implies three distinct modes, but 'system' is not properly handled in this method.This issue was previously flagged in a review comment but hasn't been addressed. Consider implementing OS preference detection when 'system' is specified:
public getThemeColor(key: keyof typeof LightTheme): string { if (this.theme === 'light') { return LightTheme[key]; } + if (this.theme === 'system') { + const prefersDark = window.matchMedia?.('(prefers-color-scheme: dark)').matches; + return (prefersDark ? DarkTheme : LightTheme)[key]; + } return DarkTheme[key]; }
🧹 Nitpick comments (1)
packages/sheet/src/formula/formula.ts (1)
74-97: Enhanced token coverage with string gap filling.The addition of STRING tokens to fill gaps between recognized tokens ensures complete coverage of the formula string, which is crucial for accurate syntax highlighting in the UI.
However, the text extraction logic could benefit from a clarifying comment:
text: formula.slice(currToken.stop + 2, token.start + 1), + // +2 accounts for the '=' prefix and 0-based indexingSimilarly for line 95:
text: formula.slice(currToken.stop + 2), + // +2 accounts for the '=' prefix and 0-based indexing
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
packages/frontend/public/icon.svgis excluded by!**/*.svg
📒 Files selected for processing (12)
packages/backend/src/documents/document.service.ts(1 hunks)packages/frontend/index.html(1 hunks)packages/frontend/src/app/documents/document-detail.tsx(1 hunks)packages/frontend/src/app/login/page.tsx(1 hunks)packages/frontend/src/components/app-sidebar.tsx(1 hunks)packages/frontend/src/components/nav-user.tsx(1 hunks)packages/frontend/src/components/theme-provider.tsx(1 hunks)packages/sheet/src/formula/formula.ts(1 hunks)packages/sheet/src/spreadsheet/spreadsheet.ts(2 hunks)packages/sheet/src/spreadsheet/worksheet.ts(14 hunks)packages/sheet/src/store/memory/cache.ts(0 hunks)packages/sheet/test/formula/formula.test.ts(2 hunks)
💤 Files with no reviewable changes (1)
- packages/sheet/src/store/memory/cache.ts
✅ Files skipped from review due to trivial changes (1)
- packages/frontend/src/app/login/page.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/frontend/index.html
- packages/frontend/src/components/nav-user.tsx
- packages/backend/src/documents/document.service.ts
- packages/frontend/src/app/documents/document-detail.tsx
- packages/frontend/src/components/theme-provider.tsx
- packages/frontend/src/components/app-sidebar.tsx
- packages/sheet/src/spreadsheet/spreadsheet.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/sheet/src/formula/formula.ts (2)
packages/sheet/antlr/FormulaLexer.ts (1)
FormulaLexer(16-212)packages/sheet/antlr/FormulaParser.ts (1)
formula(123-166)
packages/sheet/test/formula/formula.test.ts (1)
packages/sheet/src/formula/formula.ts (1)
extractTokens(53-100)
🔇 Additional comments (11)
packages/sheet/test/formula/formula.test.ts (2)
2-6: Good addition of imports for extensive token testing.The new import for
extractTokensaligns well with the existing pattern of testing formula functions comprehensively. This ensures that all formula-related functionality is properly tested.
67-107: Comprehensive test coverage for token extraction.The test cases for
extractTokenscover a wide range of formula types including arithmetic operations, function calls, cell references, boolean values, and partial formula inputs. These tests ensure that each token is correctly identified with the appropriate type, position, and text content.packages/sheet/src/formula/formula.ts (2)
62-64: Good optimization by filtering EOF tokens early.Early filtering of EOF tokens simplifies the downstream processing of tokens and makes the code more efficient.
67-67: Robust token type handling with fallback.Using the vocabulary to get the symbolic name with a fallback to 'STRING' for unrecognized token types is a good defensive programming practice that ensures all tokens have a valid type.
packages/sheet/src/spreadsheet/worksheet.ts (7)
2-2: Updated import for enhanced formula token extraction.Adding the
extractTokensimport supports the improved token handling for formula syntax highlighting throughout the worksheet.
22-44: Well-structured theme objects with consistent color mapping.The theme objects are well-organized with clear semantic naming for UI elements. The token coloring is properly included in the theme, allowing for consistent syntax highlighting across themes.
91-106: Robust event listener management system.The centralized event listener registry is an excellent practice that enables proper cleanup and prevents memory leaks. This approach is much more maintainable than scattered event attachment and removal.
190-200: Properly bound event handlers prevent context issues.Pre-binding event handlers in the constructor ensures that
thisreferences remain correct within handler methods, avoiding common issues with handler context.
208-212: Clean and thorough cleanup mechanism.The cleanup method properly removes all event listeners and clears the container, which is essential for preventing memory leaks when the component is unmounted.
214-229: Well-designed event listener management methods.These helper methods properly register and clean up event listeners, making the code more maintainable and less prone to leaks.
920-931: Simpler token processing for syntax highlighting.The token handling for syntax highlighting is now more straightforward, directly leveraging the enhanced
extractTokensfunction to obtain accurate token information. The code properly applies theme-based colors to the tokens, creating a consistent visual experience.
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 1
🧹 Nitpick comments (3)
.github/workflows/publish-ghpage.yml (3)
1-1: Workflow name consistency
The workflow is now named "GitHub Page Publish". Consider aligning this with other workflows or naming conventions (e.g., "Publish GitHub Pages") for consistency across the repo.
14-15: Upgrade checkout action
Switching toactions/checkout@v4is a good update. Optionally, you could addfetch-depth: 0to ensure the full Git history is available (useful for some deployment actions).
29-30: Install and build commands
You may want to enforce lockfile consistency during CI by usingpnpm install --frozen-lockfile. Example:- pnpm i + pnpm install --frozen-lockfileThis prevents unintended updates to
pnpm-lock.yaml.
🛑 Comments failed to post (1)
.github/workflows/publish-ghpage.yml (1)
36-37:
⚠️ Potential issueInvalid publish directory path
publish_diris set tofrontend/dist, but the monorepo layout usespackages/frontend/dist. The current path will fail to locate the build output.Please apply:
- publish_dir: frontend/dist + publish_dir: packages/frontend/dist📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.publish_dir: packages/frontend/dist enable_jekyll: false
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/frontend/package.json (1)
7-12: Add a type-check script
Since this is a TypeScript project, consider adding a"type-check": "tsc --noEmit"script to catch type errors in CI or pre-commit hooks."scripts": { "dev": "vite", "build": "vite build", "lint": "eslint .", + "type-check": "tsc --noEmit", "preview": "vite preview" },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.github/workflows/docker-publish.yml(1 hunks).github/workflows/publish-ghpage.yml(1 hunks)Dockerfile(1 hunks)package.json(1 hunks)packages/backend/package.json(1 hunks)packages/frontend/.env(1 hunks)packages/frontend/.env.production(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/sheet/package.json(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- package.json
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/frontend/.env.production
- packages/frontend/.env
- Dockerfile
- .github/workflows/docker-publish.yml
- packages/backend/package.json
- .github/workflows/publish-ghpage.yml
- packages/frontend/src/App.tsx
- packages/sheet/package.json
🔇 Additional comments (3)
packages/frontend/package.json (3)
1-6: Validate package metadata
Top-level fields (name,private,version,type,license) are correctly configured for a private monorepo package.
13-52: Dependencies look solid
The declared runtime dependencies (@dnd-kit,@radix-ui, React 19, Tailwind, etc.) align with the project's UI and state-management needs. Theworkspace:*reference for@wafflebase/sheetis correct.
53-62: DevDependencies are appropriate
ESLint, TypeScript types, Vite plugin, and related tooling are properly declared for development tasks.
| "typescript": "~5.8.3", | ||
| "typescript-eslint": "^8.24.1", |
There was a problem hiding this comment.
Incorrect ESLint TypeScript package
The "typescript-eslint" entry is not a valid package. Replace it with the official parser and plugin to enable proper TypeScript linting:
- "typescript-eslint": "^8.24.1",
+ "@typescript-eslint/parser": "^8.24.1",
+ "@typescript-eslint/eslint-plugin": "^8.24.1",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "typescript": "~5.8.3", | |
| "typescript-eslint": "^8.24.1", | |
| "typescript": "~5.8.3", | |
| - "typescript-eslint": "^8.24.1", | |
| + "@typescript-eslint/parser": "^8.24.1", | |
| + "@typescript-eslint/eslint-plugin": "^8.24.1", |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
packages/frontend/src/app/documents/page.tsx (1)
33-37: Consider adding an empty state handlerWhile the component renders the DocumentList correctly, it might be worth adding specific handling for when documents array is empty (beyond the default empty array).
return ( <div className="p-4"> + {documents.length === 0 ? ( + <div className="flex flex-col items-center justify-center h-64"> + <p className="text-gray-500 text-lg">No documents found.</p> + <p className="text-gray-400">Create a new document to get started.</p> + </div> + ) : ( <DocumentList data={documents} /> + )} </div> );packages/frontend/src/app/documents/document-list.tsx (3)
167-169: Enhance document creation with title inputCurrently, new documents are created with a hardcoded title "New Document". Consider providing a way for users to specify a title during creation.
You could either:
- Use a modal/dialog to prompt for the title before creation
- Create with default title but immediately put the user in "edit mode"
- Implement inline creation in the table itself
For example, a simple prompt approach:
onClick={() => { - createDocumentMutation.mutate({ title: "New Document" }); + const title = prompt("Enter document title:", "New Document"); + if (title) { + createDocumentMutation.mutate({ title }); + } }}
203-208: Improve click handler robustnessThe current approach to prevent navigation when clicking inputs or buttons uses a DOM traversal method that might be fragile if the component structure changes.
Consider a more robust approach using event targets and roles:
onClick={(e: MouseEvent<HTMLElement>) => { - if ((e.target as HTMLElement).closest("input, button")) { + const target = e.target as HTMLElement; + // Check for common interactive elements or their parents + if ( + target.tagName === "INPUT" || + target.tagName === "BUTTON" || + target.getAttribute("role") === "button" || + target.getAttribute("aria-role") === "button" || + target.closest("[role='button'], [aria-role='button']") + ) { return; } navigate(`/${row.getValue("id")}`); }}
74-76: Consider proper title case formattingThe
capitalizeclass only capitalizes the first letter of the entire string. For proper title case with multiple words, consider a JavaScript function.cell: ({ row }) => ( - <div className="capitalize">{row.getValue("title")}</div> + <div> + {String(row.getValue("title")) + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' ')} + </div> )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
package.json(1 hunks)packages/frontend/package.json(1 hunks)packages/frontend/src/App.tsx(1 hunks)packages/frontend/src/app/documents/document-detail.tsx(1 hunks)packages/frontend/src/app/documents/document-list.tsx(1 hunks)packages/frontend/src/app/documents/page.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/frontend/src/app/documents/document-detail.tsx
- packages/frontend/src/App.tsx
- package.json
- packages/frontend/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/frontend/src/app/documents/document-list.tsx (7)
packages/frontend/src/types/documents.ts (1)
Document(1-7)packages/frontend/src/components/ui/checkbox.tsx (1)
Checkbox(30-30)packages/frontend/src/components/ui/dropdown-menu.tsx (4)
DropdownMenu(242-242)DropdownMenuTrigger(244-244)DropdownMenuContent(245-245)DropdownMenuLabel(247-247)packages/frontend/src/components/ui/button.tsx (1)
Button(62-62)packages/frontend/src/api/documents.ts (2)
createDocument(5-22)deleteDocument(48-62)packages/frontend/src/components/ui/input.tsx (1)
Input(21-21)packages/frontend/src/components/ui/table.tsx (6)
Table(108-108)TableHeader(109-109)TableRow(113-113)TableHead(112-112)TableBody(110-110)TableCell(114-114)
🔇 Additional comments (5)
packages/frontend/src/app/documents/page.tsx (2)
1-14: Data fetching implementation looks goodThe React Query setup for fetching documents is well implemented with appropriate query key and function. The component properly handles the query state with type safety.
16-31: Loading and error states are well handledGood user experience with clear loading and error states. The Tailwind classes create a well-centered and visually appropriate UI for these states.
packages/frontend/src/app/documents/document-list.tsx (3)
43-117: Well-structured table columns with appropriate formattingThe column definitions are well organized with appropriate accessors, headers, and cell renderers. The date formatting using
formatDistanceToNowprovides a good user experience with relative timestamps.
136-153: Excellent table configuration with complete state managementThe table setup with sorting, filtering, pagination, and row selection is well implemented. All necessary models and state bindings are properly configured.
155-256: Comprehensive UI with good user experience featuresThe UI implementation includes a search filter, action buttons, clear table structure, and pagination controls with row selection status. These elements combine to create an excellent user experience.
| const createDocumentMutation = useMutation({ | ||
| mutationFn: async (data: { title: string }) => await createDocument(data), | ||
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | ||
| }); | ||
|
|
||
| const deleteDocumentMutation = useMutation({ | ||
| mutationFn: async (id: string) => await deleteDocument(id), | ||
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | ||
| }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling to mutations
Both create and delete mutations lack explicit error handling, which could lead to silent failures from the user's perspective.
Add error callbacks to handle failures gracefully:
const createDocumentMutation = useMutation({
mutationFn: async (data: { title: string }) => await createDocument(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+ onError: (error) => {
+ console.error("Failed to create document:", error);
+ // Consider adding a toast notification here
+ },
});
const deleteDocumentMutation = useMutation({
mutationFn: async (id: string) => await deleteDocument(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }),
+ onError: (error) => {
+ console.error("Failed to delete document:", error);
+ // Consider adding a toast notification here
+ },
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const createDocumentMutation = useMutation({ | |
| mutationFn: async (data: { title: string }) => await createDocument(data), | |
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | |
| }); | |
| const deleteDocumentMutation = useMutation({ | |
| mutationFn: async (id: string) => await deleteDocument(id), | |
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | |
| }); | |
| const createDocumentMutation = useMutation({ | |
| mutationFn: async (data: { title: string }) => await createDocument(data), | |
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | |
| onError: (error) => { | |
| console.error("Failed to create document:", error); | |
| // Consider adding a toast notification here | |
| }, | |
| }); | |
| const deleteDocumentMutation = useMutation({ | |
| mutationFn: async (id: string) => await deleteDocument(id), | |
| onSuccess: () => queryClient.invalidateQueries({ queryKey: ["documents"] }), | |
| onError: (error) => { | |
| console.error("Failed to delete document:", error); | |
| // Consider adding a toast notification here | |
| }, | |
| }); |
| className="cursor-pointer text-red-500" | ||
| onClick={(e: MouseEvent<HTMLElement>) => { | ||
| e.stopPropagation(); | ||
| deleteDocumentMutation.mutate(String(row.getValue("id"))); | ||
| }} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add confirmation before deleting documents
Currently, documents are deleted immediately upon clicking the "Delete" option without any confirmation. This could lead to accidental data loss.
Consider adding a confirmation dialog before proceeding with deletion:
<DropdownMenuLabel
className="cursor-pointer text-red-500"
onClick={(e: MouseEvent<HTMLElement>) => {
e.stopPropagation();
- deleteDocumentMutation.mutate(String(row.getValue("id")));
+ if (window.confirm("Are you sure you want to delete this document?")) {
+ deleteDocumentMutation.mutate(String(row.getValue("id")));
+ }
}}
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className="cursor-pointer text-red-500" | |
| onClick={(e: MouseEvent<HTMLElement>) => { | |
| e.stopPropagation(); | |
| deleteDocumentMutation.mutate(String(row.getValue("id"))); | |
| }} | |
| <DropdownMenuLabel | |
| className="cursor-pointer text-red-500" | |
| onClick={(e: MouseEvent<HTMLElement>) => { | |
| e.stopPropagation(); | |
| if (window.confirm("Are you sure you want to delete this document?")) { | |
| deleteDocumentMutation.mutate(String(row.getValue("id"))); | |
| } | |
| }} | |
| > | |
| Delete | |
| </DropdownMenuLabel> |
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
Established monorepo with pnpm workspace, configured NestJS for backend, and ShadCN/React for frontend. Implemented GitHub-based user authentication and document management API, along with frontend pages for login, document list, detail, and settings. Added reusable UI components (sidebar, buttons, tables, etc.) and spreadsheet setup with light/dark theme support. Replaced DuckDB with Yorkie storage, improved theme-aware styling and event handling, and reduced max row count for better performance. Refined formula parsing logic.
What this PR does / why we need it?
Add spreadsheet UI, frontend and backend with monorepo setup
Established monorepo with pnpm workspace, configured
ESLint/Prettier/NestJS for backend, and Vite/TypeScript for frontend.
Implemented GitHub-based user authentication and document management
API, along with frontend pages for login, document list, detail, and
settings.
Added reusable UI components (sidebar, buttons, tables, etc.) and
spreadsheet setup with light/dark theme support.
Replaced DuckDB with in-memory storage, improved theme-aware styling
and event handling, and reduced max row count for better performance.
Refined formula parsing logic.
Any background context you want to provide?
What are the relevant tickets?
Fixes #
Checklist
Summary by CodeRabbit
New Features
Bug Fixes
Chores
.gitignorefiles for project directories.Documentation
Tests