Skip to content

[WEB-4790] fix: moved typescript parser to the base eslint config#7658

Merged
sriramveeraghanta merged 4 commits intopreviewfrom
fix-eslint-parser
Aug 27, 2025
Merged

[WEB-4790] fix: moved typescript parser to the base eslint config#7658
sriramveeraghanta merged 4 commits intopreviewfrom
fix-eslint-parser

Conversation

@sriramveeraghanta
Copy link
Member

@sriramveeraghanta sriramveeraghanta commented Aug 26, 2025

Description

  • Fixed typescript parser for eslint.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Summary by CodeRabbit

  • New Features

    • None
  • Refactor

    • Simplified toggle handlers in Admin authentication settings for clearer logic.
    • Added minor type annotations and variable renames without changing behavior.
  • Style

    • Reorganized imports and suppressed an unused-variable warning in Calendar. No UI changes.
  • Chores

    • Standardized ESLint configurations across apps and packages.
    • Added/updated ESLint ignore files to exclude build outputs and env files.
    • Introduced a root ESLint config for the Live app to align linting rules.

Copilot AI review requested due to automatic review settings August 26, 2025 19:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Project-wide ESLint configuration was consolidated: local parser settings were removed from many apps/packages, new ignore files were added, and shared configs were updated to include TypeScript parser, plugins, and import order rules. Minor React/TS cleanups and import reorders landed, plus a Redis integration change within the live app’s extensions module.

Changes

Cohort / File(s) Summary of changes
ESLint ignore files (add/update)
apps/admin/.eslintignore, apps/space/.eslintignore, apps/web/.eslintignore, packages/constants/.eslintignore, packages/editor/.eslintignore, packages/ui/.eslintignore
Added/expanded ignore patterns for build outputs, node_modules, .turbo, and environment files; updated web ignore list.
App ESLint configs (parser removed/migrated)
apps/admin/.eslintrc.js, apps/space/.eslintrc.js, apps/web/.eslintrc.js
Removed explicit @typescript-eslint/parser (and type JSDoc where present) from local ESLint configs.
Live app ESLint config restructuring
apps/live/.eslintrc.json (deleted), apps/live/.eslintrc.cjs (added)
Switched to CJS-based ESLint config extending @plane/eslint-config/server.js; removed prior JSON config that included a parser.
Package ESLint configs (parser removed)
packages/constants/.eslintrc.js, packages/decorators/.eslintrc.js, packages/editor/.eslintrc.js, packages/hooks/.eslintrc.js, packages/i18n/.eslintrc.js, packages/logger/.eslintrc.js, packages/propel/.eslintrc.js, packages/services/.eslintrc.js, packages/shared-state/.eslintrc.js, packages/types/.eslintrc.js, packages/ui/.eslintrc.js, packages/utils/.eslintrc.js
Removed explicit parser entries (and JSDoc/type hints in several files). In i18n and shared-state, also removed parserOptions.project.
Shared ESLint configs (centralized TS + rules)
packages/eslint-config/library.js, packages/eslint-config/next.js, packages/eslint-config/server.js
Added parser: "@typescript-eslint/parser"; added plugins in Next config; added import/order in Server config; minor key formatting updates in no-unused-vars.
Admin UI refactors
apps/admin/app/(all)/(dashboard)/email/page.tsx, apps/admin/core/components/authentication/* (email-config-switch.tsx, github-config.tsx, gitlab-config.tsx, google-config.tsx, password-config-switch.tsx), apps/admin/core/store/instance.store.ts
Added React.FC type to a page; standardized toggle handlers to compute values before calling updateConfig; renamed unused catch/error variables to _error.
Live core imports and Redis path
apps/live/src/core/extensions/index.ts, apps/live/src/core/hocuspocus-server.ts, apps/live/src/core/lib/authentication.ts, apps/live/src/server.ts
Switched Redis integration to direct ioredis import; removed Hocuspocus Logger extension; reordered imports; no API changes.
Hooks/UI minor cleanup
packages/hooks/src/use-local-storage.tsx, packages/ui/src/auth-form/auth-form.tsx, packages/ui/src/calendar.tsx
Renamed unused variables to _error/_passwordsMatch; added eslint-disable for an unused prop in Calendar; no behavioral changes.

Sequence Diagram(s)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • fix: live server runtime errors #7314 — Also updates ESLint configs for the live app and constants package, including parser/parserOptions adjustments, indicating related linting/config consolidation.

Suggested labels

🛠️refactor, ready to merge

Suggested reviewers

  • Palanikannan1437
  • twtaylor
  • VipinDevelops

Poem

In linted fields I hop with glee,
Ignored the builds, set parsers free.
I nudge the toggles, light but swift,
Reordered imports—tidy drift.
With Redis trails now straight and fine,
I stamp “OK” with paws divine. 🐇✨

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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-eslint-parser

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR centralizes TypeScript ESLint parser configuration by moving the parser declaration from individual package/app ESLint configs to the base eslint-config files, eliminating duplication and ensuring consistency across the monorepo.

  • Removes redundant parser: "@typescript-eslint/parser" declarations from individual .eslintrc files
  • Adds the TypeScript parser to base configurations (library.js, next.js, server.js)
  • Standardizes .eslintignore files with common ignore patterns across packages and apps

Reviewed Changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

File Description
packages/*/‍.eslintrc.js Removes duplicate TypeScript parser declarations
apps/*/‍.eslintrc.js Removes duplicate TypeScript parser declarations
packages/eslint-config/*.js Adds TypeScript parser to base configs and improves formatting
Various .eslintignore files Adds standard ignore patterns for build artifacts and environment files

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@sriramveeraghanta sriramveeraghanta changed the title fix: moved typescript parser to the base eslint config [WEB-4790] fix: moved typescript parser to the base eslint config Aug 26, 2025
@makeplane
Copy link

makeplane bot commented Aug 26, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (18)
packages/editor/.eslintignore (2)

1-4: Prefer directory form over trailing globs for recursive ignores

Using "dir/" (or "dir/**") is clearer and ignores recursively; "dir/*" only matches the first level. Apply for build, dist, and out.

-node_modules
-build/*
-dist/*
-out/*
+node_modules
+build/
+dist/
+out/

1-4: Optional: standardize and centralize common ignore entries

  • ESLint already ignores node_modules by default; either keep it everywhere for clarity or remove for brevity, but be consistent repo-wide.
  • Consider adding shared tool/build artifacts (e.g., .turbo/, coverage/) here or at the repo root .eslintignore to avoid duplication across packages.

Would you like me to propose a root-level .eslintignore that apps/packages can inherit from to DRY these patterns?

packages/constants/.eslintignore (2)

1-4: Use directory form for recursive ignores

Same rationale as other packages: switch from "*/" to "/" so nested content is ignored reliably.

