Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 20, 2026

Node 20 linting surfaced missing import rule config, unsafe ref access during render, render-time component creation, setState-in-effect patterns, and unused-expression issues across tests and components.

  • Tests & typing: Removed unnecessary eslint disable in ResponsiveDataTable.test.tsx and replaced any cast in routing tests with typed RESOURCE_TYPE.
  • Worker cleanup: Simplified worker teardown with optional chaining to avoid unused-expression lint hits.
  • Hidden component: Forwarded refs directly to MuiHidden to avoid accessing refs during render.
  • Catalog tables: Normalized optional callback invocation with setSearch?.(...).
  • Challenges/Learning sections: Derived open state from data without synchronous effects and unified challenge data source handling.
  • Static icons: Inlined icon selection instead of defining components inside render in content class info and catalog card logo.
  • Flip card: Used optional chaining for callbacks to satisfy lint rules.

Example:

const renderSvg =
  type.type === 'filter'
    ? <MesheryFilterIcon width={width} height={height} style={style} />
    : <DesignIcon width={width} height={height} style={style} />;

return imgURL?.length
  ? (!imgError ? /* image + dialog */ : renderSvg)
  : renderSvg;
Original prompt

Node 20 lint checks. Fix these lint errors. See https://github.com/layer5io/sistent/actions/runs/21158045193/job/60849181565?pr=1239

/home/runner/work/sistent/sistent/src/testing/ResponsiveDataTable.test.tsx
Error: 53:1 error Definition for rule 'import/first' was not found import/first

/home/runner/work/sistent/sistent/src/testing/routing.test.ts
Error: 46:56 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any

/home/runner/work/sistent/sistent/src/actors/worker/workerfy.ts
Error: 74:7 error Expected an assignment or function call and instead saw an expression @typescript-eslint/no-unused-expressions
Error: 75:7 error Expected an assignment or function call and instead saw an expression @typescript-eslint/no-unused-expressions

/home/runner/work/sistent/sistent/src/base/Hidden/Hidden.tsx
5:55 error Error: Cannot access refs during render

React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the current property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef).

/home/runner/work/sistent/sistent/src/base/Hidden/Hidden.tsx:5:55
3 |
4 | export const Hidden = React.forwardRef<HTMLDivElement, MuiHiddenProps>((props, ref) => {

5 | return React.cloneElement(<MuiHidden {...props} />, { ref });
| ^^^^^^^ Passing a ref to a function may read its value during render
6 | });
7 |
8 | export default Hidden; react-hooks/refs

/home/runner/work/sistent/sistent/src/custom/CatalogDesignTable/CatalogDesignTable.tsx
Error: 75:11 error Expected an assignment or function call and instead saw an expression @typescript-eslint/no-unused-expressions

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/ChallengesSection.tsx
22:7 error Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:

  • Update external systems with the latest state from React.
  • Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/ChallengesSection.tsx:22:7
20 | useEffect(() => {
21 | if (autoUpdate) {

22 | setOpenChallenges((filteredAcademyData?.['challenges'] ?? []).length > 0);
| ^^^^^^^^^^^^^^^^^ Avoid calling setState() directly within an effect
23 | }
24 | }, [filteredAcademyData, autoUpdate]);
25 | react-hooks/set-state-in-effect

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/ContentClassInfo.tsx
64:10 error Error: Cannot create components during render

Components created during render will reset their state each time they are created. Declare components outside of render.

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/ContentClassInfo.tsx:64:10
62 | }}
63 | >

64 |
| ^^^^^^^^^ This component is created during render
65 | {formatToTitleCase(contentClass)}
66 |
67 |

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/ContentClassInfo.tsx:38:54
36 | } as const;
37 |

