From 91f9f4430eb2f9612481774906ced368727bd641 Mon Sep 17 00:00:00 2001 From: Miodec Date: Sun, 3 May 2026 13:14:03 +0200 Subject: [PATCH 1/2] impr(chart component): remove unnecessary theme effect, defer data effect !nuf --- frontend/src/ts/components/common/ChartJs.tsx | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/frontend/src/ts/components/common/ChartJs.tsx b/frontend/src/ts/components/common/ChartJs.tsx index 916fb539eee2..bb59d87658bb 100644 --- a/frontend/src/ts/components/common/ChartJs.tsx +++ b/frontend/src/ts/components/common/ChartJs.tsx @@ -15,10 +15,6 @@ import { createEffectOn } from "../../hooks/effects"; import { useRefWithUtils } from "../../hooks/useRefWithUtils"; import { getTheme } from "../../states/theme"; -function getThemeHash(): string { - return Object.values(getTheme()).join(""); -} - Chart.register(chartTrendline); type ChartJSProps< T extends ChartType = ChartType, @@ -38,7 +34,6 @@ export function ChartJs>( const [canvasRef, canvasEl] = useRefWithUtils(); let chart: Chart | undefined; - let theme = ""; onMount(() => { const canvas = canvasEl(); @@ -50,7 +45,6 @@ export function ChartJs>( data: props.data, options: addColorsToOptions(props.options as ChartOptions, getTheme), }); - theme = getThemeHash(); props.onChartInit?.(chart); }); @@ -68,15 +62,7 @@ export function ChartJs>( const deferredData = createDeferred(() => props.data, { timeoutMs: 500 }); - createEffectOn(deferredData, (data) => updateChart(data)); - - createEffectOn(getTheme, () => { - if (!chart) return; - const newTheme = getThemeHash(); - if (theme === newTheme) return; - theme = newTheme; - updateChart(deferredData()); - }); + createEffectOn(deferredData, (data) => updateChart(data), { defer: true }); onCleanup(() => { chart?.destroy(); From 513234c6834a1d7b836ebc81c70c46602a9c5e0a Mon Sep 17 00:00:00 2001 From: Miodec Date: Mon, 20 Apr 2026 16:15:03 +0200 Subject: [PATCH 2/2] chore: add lint rule protecting against using legacy code in components --- packages/oxlint-config/plugin.jsonc | 1 + .../oxlint-config/plugins/monkeytype-rules.js | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/oxlint-config/plugin.jsonc b/packages/oxlint-config/plugin.jsonc index ce2f5f308877..ce9537ba0ac0 100644 --- a/packages/oxlint-config/plugin.jsonc +++ b/packages/oxlint-config/plugin.jsonc @@ -24,6 +24,7 @@ { "files": ["**/*.tsx"], "rules": { + "monkeytype-rules/no-non-reactive-access-in-components": "error", "monkeytype-rules/prefer-arrow-in-component": "error", "monkeytype-rules/one-component-per-file": "error", "monkeytype-rules/component-pascal-case": "error", diff --git a/packages/oxlint-config/plugins/monkeytype-rules.js b/packages/oxlint-config/plugins/monkeytype-rules.js index 82fb3b5cf6ef..0da96cb2f685 100644 --- a/packages/oxlint-config/plugins/monkeytype-rules.js +++ b/packages/oxlint-config/plugins/monkeytype-rules.js @@ -83,6 +83,47 @@ const plugin = { }; }, }), + "no-non-reactive-access-in-components": defineRule({ + createOnce(context) { + const getComponentAncestor = (node) => { + let current = node.parent; + while (current) { + // function Foo() { return <...> } + if ( + current.type === "FunctionDeclaration" && + containsJSXReturn(current.body) + ) { + return current.id?.name ?? "component"; + } + // const Foo = () => { return <...> } or const Foo = function() { return <...> } + if ( + (current.type === "ArrowFunctionExpression" || + current.type === "FunctionExpression") && + containsJSXReturn(current.body ?? current) && + current.parent?.type === "VariableDeclarator" + ) { + return current.parent.id?.name ?? "component"; + } + current = current.parent; + } + return null; + }; + + return { + MemberExpression(node) { + if (node.object?.name === "__nonReactive") { + const componentName = getComponentAncestor(node); + if (componentName) { + context.report({ + node, + message: `__nonReactive should not be accessed in component \`${componentName}\`.`, + }); + } + } + }, + }; + }, + }), "prefer-arrow-in-component": defineRule({ meta: { hasSuggestions: true,