Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion oxlint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ const config = defineConfig({
'react/exhaustive-effect-dependencies': 'error',
'react/function-component-definition': 'error',
'react/globals': 'error',
'react/hooks': 'off', // TODO(ryan953): Fix violations and promote this warning to an error.
'react/hooks': 'error',
'react/immutability': 'error',
'react/incompatible-library': 'off', // TODO(ryan953): Fix violations and promote this warning to an error.
'react/invariant': 'error',
Expand Down
1 change: 0 additions & 1 deletion static/app/components/stream/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,6 @@ export function StreamGroup({

const groupUsersCount = (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The Tooltip for groupUsersCount is missing the disabled={!useFilteredStats} prop, so it is always enabled. The original bug this PR intended to fix remains.
Severity: LOW

Suggested Fix

Add the disabled={!useFilteredStats} prop to the Tooltip component wrapping groupUsersCount, similar to how it is used for the groupCount tooltip. This will ensure the tooltip is only enabled when filtered stats are being shown.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/components/stream/group.tsx#L644

Potential issue: The pull request attempted to fix an issue where the "Affected Users"
tooltip was always enabled. The change removed the incorrect
`disabled={!usePageFilters}` prop from the `Tooltip` component for `groupUsersCount` but
failed to add the intended replacement, `disabled={!useFilteredStats}`. Because the
`Tooltip` component defaults to being enabled when the `disabled` prop is not provided,
the tooltip remains always visible on hover, even when filtered stats are not being
displayed. This means the original bug was not fixed.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

that's not the original bug this PR is aiming at

<Tooltip
disabled={!usePageFilters}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

So, this was looking at the function called usePageFilters. Which is always defined, so this is never disabled.

title={
<CountTooltipContent>
<h4>{t('Affected Users')}</h4>
Expand Down
7 changes: 5 additions & 2 deletions static/app/scrapsProviders/tracking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ export function SentryTrackingProvider({children}: {children: React.ReactNode})
// Called here, not in `useClickTracking`, so a Button's hook count doesn't
// depend on which implementation is registered.
const useButtonTracking =
getOverride('react-hook:use-button-tracking') ?? useDefaultButtonTracking;
getOverride('react-hook:use-button-tracking') ?? useDefaultButtonTracking; // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.

return (
<TrackingContextProvider value={useButtonTracking()}>
<TrackingContextProvider
// oxlint-disable-next-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
value={useButtonTracking()}
>
{children}
</TrackingContextProvider>
);
Expand Down
6 changes: 5 additions & 1 deletion static/app/utils/provideAriaRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ export function ProvideAriaRouter({children}: {children: React.ReactNode}) {
);

return (
<AriaRouterProvider navigate={handleNavigate} useHref={useHref}>
<AriaRouterProvider
navigate={handleNavigate}
// oxlint-disable-next-line react/hooks -- react-aria RouterProvider takes useHref as a value and calls it internally.
useHref={useHref}
>
{children}
</AriaRouterProvider>
);
Expand Down
2 changes: 1 addition & 1 deletion static/app/utils/replays/useReplayForCriticalFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ const noop = (_: UseReplayForCriticalFlowOptions) => {};
*/
export function useReplayForCriticalFlow(options: UseReplayForCriticalFlowOptions) {
const useImpl = getOverride('react-hook:use-replay-for-critical-flow') ?? noop;
useImpl(options);
useImpl(options); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
}
4 changes: 2 additions & 2 deletions static/app/utils/useExperiment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ function useNoopExperiment(options: UseExperimentOptions): UseExperimentResult {
* ```
*/
export function useExperiment(options: UseExperimentOptions): UseExperimentResult {
const useExperimentHook = getOverride('react-hook:use-experiment') ?? useNoopExperiment;
return useExperimentHook(options);
const useExperimentHook = getOverride('react-hook:use-experiment') ?? useNoopExperiment; // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
return useExperimentHook(options); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
}
10 changes: 5 additions & 5 deletions static/app/utils/useMaxPickableDays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {useOrganization} from 'sentry/utils/useOrganization';
*/
export function useDefaultMaxPickableDays(): number {
const useDefaultMaxPickableDaysHook =
getOverride('react-hook:use-default-max-pickable-days') ??
useDefaultMaxPickableDaysImpl;
return useDefaultMaxPickableDaysHook();
getOverride('react-hook:use-default-max-pickable-days') ?? // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
useDefaultMaxPickableDaysImpl; // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
return useDefaultMaxPickableDaysHook(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
}

function useDefaultMaxPickableDaysImpl() {
Expand Down Expand Up @@ -50,8 +50,8 @@ export function useMaxPickableDays({
dataCategories,
}: UseMaxPickableDaysProps): MaxPickableDaysOptions {
const useMaxPickableDaysHook =
getOverride('react-hook:use-max-pickable-days') ?? useMaxPickableDaysImpl;
return useMaxPickableDaysHook({dataCategories});
getOverride('react-hook:use-max-pickable-days') ?? useMaxPickableDaysImpl; // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
return useMaxPickableDaysHook({dataCategories}); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
}

function useMaxPickableDaysImpl({dataCategories}: UseMaxPickableDaysProps) {
Expand Down
20 changes: 8 additions & 12 deletions static/app/utils/useParams.spec.tsx

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

variable rename to make the compiler happy

Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,14 @@ describe('useParams', () => {
mockCustomerDomain.mockReturnValue('albertos-apples');

let originalParams: any;
let useParamsValue: any;
let paramsValue: any;

function Component() {
// oxlint-disable-next-line react/globals -- Test captures the hook result in an outer variable to assert on it.
originalParams = useReactRouter6Params();
// oxlint-disable-next-line react/globals -- Test captures the hook result in an outer variable to assert on it.
useParamsValue = useParams();
return (
<div>rendered component for org: {useParamsValue.orgId ?? 'no org id'}</div>
);
paramsValue = useParams();
return <div>rendered component for org: {paramsValue.orgId ?? 'no org id'}</div>;
}

render(<Component />, {
Expand All @@ -95,7 +93,7 @@ describe('useParams', () => {
screen.getByText('rendered component for org: albertos-apples')
).toBeInTheDocument();
expect(originalParams).toEqual({});
expect(useParamsValue).toEqual({
expect(paramsValue).toEqual({
orgId: 'albertos-apples',
});
});
Expand All @@ -105,16 +103,14 @@ describe('useParams', () => {
mockCustomerDomain.mockReturnValue(undefined);

let originalParams: any;
let useParamsValue: any;
let paramsValue: any;

function Component() {
// oxlint-disable-next-line react/globals -- Test captures the hook result in an outer variable to assert on it.
originalParams = useReactRouter6Params();
// oxlint-disable-next-line react/globals -- Test captures the hook result in an outer variable to assert on it.
useParamsValue = useParams();
return (
<div>rendered component for org: {useParamsValue.orgId ?? 'no org id'}</div>
);
paramsValue = useParams();
return <div>rendered component for org: {paramsValue.orgId ?? 'no org id'}</div>;
}

render(<Component />, {
Expand All @@ -128,7 +124,7 @@ describe('useParams', () => {
screen.getByText('rendered component for org: no org id')
).toBeInTheDocument();
expect(originalParams).toEqual({});
expect(useParamsValue).toEqual({});
expect(paramsValue).toEqual({});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,29 @@ export function useDatasetSearchBarData(): {
? debouncedFilterKeySearch.query
: undefined;

// oxlint-disable-next-line react/hooks -- Each call names a literal WidgetType, so the dataset config and its hook are fixed.
const errorsData = getDatasetConfig(WidgetType.ERRORS).useSearchBarDataProvider!({
pageFilters: selection,
});

// oxlint-disable-next-line react/hooks -- Each call names a literal WidgetType, so the dataset config and its hook are fixed.
const logsData = getDatasetConfig(WidgetType.LOGS).useSearchBarDataProvider!({
filterKeySearch: getFilterKeySearch(WidgetType.LOGS),
pageFilters: selection,
});

// oxlint-disable-next-line react/hooks -- Each call names a literal WidgetType, so the dataset config and its hook are fixed.
const spansData = getDatasetConfig(WidgetType.SPANS).useSearchBarDataProvider!({
filterKeySearch: getFilterKeySearch(WidgetType.SPANS),
pageFilters: selection,
});

// oxlint-disable-next-line react/hooks -- Each call names a literal WidgetType, so the dataset config and its hook are fixed.
const issuesData = getDatasetConfig(WidgetType.ISSUE).useSearchBarDataProvider!({
pageFilters: selection,
});

// oxlint-disable-next-line react/hooks -- Each call names a literal WidgetType, so the dataset config and its hook are fixed.
const releasesData = getDatasetConfig(WidgetType.RELEASE).useSearchBarDataProvider!({
pageFilters: selection,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export function useGenericWidgetQueries<SeriesResponse, TableResponse>(
[needsBreakdownTable, widget]
);

// oxlint-disable-next-line react/hooks -- Optional per-dataset query hook; the config prop must not change for a mounted card.
const hookSeriesResults = config.useSeriesQuery?.({
widget,
organization,
Expand All @@ -221,6 +222,7 @@ export function useGenericWidgetQueries<SeriesResponse, TableResponse>(
widgetInterval,
});

// oxlint-disable-next-line react/hooks -- Optional per-dataset query hook; the config prop must not change for a mounted card.
const hookTableResults = config.useTableQuery?.({
widget: tableWidget,
organization,
Expand All @@ -236,6 +238,7 @@ export function useGenericWidgetQueries<SeriesResponse, TableResponse>(
widgetInterval,
});

// oxlint-disable-next-line react/hooks -- Optional per-dataset query hook; the config prop must not change for a mounted card.
const hookHeatmapResults = config.useHeatmapQuery?.({
widget,
organization,
Expand Down
1 change: 1 addition & 0 deletions static/app/views/dashboards/widgetCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ function useTimeRangeWarning({widget}: {widget: TWidget}) {
} = usePageFilters();
const useRetentionLimit =
getOverride('react-hook:use-dashboard-dataset-retention-limit') ?? (() => null);
// oxlint-disable-next-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
const retentionLimitDays = useRetentionLimit({
dataset: widget.widgetType ?? WidgetType.ERRORS,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function MonitorTypeField() {

const useMetricDetectorLimit =
getOverride('react-hook:use-metric-detector-limit') ?? (() => null);
const quota = useMetricDetectorLimit();
const quota = useMetricDetectorLimit(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
const canCreateMetricDetector = !quota?.hasReachedLimit;

const handleChange = (value: SelectableDetectorType) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function useExploreAggregatesTable({
[]
);
return useProgressiveQuery<typeof useExploreAggregatesTableImp>({
queryHookImplementation: useExploreAggregatesTableImp,
queryHookImplementation: useExploreAggregatesTableImp, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {enabled, limit, query, queryExtras},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/explore/hooks/useExploreSpansTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export function useExploreSpansTable({
);

const spansTableResult = useProgressiveQuery<typeof useExploreSpansTableImp>({
queryHookImplementation: useExploreSpansTableImp,
queryHookImplementation: useExploreSpansTableImp, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {
cursor: visibleSamples ? '' : undefined,
enabled,
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/explore/hooks/useExploreTimeseries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const useExploreTimeseries = ({
);

return useProgressiveQuery<typeof useExploreTimeseriesImpl>({
queryHookImplementation: useExploreTimeseriesImpl,
queryHookImplementation: useExploreTimeseriesImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {query, enabled, queryExtras, includeAnnotations},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function useLogsExportEstimatedRowCount(tableDataLength: number) {
const isTopN = !!baseRequest.topEvents;

const timeseriesResult = useProgressiveQuery<typeof useLogsExportEstimateTimeseries>({
queryHookImplementation: useLogsExportEstimateTimeseries,
queryHookImplementation: useLogsExportEstimateTimeseries, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {
baseRequest,
enabled: true,
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/explore/logs/useLogsAggregatesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function useLogsAggregatesTable({
const {result, pageLinks, eventView} = useProgressiveQuery<
typeof useLogsAggregatesTableImpl
>({
queryHookImplementation: useLogsAggregatesTableImpl,
queryHookImplementation: useLogsAggregatesTableImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {
enabled,
limit,
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/explore/logs/useLogsTimeseries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function useLogsTimeseries({
);

const timeseriesResult = useProgressiveQuery<typeof useLogsTimeseriesImpl>({
queryHookImplementation: useLogsTimeseriesImpl,
queryHookImplementation: useLogsTimeseriesImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {enabled, timeseriesIngestDelay},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function useMetricAggregatesTable({
[traceMetric, visualize]
);
return useProgressiveQuery<typeof useMetricAggregatesTableImp>({
queryHookImplementation: useMetricAggregatesTableImp,
queryHookImplementation: useMetricAggregatesTableImp, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {
enabled,
limit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export function useMetricSamplesTable({
);

return useProgressiveQuery<typeof useMetricSamplesTableImpl>({
queryHookImplementation: useMetricSamplesTableImpl,
queryHookImplementation: useMetricSamplesTableImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {
enabled: !disabled,
limit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function useMetricTimeseries({traceMetric, enabled}: UseMetricTimeseriesO
[topEvents, visualizes]
);
return useProgressiveQuery<typeof useMetricTimeseriesImpl>({
queryHookImplementation: useMetricTimeseriesImpl,
queryHookImplementation: useMetricTimeseriesImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {traceMetric, queryExtras: undefined, enabled},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function useMultiQueryTableAggregateMode({
[]
);
return useProgressiveQuery({
queryHookImplementation: useMultiQueryTableAggregateModeImpl,
queryHookImplementation: useMultiQueryTableAggregateModeImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {groupBys, query, yAxes, sortBys, enabled, queryExtras},
queryOptions: {
canTriggerHighAccuracy,
Expand Down Expand Up @@ -116,7 +116,7 @@ export function useMultiQueryTableSampleMode({
[]
);
return useProgressiveQuery({
queryHookImplementation: useMultiQueryTableSampleModeImpl,
queryHookImplementation: useMultiQueryTableSampleModeImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {query, yAxes, sortBys, enabled, queryExtras},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function useMultiQueryTimeseries({
[]
);
return useProgressiveQuery<typeof useMultiQueryTimeseriesImpl>({
queryHookImplementation: useMultiQueryTimeseriesImpl,
queryHookImplementation: useMultiQueryTimeseriesImpl, // oxlint-disable-line react/hooks -- useProgressiveQuery takes the query hook as a value and calls it per accuracy tier.
queryHookArgs: {enabled, index, queryExtras},
queryOptions: {
canTriggerHighAccuracy,
Expand Down
8 changes: 6 additions & 2 deletions static/app/views/insights/common/queries/useDiscover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ const useDiscover = <T extends Array<Extract<keyof ResponseType, string>>, Respo
projectIds
);

// oxlint-disable-next-line react/hooks -- queryWithoutPageFilters is a constant per call site, so the branch never flips.
const queryFn = options.queryWithoutPageFilters
? useWrappedDiscoverQueryWithoutPageFilters
: useWrappedDiscoverQuery;
? // oxlint-disable-next-line react/hooks -- queryWithoutPageFilters is a constant per call site, so the branch never flips.
useWrappedDiscoverQueryWithoutPageFilters
: // oxlint-disable-next-line react/hooks -- queryWithoutPageFilters is a constant per call site, so the branch never flips.
useWrappedDiscoverQuery;

// oxlint-disable-next-line react/hooks -- queryWithoutPageFilters is a constant per call site, so the branch never flips.
const result = queryFn({
eventView,
initialData: [],
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/issueDetails/eventMissingBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function EventMissingBanner() {

const useGetMaxRetentionDays =
getOverride('react-hook:use-get-max-retention-days') ?? (() => MAX_PICKABLE_DAYS);
const maxRetentionDays = useGetMaxRetentionDays();
const maxRetentionDays = useGetMaxRetentionDays(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
const statsPeriod = maxRetentionDays ? `${maxRetentionDays}d` : '30d';

const baseUrl = `/organizations/${organization.slug}/issues/${groupId}/events`;
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/issueDetails/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function GroupHeader({event, group, project}: GroupHeaderProps) {
const {count: eventCount, userCount} = group;
const useGetMaxRetentionDays =
getOverride('react-hook:use-get-max-retention-days') ?? (() => MAX_PICKABLE_DAYS);
const maxRetentionDays = useGetMaxRetentionDays();
const maxRetentionDays = useGetMaxRetentionDays(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
const userCountPeriod = maxRetentionDays ? `(${maxRetentionDays}d)` : '(30d)';
const {title: primaryTitle} = getTitle(group);
const secondaryTitle = getMessage(group);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function useGroupDefaultStatsPeriod(
): UseGroupDefaultStatsPeriodResult {
const useGetMaxRetentionDays =
getOverride('react-hook:use-get-max-retention-days') ?? (() => MAX_PICKABLE_DAYS);
const maxRetentionDays = useGetMaxRetentionDays();
const maxRetentionDays = useGetMaxRetentionDays(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.
let isMaxRetention = false;

if (!group) {
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/routeAnalyticsContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function RouteAnalyticsContextProvider({children}: Props) {
setOrganization,
setEventNames,
previousUrl,
} = useRouteActivatedHook?.(context) || DEFAULT_CONTEXT;
} = useRouteActivatedHook?.(context) || DEFAULT_CONTEXT; // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.

const memoizedValue = useMemo(
() => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function OrganizationSettingsNavigation() {
const organization = useOrganization();
const useBillingNavConfig =
getOverride('react-hook:use-billing-navigation-config') ?? (() => null);
const billingNavConfig = useBillingNavConfig();
const billingNavConfig = useBillingNavConfig(); // oxlint-disable-line react/hooks -- Hook comes from the override registry, which is populated before React renders.

return (
<SettingsNavigation
Expand Down
Loading