-node_modules
-build/*
-dist/*
-out/*
+node_modules
+build/
+dist/
+out/

1-4: Align ignore set with the rest of the repo

If other packages/apps add .turbo/ and coverage/, include them here too or centralize in a root .eslintignore to keep things consistent.

packages/ui/.eslintignore (1)

1-3: Normalize patterns and consider including common tooling dirs

  • Replace "*/" with "/" for recursive ignores.
  • If other workspaces list node_modules/.turbo/ explicitly, mirror that for consistency or centralize ignores.
-build/*
-dist/*
-out/*
+build/
+dist/
+out/
+node_modules/
+.turbo/
apps/web/.eslintignore (2)

4-13: Tighten directory patterns and dedupe env entries

  • Prefer "dir/" over "dir/*" for recursive directory ignores.
  • ".env*" already covers .env, .env.local, .env.development, .env.production, .env.test; the explicit lines are redundant.
-core/local-db/worker/wa-sqlite/src/*
-dist/*
-node_modules/*
-.turbo/*
-.env*
-.env
-.env.local
-.env.development
-.env.production
-.env.test
+core/local-db/worker/wa-sqlite/src/
+dist/
+node_modules/
+.turbo/
+.env*

4-13: Optional: consider additional Next.js artifacts

If this app uses Vercel, adding ".vercel/" can prevent accidental linting of deployment artifacts. Also consider "coverage/" if you generate coverage reports.

apps/admin/.eslintignore (1)

1-12: Normalize directory patterns and remove redundant env lines

  • Use "dir/" instead of "dir/*" to capture nested content.
  • Keep only ".env*" since it already matches all the explicit env files listed.
-.next/*
-out/*
-public/*
-dist/*
-node_modules/*
-.turbo/*
-.env*
-.env
-.env.local
-.env.development
-.env.production
-.env.test
+.next/
+out/
+public/
+dist/
+node_modules/
+.turbo/
+.env*
apps/space/.eslintignore (1)

7-12: Deduplicate .env entries; .env already covers them*

Keeping both .env* and the explicit .env.* lines is redundant.

Apply this minimal diff:

 .turbo/*
 .env*
-.env
-.env.local
-.env.development
-.env.production
-.env.test

Optional: consider also ignoring common folders like coverage/ or .vercel/ if they exist in this app.

packages/eslint-config/library.js (5)

7-8: Put "prettier" last in extends to ensure it wins; parser centralization looks right

Prettier should be last so it can disable conflicting rules from prior configs. The new central parser is good.

-module.exports = {
-  extends: ["prettier", "plugin:@typescript-eslint/recommended"],
+module.exports = {
+  extends: ["plugin:@typescript-eslint/recommended", "prettier"],
   parser: "@typescript-eslint/parser",

10-13: Mark React/JSX globals as readonly, not writable

Using true makes them writable. Prefer "readonly" to avoid accidental assignments.

-  globals: {
-    React: true,
-    JSX: true,
-  },
+  globals: {
+    React: "readonly",
+    JSX: "readonly",
+  },

19-24: Monorepo resolver reliability: ensure the TS project resolution works from repo root

project is computed from process.cwd(). If ESLint runs from the monorepo root, packages may not resolve correctly. Two safer options:

Option A (auto-detect):

-      typescript: {
-        project,
-      },
+      typescript: {
+        project: true,
+      },

Option B (explicit globs):

-const project = resolve(process.cwd(), "tsconfig.json");
+const project = [
+  "tsconfig.json",
+  "apps/*/tsconfig.json",
+  "packages/*/tsconfig.json",
+].map((p) => resolve(process.cwd(), p));

and keep project as-is below.

