-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: logger, chore: extension bump, chore: extension bump, feat: react-day-picker, chore: migration, fix: calendar, fix: ProjectTimeOnPeriod , chore: checkbox, chore: zod,chore: web and feat: auth #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- replaced all the raw `console.{log, dir, error},` by custom logger functions with prefix to easily identify MoonCode logs in the console
- bumped the version of the extension to `0.0.22` - removed the unnecessary `parseInt` calls in the `DayLanguagesChart` and `ProjectLanguagesTimeOnPeriod` components
- fixed the zod version in the dashboard and vscode extension - replaced default zod import in favor of single exports
- updated react-day-picker to v9
- migrated to react 19 and to tailwindcss v4
- fixed the calendar with the proper styles - added `.prettierrc` in the ui package to get the tailwind prettier plugin, also installed the plugin in the package
- fixed the issue of the chart not properly displaying after the migration to tailwind v4 and react 19
- increased the size of the check icon in the checkbox component - removed some smaller dependencies from the rollup chunks
- updated zod to v4.0.17
- migrated the web app to tailwindcss v4
WalkthroughRemoved legacy-peer-deps from .npmrc; bumped and realigned dependencies (React 19, zod ^4.0.17, Tailwind/tooling); migrated PostCSS/Tailwind configs and Vite plugins (svgr, @tailwindcss/vite); large UI refactors (many forwardRef → plain components, data-slot, tokenized CSS); moved/added dashboard auth pages; added VSCode extension logger and replaced console usage. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ProjectTimeOnPeriodChart
participant Recharts
participant Tooltip
User->>ProjectTimeOnPeriodChart: open/view chart
ProjectTimeOnPeriodChart->>ProjectTimeOnPeriodChart: check isBarChartVisible
alt isBarChartVisible == true
ProjectTimeOnPeriodChart->>Recharts: render ComposedChart (Bar + Line)
else
ProjectTimeOnPeriodChart->>Recharts: render AreaChart
end
Recharts->>Tooltip: request tooltip content/format
Tooltip-->>User: render tooltip with numeric value and originalDate
sequenceDiagram
participant VSCodeExt
participant Logger
participant Console
VSCodeExt->>Logger: logInfo/logError/logDir(...)
Logger->>Console: console.log / console.error / console.dir (prefixed with [MoonCode])
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Friedrich482
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes reviewed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 33
🔭 Outside diff range comments (12)
apps/vscode-extension/src/types-schemas.ts (2)
17-22: Replace non-standardz.iso.datetime()with a supported Zod v4 approach.
z.iso.datetime()isn’t part of Zod’s public API. Usez.coerce.date()to accept Date or ISO string and produce a Date, simplifying the union and transform.Apply:
-export const globalStateInitialDataSchema = z.object({ - lastServerSync: z.union([ - z.date(), - z.iso.datetime().transform((str) => new Date(str)), - ]), +export const globalStateInitialDataSchema = z.object({ + lastServerSync: z.coerce.date(),
39-43: Same issue here: preferz.coerce.date()for updatedAt.Aligns with Zod v4 and removes reliance on a non-existent
z.iso.datetime().Apply:
- updatedAt: z.union([ - z.date(), - z.iso.datetime().transform((str) => new Date(str)), - ]), + updatedAt: z.coerce.date(),apps/dashboard/src/components/dashboard-page/charts/dayLanguagesChart/DayLanguagesChart.tsx (1)
100-109: Incorrect prop on ; use Bar.minPointSize instead of Cell.min.Recharts’ Cell doesn’t support “min”. If you want a minimum visible bar size, set it on Bar via minPointSize and remove min from Cell.
Apply this diff:
- <Bar dataKey="timeSpent" layout="vertical" radius={5}> + <Bar dataKey="timeSpent" layout="vertical" radius={5} minPointSize={2}> {chartData.map((entry) => ( <Cell fill={entry.color} - min={0} key={entry.languageSlug} className="cursor-pointer" /> ))} </Bar>apps/dashboard/src/components/project-page/charts/ProjectLanguagesTimeOnPeriodChart.tsx (1)
111-134: Remove parseInt and type the formatter value as number for BarChart.This still parses a value that Recharts already provides as a number. Align with the PieChart and other charts by typing the arg as number and passing it through.
Apply this diff:
- formatter={(value: string, languageSlug) => - CustomChartToolTip( - parseInt(value), - getLanguageColor(languageSlug), - languageSlug, - ) - } + formatter={(value: number, languageSlug) => + CustomChartToolTip( + value, + getLanguageColor(languageSlug), + languageSlug, + ) + }apps/dashboard/src/components/dashboard-page/charts/PeriodTimeChart.tsx (1)
67-71: Drop parseInt and type the value as number in the tooltip formatter.Recharts provides numeric values for numeric dataKeys. Avoid coercion and keep types explicit.
Apply this diff:
- formatter={(value, name) => - name === "Time" - ? CustomChartToolTip(parseInt(value), "var(--color-time)") - : null - } + formatter={(value: number, name) => + name === "Time" + ? CustomChartToolTip(value, "var(--color-time)") + : null + }packages/ui/package.json (1)
5-13: Remove stale export "./tailwind.config" from packages/ui/package.jsonThe package exports "./tailwind.config": "./tailwind.config.ts", but there is no tailwind.config.ts file in the repo and no imports of @repo/ui/tailwind.config were found — remove the broken subpath export.
- packages/ui/package.json — remove the "./tailwind.config" export entry
"exports": { "./globals.css": "./src/globals.css", "./postcss.config": "./postcss.config.mjs", - "./tailwind.config": "./tailwind.config.ts", "./lib/*": "./src/lib/*.ts", "./components/*": "./src/components/*.tsx", "./index": "./src/index.ts", "./utils/*": "./src/utils/*.ts" },apps/vscode-extension/src/utils/auth/parseJwtPayload.ts (1)
3-12: Fix Zod type + JWT base64url parsing in parseJwtPayload.tsZod v4 does not export ZodSafeParseResult — use ReturnType (or z.SafeParseReturnType) and validate/decode JWT payload as base64url.
Files to update:
- apps/vscode-extension/src/utils/auth/parseJwtPayload.ts
Apply this diff:
-import { JWTDto } from "@repo/common/schemas"; -import { JwtPayloadType } from "@/types-schemas"; -import { ZodSafeParseResult } from "zod"; +import { JWTDto } from "@repo/common/schemas"; +import { JwtPayloadType } from "@/types-schemas"; @@ -const parseJwtPayload = ( - token: string | undefined, -): - | ZodSafeParseResult<JwtPayloadType> - | { - success: false; - error: unknown; - } => { +const parseJwtPayload = ( + token: string | undefined, +): | ReturnType<typeof JWTDto.safeParse> | { success: false; error: unknown } => { try { - if (!token || typeof token !== "string" || !token.includes(".")) { - return { success: false, error: new Error("Invalid token format") }; - } - const base64Payload = token.split(".")[1]; - const decodedPayload = Buffer.from(base64Payload, "base64").toString( - "utf8", - ); - const jsonPayload = JSON.parse(decodedPayload); - - return JWTDto.safeParse(jsonPayload); + if (!token || typeof token !== "string") { + return { success: false, error: new Error("Invalid token format") }; + } + const parts = token.split("."); + if (parts.length !== 3) { + return { success: false, error: new Error("Invalid token format") }; + } + // JWT payloads use base64url (RFC 7515) — convert to standard base64 + const base64UrlPayload = parts[1]; + const base64Payload = base64UrlPayload.replace(/-/g, "+").replace(/_/g, "/"); + const padded = base64Payload.padEnd(Math.ceil(base64Payload.length / 4) * 4, "="); + const decodedPayload = Buffer.from(padded, "base64").toString("utf8"); + const jsonPayload = JSON.parse(decodedPayload); + return JWTDto.safeParse(jsonPayload); } catch (error) { return { success: false, error }; } };apps/dashboard/src/components/project-page/charts/CircularPacking.tsx (1)
16-20: Guard against SSR: avoid directwindowaccess in initial stateAccessing
windowin useState initializers will throw during server-side rendering. Use lazy initializers withtypeof windowguards and perform the initial measurement insideuseEffect.Files/locations to fix:
- apps/dashboard/src/components/project-page/charts/CircularPacking.tsx — lines 16-20
- Also apply the same pattern to any other useState that reads
window(e.g. lines 35-41)Suggested change:
- const [width, setWidth] = useState( - parentDivRef.current?.clientWidth ?? (window.innerWidth * 5) / 6, - ); - const [height, setHeight] = useState((window.innerWidth * 2) / 3); + const getDefaultWidth = () => + typeof window === "undefined" + ? 0 + : parentDivRef.current?.clientWidth ?? (window.innerWidth * 5) / 6; + const getDefaultHeight = () => + typeof window === "undefined" ? 0 : (window.innerWidth * 2) / 3; + const [width, setWidth] = useState(getDefaultWidth); + const [height, setHeight] = useState(getDefaultHeight); @@ - useEffect(() => { - window.addEventListener("resize", handleWindowResize); - - return () => { - window.removeEventListener("resize", handleWindowResize); - }; - }, []); + useEffect(() => { + if (typeof window === "undefined") return; + // initial measurement on mount + handleWindowResize(); + window.addEventListener("resize", handleWindowResize); + return () => { + window.removeEventListener("resize", handleWindowResize); + }; + }, []);packages/ui/src/components/ui/form.tsx (3)
45-66: Bug: useFormField reads context before asserting presence; fix nullability and guard checks
useFormFieldaccessesfieldContext.namebefore verifying the provider is present, andFormItemContextis also assumed. This can cause runtime issues when misused. Make both contexts nullable and guard before use.-const useFormField = () => { - const fieldContext = React.useContext(FormFieldContext); - const itemContext = React.useContext(FormItemContext); - const { getFieldState } = useFormContext(); - const formState = useFormState({ name: fieldContext.name }); - const fieldState = getFieldState(fieldContext.name, formState); - - if (!fieldContext) { - throw new Error("useFormField should be used within <FormField>"); - } - - const { id } = itemContext; +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext); + const itemContext = React.useContext(FormItemContext); + const { getFieldState } = useFormContext(); + + if (!fieldContext?.name) { + throw new Error("useFormField should be used within <FormField>"); + } + if (!itemContext?.id) { + throw new Error("useFormField should be used within <FormItem>"); + } + + const formState = useFormState({ name: fieldContext.name }); + const fieldState = getFieldState(fieldContext.name, formState); + + const { id } = itemContext; return { id, name: fieldContext.name, formItemId: `${id}-form-item`, formDescriptionId: `${id}-form-item-description`, formMessageId: `${id}-form-item-message`, ...fieldState, }; };
28-31: Make FormFieldContext nullable to force correct guardingInitialize the context with null instead of a casted empty object to avoid false confidence and ensure proper runtime checks.
-const FormFieldContext = React.createContext<FormFieldContextValue>( - {} as FormFieldContextValue, -); +const FormFieldContext = React.createContext<FormFieldContextValue | null>(null);
72-74: Make FormItemContext nullable and guard itSame rationale as FormFieldContext — prevents accidental usage without a provider.
-const FormItemContext = React.createContext<FormItemContextValue>( - {} as FormItemContextValue, -); +const FormItemContext = React.createContext<FormItemContextValue | null>(null);apps/dashboard/src/components/dashboard-page/PeriodDropDown.tsx (1)
57-68: Effect missesperiodin deps; can skip updates when toggling “Custom Range”.The effect only runs on
start/endchanges. If a user switches to “Custom Range” after start/end are already set, the effect won’t run, andsetCustomRangewon’t be called. Includeperiod(and optionallysetCustomRange) in deps to avoid stale reads.Apply this diff:
- useEffect(() => { + useEffect(() => { if (period === "Custom Range") { if (start && end) { const periodResolution = getPeriodResolution(start, end); setCustomRange({ start, end, periodResolution, }); } } - }, [start, end]); + }, [start, end, period, setCustomRange]);
🧹 Nitpick comments (22)
packages/ui/src/components/ui/tooltip.tsx (1)
8-19: Confirm intent: defaultdelayDuration={0}on ProviderSetting delay to zero makes tooltips show immediately. If this wasn’t intentional, consider restoring a small delay (e.g., 200–400ms) for UX polish.
apps/vscode-extension/package.json (1)
134-134: Pinning date-fns to an exact version: confirm intent.Locking to 4.1.0 avoids accidental bundle changes for the extension but also prevents patch updates. If reproducibility is the goal, consider keeping it pinned and relying on lockfiles; otherwise, prefer a caret.
If you want to re-allow patch updates:
- "date-fns": "4.1.0", + "date-fns": "^4.1.0",apps/dashboard/src/components/layout/Layout.tsx (1)
10-10: Confirm CSS token: var(--primary) vs var(--color-primary)There’s an apparent mix of token schemes across the repo (e.g., var(--color-primary) and var(--primary)). Please confirm which is canonical post-migration and align accordingly to avoid silent theming regressions.
If the canonical token is --color-primary, apply this diff:
- <ClipLoader size={80} color="var(--primary)" /> + <ClipLoader size={80} color="var(--color-primary)" />apps/web/postcss.config.mjs (1)
1-7: PostCSS config diverges from UI package; consider re-export or align options (e.g.,base)The UI package’s PostCSS config passes a
baseoption to@tailwindcss/postcss(see packages/ui/postcss.config.mjs). This local copy omits it, which can cause styling/token resolution to drift between apps and the UI package.Two options:
- Re-export UI config to avoid config drift (preferred if no app-specific overrides are needed).
- Replicate the same options (ensure parity, including
base, if required by your setup).Apply either of the following diffs.
Option A — restore re-export:
-const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; +export { default } from "@repo/ui/postcss.config";Option B — replicate UI config (parity):
+import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + const config = { plugins: { - "@tailwindcss/postcss": {}, + "@tailwindcss/postcss": { + // keep this in sync with packages/ui/postcss.config.mjs unless the web app + // intentionally needs a different base + base: join(__dirname, "../../"), + }, }, }; export default config;apps/dashboard/src/components/project-page/charts/CircularPacking.tsx (1)
14-15: Ref type should beReact.RefObject<HTMLDivElement>(notHTMLDivElement | null)
RefObject<T>already exposescurrent: T | null. UsingRefObject<HTMLDivElement | null>redundantly nestsnullinto the generic, complicating types.Apply this diff:
- parentDivRef: React.RefObject<HTMLDivElement | null>; + parentDivRef: React.RefObject<HTMLDivElement>;apps/vscode-extension/src/utils/logger/logger.ts (2)
7-10: Use safer inspect depth and avoid any in logger APIInfinity can be heavy/ambiguous for util.inspect. null means “unlimited” and is the recommended way. Also prefer unknown over any for stronger typing.
-export const logDir = (data: any) => { +export const logDir = (data: unknown) => { console.log(`${LOG_PREFIX} Data:`); - console.dir(data, { depth: Infinity }); + console.dir(data, { depth: null }); };
3-5: Consider using a VS Code OutputChannel instead of console for better UX and discoverabilityConsole logs are easy to miss in extensions. OutputChannel provides a dedicated “MoonCode” output pane for users and support diagnostics.
Example approach (alternative to console-based logger):
import * as vscode from "vscode"; // Optionally: import { inspect } from "node:util"; const channel = vscode.window.createOutputChannel("MoonCode"); const LOG_PREFIX = "[MoonCode]"; export const logInfo = (message: string) => { channel.appendLine(`${LOG_PREFIX} INFO: ${message}`); }; export const logDir = (data: unknown) => { channel.appendLine(`${LOG_PREFIX} Data:`); channel.appendLine(String(data)); // or inspect(data, { depth: null }) }; export const logError = (err: unknown, context?: string) => { const base = context ? `${LOG_PREFIX} ERROR: ${context}:` : `${LOG_PREFIX} ERROR:`; if (err instanceof Error) { channel.appendLine(`${base} ${err.message}`); if (err.stack) channel.appendLine(err.stack); const cause = (err as any).cause; if (cause) channel.appendLine(`${LOG_PREFIX} ERROR: cause -> ${String(cause)}`); } else { channel.appendLine(`${base} ${String(err)}`); } };Also applies to: 12-14
apps/vscode-extension/src/utils/dashboard/serveDashboard.ts (1)
31-31: Include protocol and colon in the startup log messageSlight polish that also makes it clickable in many terminals.
- logInfo(`Dashboard server started on localhost ${availablePort}`); + logInfo(`Dashboard server started on http://localhost:${availablePort}`);apps/vscode-extension/src/utils/periodicSyncData.ts (2)
137-139: Log the actual Error object to preserve stack/cause; avoid manual stringifying of causePassing the Error directly (with optional context) yields better diagnostics and avoids “[object Object]” for complex causes. This pairs with the proposed logError signature.
- logError( - `tRPC Error during sync: ${error.message}, Cause: ${error.cause}.`, - ); + logError(error, "tRPC Error during sync");
141-144: Also log unknown errors for diagnostics (while keeping user-facing warning)This ensures we don’t silently drop useful debugging info in non-TRPC errors.
- vscode.window.showWarningMessage( - `Unknown error during server sync: ${error}.`, - ); + logError(error, "Unknown error during server sync"); + vscode.window.showWarningMessage( + `Unknown error during server sync: ${String(error)}.`, + );apps/vscode-extension/src/utils/time/calculateTime.ts (2)
30-30: Pass the error object to the logger for richer diagnosticsAvoid interpolating the unknown error directly. This leverages the logger to include message/stack/cause and prevents “[object Object]”.
- logError(`Error in periodic check:${error}`); + logError(error, "Error in periodic check");
19-33: Consider throttling repeated error logs in a 1s loopIf a persistent error occurs, this path logs every second. Add a simple throttle/backoff to reduce noise.
I can propose a small helper (e.g., lastLoggedAt and minimum interval) if you want to proceed.
apps/vscode-extension/src/utils/commands/initExtensionCommands.ts (1)
76-76: Nit: keep the “from server” label for clarity.If the data is indeed the initial snapshot synced from the backend, keeping that context helps during support/debugging.
Apply this minimal tweak:
- logInfo(`InitialFilesData:\n${formattedData}`); + logInfo(`InitialFilesData (server):\n${formattedData}`);apps/dashboard/vite.config.ts (1)
6-6: Tailwind v4 Vite plugin integration — looks right.
@tailwindcss/viteis correctly imported and added toplugins.- Remaining Rollup
manualChunkskeep your large deps split.Optional: ensure
@tailwindcss/viteis marked as a dev dependency in package.json since it’s only used at build time.Also applies to: 11-11
apps/dashboard/package.json (1)
18-18: Move @tailwindcss/vite to devDependencies.The Vite Tailwind plugin is a build-time tool and shouldn’t ship with the runtime bundle. Keep it in
devDependenciesto reduce install footprint.Proposed change:
"dependencies": { "@fontsource-variable/inter": "^5.1.1", "@hookform/resolvers": "^5.0.1", "@repo/common": "*", "@repo/trpc": "*", "@repo/ui": "*", - "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.74.3", ... }, "devDependencies": { + "@tailwindcss/vite": "^4.1.11", "@eslint/js": "^9.17.0", ... "prettier-plugin-tailwindcss": "^0.6.14", "rollup-plugin-visualizer": "^6.0.3", "tailwindcss": "^4.1.11", ... }Also applies to: 54-54
apps/dashboard/src/index.css (1)
10-19: Consider centralizing breakpoint tokens to avoid drift across apps/packagesI searched the repo for other --breakpoint-* definitions and @theme breakpoint blocks but found no matches, so I cannot confirm a shared source of truth. Prefer a single shared file (e.g., packages/ui/src/globals.css) and keep only app-specific extras locally (like --breakpoint-chart).
Files/actions to verify:
- apps/dashboard/src/index.css — current breakpoint tokens (lines 10–19)
- Check packages/ui (e.g., packages/ui/src/globals.css) and other apps/packages for duplicate --breakpoint-* tokens and consolidate if found
- If no shared file exists, add one and move shared tokens there; leave per-app overrides local
packages/ui/src/components/ui/Icon.tsx (1)
6-23: Optional: consider keeping ref forwarding if consumers attach refs to this buttonLess critical than Input, but if toolbars/menus focus this programmatically, dropping ref support might break UX/tests.
Do you want a patch to reintroduce forwardRef while keeping the same API?
apps/web/src/app/globals.css (1)
1-1: Prefer package-level import over deep relative pathsThe deep relative path is brittle. If possible, re-export
globals.cssfrom the UI package and import it via the package name (or a workspace alias). This improves maintainability and bundler friendliness.Example:
- In
packages/ui/package.json, add an export:"./globals.css": "./src/globals.css"- Then here:
@import "@mooncode/ui/globals.css";(or your actual package name/alias)packages/ui/src/components/ui/chart.tsx (1)
281-286: Stabilize legend item keysUsing
item.valuealone can clash. Prefer a composite key or fallback todataKey.- <div - key={item.value} + <div + key={String(item.dataKey ?? item.value)}apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx (3)
55-60: Make the chart type toggle accessible.Clickable icons without button semantics aren’t keyboard-accessible and lack an accessible name. Wrap in a semantic button (or add role, tabIndex, key handlers, and aria-label).
Apply this diff:
- <Icon - Icon={isBarChartVisible ? AreaChartIcon : BarChartIcon} - className="absolute -top-12 right-0 z-0" - onClick={handleClick} - /> + <button + type="button" + aria-label={isBarChartVisible ? "Switch to area chart" : "Switch to bar chart"} + className="absolute -top-12 right-0 z-0" + onClick={handleClick} + > + <Icon Icon={isBarChartVisible ? AreaChartIcon : BarChartIcon} /> + </button>
74-95: Tooltip labelFormatter: guard with a better fallback and avoid brittle payload access.Accessing
payload[0].payloadassumes at least one series and a stable ordering. Safer to fall back to_dateiforiginalDateis absent.Apply this diff:
- labelFormatter={( + labelFormatter={( _date: string, payload: Payload<string, string>[], ) => { if (payload.length === 0) return null; const { payload: innerPayload, }: { payload?: (typeof chartData)[number] } = payload[0]; - if (!innerPayload) return null; - - return <div>{innerPayload.originalDate}</div>; + const label = innerPayload?.originalDate ?? _date; + return <div>{label}</div>; }} - formatter={(value, name) => - name === "Time" - ? CustomChartToolTip(parseInt(value), "var(--color-time)") - : null - } + formatter={(value, name) => + name === "Time" + ? CustomChartToolTip(Number(value), "var(--color-time)") + : null + }
66-74: DRY opportunity: extract shared XAxis + tooltip config to a tiny helper.You already note not extracting ChartTooltip into its own component due to Recharts limitations. Still, you can extract the labelFormatter and formatter functions into constants within the component scope to avoid duplication between branches, improving maintainability.
If desirable, I can propose a concise refactor that keeps everything within this module and avoids the component-extraction pitfall.
Also applies to: 113-121
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (55)
.npmrc(0 hunks)apps/api/package.json(1 hunks)apps/dashboard/package.json(3 hunks)apps/dashboard/postcss.config.mjs(0 hunks)apps/dashboard/src/components/CustomChartToolTip.tsx(1 hunks)apps/dashboard/src/components/dashboard-page/PeriodDropDown.tsx(2 hunks)apps/dashboard/src/components/dashboard-page/charts/GeneralStatsChart.tsx(2 hunks)apps/dashboard/src/components/dashboard-page/charts/PeriodTimeChart.tsx(3 hunks)apps/dashboard/src/components/dashboard-page/charts/dayLanguagesChart/DayLanguagesChart.tsx(1 hunks)apps/dashboard/src/components/layout/Layout.tsx(1 hunks)apps/dashboard/src/components/project-page/Project.tsx(3 hunks)apps/dashboard/src/components/project-page/charts/CircularPacking.tsx(2 hunks)apps/dashboard/src/components/project-page/charts/ProjectLanguagesTimeOnPeriodChart.tsx(2 hunks)apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx(2 hunks)apps/dashboard/src/constants.ts(1 hunks)apps/dashboard/src/index.css(1 hunks)apps/dashboard/tailwind.config.ts(0 hunks)apps/dashboard/vite.config.ts(1 hunks)apps/vscode-extension/README.md(1 hunks)apps/vscode-extension/package.json(2 hunks)apps/vscode-extension/src/extension.ts(2 hunks)apps/vscode-extension/src/types-schemas.ts(1 hunks)apps/vscode-extension/src/utils/auth/parseJwtPayload.ts(1 hunks)apps/vscode-extension/src/utils/commands/initExtensionCommands.ts(5 hunks)apps/vscode-extension/src/utils/dashboard/serveDashboard.ts(2 hunks)apps/vscode-extension/src/utils/logger/logger.ts(1 hunks)apps/vscode-extension/src/utils/periodicSyncData.ts(2 hunks)apps/vscode-extension/src/utils/time/calculateTime.ts(2 hunks)apps/web/package.json(1 hunks)apps/web/postcss.config.mjs(1 hunks)apps/web/src/app/globals.css(1 hunks)apps/web/tailwind.config.ts(0 hunks)packages/common/package.json(1 hunks)packages/common/src/types.ts(1 hunks)packages/ui/.prettierrc(1 hunks)packages/ui/components.json(1 hunks)packages/ui/package.json(1 hunks)packages/ui/postcss.config.mjs(1 hunks)packages/ui/src/components/ui/CalendarPopover.tsx(1 hunks)packages/ui/src/components/ui/Icon.tsx(1 hunks)packages/ui/src/components/ui/button-variants.ts(0 hunks)packages/ui/src/components/ui/button.tsx(1 hunks)packages/ui/src/components/ui/calendar.tsx(1 hunks)packages/ui/src/components/ui/card.tsx(1 hunks)packages/ui/src/components/ui/chart.tsx(3 hunks)packages/ui/src/components/ui/checkbox.tsx(2 hunks)packages/ui/src/components/ui/dropdown-menu.tsx(1 hunks)packages/ui/src/components/ui/form.tsx(3 hunks)packages/ui/src/components/ui/input.tsx(1 hunks)packages/ui/src/components/ui/label.tsx(1 hunks)packages/ui/src/components/ui/popover.tsx(1 hunks)packages/ui/src/components/ui/tooltip.tsx(1 hunks)packages/ui/src/globals.css(2 hunks)packages/ui/src/index.ts(0 hunks)packages/ui/tailwind.config.ts(0 hunks)
💤 Files with no reviewable changes (7)
- packages/ui/src/components/ui/button-variants.ts
- apps/dashboard/postcss.config.mjs
- .npmrc
- apps/dashboard/tailwind.config.ts
- packages/ui/src/index.ts
- apps/web/tailwind.config.ts
- packages/ui/tailwind.config.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-06T20:22:58.925Z
Learnt from: Friedrich482
PR: Friedrich482/mooncode#85
File: apps/api/src/filters/errorFormatter.ts:1-1
Timestamp: 2025-08-06T20:22:58.925Z
Learning: In Zod v4, the $ZodIssue types are officially available at the import path "zod/v4/core/errors.cjs" as part of the new module structure. This is the correct way to import these types in v4, not an internal or fragile import path.
Applied to files:
apps/vscode-extension/src/types-schemas.tspackages/common/src/types.ts
📚 Learning: 2025-08-06T23:16:51.944Z
Learnt from: Friedrich482
PR: Friedrich482/mooncode#86
File: apps/api/src/common/dto.ts:13-16
Timestamp: 2025-08-06T23:16:51.944Z
Learning: In Zod v4, using shape spreading syntax (e.g., `z.object({...BaseSchema.shape, newField: z.string()})`) is recommended over the `.extend()` method for optimizing TypeScript compiler performance. This represents a change in best practices from earlier Zod versions.
Applied to files:
apps/vscode-extension/src/types-schemas.ts
🧬 Code Graph Analysis (20)
apps/vscode-extension/src/utils/dashboard/serveDashboard.ts (1)
apps/vscode-extension/src/utils/logger/logger.ts (1)
logInfo(3-5)
apps/vscode-extension/src/extension.ts (1)
apps/vscode-extension/src/utils/logger/logger.ts (1)
logInfo(3-5)
apps/vscode-extension/src/utils/periodicSyncData.ts (1)
apps/vscode-extension/src/utils/logger/logger.ts (1)
logError(12-14)
apps/web/postcss.config.mjs (1)
packages/ui/postcss.config.mjs (1)
config(3-9)
apps/vscode-extension/src/utils/time/calculateTime.ts (1)
apps/vscode-extension/src/utils/logger/logger.ts (1)
logError(12-14)
packages/ui/postcss.config.mjs (1)
apps/web/postcss.config.mjs (1)
config(1-5)
packages/ui/src/components/ui/input.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
apps/vscode-extension/src/utils/commands/initExtensionCommands.ts (1)
apps/vscode-extension/src/utils/logger/logger.ts (2)
logInfo(3-5)logDir(7-10)
apps/vscode-extension/src/utils/auth/parseJwtPayload.ts (1)
apps/vscode-extension/src/types-schemas.ts (1)
JwtPayloadType(49-49)
packages/ui/src/components/ui/Icon.tsx (2)
packages/ui/src/components/ui/button.tsx (1)
Button(58-58)packages/ui/src/lib/utils.ts (1)
cn(4-6)
apps/dashboard/src/components/dashboard-page/PeriodDropDown.tsx (1)
packages/ui/src/components/ui/button.tsx (1)
Button(58-58)
packages/ui/src/components/ui/popover.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/label.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/card.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/button.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/tooltip.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/form.tsx (2)
packages/ui/src/lib/utils.ts (1)
cn(4-6)packages/ui/src/components/ui/label.tsx (1)
Label(24-24)
packages/ui/src/components/ui/calendar.tsx (2)
packages/ui/src/lib/utils.ts (1)
cn(4-6)packages/ui/src/components/ui/button.tsx (1)
buttonVariants(58-58)
packages/ui/src/components/ui/chart.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
packages/ui/src/components/ui/dropdown-menu.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
🔇 Additional comments (60)
packages/ui/src/components/ui/checkbox.tsx (1)
4-4: LGTM on import placement and usage.Importing the Radix checkbox primitive directly and keeping it adjacent to React is fine. No issues here.
packages/ui/src/components/ui/dropdown-menu.tsx (4)
154-160: Minor: consistent className blocks (no functional issue)All good. Keeping label styling consistent with the new slot approach looks solid.
169-173: Separator looks goodThe slot and styling are straightforward and consistent with Tailwind v4.
184-187: Shortcut styling LGTMGood use of ml-auto and tracking-widest for accelerator text.
7-11: API change: wrappers don’t forward refs—verify downstream usageThese wrappers don’t use React.forwardRef, which is a change from common patterns in UI libs. Consumers won’t be able to pass refs to e.g., DropdownMenuTrigger, Content, Item, etc. Radix itself doesn’t require you to forward refs for functionality, but some apps do for focus management, measurements, or effect dependencies.
- Confirm no downstream code relies on refs to these components.
- If needed, I can generate a follow-up patch to add forwardRef consistently.
Example pattern for DropdownMenuItem:
const DropdownMenuItem = React.forwardRef< React.ElementRef<typeof DropdownMenuPrimitive.Item>, React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean; variant?: "default" | "destructive"; } >(function DropdownMenuItem( { className, inset, variant = "default", ...props }, ref ) { return ( <DropdownMenuPrimitive.Item ref={ref} data-slot="dropdown-menu-item" data-inset={inset} data-variant={variant} className={cn(/* ... */)} {...props} /> ); });Would you like me to apply this pattern across Trigger, Content, Item, CheckboxItem, RadioItem, SubTrigger, Label, Separator, Shortcut, and SubContent?
Also applies to: 21-30, 32-50, 52-58, 60-81, 83-107, 109-118, 120-142, 144-162, 164-175, 177-191, 193-198, 199-221, 223-237, 239-255
packages/ui/src/components/ui/calendar.tsx (6)
1-2: Good: client directive is appropriate hereUsing "use client" is necessary for an interactive component in Next.js.
3-8: Good: icon imports align with v9 Chevron orientationsUsing lucide-react’s Chevron*Icon variants is appropriate and keeps the bundle minimal.
17-23: Good: switch to inline named const exportThis keeps types intact and avoids hoisting surprises.
26-26: Padding increased to p-6 — verify layout parityThe larger padding can affect small viewports and popover positioning. Please sanity-check CalendarPopover and any constrained containers for overflow or clipping.
12-13: Action: confirm bundler/consumer resolution for#lib/utils.ts(or remove the.tsextension)Finding: every UI component imports "#lib/utils.ts" and none import "#lib/utils" (no extension).
Files referencing "#lib/utils.ts":
- packages/ui/src/components/ui/checkbox.tsx:7
- packages/ui/src/components/ui/dropdown-menu.tsx:5
- packages/ui/src/components/ui/popover.tsx:6
- packages/ui/src/components/ui/label.tsx:6
- packages/ui/src/components/ui/tooltip.tsx:6
- packages/ui/src/components/ui/input.tsx:3
- packages/ui/src/components/ui/card.tsx:3
- packages/ui/src/components/ui/calendar.tsx:12
- packages/ui/src/components/ui/button.tsx:5
- packages/ui/src/components/ui/Icon.tsx:4
- packages/ui/src/components/ui/chart.tsx:5
- packages/ui/src/components/ui/form.tsx:16
- packages/ui/src/components/ui/skeleton.tsx:1
Example (calendar.tsx):
import { cn } from "#lib/utils.ts";Recommendation (pick one):
- Standardize imports to "#lib/utils" (no extension), or
- Ensure your tsconfig paths and bundler configs (Vite/Next/tsup, etc.) resolve the
#lib/utils.tsalias for consumers and published builds.Please verify consumer/bundle builds (or update imports/config) to avoid cross-bundler resolution issues.
27-61: Confirm classNames keys match react-day-picker v9 API — confirmedThe keys used in packages/ui/src/components/ui/calendar.tsx (lines 27–61) match react-day-picker v9’s supported structure and modifier classNames (months, month, month_caption, caption_label, button_previous, button_next, month_grid, weekdays, weekday, week, day, day_button, selected, today, outside, disabled, hidden, range_start, range_end, range_middle). No changes required.
- packages/ui/src/components/ui/calendar.tsx — lines 27–61: OK
packages/ui/src/components/ui/tooltip.tsx (1)
31-35: LGTM: Thin wrapper for TriggerWrapper looks good and keeps
asChildopt-in available for consumers.packages/ui/src/components/ui/popover.tsx (3)
8-12: LGTM: Root wrapperSimple wrapper with data-slot is fine and keeps the public surface minimal.
14-18: LGTM: Trigger wrapperStraightforward wrapper;
asChildremains available to consumers via props.
42-46: LGTM: Anchor wrapperConsistent slot naming and minimal wrapper — good.
apps/web/package.json (1)
29-29: Tailwind v4 upgrade: looks good.This aligns with the repo-wide migration to Tailwind v4. Assuming the PostCSS plugin has been wired via @tailwindcss/postcss in this app (as done elsewhere), this is good to go.
packages/common/src/types.ts (2)
2-2: Switch to named import from zod is correct.This matches Zod v4’s recommended import style and keeps types consistent.
2-2: Confirm repo-wide removal of default zod imports — fix requiredrg found one remaining default import; convert it to the named import to avoid mixed import styles and potential type duplication.
- packages/common/src/schemas.ts:1 — replace:
- Old:
import z from "zod";- New:
import { z } from "zod";⛔ Skipped due to learnings
Learnt from: Friedrich482 PR: Friedrich482/mooncode#85 File: apps/api/src/filters/errorFormatter.ts:1-1 Timestamp: 2025-08-06T20:22:58.925Z Learning: In Zod v4, the $ZodIssue types are officially available at the import path "zod/v4/core/errors.cjs" as part of the new module structure. This is the correct way to import these types in v4, not an internal or fragile import path.Learnt from: Friedrich482 PR: Friedrich482/mooncode#86 File: apps/api/src/common/dto.ts:13-16 Timestamp: 2025-08-06T23:16:51.944Z Learning: In Zod v4, using shape spreading syntax (e.g., `z.object({...BaseSchema.shape, newField: z.string()})`) is recommended over the `.extend()` method for optimizing TypeScript compiler performance. This represents a change in best practices from earlier Zod versions.apps/vscode-extension/package.json (2)
5-5: Extension version bump to 0.0.22 approved.Changelog alignment looks consistent with the rest of the PR.
138-138: No action needed — extension already uses namedzimportScanned apps/vscode-extension for default imports, namespace imports, and require() usages of zod. Only named imports were found:
- apps/vscode-extension/src/types-schemas.ts — line 2:
import { z } from "zod";- apps/vscode-extension/src/utils/auth/storeJWTToken.ts — line 2:
import { z } from "zod";No
import z from "zod",import * as ... from "zod", orrequire("zod")usages detected.apps/vscode-extension/src/types-schemas.ts (2)
2-2: Named import from zod is correct.Matches Zod v4 usage across the repo.
17-22: Replace non-standardz.isousages — fix requiredz.iso is not a standard Zod API and there is no module augmentation in the repo — the current
z.iso.datetime()calls will throw at runtime. Replace them with the existing IsoDateSchema from @repo/common/schemas.Locations to fix:
- apps/vscode-extension/src/types-schemas.ts — fields:
lastServerSync,updatedAtSuggested changes (concise diff):
- import { IsoDateStringSchema, JWTDto } from "@repo/common/schemas"; + import { IsoDateStringSchema, IsoDateSchema, JWTDto } from "@repo/common/schemas"; - lastServerSync: z.union([ - z.date(), - z.iso.datetime().transform((str) => new Date(str)), - ]), + lastServerSync: z.union([z.date(), IsoDateSchema]), ... - updatedAt: z.union([ - z.date(), - z.iso.datetime().transform((str) => new Date(str)), - ]), + updatedAt: z.union([z.date(), IsoDateSchema]),[fiz_required]
packages/common/package.json (1)
41-41: Zod bumped to ^4.0.17: approved.Matches the import changes and keeps versions consistent across packages.
apps/api/package.json (1)
42-42: Zod upgrade to ^4.0.17 — declared versions are consistentAll package.json files that reference zod declare "^4.0.17":
- apps/api/package.json — dependencies: ^4.0.17
- apps/dashboard/package.json — dependencies: ^4.0.17
- apps/vscode-extension/package.json — dependencies: ^4.0.17
- packages/common/package.json — dependencies: ^4.0.17
packages/ui/components.json (2)
7-7: Empty Tailwind config path may break shadcn/ui toolingSetting "tailwind.config" to an empty string could cause the shadcn/ui CLI to not find a Tailwind config, depending on the CLI version. With Tailwind v4’s config-optional approach this might be intentional, but please confirm the CLI supports it to avoid generation errors.
If not supported, point "config" to the root Tailwind config (if any) or adjust to the CLI’s recommended v4 setup.
10-10: Enabling cssVariables is aligned with your v4 token strategyThis aligns with the broader move to CSS tokens and is consistent with your globals/tokens work.
apps/dashboard/src/components/CustomChartToolTip.tsx (1)
31-31: Class reordering is a no-op; looks goodReordering Tailwind classes doesn’t change output. No issues here.
apps/dashboard/src/components/dashboard-page/charts/dayLanguagesChart/DayLanguagesChart.tsx (1)
85-94: Good fix: tooltip now receives a numeric value (no parseInt).Aligns with Recharts’ numeric payloads and removes unnecessary coercion. Keep this pattern consistent across all charts.
apps/dashboard/src/components/project-page/charts/ProjectLanguagesTimeOnPeriodChart.tsx (1)
58-74: LGTM: PieChart tooltip now treats value as number.Directly passing numeric value to CustomChartToolTip removes unnecessary parsing and potential NaN pitfalls.
apps/dashboard/src/constants.ts (1)
74-75: Confirmed — --primary resolves to a concrete color (oklch(...))packages/ui/src/globals.css defines --primary as oklch(...) (lines 16–17 and 69–70) and exposes --color-primary: var(--primary) (lines 120–121). apps/dashboard currently uses var(--primary) (apps/dashboard/src/constants.ts:74 and apps/dashboard/src/components/layout/Layout.tsx:10).
- No breakage expected from switching from hsl(var(--primary)) → var(--primary) because --primary is already a full color value (oklch(...)).
- Optional: use var(--color-primary) if you prefer the public alias.
Snippet (apps/dashboard/src/constants.ts:74-75):
color: "var(--primary)", },apps/dashboard/src/components/dashboard-page/charts/PeriodTimeChart.tsx (2)
38-38: No-op class reordering.Class reordering is fine; no behavioral impact.
83-84: LGTM: stroke now uses direct CSS var.Using var(--destructive) aligns with the token strategy elsewhere in the PR.
apps/dashboard/src/components/dashboard-page/charts/GeneralStatsChart.tsx (4)
60-60: Container class reordering is fine.No functional change; layout remains consistent.
66-66: Typography class reorder is harmless.No change in semantics; leaving as-is is fine.
86-86: Typography class reorder is fine.No behavior change.
98-99: Typography class reorder is fine.No impact to rendering.
packages/ui/.prettierrc (1)
1-3: LGTM; aligns with Tailwind v4 formatting workflowConfiguration is correct. With the move of
prettier-plugin-tailwindcssto devDependencies in package.json (see related comment), this will be cleanly scoped to development.apps/dashboard/src/components/project-page/charts/CircularPacking.tsx (1)
85-86: LGTM: tokenized color usage (var(--muted-foreground))Switching from
hsl(var(--...))to directvar(--...)matches the new token strategy in Tailwind v4/theming and aligns with other changes in this PR.Also applies to: 92-93
apps/vscode-extension/src/extension.ts (1)
52-52: LGTM: centralized logger used for deactivationAdopts the new logger consistently. No concerns.
apps/vscode-extension/src/utils/commands/initExtensionCommands.ts (2)
2-2: Good move: centralize logging via the new logger.Importing and using
logInfo/logDirimproves consistency and makes logs identifiable. Path looks correct relative to this file.
34-34: Consistent log formatting for debug commands — LGTM.Replacing
console.logwithlogInfokeeps the output uniform and prefixed. Message content remains clear.Also applies to: 52-52, 63-63
packages/ui/src/components/ui/CalendarPopover.tsx (1)
3-3: Approve: type-only import for DateRange is correct — no remaining consumers foundrg output shows only one occurrence importing the type directly from react-day-picker and no imports from @repo/ui.
- packages/ui/src/components/ui/CalendarPopover.tsx — line 3
import { type DateRange } from "react-day-picker";apps/dashboard/package.json (1)
27-29: React 19 / types / Tailwind upgrades — quick verification
I inspected apps/dashboard:
- apps/dashboard/package.json: react/react-dom = 19.1.1, @types/react = 19.1.9, @types/react-dom = 19.1.7, react-error-boundary ^5, zustand ^5, react-router ^7.
- apps/dashboard/vite.config.ts imports @vitejs/plugin-react-swc and the plugin is listed in devDependencies.
- apps/dashboard/src/main.tsx uses createRoot(...).render(...) (modern root API).
- Repo scan found no ReactDOM.render / ReactDOM.hydrate / UNSAFE_* / legacy lifecycle usages.
Recommendation: I could not run installs/builds in the sandbox — please run a local smoke install + build + dev to catch peer-dependency warnings or subtle type mismatches. From the repo root, e.g.:
npm install && npm --workspace=apps/dashboard run build && npm --workspace=apps/dashboard run devpackages/ui/src/components/ui/label.tsx (2)
15-17: Label uses peer-disabled variants; ensure inputs are peers with the peer classThe label relies on peer-disabled:… which won’t activate unless the associated input has the peer class. Confirm that your Input component sets className to include peer by default.
If not already present, update Input to include peer (see suggestion in input.tsx review).
6-6: #lib alias is resolved via package.json imports — verifiedThe repo uses the package-import map rather than a tsconfig.paths entry; TypeScript's NodeNext resolution is enabled so the imports resolve.
- Evidence:
- packages/ui/package.json — "imports": { "#": "./src/" }
- packages/ui/src/lib/utils.ts — target file exists
- packages/ui/src/components/ui/label.tsx (and other UI components) import using: import { cn } from "#lib/utils.ts";
- packages/typescript-config/base.json — "moduleResolution": "NodeNext" (packages/ui/tsconfig.json extends the react-library.json which inherits this)
- Action: no change required for correctness. If you need compatibility with older tooling/IDEs that don't honor package.json "imports", add a matching "paths" mapping (e.g. "#": ["src/"]) to packages/ui/tsconfig.json.
packages/ui/src/components/ui/card.tsx (2)
18-29: @container usage in class string — verify Tailwind v4 syntax compatibilityThe token @container/card-header in a className string is unconventional but may be intended as a container-name utility in Tailwind v4. Validate that this compiles as expected in your current Tailwind config and Vite plugin, and that it produces the desired container behavior at runtime.
If needed, I can help translate this into explicit container-name CSS or Tailwind’s container utilities for clarity.
84-92: Addition of CardAction slot looks goodThe new slot provides a clear, semantic hook for action placement and aligns with the data-slot styling pattern across the UI.
packages/ui/src/components/ui/button.tsx (1)
7-35: Inline variants via cva look goodConsolidating
buttonVariantslocally with cva is clear and keeps the API surface in one place. Defaults and variant/size options read well.packages/ui/src/globals.css (1)
188-191: Scrollbar thumb token alignment looks goodSwitching to
background: var(--border)aligns with your new token system and avoids HSL mismatch. Nice consistency cleanup.packages/ui/src/components/ui/chart.tsx (1)
165-239: Tooltip content logic reads well; good accessibility touchesGood handling of ARIA attributes via FormControl elsewhere, and the tooltip label logic (labelFormatter/hideLabel/indicator) looks robust. The variable-color indicator via CSS variables is clean and Tailwind v4-friendly.
apps/dashboard/src/components/dashboard-page/PeriodDropDown.tsx (2)
13-13: Directly importing DateRange from react-day-picker v9 looks good.This aligns with the migration away from re-exporting DateRange from the UI package and avoids type drift.
75-78: Confirm Button ref-forwarding (not found) — ChartTooltip formatters OKBrief: The provided search output shows no evidence that Button forwards refs in packages/ui/src/components/ui/button.tsx; ChartTooltipContent in packages/ui/src/components/ui/chart.tsx does use labelFormatter/formatter (confirmed).
Please verify / act:
- packages/ui/src/components/ui/button.tsx — no
forwardRef/ exported Button found in the search output. Confirm Button forwards refs (React.forwardRef) or locate the actual Button implementation.- apps/dashboard/src/components/dashboard-page/PeriodDropDown.tsx — currently uses as child of DropdownMenuTrigger asChild; if Button doesn't forward refs, replace with a native or make Button forward refs.
- packages/ui/src/components/ui/chart.tsx — labelFormatter and formatter usage confirmed (labelFormatter around lines ~140–145; formatter usage around ~185–186).
Suggested fixes (pick one):
- Wrap/implement Button with React.forwardRef and forward to the underlying element, or
- Change DropdownMenuTrigger child to a primitive in PeriodDropDown.
apps/dashboard/src/components/project-page/Project.tsx (4)
31-34: Class re-order is benign.No behavioral change; error fallback remains clear and accessible.
61-64: LGTM on layout wrapper re-ordering.Purely presentational; no functional impact.
66-74: LGTM on text classes reorder.No semantic changes; layout remains consistent.
98-99: LGTM on ErrorFallBack class reorder.No effect on behavior; keeps style token usage consistent.
apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx (4)
1-5: Imports and icon aliasing look correct.Brings in AreaChart to support the new toggle; lucide aliases read cleanly.
96-111: Confirm tooltip intent: only Bar is named "Time" — should the Line be included in the tooltip?I couldn't find other ChartTooltip formatters or named series elsewhere in the repo, so I can't verify intent automatically.
- File to check: apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx (around lines 96–111)
- Current: Bar has name="Time"; Line has no name.
- If you want both series shown with the same tooltip formatting, add name to the Line (or give a distinct name and handle it in your tooltip formatter). If the Line is just an overlay, no change needed.
Suggested minimal change:
<Line dataKey="timeSpentLine" name="Time" <-- add this if you want it in the tooltip stroke="var(--destructive)" ... />Please confirm desired tooltip behavior.
66-111: Confirmed — backend emits timeSpentBar / timeSpentLine / timeSpentArea and originalDate for getProjectPerDayOfPeriod.The front-end keys used in ProjectTimeOnPeriodChart are already produced by the server mappers, so no client change is required.
Files verified:
- apps/api/src/files-stats/utils/getProjectPerDayOfPeriodGroupByMonths.ts — returns timeSpentLine, timeSpentBar, timeSpentArea and originalDate (lines ~39–42).
- apps/api/src/files-stats/utils/getProjectPerDayOfPeriodGroupByWeeks.ts — returns timeSpentLine, timeSpentBar, timeSpentArea and originalDate (lines ~78–81).
- apps/api/src/files-stats/files-stats-dashboard.service.ts — getProjectPerDayOfPeriod maps dailyProjectsForPeriod -> timeSpentLine/timeSpentBar/timeSpentArea and originalDate (lines ~95–102, ~196–199).
- apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx — uses dataKey="timeSpentBar"/"timeSpentLine" (and area variant uses "timeSpentArea") and reads innerPayload.originalDate in the tooltip (lines referenced in PR).
Optional note: if other endpoints emit only a single numeric field (timeSpent) and you want less duplication, consider standardizing on one key and adapting client-side usage accordingly.
143-153: Area props OK — no change requiredConfirmed: apps/dashboard/package.json lists "recharts": "^2.15.1" and Recharts v2.x supports both
dotandactiveDoton . The Area usage in apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx (lines 143–153) — includingdot={{ r: 4 }}— is valid.
- Checked package: apps/dashboard/package.json -> "recharts": "^2.15.1"
- Checked chart file: apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx (lines 143–153)
apps/dashboard/src/components/dashboard-page/charts/GeneralStatsChart.tsx
Show resolved
Hide resolved
apps/dashboard/src/components/project-page/charts/ProjectTimeOnPeriodChart.tsx
Show resolved
Hide resolved
- added an animated night sky with full moon (moonCode logo) svg to the auth pages (login && register) - installed the `vite-plugin-svgr` to render svgs directly in the DOM - grouped the login and register page components under an auth route group
- inferred the badge version from the vscode marketplace instead of manual bumps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (15)
apps/dashboard/src/components/layout/header/Logo.tsx (2)
4-8: Consider explicit width/height to eliminate potential CLS.Since size-8 maps to 2rem, adding width/height attributes (32px) will reserve space and avoid layout shift without changing visuals.
<img src="/moon.svg" - className={cn("size-8", className)} + className={cn("size-8", className)} + width={32} + height={32} alt="MoonCode Logo" />
3-9: Optionally expose standardprops for broader reuse.
If you foresee needing to override alt, add titles, aria labels, etc., consider typing against ImgHTMLAttributes and forwarding the rest of the props. Keeps src fixed while increasing reusability.
-import { cn } from "@repo/ui/lib/utils"; +import { cn } from "@repo/ui/lib/utils"; +import type { ImgHTMLAttributes } from "react"; -const Logo = ({ className }: { className?: string }) => ( +type Props = Omit<ImgHTMLAttributes<HTMLImageElement>, "src">; +const Logo = ({ className, alt = "MoonCode Logo", ...props }: Props) => ( <img src="/moon.svg" - className={cn("size-8", className)} - alt="MoonCode Logo" + className={cn("size-8", className)} + alt={alt} + {...props} /> );apps/dashboard/package.json (1)
54-54: Remove unused PostCSS & Autoprefixer from apps/dashboardI verified that in apps/dashboard:
- No
postcss.config.*file exists.- Vite is wired up with
@tailwindcss/vitein apps/dashboard/vite.config.ts.package.jsonstill lists both"postcss": "^8.5.1"and"autoprefixer": "^10.4.20"under devDependencies.Since the Tailwind v4 Vite plugin handles all PostCSS transforms out of the box, you can drop these two entries to clean up your toolchain.
Suggested diff:
--- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -45,8 +45,6 @@ "tailwindcss": "^4.1.11", "typescript": "^5.2.2", - "postcss": "^8.5.1", "vite": "^4.4.9", - "autoprefixer": "^10.4.20", },After removal, run a quick local build to confirm nothing breaks. [optional_refactors_recommended]
apps/dashboard/src/components/auth/register-page/RegisterForm.tsx (6)
57-59: Guard missing VITE_REGISTER_URL earlyIf the env var is unset,
fetchJWTTokenwill likely fail with a less actionable error. Fail fast with a clear message.const REGISTER_URL = import.meta.env.VITE_REGISTER_URL; + if (!REGISTER_URL) { + throw new Error("Missing VITE_REGISTER_URL"); + }
70-76: Avoid post-redirect work by returning earlyAfter setting
window.location.href, the app navigates away. Add areturnto prevent unnecessary query invalidation andnavigate("/dashboard"). This is handled in the previous diff by returning inside the redirect branch.
78-78: Use the new prefixed logger instead of console.errorThis PR refactors raw console usage. Replace
console.error(error)with the new logger for consistency and discoverability.Please confirm the intended logger import path (e.g., a shared logger in @repo/common or a local util), and I can provide a concrete patch.
115-120: Improve email field semantics and autofillSet proper type and autocomplete to help validation and browser autofill.
- <Input + <Input + type="email" + autoComplete="email" placeholder="example@email.com" {...field} className="border-border h-10" />
151-157: Improve password field autofill for registrationFor sign-up, prefer
autoComplete="new-password".- <Input + <Input placeholder="**********" {...field} type={isPasswordVisible ? "text" : "password"} + autoComplete="new-password" className="border-border h-10 flex-nowrap" />
29-36: Deduplicate root-class toggling via a small hookBoth auth forms add/remove
#root.auth-root. Consider extracting auseAuthRootClass()hook to centralize this behavior.I can generate a tiny shared hook under
@/hooks/useAuthRootClassand wire it in both forms if you want.apps/dashboard/src/components/auth/login-page/LoginForm.tsx (6)
58-60: Guard missing VITE_LOGIN_URL earlyFail fast when the login endpoint env var is absent.
const LOGIN_URL = import.meta.env.VITE_LOGIN_URL; + if (!LOGIN_URL) { + throw new Error("Missing VITE_LOGIN_URL"); + }
115-119: Improve email field semantics and autofillAdd
type="email"andautoComplete="email".- <Input + <Input + type="email" + autoComplete="email" placeholder="example@email.com" {...field} className="border-border h-10" />
133-137: Improve password field autofill for loginUse
autoComplete="current-password".- <Input + <Input placeholder="**********" {...field} type={isPasswordVisible ? "text" : "password"} + autoComplete="current-password" className="border-border h-10 flex-nowrap" />
146-147: Fix typography: remove extra space before question markMinor copy nit.
- Not registered yet ?{" "} + Not registered yet?{" "}
16-16: Use the same alias-based import for Logo as in RegisterFormFor consistency and resilience to file moves, prefer the
@alias here too.-import Logo from "../../layout/header/Logo"; +import Logo from "@/components/layout/header/Logo";
29-36: Deduplicate root-class toggling via a small hookSame suggestion as RegisterForm: extract a
useAuthRootClass()hook for adding/removingauth-root.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
apps/dashboard/public/animated-night.svgis excluded by!**/*.svgpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
apps/dashboard/package.json(3 hunks)apps/dashboard/src/components/auth/login-page/LoginForm.tsx(1 hunks)apps/dashboard/src/components/auth/register-page/RegisterForm.tsx(1 hunks)apps/dashboard/src/components/layout/header/Logo.tsx(1 hunks)apps/dashboard/src/components/login-page/LoginForm.tsx(0 hunks)apps/dashboard/src/components/register-page/RegisterForm.tsx(0 hunks)apps/dashboard/src/index.css(1 hunks)apps/dashboard/src/main.tsx(1 hunks)apps/dashboard/src/vite-env.d.ts(1 hunks)apps/dashboard/vite.config.ts(1 hunks)
💤 Files with no reviewable changes (2)
- apps/dashboard/src/components/login-page/LoginForm.tsx
- apps/dashboard/src/components/register-page/RegisterForm.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/dashboard/src/vite-env.d.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/dashboard/vite.config.ts
- apps/dashboard/src/index.css
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/dashboard/src/components/auth/login-page/LoginForm.tsx (3)
packages/common/src/types.ts (1)
SignInUserDtoType(10-10)packages/common/src/schemas.ts (1)
SignInUserDto(9-13)packages/common/src/constants.ts (2)
INCORRECT_PASSWORD_MESSAGE(4-4)USER_NOT_FOUND_MESSAGE(3-3)
apps/dashboard/src/components/layout/header/Logo.tsx (1)
packages/ui/src/lib/utils.ts (1)
cn(4-6)
🔇 Additional comments (9)
apps/dashboard/src/components/layout/header/Logo.tsx (2)
3-9: Nice prop-ification and className merging with cn.Allowing an optional className and merging via cn with Tailwind’s twMerge improves flexibility while keeping sane defaults. This is aligned with your broader UI refactors.
5-5: Asset path validated – no custom base path detected
- The asset
moon.svgis located atapps/dashboard/public/moon.svg.- No
basesetting was found in anyvite.config.*, norbasePathinnext.config.*.- With default config (serving at the domain root),
src="/moon.svg"will resolve correctly.If you later deploy under a sub-directory, remember to update the
base/basePathoption or switch to an asset import (e.g. usingimport.meta.env.BASE_URL) to ensure the path remains accurate.apps/dashboard/package.json (4)
41-42: React 19 type definitions aligned.@types/react and @types/react-dom are correctly bumped to 19.x, matching react/react-dom. LGTM.
52-52: Prettier Tailwind plugin bump: looks good.Matches Tailwind v4 adoption. Ensure .prettierrc includes the plugin where needed.
58-59: Plugins properly configured in vite.config.ts
Verified that bothvite-plugin-commonjsandvite-plugin-svgrare:
- Imported in apps/dashboard/vite.config.ts (lines 2 and 6)
- Included in the
pluginsarray (tailwindcss(), react(), commonjs(), svgr(), visualizer())No further changes needed.
34-34: Replace default Zod import in packages/common/src/schemas.tsA default import of Zod was detected, which is incompatible with Zod v4’s named-only export model. Please update it as follows:
• packages/common/src/schemas.ts:1
- import z from "zod"; + import { z } from "zod";No other default or mixed imports of Zod were found.
⛔ Skipped due to learnings
Learnt from: Friedrich482 PR: Friedrich482/mooncode#85 File: apps/api/src/filters/errorFormatter.ts:1-1 Timestamp: 2025-08-06T20:22:58.925Z Learning: In Zod v4, the $ZodIssue types are officially available at the import path "zod/v4/core/errors.cjs" as part of the new module structure. This is the correct way to import these types in v4, not an internal or fragile import path.Learnt from: Friedrich482 PR: Friedrich482/mooncode#86 File: apps/api/src/common/dto.ts:13-16 Timestamp: 2025-08-06T23:16:51.944Z Learning: In Zod v4, using shape spreading syntax (e.g., `z.object({...BaseSchema.shape, newField: z.string()})`) is recommended over the `.extend()` method for optimizing TypeScript compiler performance. This represents a change in best practices from earlier Zod versions.apps/dashboard/src/main.tsx (3)
6-6: LGTM: Auth form import path relocationImporting LoginForm from the new auth/ path looks correct and matches the file move.
11-11: LGTM: Register form import path relocationImporting RegisterForm from the new auth/ path looks correct and matches the file move.
1-1: Imports from “react-router” are correct for v7
The dashboard app only depends on react-router@^7.5.1 (no react-router-dom) and, as of v7, the package now includes DOM APIs (RouterProvider, createBrowserRouter, hooks, etc.). No changes needed here.
- moved the `animated-night.svg` in the assets folder for the dashboard - updated the paths in the login and register forms
- bumped react and react-dom to `v19.1.1` in the web app
- removed useless path base in the `postcss.config.mjs` in the `@repo/ui` package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
apps/web/package.json (1)
17-18: Good alignment: apps/web upgraded to React 19React and ReactDOM now match the rest of the repo and Next 15.4.1 requirements. This addresses the earlier concern about apps/web being on React 18.
apps/dashboard/src/components/auth/login-page/LoginForm.tsx (2)
148-152: Encode the callback in the Sign Up linkThe raw
callbackUrlcan contain characters that break the URL. Encode it.- to={`/register${callbackUrl ? `?callback=${callbackUrl}` : ""}`} + to={`/register${callbackUrl ? `?callback=${encodeURIComponent(callbackUrl)}` : ""}`}
66-69: Stop leaking JWT via query string; build redirect safely and return after redirectAppending
&token=...breaks for URLs without a query and exposes the JWT (and email) to servers/logs and referers. Use the URL API, put the token in the hash (fragment) instead of the query, and return immediately after redirect.- if (callbackUrl) { - window.location.href = `${callbackUrl}&token=${token}&email=${encodeURIComponent(values.email)}`; - } + if (callbackUrl) { + try { + const url = new URL(callbackUrl, window.location.origin); + // Keep email only if needed by the destination; otherwise omit or also move to the hash. + url.searchParams.set("email", values.email); + // Avoid server/referrer exposure by keeping the JWT in the fragment. + url.hash = `token=${encodeURIComponent(token)}`; + window.location.href = url.toString(); + return; + } catch { + form.setError("root", { message: "Invalid callback URL" }); + return; + } + }
🧹 Nitpick comments (5)
apps/dashboard/src/components/auth/login-page/LoginForm.tsx (5)
53-54: Gate the callback URL with an allowlist to prevent open redirects/exfiltrationBefore honoring a user-supplied callback, validate its origin against a known allowlist (or constrain to same-origin). This avoids redirecting tokens/PII to attacker-controlled domains.
If helpful, I can add an ALLOWED_CALLBACK_ORIGINS constant and wire the check into the redirect code.
58-63: Guard against missing LOGIN_URL to avoid runtime failuresFail fast with a user-facing error if
VITE_LOGIN_URLis not configured.- const LOGIN_URL = import.meta.env.VITE_LOGIN_URL; + const LOGIN_URL = import.meta.env.VITE_LOGIN_URL; + if (!LOGIN_URL) { + form.setError("root", { message: "Login URL is not configured" }); + return; + }
114-118: Add autocomplete for better UX and accessibility on emailLet the browser assist users with the email field.
- <Input - placeholder="example@email.com" - {...field} - className="border-border h-10" - /> + <Input + placeholder="example@email.com" + autoComplete="email" + {...field} + className="border-border h-10" + />
133-137: Add autocomplete on password fieldSmall UX win and consistent with best practices.
- <Input - placeholder="**********" - {...field} - type={isPasswordVisible ? "text" : "password"} - className="border-border h-10 flex-nowrap" - /> + <Input + placeholder="**********" + autoComplete="current-password" + {...field} + type={isPasswordVisible ? "text" : "password"} + className="border-border h-10 flex-nowrap" + />
146-147: Minor copy fix: remove extra space before the question markPolish the UI text.
- <p> - Not registered yet ?{" "} + <p> + Not registered yet?{" "}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
apps/dashboard/src/assets/animated-night.svgis excluded by!**/*.svgpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (4)
apps/dashboard/src/components/auth/login-page/LoginForm.tsx(1 hunks)apps/dashboard/src/components/auth/register-page/RegisterForm.tsx(1 hunks)apps/vscode-extension/README.md(1 hunks)apps/web/package.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/vscode-extension/README.md
- apps/dashboard/src/components/auth/register-page/RegisterForm.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/dashboard/src/components/auth/login-page/LoginForm.tsx (3)
packages/common/src/types.ts (1)
SignInUserDtoType(10-10)packages/common/src/schemas.ts (1)
SignInUserDto(9-13)packages/common/src/constants.ts (2)
INCORRECT_PASSWORD_MESSAGE(4-4)USER_NOT_FOUND_MESSAGE(3-3)
- updated the versions of react and react-dom in the web app - moved `@tailwindcss/vite` in the devDependencies in the dashboard
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
apps/web/package.json (2)
23-24: Remove @types/react and @types/react-dom — React 19 ships its own typesWith React 19, the types are bundled and these @types are unnecessary and can cause TS conflicts. Safe to remove both.
Apply this diff to drop them:
"devDependencies": { "@eslint/eslintrc": "^3", "@types/node": "^20", - "@types/react": "19.1.9", - "@types/react-dom": "19.1.7", "autoprefixer": "^10.4.21", "eslint": "^9.21.0", "eslint-config-next": "15.4.1", "postcss": "^8.4.31", "tailwindcss": "^4.1.11", "typescript": "^5" }
29-29: Add @tailwindcss/postcss to devDependencies (or remove Tailwind here)Your PostCSS config for this app uses the Tailwind v4 PostCSS plugin. Ensure
@tailwindcss/postcssis listed indevDependencies, or remove Tailwind from this app if it only imports CSS from@repo/ui.Run this to verify plugin usage and decide the action:
#!/bin/bash set -euo pipefail echo "== PostCSS config presence" if [[ -f apps/web/postcss.config.mjs ]]; then sed -n '1,120p' apps/web/postcss.config.mjs else echo "apps/web/postcss.config.mjs not found" fi echo echo "== Check for @tailwindcss/postcss reference" rg -nP '@tailwindcss/postcss' apps/web/postcss.config.mjs || true echo echo "== Check Tailwind directives in apps/web sources" rg -nP '@tailwind\s' apps/web || true echo echo "== Is @tailwindcss/postcss listed in devDependencies?" jq -r '.devDependencies["@tailwindcss/postcss"] // "NOT_FOUND"' apps/web/package.jsonDecision:
- If the plugin is referenced, add
@tailwindcss/postcssto devDependencies (version aligned with your root/workspace).- If no Tailwind directives are present and CSS is sourced from
@repo/ui, consider removing"tailwindcss"from devDependencies and dropping the plugin frompostcss.config.mjsfor this app.apps/dashboard/package.json (1)
26-27: Prefer caret ranges for React 19 and re-verify monorepo alignmentExact pins can impede receiving patch updates. Unless you intentionally pin, prefer caret ranges. Also, confirm all packages in the monorepo use React 19 to avoid multiple React trees.
Apply this diff:
- "react": "19.1.1", - "react-dom": "19.1.1", + "react": "^19.1.1", + "react-dom": "^19.1.1",Run this script to surface any stragglers still on React 18:
#!/bin/bash set -euo pipefail echo "== React versions across all package.json ==" fd -t f package.json | while read -r file; do react=$(jq -r '.dependencies.react // .peerDependencies.react // empty' "$file") reactdom=$(jq -r '.dependencies["react-dom"] // .peerDependencies["react-dom"] // empty' "$file") if [[ -n "${react}" || -n "${reactdom}" ]]; then echo "File: $file" echo " react: ${react:-"(none)"}" echo " react-dom: ${reactdom:-"(none)"}" echo fi done | sed -n '1p;/\^?18\./,/^$/p' || true
🧹 Nitpick comments (1)
apps/dashboard/package.json (1)
41-42: Use caret ranges for @types to ease patch updatesUnless you have a reason to pin exactly, caret ranges reduce churn while staying within the same major.
Apply this diff:
- "@types/react": "19.1.9", - "@types/react-dom": "19.1.7", + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
apps/dashboard/package.json(2 hunks)apps/web/package.json(1 hunks)
🔇 Additional comments (5)
apps/web/package.json (1)
17-18: React 19 bump looks good and matches Next 15.x expectationsPinning
reactandreact-domto 19.1.1 is consistent with the migration and should align with Next 15.4.1.apps/dashboard/package.json (4)
33-33: Zod upgrade aligns with repo-wide move to v4.0.17 — LGTM
37-37: Good: @tailwindcss/vite correctly scoped to devDependencies
52-54: Tailwind v4 + prettier-plugin-tailwindcss bump looks consistent with the migration
58-59: Build-time Vite plugins (commonjs, svgr) correctly live in devDependencies
Commits
refactor: logger
console.{log, dir, error},by custom logger functions with prefix to easily identify MoonCode logs in the consolechore: extension bump
0.0.22parseIntcalls in theDayLanguagesChartandProjectLanguagesTimeOnPeriodcomponentschore: zod
feat: react-day-picker
v9chore: migration
19and to tailwindcssv4fix: calendar
.prettierrcin the ui package to get the tailwind prettier plugin, also installed the plugin in the packagefix: ProjectTimeOnPeriod
v4and react19chore: checkbox
chore: zod
v4.0.17chore: web
v4Summary by CodeRabbit
New Features
Improvements
Tooling
VS Code Extension
Chores