Skip to content

[ENHANCEMENT] Upgrade Oxlint and fix React Compiler errors - #826

Merged
Gladorme merged 9 commits into
perses:mainfrom
Gladorme:t3code/upgrade-oxlint-oxfmt-fix-react-memo
Oct 7, 2026
Merged

Gladorme merged 9 commits into
perses:mainfrom
Gladorme:t3code/upgrade-oxlint-oxfmt-fix-react-memo

Conversation

@Gladorme

@Gladorme Gladorme commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

Description

Enforcing stricter rules around React to be compliant with React Compiler rules (https://oxc.rs/blog/2026-08-18-react-compiler-support)

Screenshots

User-facing fixes

  • Prometheus (query tree view): the tree connector lines now update when a node or its parent changes size. Before, they were placed only once on mount, so they could end up misaligned. Switching a connector's direction also now clears the old border style, so you no longer get both a top and a bottom border.
  • Prometheus (query tree view): when a node's instant query doesn't succeed, its stats (series count, label examples, cardinalities) reset to empty. Before, it kept showing stats from the last successful result.
  • Table: the filter row now stays lined up with the columns after the table rebuilds its header row. That happens when the panel is resized, or when rows, columns, selection or action buttons change. Before, the width sync kept watching the old header row that was no longer on the page, so later changes stopped re-syncing.
  • PieChart: the chart now resizes to the panel's exact width and height (resize({ width, height })), instead of letting ECharts measure the container itself.
  • Tracing Gantt chart: the divider now accounts for the gap between columns even on the first render. Before, the gap was read during the parent's render, before the element existed, so the first drag ignored it. The gap is now read once each time a drag starts.

Behavior-preserving changes

  • Text fields (Alertmanager, Jaeger, Tempo, VictoriaLogs): fields that keep a draft value now reset it during render when the incoming value changes, instead of in an effect. This removes the short moment where the field showed the old value.
  • Alertmanager columns editor: the ids used to track columns are now kept in React state, so each column keeps its own editor state when you move, remove or add columns. New tests cover this.
  • Time series query settings: a newly added query setting is focused through a callback ref, instead of an effect that ran on every render.

Checklist

  • Pull request has a descriptive title and context useful to a reviewer.
  • Pull request title follows the [<catalog_entry>] <commit message> naming convention using one of the
    following catalog_entry values: FEATURE, ENHANCEMENT, BUGFIX, BREAKINGCHANGE, DOC,IGNORE.
  • All commits have DCO signoffs.

UI Changes

  • Changes that impact the UI include screenshots and/or screencasts of the relevant changes.
  • Code follows the UI guidelines.

@Gladorme
Gladorme force-pushed the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch 4 times, most recently from dd32ad4 to 3acf811 Compare September 23, 2026 12:13
@Gladorme Gladorme changed the title [IGNORE] Upgrade Oxlint and fix React Compiler errors [ENHANCEMENT] Upgrade Oxlint and fix React Compiler errors Sep 23, 2026
@Gladorme
Gladorme marked this pull request as ready for review September 23, 2026 12:32
@Gladorme
Gladorme requested review from a team and andreasgerstmayr as code owners September 23, 2026 12:32
@Gladorme
Gladorme requested review from shahrokni and removed request for a team September 23, 2026 12:32
@Gladorme
Gladorme force-pushed the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch from d20d706 to 495ee90 Compare September 23, 2026 22:52
@Gladorme Gladorme changed the title [ENHANCEMENT] Upgrade Oxlint and fix React Compiler errors [IGNORE] Upgrade Oxlint and fix React Compiler errors Sep 23, 2026
@Gladorme
Gladorme force-pushed the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch 3 times, most recently from ea19e05 to 844d19f Compare September 25, 2026 09:07
@Gladorme
Gladorme force-pushed the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch from 844d19f to 286ab07 Compare October 1, 2026 15:05
@Gladorme

Gladorme commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

Should fix

1. Table filter row can drift out of line with the columns — TablePanel.tsx

  • What changed: the effect that matches filter-cell widths to header widths dropped contentDimensions, selectionEnabled and actionButtons from its dependencies. Those were added on purpose by the earlier alignment bugfix ([BUGFIX] Table: align filter rows with table columns  #755).
  • Why it matters: the shared VirtualizedTable rebuilds its table component whenever width or rows change, so the <thead><tr> element gets replaced. The ResizeObserver is still watching the old, detached headerRow, so later panel resizes or turning selection/actions on or off stop re-syncing the widths.
  • Likely limited impact at first: removing the old row probably triggers one last callback, so the first rebuild still re-syncs. After that, nothing does.
  • Suggested fix: watch something that stays put (the .MuiTableContainer-root scroll container) and look up thead tr th inside the callback. A MutationObserver for replaced rows would also work, or put the dependencies back.
  • The scroll-sync effect is fine: its scroll container is a stable component and stays mounted.

Minor

2. Missing equality check in ListboxComponent — FilterInputs.tsx

  • The inline ref callback runs on every commit and now always calls setMaxHeight. The old code only updated when the value changed.
  • React usually skips same-value updates, so this won't loop. Still, put back if (measuredMaxHeight && measuredMaxHeight !== maxHeight) to avoid extra renders.

3. Focus effect with no dependencies — QuerySettingsEditor.tsx

  • The focus effect now has no dependency array, so it runs after every render. The focusRef guard keeps it correct.
  • A callback ref on the newly added input would be cleaner.

4. Behavior changes that go beyond lint fixes — TreeNode.tsx, PieChartBase.tsx

  • In TreeNode, connectors are now positioned by a ResizeObserver, and the result stats reset to zero on a non-success response instead of keeping the last ones. In PieChartBase, resize({ width, height }) is new.
  • These are reasonable, but neither the PR description nor the commit message explains them. Mention them in the description.

Looks good

  • Draft fields: the LazyTextField and LazyTextInput copies, the Jaeger and VictoriaLogs query editors, and the alertmanager ColumnsEditor now update their state during render instead of in an effect. Each update is guarded so it can't loop. ColumnsEditor keeps an id per column through move, remove and add, and it's covered by new tests.
  • TimeSeriesChartBase pin logic: it behaves the same as the old effect, including on first mount.
  • Small syntax workarounds: moving try/finally into downloadCsv and .then().finally(), and swapping ??= for x = x ?? [], are fine workarounds for syntax the React Compiler can't handle yet.
  • useId: switching from the Perses useId to React's useId is safe, since nothing outside the component depends on the generated ids.
  • ResizableDivider: it now reads the gap from the DOM itself. GanttTable's container has no gap, so its result is still 0.

@Nexucis Nexucis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 This review was written by GitHub Copilot (an AI coding assistant) and posted by @Nexucis, who asked for it. It is based on the diff at a5119b8 plus checks against the PR branch and the published @perses-dev/components / @perses-dev/plugin-system packages. Please read it as AI-generated feedback, not as a maintainer decision.

Summary

Overall this is a good cleanup. CI is green, and the points from the earlier self-review are fixed in a5119b8. I found nothing that should block merging. Item 1 is a behavior change, and item 2 is a policy question worth discussing.

Should address

1. table/.../EmbeddedPanelOptionsEditor.tsx: the effect now re-runs on every parent render
The latest-ref pattern was replaced by putting onChange in the effect deps. The only caller (ColumnEditor.tsx) passes an inline arrow, so while the spec is empty the effect re-runs (and calls onChange, capturing the current column) on every ColumnEditor render. If the parent applies updates asynchronously, this can overwrite concurrent edits. @perses-dev/plugin-system already exports useEvent, which is compiler-safe because it updates the ref in a layout effect. ResizableDivider already uses it, and it keeps the old behavior:

const handleChange = useEvent(onChange);
useEffect(() => {
  if (!panelPlugin || !isSpecEmpty(spec)) return;
  handleChange(mergeWithPluginDefaults(panelPlugin, spec));
}, [panelPlugin, spec, handleChange]);

2. .oxlintrc.json: should react/todo be "error"?
todo reports React Compiler limitations, not incorrect code. The compiler is not actually enabled in the build: there is no babel-plugin-react-compiler or compiler option in rsbuild.shared.ts or the lockfile. Making todo an error is what forced these rewrites, which have no runtime benefit today:

  • ??= rewritten as x = x ?? []
  • try/finally moved out into downloadCsv
  • try/catch turned into a .then().catch().finally() chain

Suggest "warn" until the compiler is turned on. Note that the rest of the config is complete: refs, set-state-in-render, set-state-in-effect, purity and immutability are already errors through categories.correctness: "error".

3. PR hygiene

  • The title is [IGNORE], but the PR has fixes users will notice:

    • TreeNode connectors now follow resizes and reset the opposite border style.
    • PieChart now calls resize({ width, height }).
    • The table filter row stays aligned after the header row is replaced.
    • The Gantt divider gap is correct on the first render.

    Consider [BUGFIX]/[ENHANCEMENT], or at least list these in the description, which is still a single line. The checklist is also unchecked.

  • Optional: splitting would make review and revert easier: (a) oxlint/oxfmt bump + formatting churn, (b) no-explicit-any, (c) React Compiler fixes.

Minor / nits

  1. prometheus/.../FilterInputs.tsx (ListboxComponent): the inline ref callback is detached and re-attached on every commit. Each time it runs getComputedStyle, which forces a style recalculation, and may trigger an extra render. Consider:

    • a stable callback (useCallback) with a functional update: setMaxHeight((prev) => (m && m !== prev ? m : prev))
    • MUI's useForkRef to merge the forwarded ref, instead of the hand-written ref.current = …
  2. table/src/components/TablePanel.test.tsx: expect(currentHeaderRow).not.toBe(initialHeaderRow) depends on how VirtualizedTable (in @perses-dev/components) builds its inline Table component. If that changes upstream, the test fails even though the feature still works. Keep only the "the current header row is observed / the old one is not" assertions.

  3. table/src/components/TablePanel.tsx: the MutationObserver watches the whole scroll container with subtree: true, so it fires on every virtualized scroll as rows mount and unmount. The callback is cheap, but it could skip mutation records that don't touch the thead.

  4. alertmanager/.../AlertTablePanel.tsx: currentKeys (groups.map(...).join('\0')) is now recomputed on every render. Wrap it in useMemo(..., [groups]).

  5. datasourcevariable/src/DatasourceVariable.tsx: selectedKind is a new object every render, so the effect still runs every render. This was already the case before, but since this deps array is being changed, use selectedKind.value.

  6. alertmanager/.../SilenceTablePanel.tsx: mixing await with .then/.catch/.finally is harder to read. try { … } catch (e) { exceptionSnackbar(e); } followed by setIsExpiring(false); avoids finally and stays compiler-friendly.

  7. prometheus/src/components/TreeNode.tsx:

    • ResizeObserver reacts to size changes, not position changes. If a sibling above the node grows, the connector can still be stale (still better than before).
    • Consider an explicit return type on the resultStats useMemo; the old useState had one.
  8. tracingganttchart/.../ResizableDivider.tsx: getComputedStyle(...).columnGap is now read on every mousemove. Read it once when the drag starts.

  9. piechart/src/PieChartBase.tsx:

    • useMemo for { width, height } passed to a non-memoized Box adds little.
    • Please explain why resize({ width, height }) was needed (commit "Fix PieChart").
  10. Import aliases (LogQLExtension as createLogQLExtension, and the same in VictoriaLogs):

    • The Loki and VictoriaLogs factories are internal, so they could be renamed at the source.
    • Tempo's TraceQLExtension is public (re-exported from tempo/src/index.ts), so the alias is the right choice there.
  11. Small cleanups:

    • MiniGanttChart/Canvas.tsx mixes height and CANVAS_HEIGHT; pick one.
    • tracingganttchart/src/test/convert/jaeger.ts: use switch (tagType).
    • canvas/.../EditorCanvas.tsx still uses eslint-disable, while StaticListVariable moved to oxlint-disable.
  12. Follow-up idea: the same "previous value" draft-sync code (store the last prop in state, reset the draft when it changes) appears 6 times (alertmanager LazyTextField, Jaeger ×2, Tempo LazyTextInput, VictoriaLogs ×2). A shared useDraftValue(value) hook would remove the duplication.

Checked and fine

  • useId migration: Perses' useId is a thin wrapper around React's useId with a prefix. Nothing (tests, e2e, CSS selectors) depends on the old prefixed ids, so only debugging readability is lost.
  • TimeSeriesChartBase pin logic: seriesMapping is a prop, so updating state during render cannot loop, and the behavior matches the old effect.
  • TablePanel scroll-sync deps: the scroll container (Scroller: VirtualizedTableContainer) is a stable module-level component, so dropping columns/contentDimensions from that effect is safe.
  • Derived state instead of effects: TreeNode resultStats with useMemo, renderItem hoisted in FlameChart, the QuerySettingsEditor callback ref, and ColumnsEditor id tracking (with new tests) all look good.
  • Type cleanup (Scatterplot formatter, markPointData, exemplar params) is a nice improvement.

🤖 Generated by GitHub Copilot. Please double-check before acting on it.

@Gladorme Gladorme changed the title [IGNORE] Upgrade Oxlint and fix React Compiler errors [BUGFIX] Upgrade Oxlint and fix React Compiler errors Oct 7, 2026
@Gladorme Gladorme changed the title [BUGFIX] Upgrade Oxlint and fix React Compiler errors [ENHANCEMENT] Upgrade Oxlint and fix React Compiler errors Oct 7, 2026

@Nexucis Nexucis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 This follow-up review was written by GitHub Copilot (an AI coding assistant) and posted by @Nexucis, who asked for it. It covers 095ec3e and uses React best-practice guidelines. Please read it as AI-generated feedback, not as a maintainer decision.

Summary

Thanks for the quick follow-up. 095ec3e fixes items 1, 4, 7, 8, 11 and 13 from the previous review. The title and description now list the user-facing changes (item 3), and CI is green. Nothing blocks merging. One policy question is still open (react/todo). The other comments are inline nits; resolve or dismiss each one as you prefer.

Checked in 095ec3e

  • EmbeddedPanelOptionsEditor: useEvent(onChange) restores the old "always call the latest callback" behavior. The effect no longer re-runs on every parent render. ✅
  • FilterInputs: the callback ref is now stable and uses a functional update. Object refs are now forwarded too, which the old code missed. ✅
  • AlertTablePanel: currentKeys is memoized on groups. ✅
  • DatasourceVariable: the effect now depends on selectedKind.value, so it no longer runs on every render. ✅
  • ResizableDivider: the gap is read once when a drag starts. ✅ (one inline nit)
  • Loki / VictoriaLogs: the factories are renamed where they're defined, and no old names are left. Tempo keeps the alias because TraceQLExtension is part of its public API. ✅
  • EditorCanvas: now uses oxlint-disable. ✅

React-specific checks

  • State reset during render: these components now store the previous prop in state and reset the draft during render, instead of in an effect: LazyTextField ×2, Jaeger ×2, Tempo, VictoriaLogs ×2, FlameChartPanel, AlertTablePanel, the TablePanel pagination and the TimeSeriesChartBase pin. All of them follow the React docs pattern for adjusting state when a prop changes. Each one is guarded, compares against a stable value (a primitive, a memoized value or a prop), and only updates its own component's state, so I found no loop risk. resolvedDefaultGroupBy is a useMemo, so the reference comparison there is safe.
  • QuerySettingsEditor: the callback ref is only attached to the last input. It fires once per added row, and focusRef stops it from focusing after a delete. ✅
  • FlameChart: handleItemClick with [] deps only uses state setters, so the empty deps are correct. Moving renderItem to module scope gives ECharts a stable function. ✅
  • TablePanel: keeping the container in state (ref={setPanelContainer}) means the effects run again when the table comes back after the "No data" view. The old ref-based version didn't do that. ✅

Still open from the previous review

Items 2, 6, 9, 10 and 14 are inline below. Item 15 (a shared useDraftValue hook for the 6 copies of the draft-reset code) can wait for a follow-up PR. I dropped item 5: if VirtualizedTable stopped replacing the header row, the observedElements checks would fail as well, so that assertion just states what the test assumes.


🤖 Generated by GitHub Copilot. Please double-check before acting on it.

Comment thread .oxlintrc.json
const { parentRef, spacing = 0, onMove } = props;
const { parentRef, onMove } = props;
const [isResizing, setResizing] = useState(false);
const [spacing, setSpacing] = useState(0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (rerender-use-ref-transient-values): spacing is never rendered. It is only read in handleMouseMove, so a ref fits better than state:

const spacingRef = useRef(0);

// handleMouseDown
spacingRef.current = parentRef.current ? parseFloat(getComputedStyle(parentRef.current).columnGap) || 0 : 0;

// handleMouseMove
const offsetX = e.clientX - parentRect.left + spacingRef.current;

The compiler rules allow writing a ref in an event handler. There's no extra render today, because setSpacing is batched with setResizing. The change only makes the intent clearer.

}));
}
}, [parentEl, nodeEl, reverse, nodeRef, setConnectorStyle]);
const updateConnector = (): void => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: updateConnector always returns a new style object, so every ResizeObserver callback re-renders the node, even when top and bottom haven't changed. In a large query tree, resizing the panel re-renders every node. Consider returning prevStyle unchanged when the computed top/bottom and border values are the same.

(From item 10, for reference: ResizeObserver doesn't fire when a node only moves without resizing. Still better than before, and fine to leave as is.)


if (reportNodeState) {
reportNodeState(childIdx, 'success');
const resultStats = useMemo(() => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (item 10): give this useMemo an explicit type, as the old useState had. Right now the early-return branch infers labelExamples: {} and sortedLabelCards: never[], so the result type is a union of the two branches. You can also move the empty value to module scope so it is the same object every time (rerender-memo-with-default-value):

interface ResultStats {
  numSeries: number;
  labelExamples: Record<string, Array<{ value: string; count: number }>>;
  sortedLabelCards: Array<[string, number]>;
}
const EMPTY_RESULT_STATS: ResultStats = { numSeries: 0, labelExamples: {}, sortedLabelCards: [] };

const resultStats = useMemo<ResultStats>(() => {
  if (instantQueryResponse?.status !== 'success') return EMPTY_RESULT_STATS;
  // …
}, [instantQueryResponse]);

} finally {
setIsExpiring(false);
}
await amClient

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (item 9): mixing await with .then/.catch/.finally is harder to read. The compiler limitation is about finally, so a plain try/catch with the reset after it should behave the same and still pass react/todo (please confirm with lint):

try {
  await amClient.deleteSilence(expireTarget.id);
  setExpireTarget(null);
  successSnackbar('Silence expired successfully');
  queryClient.invalidateQueries({ queryKey: ['query', 'AlertsQuery'] });
  queryClient.invalidateQueries({ queryKey: ['query', 'SilencesQuery'] });
} catch (err) {
  exceptionSnackbar(err);
}
setIsExpiring(false);

If you keep the promise chain, you can remove async/await and return the chain instead.


observeHeaderRow();
const mutationObserver = new MutationObserver(observeHeaderRow);
mutationObserver.observe(scrollContainer, { childList: true, subtree: true });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (item 6): with subtree: true, this callback fires on every virtualized scroll, because rows mount and unmount. It's cheap, but each call still runs querySelector. A simple guard skips that until the observed row is detached:

const observeHeaderRow = (): void => {
  if (headerRow?.isConnected) {
    return;
  }
  const currentHeaderRow = scrollContainer.querySelector('thead tr');
  // …
};

if (typeof ref === 'function') {
ref(reference);
} else if (ref) {
ref.current = reference;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (second half of item 4): MUI's useForkRef (@mui/material/utils) does this ref merge for you, for both callback and object refs:

const measureRef = useCallback((node: HTMLUListElement | null) => {
  if (!node) return;
  const measured = getComputedStyle(node).maxHeight;
  setMaxHeight((prev) => (measured && measured !== prev ? measured : prev));
}, []);
const listRef = useForkRef(ref, measureRef);


drawSpans(ctx, width, height, trace, spanColorGenerator);
}, [width, height, trace, spanColorGenerator]);
drawSpans(ctx, width, CANVAS_HEIGHT, trace, spanColorGenerator);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (item 14): line 49 still defines const height = CANVAS_HEIGHT, while this line uses CANVAS_HEIGHT directly. Pick one: either use height here, or remove the local variable and use CANVAS_HEIGHT everywhere.


function buildAnyValue(tags: Tag): otlpcommonv1.AnyValue {
const tagType = tags.type;
switch (tags.type) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit (item 14): tagType is only used in the default error message. switch (tagType) would be more consistent, and TypeScript should still narrow tags through the aliased discriminant (TS ≥ 4.4). Ignore this if type-check disagrees.

Gladorme and others added 8 commits October 7, 2026 14:19
- Enforce React Compiler rules as errors
- Preserve component state across rerenders and list updates
- Add regression tests for draft and column state

Signed-off-by: Guillaume LADORME <gladorme@gmail.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <gladorme@gmail.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <gladorme@gmail.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume <gladorme@gmail.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume <gladorme@gmail.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <gladorme@gmail.com>
- Table: follow the current header row when syncing filter cell widths,
  since the virtualized table remounts it on width, row, or column changes
- Prometheus: only update the listbox max height when it changes
- Time series: focus newly added query settings via a callback ref
  instead of an effect that ran on every render

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
@Gladorme
Gladorme force-pushed the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch from 095ec3e to 4e1216f Compare October 7, 2026 12:23

@Nexucis Nexucis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 This follow-up review was written by GitHub Copilot (an AI coding assistant) and posted by @Nexucis, who asked for it. It covers 4e1216f. Please read it as AI-generated feedback, not as a maintainer decision.

Summary

Since 095ec3e, the branch was rebased onto main. A git range-diff shows the 9 PR commits are unchanged, apart from conflict resolution in two files. No new inline comments: nothing new to flag. CI is green on 4e1216f.

Rebase check

  • AnnotationTooltip.tsx / TimeSeriesChartBase.tsx (conflict with #855): resolved correctly. #855's ANNOTATION_Y_AXIS, the annotationYAxisIndex parameter and yAxisIndex on the annotation series are all kept. The PR's typed markPointData, name: '' entries and typed mouseover/mouseout handlers are added on top of them. ✅
  • Code merged from main since the last review (palette selector, pyroscope label lookups, statchart auto sizing, datasource fetch provider): it passes the stricter rules with no changes needed. No @perses-dev/components useId and no eslint-disable comments are left in the repository. ✅

Open points

  • react/todo as "error": answered, it's intentional, to prepare for enabling the compiler. Thanks. The README already says these rules are enforced as errors, so the docs match. A sentence in the PR description would help future readers who wonder why ??= and try/finally were rewritten.
  • The 8 nits from the last review are still open: ResizableDivider ref, TreeNode style bail-out and useMemo type, SilenceTablePanel try/catch, TablePanel isConnected guard, FilterInputs useForkRef, Canvas height, jaeger.ts switch. None of them block merging. Fix them, or reply/resolve the threads if you'd rather leave them for a follow-up.

Nothing blocks merging from my side.


🤖 Generated by GitHub Copilot. Please double-check before acting on it.

@Gladorme
Gladorme added this pull request to the merge queue Oct 7, 2026
Merged via the queue into perses:main with commit 91bfd76 Oct 7, 2026
17 checks passed
@Gladorme
Gladorme deleted the t3code/upgrade-oxlint-oxfmt-fix-react-memo branch October 7, 2026 13:24
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