Please verify your CI runs ESLint from a working directory that makes the current approach resolve each package’s tsconfig correctly.


55-77: Tidy import/order: remove non-existent "react" type from exclusions

pathGroupsExcludedImportTypes expects import types (e.g., builtin, external, internal, parent...). "react" isn’t a valid type and is ignored.

-        pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
+        pathGroupsExcludedImportTypes: ["builtin", "internal"],

33-35: Avoid false positives: turn off no-undef for TS files only

Core no-undef can misfire on types. Keep it for JS, but disable for TS via an override.

Add this override near the end of the config (before ignorePatterns):

   rules: {
     "no-useless-escape": "off",
@@
   },
+  overrides: [
+    {
+      files: ["**/*.ts", "**/*.tsx"],
+      rules: {
+        "no-undef": "off",
+      },
+    },
+  ],
 
   ignorePatterns: [".*.js", "node_modules/", "dist/"],
packages/eslint-config/next.js (3)

5-7: Put "prettier" last; central parser looks good

Ensure Prettier is last so it can disable conflicting rules.

-module.exports = {
-  extends: ["next", "prettier", "plugin:@typescript-eslint/recommended"],
+module.exports = {
+  extends: ["next", "plugin:@typescript-eslint/recommended", "prettier"],
   parser: "@typescript-eslint/parser",
   plugins: ["react", "@typescript-eslint", "import"],

97-103: Remove "react" from excluded import types

It’s not a valid import type and is ignored by the rule.

-        pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
+        pathGroupsExcludedImportTypes: ["builtin", "internal"],

32-34: Consider disabling no-undef for TS files only

Same rationale as the library config to avoid false positives on types.

Example override (place after rules):

   rules: {
@@
   },
+  overrides: [
+    {
+      files: ["**/*.ts", "**/*.tsx"],
+      rules: {
+        "no-undef": "off",
+      },
+    },
+  ],
packages/eslint-config/server.js (1)

29-33: no-unused-vars patterns look good; consider enabling ignoreRestSiblings to reduce noise.

Common when stripping props via object rest: avoids false positives without weakening the rule.

       {
         argsIgnorePattern: "^_",
         varsIgnorePattern: "^_",
         caughtErrorsIgnorePattern: "^_",
+        ignoreRestSiblings: true,
       },
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1ad8a and b223cd4.

📒 Files selected for processing (25)
  • apps/admin/.eslintignore (1 hunks)
  • apps/admin/.eslintrc.js (0 hunks)
  • apps/live/.eslintrc.json (1 hunks)
  • apps/space/.eslintignore (1 hunks)
  • apps/space/.eslintrc.js (0 hunks)
  • apps/web/.eslintignore (1 hunks)
  • apps/web/.eslintrc.js (0 hunks)
  • packages/constants/.eslintignore (1 hunks)
  • packages/constants/.eslintrc.js (1 hunks)
  • packages/decorators/.eslintrc.js (0 hunks)
  • packages/editor/.eslintignore (1 hunks)
  • packages/editor/.eslintrc.js (0 hunks)
  • packages/eslint-config/library.js (2 hunks)
  • packages/eslint-config/next.js (2 hunks)
  • packages/eslint-config/server.js (2 hunks)
  • packages/hooks/.eslintrc.js (0 hunks)
  • packages/i18n/.eslintrc.js (0 hunks)
  • packages/logger/.eslintrc.js (0 hunks)
  • packages/propel/.eslintrc.js (0 hunks)
  • packages/services/.eslintrc.js (0 hunks)
  • packages/shared-state/.eslintrc.js (0 hunks)
  • packages/types/.eslintrc.js (0 hunks)
  • packages/ui/.eslintignore (1 hunks)
  • packages/ui/.eslintrc.js (0 hunks)
  • packages/utils/.eslintrc.js (0 hunks)
💤 Files with no reviewable changes (14)
  • packages/shared-state/.eslintrc.js
  • packages/decorators/.eslintrc.js
  • packages/types/.eslintrc.js
  • apps/web/.eslintrc.js
  • packages/utils/.eslintrc.js
  • packages/services/.eslintrc.js
  • packages/hooks/.eslintrc.js
  • apps/admin/.eslintrc.js
  • packages/propel/.eslintrc.js
  • packages/i18n/.eslintrc.js
  • packages/logger/.eslintrc.js
  • packages/editor/.eslintrc.js
  • packages/ui/.eslintrc.js
  • apps/space/.eslintrc.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/admin/.eslintignore (1)

1-12: No lingering parser declarations found – parser centralization verified.

  • Confirmed that no workspace-level .eslintrc files outside of packages/eslint-config still declare parser: "@typescript-eslint/parser".
  • Verified there are no parserOptions.project entries in any local ESLint configs that could point to outdated tsconfig files.

All TypeScript parsing is correctly centralized in the shared ESLint config. The change can be approved.

apps/space/.eslintignore (1)

1-6: LGTM: solid baseline ignores for build artifacts

The patterns for .next, out, public, dist, node_modules, and .turbo look good for a Next.js app.

packages/eslint-config/library.js (2)

45-51: No behavior change in no-unused-vars options

Unquoting the option keys is fine; values are unchanged.


80-81: Double-check global ignorePatterns scope

Ignoring dot-JS files globally can hide lint issues in dotfile configs (e.g., .storybook/*.js) if any consumer wants to lint them. If that’s intentional, ignore this; otherwise consider scoping this ignore at app level.

packages/constants/.eslintrc.js (1)

1-5: Parser configuration verified

All consumer ESLint configs no longer declare their own parser, and each shared config (packages/eslint-config/library.js, next.js, server.js) explicitly defines parser: "@typescript-eslint/parser". The removal of local parser settings is safe and requires no further changes.

packages/eslint-config/next.js (1)

43-50: No behavior change in no-unused-vars options

Unquoted option keys are fine.

apps/live/.eslintrc.json (1)

3-3: TS parser correctly centralized in server.js

The packages/eslint-config/server.js file explicitly defines parser: "@typescript-eslint/parser" and includes the appropriate import/resolver settings, and none of the individual .eslintrc.* files in apps/ or packages/ override the parser. Consumers extending @plane/eslint-config/server.js will correctly inherit the TypeScript parser. No further changes required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (3)
packages/hooks/src/use-local-storage.tsx (1)

4-4: Fix SSR guard: correct invalid typeof comparison across the repo

typeof always returns a string, so comparing it to the bare undefined is both incorrect (and will be flagged by ESLint’s valid-typeof rule) and redundant when you already compare to the string "undefined". Simplify each guard to a single string check.

Please apply these diffs in all listed locations:

  • packages/hooks/src/use-local-storage.tsx

    -  if (typeof window === undefined || typeof window === "undefined") return defaultValue;
    +  if (typeof window === "undefined") return defaultValue;
    
    -  if (typeof window === undefined || typeof window === "undefined") return false;
    +  if (typeof window === "undefined") return false;
  • apps/web/core/hooks/use-local-storage.tsx

    -  if (typeof window === undefined || typeof window === "undefined") return defaultValue;
    +  if (typeof window === "undefined") return defaultValue;
    
    -  if (typeof window === undefined || typeof window === "undefined") return false;
    +  if (typeof window === "undefined") return false;
  • apps/web/core/lib/local-storage.ts

    -    if (typeof window === undefined || typeof window === "undefined" || !key || !value) return undefined;
    +    if (typeof window === "undefined" || !key || !value) return undefined;
    
    -    if (typeof window === undefined || typeof window === "undefined") return undefined;
    +    if (typeof window === "undefined") return undefined;
    
    -    if (typeof window === undefined || typeof window === "undefined" || !key) return undefined;
    +    if (typeof window === "undefined" || !key) return undefined;

To ensure no other occurrences remain, you can rerun:

#!/bin/bash
rg -nP 'typeof\s+\w+\s*===\s*undefined' -g '!**/node_modules/**'
apps/live/src/core/extensions/index.ts (2)

32-49: Promise never settles on error; remove async executor anti-pattern in fetch

Wrapping an async body in new Promise(async …) and only calling resolve results in a hung promise on exceptions. This can stall the document load indefinitely. Return/throw directly from an async function.

-        // TODO: Fix this lint error.
-        // eslint-disable-next-line no-async-promise-executor
-        return new Promise(async (resolve) => {
-          try {
-            let fetchedData = null;
-            if (documentType === "project_page") {
-              fetchedData = await fetchPageDescriptionBinary(params, pageId, cookie);
-            } else {
-              fetchedData = await fetchDocument({
-                cookie,
-                documentType,
-                pageId,
-                params,
-              });
-            }
-            resolve(fetchedData);
-          } catch (error) {
-            manualLogger.error("Error in fetching document", error);
-          }
-        });
+        try {
+          if (documentType === "project_page") {
+            return await fetchPageDescriptionBinary(params, pageId, cookie);
+          }
+          return await fetchDocument({
+            cookie,
+            documentType,
+            pageId,
+            params,
+          });
+        } catch (error) {
+          manualLogger.error("Error in fetching document", error);
+          throw error;
+        }

59-76: Same issue in store: promise never resolves/rejects; let the async function resolve naturally

If an exception occurs, the promise stays pending and the server may assume the store is still in-flight. Let the function complete or propagate the error so the caller can react.

-        // TODO: Fix this lint error.
-        // eslint-disable-next-line no-async-promise-executor
-        return new Promise(async () => {
-          try {
-            if (documentType === "project_page") {
-              await updatePageDescription(params, pageId, state, cookie);
-            } else {
-              await updateDocument({
-                cookie,
-                documentType,
-                pageId,
-                params,
-                updatedDescription: state,
-              });
-            }
-          } catch (error) {
-            manualLogger.error("Error in updating document:", error);
-          }
-        });
+        try {
+          if (documentType === "project_page") {
+            await updatePageDescription(params, pageId, state, cookie);
+          } else {
+            await updateDocument({
+              cookie,
+              documentType,
+              pageId,
+              params,
+              updatedDescription: state,
+            });
+          }
+        } catch (error) {
+          manualLogger.error("Error in updating document:", error);
+          throw error;
+        }
🧹 Nitpick comments (25)
packages/hooks/src/use-local-storage.tsx (4)

27-34: Route writes through the helper to handle SSR and quota errors uniformly

setValue directly uses window.localStorage without the guard/try-catch you already encapsulated in setValueIntoLocalStorage. Reusing it keeps behavior consistent and resilient (SSR-safe and handles quota/serialization failures).

Apply:

   const setValue = useCallback(
     (value: T) => {
-      window.localStorage.setItem(key, JSON.stringify(value));
-      setStoredValue(value);
-      window.dispatchEvent(new Event(`local-storage:${key}`));
+      if (setValueIntoLocalStorage(key, value)) {
+        setStoredValue(value);
+        window.dispatchEvent(new Event(`local-storage:${key}`));
+      }
     },
     [key]
   );

36-41: Add SSR guard to clearValue to prevent ReferenceError during SSR

While this hook is typically used client-side, guarding matches the pattern above and avoids surprises if invoked pre-mount.

Apply:

   const clearValue = useCallback(() => {
-    window.localStorage.removeItem(key);
-    setStoredValue(null);
-    window.dispatchEvent(new Event(`local-storage:${key}`));
+    if (typeof window !== "undefined") {
+      window.localStorage.removeItem(key);
+      setStoredValue(null);
+      window.dispatchEvent(new Event(`local-storage:${key}`));
+    }
   }, [key]);

47-52: Sync state across browser tabs with the native "storage" event (optional)

You already dispatch a custom event for in-tab updates. Listening to "storage" keeps multiple tabs in sync when the same key changes elsewhere.

Apply:

   useEffect(() => {
-    window.addEventListener(`local-storage:${key}`, reHydrate);
-    return () => {
-      window.removeEventListener(`local-storage:${key}`, reHydrate);
-    };
+    const onCustom = () => reHydrate();
+    const onStorage = (e: StorageEvent) => {
+      if (!e.key || e.key === key) reHydrate();
+    };
+    window.addEventListener(`local-storage:${key}`, onCustom);
+    window.addEventListener("storage", onStorage);
+    return () => {
+      window.removeEventListener(`local-storage:${key}`, onCustom);
+      window.removeEventListener("storage", onStorage);
+    };
   }, [key, reHydrate]);

24-26: Optional: consider returning T instead of T | null for a simpler consumer API

Today clearValue() sets storedValue to null even though reads default to initialValue when absent. If consumers rarely need nullability, you can simplify by keeping storedValue as T and setting initialValue on clear. If you like this direction, I can draft a minimal diff.

apps/admin/app/(all)/(dashboard)/email/page.tsx (2)

32-38: Good: catch param renamed to underscore without exposing error details to users

Keeping the toast generic is the right UX. If you have centralized logging (Sentry/etc.), consider capturing _error there to aid debugging.

Example:

} catch (_error) {
  // log/capture error for diagnostics
  // captureException?.(_error);
  setToast({ /* ... */ });
}

