Skip to content

Commit 6e7e4e1

Browse files
ryan953george-sentry
authored andcommitted
ref: Replace useUrlParams in favor of nuqs (#112268)
Related to getsentry/frontend-tsc#78, we shouldn't be using browserHistory anymore: `useNavigate()` covers cases where we want to change it, and location/nuqs covers reading and query-params too. So this aims to remove `useUrlParams` from the codebase, it's a query-param helper that is basically a bad version of nuqs. We can use nuqs instead. Related to getsentry/frontend-tsc#78
1 parent e8ed321 commit 6e7e4e1

File tree

16 files changed

+212
-355
lines changed

16 files changed

+212
-355
lines changed

static/app/components/feedback/feedbackOnboarding/sidebar.tsx

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type {ReactNode} from 'react';
22
import {Fragment, useEffect, useMemo, useState} from 'react';
33
import styled from '@emotion/styled';
4+
import {parseAsStringLiteral, useQueryState} from 'nuqs';
45
import {PlatformIcon} from 'platformicons';
56

67
import HighlightTopRightPattern from 'sentry-images/pattern/highlight-top-right.svg';
78

89
import {LinkButton} from '@sentry/scraps/button';
910
import {CompactSelect} from '@sentry/scraps/compactSelect';
10-
import {Flex} from '@sentry/scraps/layout';
11+
import {Container, Flex} from '@sentry/scraps/layout';
1112
import {OverlayTrigger} from '@sentry/scraps/overlayTrigger';
1213

1314
import {FeedbackOnboardingLayout} from 'sentry/components/feedback/feedbackOnboarding/feedbackOnboardingLayout';
@@ -42,7 +43,6 @@ import {useLegacyStore} from 'sentry/stores/useLegacyStore';
4243
import type {SelectValue} from 'sentry/types/core';
4344
import type {PlatformKey, Project} from 'sentry/types/project';
4445
import {trackAnalytics} from 'sentry/utils/analytics';
45-
import {useUrlParams} from 'sentry/utils/url/useUrlParams';
4646
import {useLocation} from 'sentry/utils/useLocation';
4747
import {useOrganization} from 'sentry/utils/useOrganization';
4848

@@ -197,21 +197,20 @@ function OnboardingContent({currentProject}: {currentProject: Project}) {
197197
textValue?: string;
198198
}>(jsFrameworkSelectOptions[0]!);
199199

200-
const defaultTab = 'npm';
201200
const location = useLocation();
202201
const crashReportOnboarding = location.hash === CRASH_REPORT_HASH;
203202

204-
const {getParamValue: setupMode, setParamValue: setSetupMode} = useUrlParams(
203+
const [setupMode, setSetupMode] = useQueryState(
205204
'mode',
206-
defaultTab
205+
parseAsStringLiteral(['npm', 'jsLoader'] as const).withDefault('npm')
207206
);
208207

209208
const currentPlatform = currentProject.platform
210209
? (platforms.find(p => p.id === currentProject.platform) ?? otherPlatform)
211210
: otherPlatform;
212211

213212
const webBackendPlatform = replayBackendPlatforms.includes(currentPlatform.id);
214-
const showJsFrameworkInstructions = webBackendPlatform && setupMode() === 'npm';
213+
const showJsFrameworkInstructions = webBackendPlatform && setupMode === 'npm';
215214

216215
const crashApiPlatform = feedbackCrashApiPlatforms.includes(currentPlatform.id);
217216
const widgetPlatform = feedbackWidgetPlatforms.includes(currentPlatform.id);
@@ -261,48 +260,50 @@ function OnboardingContent({currentProject}: {currentProject: Project}) {
261260
const radioButtons = (
262261
<Header>
263262
{showRadioButtons ? (
264-
<StyledRadioGroup
265-
label="mode"
266-
choices={[
267-
[
268-
'npm',
269-
webBackendPlatform ? (
270-
<Flex align="center" wrap="wrap" gap="md" key="platform-select">
271-
{tct('I use [platformSelect]', {
272-
platformSelect: (
273-
<CompactSelect
274-
size="xs"
275-
trigger={triggerProps => (
276-
<OverlayTrigger.Button {...triggerProps}>
277-
{jsFramework.label ?? triggerProps.children}
278-
</OverlayTrigger.Button>
279-
)}
280-
value={jsFramework.value}
281-
onChange={setJsFramework}
282-
options={jsFrameworkSelectOptions}
283-
position="bottom-end"
284-
key={jsFramework.textValue}
285-
disabled={setupMode() === 'jsLoader'}
263+
<Container padding="md 0">
264+
<RadioGroup<typeof setupMode>
265+
label="mode"
266+
choices={[
267+
[
268+
'npm',
269+
webBackendPlatform ? (
270+
<Flex align="center" wrap="wrap" gap="md" key="platform-select">
271+
{tct('I use [platformSelect]', {
272+
platformSelect: (
273+
<CompactSelect
274+
size="xs"
275+
trigger={triggerProps => (
276+
<OverlayTrigger.Button {...triggerProps}>
277+
{jsFramework.label ?? triggerProps.children}
278+
</OverlayTrigger.Button>
279+
)}
280+
value={jsFramework.value}
281+
onChange={setJsFramework}
282+
options={jsFrameworkSelectOptions}
283+
position="bottom-end"
284+
key={jsFramework.textValue}
285+
disabled={setupMode === 'jsLoader'}
286+
/>
287+
),
288+
})}
289+
{jsFrameworkDocs?.platformOptions && (
290+
<PlatformOptionDropdown
291+
platformOptions={jsFrameworkDocs?.platformOptions}
292+
disabled={setupMode === 'jsLoader'}
286293
/>
287-
),
288-
})}
289-
{jsFrameworkDocs?.platformOptions && (
290-
<PlatformOptionDropdown
291-
platformOptions={jsFrameworkDocs?.platformOptions}
292-
disabled={setupMode() === 'jsLoader'}
293-
/>
294-
)}
295-
</Flex>
296-
) : (
297-
t('I use NPM or Yarn')
298-
),
299-
],
300-
['jsLoader', t('I use HTML templates (Loader Script)')],
301-
]}
302-
value={setupMode()}
303-
onChange={setSetupMode}
304-
tooltipPosition="top-start"
305-
/>
294+
)}
295+
</Flex>
296+
) : (
297+
t('I use NPM or Yarn')
298+
),
299+
],
300+
['jsLoader', t('I use HTML templates (Loader Script)')],
301+
]}
302+
value={setupMode}
303+
onChange={value => setSetupMode(value)}
304+
tooltipPosition="top-start"
305+
/>
306+
</Container>
306307
) : (
307308
(newDocs?.platformOptions?.siblingOption ||
308309
newDocs?.platformOptions?.packageManager) &&
@@ -370,9 +371,8 @@ function OnboardingContent({currentProject}: {currentProject: Project}) {
370371
return 'feedbackOnboardingCrashApi';
371372
}
372373
if (
373-
setupMode() === 'npm' || // switched to NPM option
374-
(!setupMode() && defaultTab === 'npm' && widgetPlatform) || // default value for FE frameworks when ?mode={...} in URL is not set yet
375-
npmOnlyFramework // even if '?mode=jsLoader', only show npm instructions for FE frameworks)
374+
setupMode === 'npm' || // switched to NPM option
375+
npmOnlyFramework // even if '?mode=jsLoader', only show npm instructions for FE frameworks
376376
) {
377377
return 'feedbackOnboardingNpm';
378378
}
@@ -431,7 +431,3 @@ const StyledIdBadge = styled(IdBadge)`
431431
white-space: nowrap;
432432
flex-shrink: 1;
433433
`;
434-
435-
const StyledRadioGroup = styled(RadioGroup)`
436-
padding: ${p => p.theme.space.md} 0;
437-
`;

static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.spec.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {createMemoryRouter, RouterProvider} from 'react-router-dom';
22
import {ProjectFixture} from 'sentry-fixture/project';
33

4+
import {SentryNuqsTestingAdapter} from 'sentry-test/nuqsTestingAdapter';
45
import {act, renderHook} from 'sentry-test/reactTestingLibrary';
56

67
import {useCurrentProjectState} from 'sentry/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState';
@@ -16,14 +17,15 @@ import type {Project} from 'sentry/types/project';
1617

1718
function createWrapper(projectSlug?: string) {
1819
return function Wrapper({children}: any) {
20+
const wrapped = <SentryNuqsTestingAdapter>{children}</SentryNuqsTestingAdapter>;
1921
const memoryRouter = createMemoryRouter([
2022
{
2123
path: '/',
22-
element: children,
24+
element: wrapped,
2325
},
2426
{
2527
path: '/:projectId/',
26-
element: children,
28+
element: wrapped,
2729
},
2830
]);
2931

static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import {useCallback, useEffect, useMemo, useState} from 'react';
22
import partition from 'lodash/partition';
3+
import {parseAsString, useQueryState} from 'nuqs';
34

45
import {PageFiltersStore} from 'sentry/components/pageFilters/store';
56
import type {OnboardingDrawerKey} from 'sentry/stores/onboardingDrawerStore';
67
import {useLegacyStore} from 'sentry/stores/useLegacyStore';
78
import type {PlatformKey, Project} from 'sentry/types/project';
89
import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField';
9-
import {useUrlParams} from 'sentry/utils/url/useUrlParams';
1010
import {useProjects} from 'sentry/utils/useProjects';
1111

1212
type Props = {
@@ -24,8 +24,7 @@ export function useCurrentProjectState({
2424
}: Props) {
2525
const {projects, initiallyLoaded: projectsLoaded} = useProjects();
2626
const {selection, isReady} = useLegacyStore(PageFiltersStore);
27-
const {getParamValue: projectIds} = useUrlParams('project');
28-
const projectId = projectIds()?.split('&').at(0);
27+
const [projectId] = useQueryState('project', parseAsString);
2928
const isActive = currentPanel === targetPanel;
3029

3130
// Projects with onboarding instructions

static/app/components/replays/virtualizedGrid/useDetailsSplit.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {RefObject} from 'react';
22
import {useCallback} from 'react';
3+
import {parseAsInteger, useQueryState} from 'nuqs';
34

4-
import {useUrlParams} from 'sentry/utils/url/useUrlParams';
55
import {useResizableDrawer} from 'sentry/utils/useResizableDrawer';
66

77
interface OnClickProps {
@@ -26,26 +26,23 @@ export function useDetailsSplit({
2626
onShowDetails,
2727
urlParamName,
2828
}: Props) {
29-
const {getParamValue: getDetailIndex, setParamValue: setDetailIndex} = useUrlParams(
30-
urlParamName,
31-
''
32-
);
29+
const [detailIndex, setDetailIndex] = useQueryState(urlParamName, parseAsInteger);
3330

3431
const onClickCell = useCallback(
3532
({dataIndex, rowIndex}: OnClickProps) => {
36-
if (getDetailIndex() === String(dataIndex)) {
37-
setDetailIndex('');
33+
if (detailIndex === dataIndex) {
34+
setDetailIndex(null);
3835
onHideDetails?.();
3936
} else {
40-
setDetailIndex(String(dataIndex));
37+
setDetailIndex(dataIndex);
4138
onShowDetails?.({dataIndex, rowIndex});
4239
}
4340
},
44-
[getDetailIndex, setDetailIndex, onHideDetails, onShowDetails]
41+
[detailIndex, setDetailIndex, onHideDetails, onShowDetails]
4542
);
4643

4744
const onCloseDetailsSplit = useCallback(() => {
48-
setDetailIndex('');
45+
setDetailIndex(null);
4946
onHideDetails?.();
5047
}, [setDetailIndex, onHideDetails]);
5148

@@ -63,13 +60,15 @@ export function useDetailsSplit({
6360
const maxContainerHeight =
6461
(containerRef.current?.clientHeight || window.innerHeight) - handleHeight;
6562
const splitSize =
66-
frames && getDetailIndex() ? Math.min(maxContainerHeight, containerSize) : undefined;
63+
frames && detailIndex !== null
64+
? Math.min(maxContainerHeight, containerSize)
65+
: undefined;
6766

6867
return {
6968
onClickCell,
7069
onCloseDetailsSplit,
7170
resizableDrawerProps,
72-
selectedIndex: getDetailIndex(),
71+
selectedIndex: detailIndex,
7372
splitSize,
7473
};
7574
}

0 commit comments

Comments
 (0)