-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: [M3-8981] - User Preferences optimization with selector pattern (Part 1) #11386
Changes from 2 commits
ad02ddb
a31c62c
08308d9
4fe21d3
605fa4f
b7e1bc9
d185cc4
f4f9070
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,7 +93,12 @@ export const PrimaryNav = (props: PrimaryNavProps) => { | |
|
||
const { isIAMEnabled, isIAMBeta } = useIsIAMEnabled(); | ||
|
||
const { data: preferences } = usePreferences(); | ||
const { data: collapsedSideNavPreference } = usePreferences( | ||
(preferences) => preferences?.collapsedSideNavProductFamilies | ||
); | ||
Comment on lines
+96
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the new pattern in-use! β¨ Before: The primary nav would re-render when any preference was updated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be unrelated, but Iβm noticing that PrimaryNav re-renders when navigating to Create understood - it's a Create Image, but is PrimaryNav supposed to get re-rendered in such cases?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that is unrelated. From my understanding, the primary nav will re-render when we change routes no matter what. |
||
|
||
const collapsedAccordions = collapsedSideNavPreference ?? []; | ||
|
||
const { mutateAsync: updatePreferences } = useMutatePreferences(); | ||
|
||
const productFamilyLinkGroups: ProductFamilyLinkGroup< | ||
|
@@ -253,10 +258,6 @@ export const PrimaryNav = (props: PrimaryNavProps) => { | |
] | ||
); | ||
|
||
const [collapsedAccordions, setCollapsedAccordions] = React.useState< | ||
number[] | ||
>(preferences?.collapsedSideNavProductFamilies ?? []); | ||
Comment on lines
-256
to
-258
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to use extra state here. Because our user preferences optimistically update, we can essentially treat it as state. |
||
|
||
const accordionClicked = (index: number) => { | ||
let updatedCollapsedAccordions; | ||
if (collapsedAccordions.includes(index)) { | ||
|
@@ -266,13 +267,11 @@ export const PrimaryNav = (props: PrimaryNavProps) => { | |
updatePreferences({ | ||
collapsedSideNavProductFamilies: updatedCollapsedAccordions, | ||
}); | ||
setCollapsedAccordions(updatedCollapsedAccordions); | ||
} else { | ||
updatedCollapsedAccordions = [...collapsedAccordions, index]; | ||
updatePreferences({ | ||
collapsedSideNavProductFamilies: updatedCollapsedAccordions, | ||
}); | ||
setCollapsedAccordions(updatedCollapsedAccordions); | ||
} | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,6 @@ import type { ExtendedStatus } from './utils'; | |
import type { Config } from '@linode/api-v4/lib/linodes/types'; | ||
import type { APIError } from '@linode/api-v4/lib/types'; | ||
import type { RouteComponentProps } from 'react-router-dom'; | ||
import type { PreferenceToggleProps } from 'src/components/PreferenceToggle/PreferenceToggle'; | ||
import type { WithFeatureFlagProps } from 'src/containers/flags.container'; | ||
import type { WithProfileProps } from 'src/containers/profile.container'; | ||
import type { DialogType } from 'src/features/Linodes/types'; | ||
|
@@ -308,17 +307,17 @@ class ListLinodes extends React.Component<CombinedProps, State> { | |
)} | ||
<DocumentTitleSegment segment="Linodes" /> | ||
<ProductInformationBanner bannerLocation="Linodes" /> | ||
<PreferenceToggle<boolean> | ||
<PreferenceToggle | ||
preferenceKey="linodes_group_by_tag" | ||
preferenceOptions={[false, true]} | ||
toggleCallbackFn={sendGroupByAnalytic} | ||
> | ||
{({ | ||
preference: linodesAreGrouped, | ||
togglePreference: toggleGroupLinodes, | ||
}: PreferenceToggleProps<boolean>) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I improved the type-safety of |
||
}) => { | ||
return ( | ||
<PreferenceToggle<'grid' | 'list'> | ||
<PreferenceToggle | ||
preferenceKey="linodes_view_style" | ||
preferenceOptions={['list', 'grid']} | ||
toggleCallbackFn={this.changeView} | ||
|
@@ -331,7 +330,7 @@ class ListLinodes extends React.Component<CombinedProps, State> { | |
{({ | ||
preference: linodeViewPreference, | ||
togglePreference: toggleLinodeView, | ||
}: PreferenceToggleProps<'grid' | 'list'>) => { | ||
}) => { | ||
return ( | ||
<React.Fragment> | ||
<React.Fragment> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,42 @@ | ||
import { updateUserPreferences } from '@linode/api-v4'; | ||
import { | ||
QueryClient, | ||
useMutation, | ||
useQuery, | ||
useQueryClient, | ||
} from '@tanstack/react-query'; | ||
|
||
import { ManagerPreferences } from 'src/types/ManagerPreferences'; | ||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | ||
|
||
import { queryPresets } from '../base'; | ||
import { profileQueries } from './profile'; | ||
|
||
import type { APIError } from '@linode/api-v4'; | ||
import type { QueryClient } from '@tanstack/react-query'; | ||
import type { ManagerPreferences } from 'src/types/ManagerPreferences'; | ||
|
||
export const usePreferences = (enabled = true) => | ||
useQuery<ManagerPreferences, APIError[]>({ | ||
export const usePreferences = <TData = ManagerPreferences>( | ||
bnussman-akamai marked this conversation as resolved.
Show resolved
Hide resolved
|
||
select?: (data: ManagerPreferences | undefined) => TData, | ||
enabled = true | ||
) => | ||
useQuery({ | ||
...profileQueries.preferences, | ||
...queryPresets.oneTimeFetch, | ||
enabled, | ||
select, | ||
}); | ||
|
||
export const useMutatePreferences = (replace = false) => { | ||
const { data: preferences } = usePreferences(!replace); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed this use of Using |
||
const queryClient = useQueryClient(); | ||
|
||
return useMutation< | ||
ManagerPreferences, | ||
APIError[], | ||
Partial<ManagerPreferences> | ||
>({ | ||
mutationFn: (data) => | ||
updateUserPreferences({ | ||
...(!replace && preferences !== undefined ? preferences : {}), | ||
...data, | ||
}), | ||
async mutationFn(data) { | ||
if (replace) { | ||
return updateUserPreferences(data); | ||
} else { | ||
const existingPreferences = await queryClient.ensureQueryData<ManagerPreferences>( | ||
profileQueries.preferences | ||
); | ||
return updateUserPreferences({ ...existingPreferences, ...data }); | ||
} | ||
}, | ||
bnussman-akamai marked this conversation as resolved.
Show resolved
Hide resolved
|
||
onMutate: (data) => updatePreferenceData(data, replace, queryClient), | ||
}); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import type { UserPreferences } from '@linode/api-v4'; | ||
import type { AclpConfig } from '@linode/api-v4'; | ||
import type { Order } from 'src/hooks/useOrder'; | ||
import type { ThemeChoice } from 'src/utilities/theme'; | ||
|
||
|
@@ -14,9 +14,11 @@ export interface DismissedNotification { | |
label?: string; | ||
} | ||
|
||
export interface ManagerPreferences extends UserPreferences { | ||
export interface ManagerPreferences { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
aclpPreference?: AclpConfig; // Why is this type in @linode/api-v4? | ||
avatarColor?: string; | ||
backups_cta_dismissed?: boolean; | ||
collapsedSideNavProductFamilies?: number[]; | ||
desktop_sidebar_open?: boolean; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were types missing... Now that type-safety is better, developers will see type errors that will catch this |
||
dismissed_notifications?: Record<string, DismissedNotification>; | ||
domains_group_by_tag?: boolean; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to make some changes here to improve type-safety. See other comment in
LinodesLanding.tsx