21-24: Guard against re-entrancy while submitting (optional)

The toggle is disabled during submit, but adding a quick check avoids accidental programmatic calls.

Apply:

   const handleToggle = async () => {
+    if (isSubmitting) return;
     if (isSMTPEnabled) {
       setIsSubmitting(true);
packages/ui/src/calendar.tsx (2)

21-21: Remove redundant weekStartsOn prop; it’s already included in ...props.

You pass weekStartsOn explicitly and then again via spread. Drop the explicit prop to avoid duplication.

-      weekStartsOn={props.weekStartsOn}

15-15: Variable name doesn’t match the value (Dec 31 vs “FirstDay”).

thirtyYearsFromNowFirstDay is actually December 31. Rename for clarity and update the usage.

-  const thirtyYearsFromNowFirstDay = new Date(currentYear + 30, 11, 31);
+  const thirtyYearsFromNowLastDay = new Date(currentYear + 30, 11, 31);
@@
-      endMonth={thirtyYearsFromNowFirstDay}
+      endMonth={thirtyYearsFromNowLastDay}

Also applies to: 81-81

apps/live/src/core/lib/authentication.ts (1)

24-24: Use new Error for consistency with other throws

Elsewhere in this codebase (and even in this file’s caller), new Error is used. Align here too.

-    throw Error("Authentication failed: Token doesn't match the current user.");
+    throw new Error("Authentication failed: Token doesn't match the current user.");
apps/live/src/core/hocuspocus-server.ts (2)

35-36: Prefer centralized logger over console.error

Use manualLogger for consistency and to keep logs flowing through the same sink.

-        console.error("Token parsing failed, using request headers:", error);
+        manualLogger.error("Token parsing failed, using request headers:", error);

Add this import at the top with the other core imports:

import { manualLogger } from "@/core/helpers/logger.js";

56-56: Minor: throw new Error (match the style used above at Line 44)

-        throw Error("Authentication unsuccessful!");
+        throw new Error("Authentication unsuccessful!");
apps/admin/core/components/authentication/email-config-switch.tsx (2)

28-30: Simplify toggle logic and avoid parseInt; compare string flags directly

Comparing against the string literal is clearer and avoids numeric parsing edge cases. Also drop the redundant === true.

Apply within this hunk:

-        const newEnableMagicLogin = Boolean(parseInt(enableMagicLogin)) === true ? "0" : "1";
+        const newEnableMagicLogin = enableMagicLogin === "1" ? "0" : "1";

Optionally (outside this hunk) also simplify the value prop:

// before
value={Boolean(parseInt(enableMagicLogin))}
// after
value={enableMagicLogin === "1"}

28-30: Consider centralizing the "0"/"1" toggle pattern to a small helper

This string-flag toggle appears across multiple auth components. A tiny util like toggle01(value: string): "0" | "1" improves consistency and reduces repetition.

Example helper (outside this hunk):

export const toggle01 = (v: string) => (v === "1" ? "0" : "1");

Then in the handler:

-        const newEnableMagicLogin = enableMagicLogin === "1" ? "0" : "1";
+        const newEnableMagicLogin = toggle01(enableMagicLogin);
apps/admin/core/components/authentication/google-config.tsx (3)

38-40: Prefer direct string comparison over parseInt in toggles

Removes unnecessary parsing and redundant === true.

-              const newEnableGoogleConfig = Boolean(parseInt(enableGoogleConfig)) === true ? "0" : "1";
+              const newEnableGoogleConfig = enableGoogleConfig === "1" ? "0" : "1";

Optional (outside this hunk) align the value prop:

value={enableGoogleConfig === "1"}

38-40: Extract a shared 0/1 toggle helper to reduce duplication across auth switches

Same pattern exists in GitHub, GitLab, Email codes, and Password toggles.

-              const newEnableGoogleConfig = enableGoogleConfig === "1" ? "0" : "1";
+              const newEnableGoogleConfig = toggle01(enableGoogleConfig);

Where toggle01 is the small helper suggested in a prior comment.


38-40: Leverage ToggleSwitch’s boolean onChange for direct mapping

You can simplify the Google config toggle by using the checked: boolean parameter that ToggleSwitch already provides, instead of manually parsing and re-stringifying the config value.

• File: apps/admin/core/components/authentication/google-config.tsx
Lines: ~38–40

Suggested diff:

-              const newEnableGoogleConfig = Boolean(parseInt(enableGoogleConfig)) === true ? "0" : "1";
-              updateConfig("IS_GOOGLE_ENABLED", newEnableGoogleConfig);
+              <ToggleSwitch
+                value={enableGoogleConfig === "1"}
+                onChange={(checked: boolean) => updateConfig("IS_GOOGLE_ENABLED", checked ? "1" : "0")}
+                /* ...other props... */
+              />

This change:

  • Removes unnecessary parseInt + Boolean conversions.
  • Directly maps the checked boolean to "1"/"0".
apps/admin/core/components/authentication/gitlab-config.tsx (3)

38-40: Use string comparison to toggle instead of parseInt and redundant === true

Keeps intent explicit and avoids numeric parsing.

-              const newEnableGitlabConfig = Boolean(parseInt(enableGitlabConfig)) === true ? "0" : "1";
+              const newEnableGitlabConfig = enableGitlabConfig === "1" ? "0" : "1";

Optional (outside this hunk):

value={enableGitlabConfig === "1"}

38-40: Consider reusing a tiny toggle01 helper across all auth toggles

Prevents repeating the same conditional everywhere.

-              const newEnableGitlabConfig = enableGitlabConfig === "1" ? "0" : "1";
+              const newEnableGitlabConfig = toggle01(enableGitlabConfig);

38-40: Leverage ToggleSwitch’s onChange signature to simplify config update

  • File: apps/admin/core/components/authentication/gitlab-config.tsx (around lines 38–40)

Replace the current handler, which parses the previous state, with a direct use of the checked boolean that ToggleSwitch provides:

- onChange={() => {
-   const newEnableGitlabConfig = Boolean(parseInt(enableGitlabConfig)) === true ? "0" : "1";
-   updateConfig("IS_GITLAB_ENABLED", newEnableGitlabConfig);
- }}
+ onChange={(checked: boolean) => 
+   updateConfig("IS_GITLAB_ENABLED", checked ? "1" : "0")
+ }

This removes the need to parse the existing string value, computing the new config directly from the boolean you already receive.

apps/admin/core/components/authentication/github-config.tsx (3)

38-40: Tighten logic: drop parseInt and redundant comparison

String flag comparison is clearer.

-              const newEnableGithubConfig = Boolean(parseInt(enableGithubConfig)) === true ? "0" : "1";
+              const newEnableGithubConfig = enableGithubConfig === "1" ? "0" : "1";

Optional (outside this hunk):

value={enableGithubConfig === "1"}

38-40: De-duplicate with a shared toggle01 helper

Same micro-pattern across all four providers and password/email codes.

-              const newEnableGithubConfig = enableGithubConfig === "1" ? "0" : "1";
+              const newEnableGithubConfig = toggle01(enableGithubConfig);

38-40: Simplify onChange handler by using ToggleSwitch’s boolean parameter

ToggleSwitch’s API defines onChange: (value: boolean) => void (see packages/ui/src/button/toggle-switch.tsx), so your handler can receive the new boolean directly instead of re-reading enableGithubConfig.

Changes needed in apps/admin/core/components/authentication/github-config.tsx:

  • Remove manual Boolean(parseInt(enableGithubConfig)) checks.
  • Accept the boolean argument (checked) in your onChange.
  • Convert checked to "1" or "0" when calling updateConfig.

Suggested diff:

--- a/apps/admin/core/components/authentication/github-config.tsx
+++ b/apps/admin/core/components/authentication/github-config.tsx
@@ -36,8 +36,7 @@ export const GithubConfigSwitch = () => {
     <ToggleSwitch
       value={Boolean(parseInt(enableGithubConfig))}
-      onChange={() => {
-        const newEnableGithubConfig = Boolean(parseInt(enableGithubConfig)) === true ? "0" : "1";
-        updateConfig("IS_GITHUB_ENABLED", newEnableGithubConfig);
-      }}
+      onChange={(checked: boolean) => updateConfig("IS_GITHUB_ENABLED", checked ? "1" : "0")}
       size="sm"
     />

This removes unnecessary state probing and makes the handler clearer.

apps/admin/core/components/authentication/password-config-switch.tsx (3)

28-30: Prefer direct string comparison and remove redundant === true

Avoids unnecessary numeric parsing and clarifies intent.

-        const newEnableEmailPassword = Boolean(parseInt(enableEmailPassword)) === true ? "0" : "1";
+        const newEnableEmailPassword = enableEmailPassword === "1" ? "0" : "1";

Optional (outside this hunk):

value={enableEmailPassword === "1"}

28-30: Optional: centralize the flip logic via a helper

Keeps all toggles uniform and easier to unit test.

-        const newEnableEmailPassword = enableEmailPassword === "1" ? "0" : "1";
+        const newEnableEmailPassword = toggle01(enableEmailPassword);

28-30: Simplify ToggleSwitch onChange handler

ToggleSwitch’s onChange callback already receives the new boolean state, so you can drop the manual parsing/toggling logic and derive the config value directly.

• File: apps/admin/core/components/authentication/password-config-switch.tsx (around lines 28–30)
• Signature in packages/ui/src/button/toggle-switch.tsx:

interface IToggleSwitchProps {
  value: boolean;
  onChange: (value: boolean) => void;
  
}

Suggested change:

-        onChange={() => {
-          const newEnableEmailPassword = Boolean(parseInt(enableEmailPassword)) === true ? "0" : "1";
-          updateConfig("ENABLE_EMAIL_PASSWORD", newEnableEmailPassword);
-        }}
+        onChange={(checked: boolean) =>
+          updateConfig("ENABLE_EMAIL_PASSWORD", checked ? "1" : "0")
+        }

This removes the extra parsing/Boolean conversion and makes the intent clearer.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between b223cd4 and 190beae.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • apps/admin/app/(all)/(dashboard)/email/page.tsx (2 hunks)
  • apps/admin/core/components/authentication/email-config-switch.tsx (1 hunks)
  • apps/admin/core/components/authentication/github-config.tsx (1 hunks)
  • apps/admin/core/components/authentication/gitlab-config.tsx (1 hunks)
  • apps/admin/core/components/authentication/google-config.tsx (1 hunks)
  • apps/admin/core/components/authentication/password-config-switch.tsx (1 hunks)
  • apps/admin/core/store/instance.store.ts (1 hunks)
  • apps/live/src/core/extensions/index.ts (1 hunks)
  • apps/live/src/core/hocuspocus-server.ts (1 hunks)
  • apps/live/src/core/lib/authentication.ts (1 hunks)
  • apps/live/src/server.ts (1 hunks)
  • packages/hooks/src/use-local-storage.tsx (2 hunks)
  • packages/ui/src/auth-form/auth-form.tsx (1 hunks)
  • packages/ui/src/calendar.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • apps/admin/core/store/instance.store.ts
  • apps/live/src/server.ts
  • packages/ui/src/auth-form/auth-form.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-14T11:22:43.964Z
Learnt from: gakshita
PR: makeplane/plane#7393
File: apps/admin/app/(all)/(dashboard)/email/email-config-form.tsx:104-104
Timestamp: 2025-07-14T11:22:43.964Z
Learning: In the Plane project's SMTP configuration implementation, the email configuration form (email-config-form.tsx) hardcodes ENABLE_SMTP to "1" in form submission because the form is only rendered when SMTP is enabled. The enable/disable functionality is managed at the page level (page.tsx) with a toggle, and the form only handles configuration details when SMTP is already enabled.

Applied to files:

  • apps/admin/core/components/authentication/email-config-switch.tsx
  • apps/admin/core/components/authentication/password-config-switch.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
packages/hooks/src/use-local-storage.tsx (2)

8-11: Catch param rename is correct and consistent with linting conventions

Using _error communicates intentional non-use and silences no-unused-vars. No functional changes introduced.


19-21: Same here — good unused error handling

Consistent with the pattern across the PR; behavior remains unchanged.

apps/admin/app/(all)/(dashboard)/email/page.tsx (1)

12-12: Confirm React.FC usage for MobX observer components

Based on a quick scan of the codebase, we currently have:

  • 592 components annotated with React.FC
  • 235 components wrapped in observer(...)
  • Only 54 observer-wrapped components explicitly annotated as React.FC

This indicates a mixed pattern: most observer components rely on type inference, while a subset use the React.FC annotation. If consistency is a goal for this PR, please confirm which convention we should follow:

  • Adopt React.FC for all observer-wrapped components
  • Avoid React.FC on observer components and rely on inference
  • Allow both patterns but document the rationale in our style guide

Once decided, we can either update this page.tsx or align the rest of the codebase in a follow-up.

apps/live/src/core/lib/authentication.ts (1)

3-4: LGTM: import reorg is clean and consistent with ESM/.js paths

No runtime impact. Keeping services under a dedicated header improves scan-ability.

apps/live/src/core/hocuspocus-server.ts (1)

5-9: LGTM: import restructuring aligns editor events, extensions, and lib imports

Centralizing editor event types and moving core imports here reads better; no behavioral change.

apps/admin/core/components/authentication/email-config-switch.tsx (2)

28-30: LGTM on consolidating the toggle update into a single updateConfig call

This refactor removes duplicated calls and keeps the handler concise. Behavior remains unchanged.


28-30: Please confirm the ToggleSwitch onChange signature

It looks like the rg search didn’t locate the ToggleSwitch declaration (likely because it lives in @plane/ui’s distributed types). Could you manually inspect the type definitions in your node_modules/@plane/ui package (for example, in dist/index.d.ts or wherever ToggleSwitch is exported) and verify whether the onChange prop is declared as (checked: boolean) => void?

If it is, you can simplify your handler as follows:

- onChange={() => {
-   const newEnableMagicLogin = Boolean(parseInt(enableMagicLogin)) === true ? "0" : "1";
-   updateConfig("ENABLE_MAGIC_LINK_LOGIN", newEnableMagicLogin);
- }}
+ onChange={(checked: boolean) =>
+   updateConfig("ENABLE_MAGIC_LINK_LOGIN", checked ? "1" : "0")
+ }
apps/admin/core/components/authentication/google-config.tsx (1)

38-40: LGTM on reducing duplicate updateConfig calls

One computation + one update keeps the handler tidy; behavior is preserved.

apps/admin/core/components/authentication/gitlab-config.tsx (1)

38-40: LGTM; single-source-of-truth for the new value is clearer

Nice reduction from two branches to one computed value + one update.

apps/admin/core/components/authentication/github-config.tsx (1)

38-40: LGTM; handler now does a single, deterministic update

Refactor improves readability and avoids duplicate updateConfig calls.

apps/admin/core/components/authentication/password-config-switch.tsx (1)

28-30: LGTM; single update path is cleaner

Keeps the toggle handler straightforward and consistent with other auth configs.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 190beae and 3cf6c9d.

📒 Files selected for processing (14)
  • apps/live/.eslintrc.js (1 hunks)
  • apps/live/.eslintrc.json (0 hunks)
  • apps/space/.eslintrc.js (0 hunks)
  • apps/web/.eslintrc.js (0 hunks)
  • packages/constants/.eslintrc.js (0 hunks)
  • packages/decorators/.eslintrc.js (0 hunks)
  • packages/hooks/.eslintrc.js (0 hunks)
  • packages/i18n/.eslintrc.js (0 hunks)
  • packages/logger/.eslintrc.js (0 hunks)
  • packages/propel/.eslintrc.js (0 hunks)
  • packages/services/.eslintrc.js (0 hunks)
  • packages/shared-state/.eslintrc.js (0 hunks)
  • packages/ui/.eslintrc.js (0 hunks)
  • packages/utils/.eslintrc.js (0 hunks)
💤 Files with no reviewable changes (13)
  • packages/ui/.eslintrc.js
  • packages/services/.eslintrc.js
  • packages/shared-state/.eslintrc.js
  • packages/decorators/.eslintrc.js
  • apps/web/.eslintrc.js
  • packages/hooks/.eslintrc.js
  • packages/logger/.eslintrc.js
  • packages/constants/.eslintrc.js
  • packages/propel/.eslintrc.js
  • apps/live/.eslintrc.json
  • packages/utils/.eslintrc.js
  • apps/space/.eslintrc.js
  • packages/i18n/.eslintrc.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/live/.eslintrc.js (2)

1-4: LGTM — minimal config correctly delegates to shared server rules.
Root flag + single extend is aligned with the PR objective of centralizing the TS parser in the base config.


3-3: I've added a script to locate and inspect the @plane/eslint-config package’s package.json so we can verify if it exports a server entrypoint without the .js suffix. Once we review that export configuration, we can confirm whether dropping the .js is safe or not.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/live/.eslintrc.cjs (1)

3-3: Prefer shareable-config subpath without file extension

Referencing the package subpath without “.js” reduces coupling to the package’s internal file layout and export map.

-  extends: ["@plane/eslint-config/server.js"],
+  extends: ["@plane/eslint-config/server"],
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 3cf6c9d and 7229f95.

📒 Files selected for processing (1)
  • apps/live/.eslintrc.cjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/live/.eslintrc.cjs (2)

1-4: Centralizing the TS parser via shared config looks good

Straightforward switch to the shared server config; aligns with the PR goal to remove local parser settings. Using .cjs and root: true here is consistent with classic ESLint configs.


1-4: Parser Inheritance Confirmed

The shared ESLint config in packages/eslint-config (server.js, library.js, next.js) explicitly declares parser: "@typescript-eslint/parser", and there are no local parser overrides in apps/live/.eslintrc.cjs. The TypeScript parser will be correctly applied.

@sriramveeraghanta sriramveeraghanta merged commit 0e6fbae into preview Aug 27, 2025
6 of 7 checks passed
@sriramveeraghanta sriramveeraghanta deleted the fix-eslint-parser branch August 27, 2025 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants