{confirmDialog}
{spec.enableFiltering && (
;
diff --git a/tempo/src/components/AttributeFilters.tsx b/tempo/src/components/AttributeFilters.tsx
index 3bc9f9de5..4dec3523d 100644
--- a/tempo/src/components/AttributeFilters.tsx
+++ b/tempo/src/components/AttributeFilters.tsx
@@ -17,7 +17,7 @@ import { useTimeRange } from '@perses-dev/plugin-system';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import type { ReactElement, SyntheticEvent } from 'react';
-import { useCallback, useEffect, useState } from 'react';
+import { useCallback, useState } from 'react';
import type { TempoClient } from '../model';
import { getUnixTimeRange } from '../plugins';
@@ -220,9 +220,11 @@ function LazyTextInput(props: LazyTextInputProps): ReactElement {
const [draftValue, setDraftValue] = useState(value);
const isValidInput = draftValue === '' || validationRegex === undefined || validationRegex.test(draftValue);
- useEffect(() => {
+ const [previousValue, setPreviousValue] = useState(value);
+ if (value !== previousValue) {
+ setPreviousValue(value);
setDraftValue(value);
- }, [value, setDraftValue]);
+ }
const handleChange = useCallback((event: React.ChangeEvent) => {
setDraftValue(event.target.value);
diff --git a/tempo/src/components/TraceQLEditor.tsx b/tempo/src/components/TraceQLEditor.tsx
index ac4193399..814aa2a21 100644
--- a/tempo/src/components/TraceQLEditor.tsx
+++ b/tempo/src/components/TraceQLEditor.tsx
@@ -20,7 +20,7 @@ import type { ReactElement } from 'react';
import { useMemo } from 'react';
import type { TempoClient } from '../model';
-import { TraceQLExtension } from './TraceQLExtension';
+import { TraceQLExtension as createTraceQLExtension } from './TraceQLExtension';
export interface TraceQLEditorProps extends Omit {
client?: TempoClient;
@@ -32,7 +32,7 @@ export function TraceQLEditor({ client, ...rest }: TraceQLEditorProps): ReactEle
const { absoluteTimeRange } = useTimeRange();
const traceQLExtension = useMemo(() => {
- return TraceQLExtension({ client, timeRange: absoluteTimeRange });
+ return createTraceQLExtension({ client, timeRange: absoluteTimeRange });
}, [client, absoluteTimeRange]);
const codemirrorTheme = useMemo(() => {
diff --git a/tempo/src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx b/tempo/src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx
index 450a4d887..a949e5f72 100644
--- a/tempo/src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx
+++ b/tempo/src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx
@@ -12,12 +12,11 @@
// limitations under the License.
import { Box, Button, FormControl, InputLabel, MenuItem, Select, Stack } from '@mui/material';
-import { useId } from '@perses-dev/components';
import type { DatasourceSelectProps } from '@perses-dev/plugin-system';
import { DatasourceSelect, useDatasourceClient, useDatasourceSelectValueToSelector } from '@perses-dev/plugin-system';
import { produce } from 'immer';
import type { ReactElement } from 'react';
-import { useCallback, useState } from 'react';
+import { useId, useCallback, useState } from 'react';
import { TraceQLEditor, filterToTraceQL, traceQLToFilter } from '../../components';
import { AttributeFilters } from '../../components/AttributeFilters';
@@ -35,7 +34,7 @@ export function TempoTraceQueryEditor(props: TraceQueryEditorProps): ReactElemen
const datasourceSelectValue = datasource ?? DEFAULT_TEMPO;
const selectedDatasource = useDatasourceSelectValueToSelector(datasourceSelectValue, TEMPO_DATASOURCE_KIND);
- const datasourceSelectLabelID = useId('tempo-datasource-label'); // for panels with multiple queries, this component is rendered multiple times on the same page
+ const datasourceSelectLabelID = useId(); // for panels with multiple queries, this component is rendered multiple times on the same page
const { data: client } = useDatasourceClient(selectedDatasource);
const { query, handleQueryChange, handleQueryBlur } = useQueryState(props);
diff --git a/timeserieschart/src/QuerySettingsEditor.tsx b/timeserieschart/src/QuerySettingsEditor.tsx
index 9d24c7395..efdbc4199 100644
--- a/timeserieschart/src/QuerySettingsEditor.tsx
+++ b/timeserieschart/src/QuerySettingsEditor.tsx
@@ -34,7 +34,7 @@ import CloseIcon from 'mdi-material-ui/Close';
import DeleteIcon from 'mdi-material-ui/DeleteOutline';
import AddIcon from 'mdi-material-ui/Plus';
import type { ReactElement } from 'react';
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
import type {
QuerySettingsOptions,
@@ -58,13 +58,12 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
);
};
// Every time a new query settings input is added, we want to focus the recently added input
- const recentlyAddedInputRef = useRef(null);
const focusRef = useRef(false);
- useEffect(() => {
- if (!recentlyAddedInputRef.current || !focusRef.current) return;
- recentlyAddedInputRef.current?.focus();
+ const recentlyAddedInputRef = useCallback((input: HTMLInputElement | null): void => {
+ if (!input || !focusRef.current) return;
+ input.focus();
focusRef.current = false;
- }, [querySettingsList?.length]);
+ }, []);
const handleQueryIndexChange = (e: React.ChangeEvent, i: number): void => {
if (querySettingsList !== undefined) {
@@ -348,7 +347,7 @@ interface QuerySettingsInputProps {
onLineStyleChange: (lineStyle: string) => void;
onAreaOpacityChange: (event: Event, value: number | number[]) => void;
onDelete: () => void;
- inputRef?: React.RefObject;
+ inputRef?: React.Ref;
// Optional control handlers
onAddColor: () => void;
onRemoveColor: () => void;
diff --git a/timeserieschart/src/TimeSeriesChartBase.tsx b/timeserieschart/src/TimeSeriesChartBase.tsx
index 3be9ed12b..dcb4ec87a 100644
--- a/timeserieschart/src/TimeSeriesChartBase.tsx
+++ b/timeserieschart/src/TimeSeriesChartBase.tsx
@@ -69,7 +69,7 @@ import { CanvasRenderer } from 'echarts/renderers';
import isEqual from 'lodash/isEqual';
import merge from 'lodash/merge';
import type { MouseEvent } from 'react';
-import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
+import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
import useResizeObserver from 'use-resize-observer';
import { ANNOTATION_Y_AXIS, AnnotationTooltip, buildAnnotationSeries } from './annotations/AnnotationTooltip';
@@ -223,7 +223,7 @@ export const TimeSeriesChartBase = forwardRef(fun
};
}, []);
- const handleEvents: OnEventsType = useMemo(() => {
+ const handleEvents = useMemo>(() => {
return {
datazoom: (params): void => {
if (onDataZoom === undefined) {
@@ -248,19 +248,21 @@ export const TimeSeriesChartBase = forwardRef(fun
enableDataZoom(chartRef.current);
}
},
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- mouseover: (params: any): void => {
+ mouseover: (params): void => {
if (
params.componentType === 'series' &&
params.seriesType === 'scatter' &&
+ 'seriesId' in params &&
typeof params.seriesId === 'string' &&
params.seriesId.startsWith(EXEMPLAR_SERIES_ID_PREFIX)
) {
- if (params.data?.exemplar) {
+ // This series ID identifies the metadata embedded by getExemplarSeries.
+ const point = params.data as { exemplar?: Exemplar; seriesLabels?: Labels; value?: number[] };
+ if (point?.exemplar) {
setHoveredExemplar({
- exemplar: params.data.exemplar,
- seriesLabels: params.data.seriesLabels,
- plottedValue: params.data?.value?.[1] ?? params.data.exemplar.value,
+ exemplar: point.exemplar,
+ seriesLabels: point.seriesLabels,
+ plottedValue: point.value?.[1] ?? point.exemplar.value,
});
return;
}
@@ -269,7 +271,7 @@ export const TimeSeriesChartBase = forwardRef(fun
// Only markPoint (triangles under the X-axis) opens the annotation tooltip.
// Hovering markLine or anything else keeps the regular TimeSeries tooltip visible
// and clears any stale hovered annotation (mouseout is sometimes missed by ECharts).
- if (annotations && params.componentType === 'markPoint' && params.data?.annotationIndex !== undefined) {
+ if (annotations && params.componentType === 'markPoint' && typeof params.data?.annotationIndex === 'number') {
const matchedAnnotation = annotations[params.data.annotationIndex] || null;
if (matchedAnnotation) {
setHoveredAnnotation(matchedAnnotation);
@@ -278,11 +280,11 @@ export const TimeSeriesChartBase = forwardRef(fun
}
setHoveredAnnotation(null);
},
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- mouseout: (params: any): void => {
+ mouseout: (params): void => {
if (
params.componentType === 'series' &&
params.seriesType === 'scatter' &&
+ 'seriesId' in params &&
typeof params.seriesId === 'string' &&
params.seriesId.startsWith(EXEMPLAR_SERIES_ID_PREFIX)
) {
@@ -292,7 +294,7 @@ export const TimeSeriesChartBase = forwardRef(fun
if (
annotations &&
params.componentType === 'markPoint' &&
- params.data?.annotationIndex !== undefined &&
+ typeof params.data?.annotationIndex === 'number' &&
annotations
) {
// Only clear if the mouseout corresponds to the currently hovered annotation, so that
@@ -420,18 +422,21 @@ export const TimeSeriesChartBase = forwardRef(fun
getTimezoneAwareAxisFormatter,
]);
- // Update adjacent charts so tooltip is unpinned when current chart is clicked.
- useEffect(() => {
- // Only allow pinning one tooltip at a time, subsequent tooltip click unpins previous.
- // Multiple tooltips can only be pinned if Ctrl or Cmd key is pressed while clicking.
- const multipleTooltipsPinned = tooltipPinnedCoords !== null && lastTooltipPinnedCoords !== null;
- if (multipleTooltipsPinned) {
- if (!isEqual(lastTooltipPinnedCoords, tooltipPinnedCoords)) {
- setTooltipPinnedCoords(null);
- if (tooltipPinnedCoords !== null && pinnedCrosshair !== null) {
- setPinnedCrosshair(null);
- }
- }
+ // Only changes from another chart (or new series) can clear the local pin.
+ // A local click may update its coordinates without updating the shared pin.
+ const [previousPinState, setPreviousPinState] = useState({ lastTooltipPinnedCoords, seriesMapping });
+ if (
+ previousPinState.lastTooltipPinnedCoords !== lastTooltipPinnedCoords ||
+ previousPinState.seriesMapping !== seriesMapping
+ ) {
+ setPreviousPinState({ lastTooltipPinnedCoords, seriesMapping });
+ if (
+ tooltipPinnedCoords !== null &&
+ lastTooltipPinnedCoords !== null &&
+ !isEqual(lastTooltipPinnedCoords, tooltipPinnedCoords)
+ ) {
+ setTooltipPinnedCoords(null);
+ setPinnedCrosshair(null);
}
// A pinned exemplar tooltip is also unpinned when a tooltip is pinned in another chart,
// unless it is the one just pinned by this chart at these exact coordinates.
@@ -443,9 +448,7 @@ export const TimeSeriesChartBase = forwardRef(fun
setPinnedExemplar(null);
setPinnedExemplarPos(null);
}
- // tooltipPinnedCoords CANNOT be in dep array or tooltip pinning breaks in the current chart's onClick
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [lastTooltipPinnedCoords, seriesMapping]);
+ }
return (
(null);
@@ -238,7 +237,7 @@ function TimeSeriesChartPanelComponent(props: TimeSeriesChartProps): ReactElemen
exemplars: [],
});
}
- seriesIndex++;
+ seriesIndex += 1;
}
for (const group of exemplars ?? []) {
if (group.exemplars.length === 0) continue;
@@ -405,7 +404,7 @@ function TimeSeriesChartPanelComponent(props: TimeSeriesChartProps): ReactElemen
values: thresholdTimeValueTuple,
});
timeSeriesMapping.push(getThresholdSeries(thresholdName, stepOption, seriesIndex));
- seriesIndex++;
+ seriesIndex += 1;
});
}
diff --git a/timeserieschart/src/annotations/AnnotationTooltip.tsx b/timeserieschart/src/annotations/AnnotationTooltip.tsx
index 07d7691fa..d6f4b53ad 100644
--- a/timeserieschart/src/annotations/AnnotationTooltip.tsx
+++ b/timeserieschart/src/annotations/AnnotationTooltip.tsx
@@ -24,7 +24,7 @@ import {
useMousePosition,
} from '@perses-dev/components';
import { DEFAULT_ANNOTATION_COLOR } from '@perses-dev/plugin-system';
-import type { LineSeriesOption, YAXisComponentOption } from 'echarts';
+import type { LineSeriesOption, MarkPointComponentOption, YAXisComponentOption } from 'echarts';
import Pin from 'mdi-material-ui/Pin';
import PinOutline from 'mdi-material-ui/PinOutline';
import useResizeObserver from 'use-resize-observer';
@@ -183,8 +183,14 @@ export function buildAnnotationSeries(
label?: { show: boolean };
annotationIndex?: number;
}> = [];
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const markPointData: any[] = [];
+ const markPointData: Array<
+ NonNullable[number] & {
+ annotationIndex: number;
+ isStart?: boolean;
+ isEnd?: boolean;
+ isPoint?: boolean;
+ }
+ > = [];
annotations.forEach((annotation, index) => {
const color = annotation.color ?? DEFAULT_ANNOTATION_COLOR;
@@ -217,6 +223,7 @@ export function buildAnnotationSeries(
// Add start and end markers
for (const isStart of [true, false]) {
markPointData.push({
+ name: '',
coord: [isStart ? annotation.start : annotation.end, 0],
symbol: 'triangle',
symbolSize: [12, 12],
@@ -242,6 +249,7 @@ export function buildAnnotationSeries(
// Add point marker
markPointData.push({
+ name: '',
coord: [annotation.start, 0],
symbol: 'triangle',
symbolSize: [12, 10],
diff --git a/timeserieschart/src/utils/data-transform.ts b/timeserieschart/src/utils/data-transform.ts
index 86a8f464d..b1caa3853 100644
--- a/timeserieschart/src/utils/data-transform.ts
+++ b/timeserieschart/src/utils/data-transform.ts
@@ -252,7 +252,6 @@ function findMax(data: LegacyTimeSeries[] | TimeSeries[]): number {
if (data.length && data[0] !== undefined && (data as TimeSeries[])[0]?.values) {
(data as TimeSeries[]).forEach((series) => {
series.values.forEach((valueTuple: TimeSeriesValueTuple) => {
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, value] = valueTuple;
// Use the absolute value so percent thresholds compute correctly against
// negated series (e.g. when `querySettings[].negativeY` is enabled).
diff --git a/timeseriestable/src/components/DataTable.tsx b/timeseriestable/src/components/DataTable.tsx
index 841f17f3e..5d68567fe 100644
--- a/timeseriestable/src/components/DataTable.tsx
+++ b/timeseriestable/src/components/DataTable.tsx
@@ -82,7 +82,7 @@ export const DataTable = ({ queryResults, spec }: DataTableProps): ReactElement
const itemActionsConfig = spec.actions ? (spec.actions as ActionOptions) : undefined;
const itemActionsListConfig = useMemo(
() => (itemActionsConfig?.enabled && itemActionsConfig.displayWithItem ? itemActionsConfig.actionsList : []),
- [itemActionsConfig?.enabled, itemActionsConfig?.displayWithItem, itemActionsConfig?.actionsList],
+ [itemActionsConfig],
);
const { getItemActionButtons, confirmDialog, actionButtons } = useSelectionItemActions({
diff --git a/tracetable/src/DataTable.tsx b/tracetable/src/DataTable.tsx
index 2600e7e1a..ee3121dd1 100644
--- a/tracetable/src/DataTable.tsx
+++ b/tracetable/src/DataTable.tsx
@@ -108,7 +108,7 @@ export function DataTable(props: DataTableProps): ReactElement {
}
}
return result_rows;
- }, [result, options.links?.trace, variableValues]);
+ }, [result, options.links, variableValues]);
const rowsById = useMemo(() => {
const map = new Map();
diff --git a/tracingganttchart/src/TracingGanttChart/GanttTable/ResizableDivider.tsx b/tracingganttchart/src/TracingGanttChart/GanttTable/ResizableDivider.tsx
index edcfbd8f4..b22365eae 100644
--- a/tracingganttchart/src/TracingGanttChart/GanttTable/ResizableDivider.tsx
+++ b/tracingganttchart/src/TracingGanttChart/GanttTable/ResizableDivider.tsx
@@ -18,18 +18,20 @@ import { useEffect, useState } from 'react';
interface ResizableDividerProps {
parentRef: React.RefObject;
- spacing?: number;
onMove: (left: number) => void;
}
export function ResizableDivider(props: ResizableDividerProps): ReactElement {
- const { parentRef, spacing = 0, onMove } = props;
+ const { parentRef, onMove } = props;
const [isResizing, setResizing] = useState(false);
+ const [spacing, setSpacing] = useState(0);
const handleMouseDown = (e: ReactMouseEvent): void => {
// disable any default actions (text selection, etc.)
e.preventDefault();
+ // read the flex gap once per drag instead of on every mousemove
+ setSpacing(parentRef.current ? parseFloat(getComputedStyle(parentRef.current).columnGap) || 0 : 0);
setResizing(true);
};
diff --git a/tracingganttchart/src/TracingGanttChart/MiniGanttChart/Canvas.tsx b/tracingganttchart/src/TracingGanttChart/MiniGanttChart/Canvas.tsx
index 91c38cdc5..e72a4367f 100644
--- a/tracingganttchart/src/TracingGanttChart/MiniGanttChart/Canvas.tsx
+++ b/tracingganttchart/src/TracingGanttChart/MiniGanttChart/Canvas.tsx
@@ -60,13 +60,13 @@ export function Canvas(props: CanvasProps): ReactElement {
);
useEffect(() => {
- if (!canvasRef.current || !width || !height) return;
+ if (!canvasRef.current || !width) return;
const ctx = canvasRef.current.getContext('2d');
if (!ctx) return;
- drawSpans(ctx, width, height, trace, spanColorGenerator);
- }, [width, height, trace, spanColorGenerator]);
+ drawSpans(ctx, width, CANVAS_HEIGHT, trace, spanColorGenerator);
+ }, [width, trace, spanColorGenerator]);
const translateCursorToTime = (e: ReactMouseEvent | MouseEvent): number => {
if (!canvasRef.current || !width) return 0;
diff --git a/tracingganttchart/src/TracingGanttChart/TracingGanttChart.tsx b/tracingganttchart/src/TracingGanttChart/TracingGanttChart.tsx
index f85a2b89b..a8b469bef 100644
--- a/tracingganttchart/src/TracingGanttChart/TracingGanttChart.tsx
+++ b/tracingganttchart/src/TracingGanttChart/TracingGanttChart.tsx
@@ -64,7 +64,6 @@ export function TracingGanttChart(props: TracingGanttChartProps): ReactElement {
// setTableWidth() is only called by
const [tableWidth, setTableWidth] = useState(0.82);
const gap = 2;
- const spacing = ganttChart.current ? parseFloat(getComputedStyle(ganttChart.current).columnGap) || 0 : 0;
return (
@@ -86,7 +85,7 @@ export function TracingGanttChart(props: TracingGanttChartProps): ReactElement {
{selectedSpan && (
<>
-
+
;
@@ -26,7 +26,7 @@ export function LogsQLEditor(props: LogsQLEditorProps): ReactElement {
const isDarkMode = theme.palette.mode === 'dark';
const logsqlExtension = useMemo(() => {
- return LogsQLExtension();
+ return createLogsQLExtension();
}, []);
const codemirrorTheme = useMemo(() => {
diff --git a/victorialogs/src/components/logsql-extension.ts b/victorialogs/src/components/logsql-extension.ts
index c2809fc1a..636cdb89f 100644
--- a/victorialogs/src/components/logsql-extension.ts
+++ b/victorialogs/src/components/logsql-extension.ts
@@ -29,7 +29,7 @@ function logsqlLanguage(): LRLanguage {
});
}
-export function LogsQLExtension(): Array {
+export function createLogsQLExtension(): Array {
const language = logsqlLanguage();
return [language];
}
diff --git a/victorialogs/src/queries/victorialogs-log-query/VictoriaLogsLogQueryEditor.tsx b/victorialogs/src/queries/victorialogs-log-query/VictoriaLogsLogQueryEditor.tsx
index 2c2451cfd..2e90cadd8 100644
--- a/victorialogs/src/queries/victorialogs-log-query/VictoriaLogsLogQueryEditor.tsx
+++ b/victorialogs/src/queries/victorialogs-log-query/VictoriaLogsLogQueryEditor.tsx
@@ -16,7 +16,7 @@ import { createModEnterHandler } from '@perses-dev/dashboards';
import type { DatasourceSelectProps, OptionsEditorProps } from '@perses-dev/plugin-system';
import { DatasourceSelect, isVariableDatasource, useDatasourceSelectValueToSelector } from '@perses-dev/plugin-system';
import type { ReactElement } from 'react';
-import { useCallback, useState, useEffect } from 'react';
+import { useCallback, useState } from 'react';
import { LogsQLEditor } from '../../components/logsql-editor';
import type { VictoriaLogsDatasourceSelector } from '../../model';
@@ -41,10 +41,11 @@ export function VictoriaLogsLogQueryEditor(props: VictoriaLogsQueryEditorProps):
// Local state for editor value to prevent query_range calls on every keystroke
const [localQuery, setLocalQuery] = useState(value.query);
- // Update local state when prop changes
- useEffect(() => {
+ const [previousQuery, setPreviousQuery] = useState(value.query);
+ if (value.query !== previousQuery) {
+ setPreviousQuery(value.query);
setLocalQuery(value.query);
- }, [value.query]);
+ }
const handleDatasourceChange: DatasourceSelectProps['onChange'] = (newDatasourceSelection) => {
if (!isVariableDatasource(newDatasourceSelection) && newDatasourceSelection.kind === DATASOURCE_KIND) {
diff --git a/victorialogs/src/queries/victorialogs-time-series-query/VictoriaLogsTimeSeriesQueryEditor.tsx b/victorialogs/src/queries/victorialogs-time-series-query/VictoriaLogsTimeSeriesQueryEditor.tsx
index b64c4a53a..f7d3a73ee 100644
--- a/victorialogs/src/queries/victorialogs-time-series-query/VictoriaLogsTimeSeriesQueryEditor.tsx
+++ b/victorialogs/src/queries/victorialogs-time-series-query/VictoriaLogsTimeSeriesQueryEditor.tsx
@@ -16,7 +16,7 @@ import { createModEnterHandler } from '@perses-dev/dashboards';
import type { DatasourceSelectProps, OptionsEditorProps } from '@perses-dev/plugin-system';
import { DatasourceSelect, isVariableDatasource, useDatasourceSelectValueToSelector } from '@perses-dev/plugin-system';
import type { ReactElement } from 'react';
-import { useCallback, useState, useEffect } from 'react';
+import { useCallback, useState } from 'react';
import { LogsQLEditor } from '../../components/logsql-editor';
import type { VictoriaLogsDatasourceSelector } from '../../model';
@@ -38,10 +38,11 @@ export function VictoriaLogsQueryEditor(props: VictoriaLogsQueryEditorProps): Re
// Local state for editor value to prevent query_range calls on every keystroke
const [localQuery, setLocalQuery] = useState(value.query);
- // Update local state when prop changes
- useEffect(() => {
+ const [previousQuery, setPreviousQuery] = useState(value.query);
+ if (value.query !== previousQuery) {
+ setPreviousQuery(value.query);
setLocalQuery(value.query);
- }, [value.query]);
+ }
const handleDatasourceChange: DatasourceSelectProps['onChange'] = (newDatasourceSelection) => {
if (!isVariableDatasource(newDatasourceSelection) && newDatasourceSelection.kind === DATASOURCE_KIND) {
diff --git a/vitest.shared.ts b/vitest.shared.ts
index fd58ce49a..35cfcfa6b 100644
--- a/vitest.shared.ts
+++ b/vitest.shared.ts
@@ -52,7 +52,7 @@ export function definePackageVitestConfig({
packageDir,
setupFiles = [],
passWithNoTests = false,
-}: VitestPackageOptions) {
+}: VitestPackageOptions): ReturnType {
return mergeConfig(
sharedConfig,
defineConfig({