38 | const ClassIcon: React.FC<{ className: string }> = ({ className }) => {
| ^^^^^^^^^^^^^^^^^^^^
39 | const Icon = CONTENT_CLASS[className]?.icon;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40 | const fill = CONTENT_CLASS[className]?.color;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41 | return Icon ? : null;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42 | };
| ^^^^ The component is created during render here
43 |
44 | return (
45 |

react-hooks/static-components

/home/runner/work/sistent/sistent/src/custom/CatalogDetail/LearningSection.tsx
22:7 error Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:

  • Update external systems with the latest state from React.
  • Subscribe for updates from some external system, calling se...

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 20, 2026 03:59
Co-authored-by: hortison <160366376+hortison@users.noreply.github.com>
Co-authored-by: hortison <160366376+hortison@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix lint checks for Node 20 in test files Fix Node 20 lint violations and React hook warnings Jan 20, 2026
Copilot AI requested a review from hortison January 20, 2026 04:04
@hortison hortison marked this pull request as ready for review January 20, 2026 04:08
Copilot AI review requested due to automatic review settings January 20, 2026 04:08
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 fixes Node 20 lint violations and React hook warnings by addressing missing import rules, unsafe ref access, render-time component creation, setState-in-effect patterns, and unused-expression issues.

Changes:

  • Removed unnecessary eslint disable comments and improved type safety in tests
  • Simplified worker cleanup and callback invocation with optional chaining
  • Fixed ref forwarding in Hidden component to avoid accessing refs during render
  • Removed setState-in-effect patterns by deriving open state from data
  • Inlined icon/SVG selection to prevent component creation during render

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ResponsiveDataTable.test.tsx Removed unnecessary eslint disable comment for import/first rule
routing.test.ts Replaced any cast with more specific unknown as RESOURCE_TYPE cast
workerfy.ts Added optional chaining for worker cleanup method calls
Hidden.tsx Fixed ref forwarding by passing ref directly to MuiHidden
CatalogDesignTable.tsx Used optional chaining for setSearch callback invocation
ChallengesSection.tsx Derived isOpen state from data to avoid setState-in-effect
LearningSection.tsx Derived isOpen state from data to avoid setState-in-effect
ContentClassInfo.tsx Inlined icon rendering to avoid creating components during render
CatalogCardDesignLogo.tsx Inlined SVG selection logic instead of creating component
FlipCard.tsx Used optional chaining for onClick and onShow callbacks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const toggleOpenLearning = (): void => {
setOpenLearning((prev) => !prev);
setAutoUpdate(false);
setOpenLearning(!isOpen);
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The toggle logic has a race condition. When toggling, setOpenLearning(!isOpen) uses the value of isOpen which is derived from autoUpdate and other state. If autoUpdate is true when the function runs, isOpen will be hasLearning, not openLearning. This means the toggle won't work correctly after the first click. The fix should read the previous state value: setOpenLearning((prev) => !prev) to ensure proper toggle behavior.

Suggested change
setOpenLearning(!isOpen);
setOpenLearning((prev) => !prev);

Copilot uses AI. Check for mistakes.
const toggleOpenChallenges = () => {
setOpenChallenges((prev) => !prev);
setAutoUpdate(false);
setOpenChallenges(!isOpen);
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The toggle logic has a race condition. When toggling, setOpenChallenges(!isOpen) uses the value of isOpen which is derived from autoUpdate and other state. If autoUpdate is true when the function runs, isOpen will be hasChallenges, not openChallenges. This means the toggle won't work correctly after the first click. The fix should read the previous state value: setOpenChallenges((prev) => !prev) to ensure proper toggle behavior.

Suggested change
setOpenChallenges(!isOpen);
setOpenChallenges((prev) => !prev);

Copilot uses AI. Check for mistakes.
if (event.data.type === WORKER_COMMANDS.STOP_ACTOR) {
snapshotSubscription?.unsubscribe && snapshotSubscription.unsubscribe();
actorRef?.stop && actorRef.stop();
snapshotSubscription?.unsubscribe?.();
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The double optional chaining ?.unsubscribe?.() is unnecessary. The Subscription type from xstate guarantees that unsubscribe is a method on the object. Since snapshotSubscription can be null, only the first optional chaining is needed: snapshotSubscription?.unsubscribe(). The second optional chaining adds no value and suggests the method might not exist, which is not the case.

Suggested change
snapshotSubscription?.unsubscribe?.();
snapshotSubscription?.unsubscribe();

Copilot uses AI. Check for mistakes.
snapshotSubscription?.unsubscribe && snapshotSubscription.unsubscribe();
actorRef?.stop && actorRef.stop();
snapshotSubscription?.unsubscribe?.();
actorRef?.stop?.();
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The double optional chaining ?.stop?.() is unnecessary. The AnyActorRef type from xstate guarantees that stop is a method on the object. Since actorRef can be null, only the first optional chaining is needed: actorRef?.stop(). The second optional chaining adds no value and suggests the method might not exist, which is not the case.

Suggested change
actorRef?.stop?.();
actorRef?.stop();

Copilot uses AI. Check for mistakes.
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.

2 participants