Skip to content

Commit

Permalink
refactor: [M3-8981] - Use new preferences selector pattern in more pl…
Browse files Browse the repository at this point in the history
…aces (#11459)

* use selector pattern in most places

* update mocked unit test

* clean up profile settings

* add unit testing

* remove react scan before merging

---------

Co-authored-by: Banks Nussman <banks@nussman.us>
  • Loading branch information
bnussman-akamai and bnussman authored Jan 2, 2025
1 parent 2e89ecc commit 1fd49e8
Show file tree
Hide file tree
Showing 35 changed files with 574 additions and 229 deletions.
2 changes: 1 addition & 1 deletion packages/manager/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
</html>
9 changes: 6 additions & 3 deletions packages/manager/src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,20 @@ export const Avatar = (props: AvatarProps) => {

const theme = useTheme();

const { data: preferences } = usePreferences();
const { data: avatarColorPreference } = usePreferences(
(preferences) => preferences?.avatarColor
);
const { data: profile } = useProfile();

const _username = username ?? profile?.username ?? '';
const isAkamai =
_username === 'Akamai' || _username.startsWith('lke-service-account');

const savedAvatarColor =
isAkamai || !preferences?.avatarColor
isAkamai || !avatarColorPreference
? theme.palette.primary.dark
: preferences.avatarColor;
: avatarColorPreference;

const avatarLetter = _username[0]?.toUpperCase() ?? '';

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ export const DeletionDialog = React.memo((props: DeletionDialogProps) => {
typeToConfirm,
...rest
} = props;
const { data: preferences } = usePreferences();

const { data: typeToConfirmPreference } = usePreferences(
(preferences) => preferences?.type_to_confirm
);

const [confirmationText, setConfirmationText] = React.useState('');

const typeToConfirmRequired =
typeToConfirm && preferences?.type_to_confirm !== false;
typeToConfirm && typeToConfirmPreference !== false;

const renderActions = () => (
<ActionsPanel
primaryButtonProps={{
Expand Down
8 changes: 5 additions & 3 deletions packages/manager/src/components/MainContentBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ export const MainContentBanner = React.memo(() => {

const flags = useFlags();

const { data: preferences } = usePreferences();
const { data: mainContentBannerPreferences } = usePreferences(
(preferences) => preferences?.main_content_banner_dismissal
);
const { mutateAsync: updatePreferences } = useMutatePreferences();

const handleDismiss = (key: string) => {
const existingMainContentBannerDismissal =
preferences?.main_content_banner_dismissal ?? {};
mainContentBannerPreferences ?? {};

updatePreferences({
main_content_banner_dismissal: {
Expand All @@ -44,7 +46,7 @@ export const MainContentBanner = React.memo(() => {

const hasDismissedBanner =
flags.mainContentBanner?.key !== undefined &&
preferences?.main_content_banner_dismissal?.[flags.mainContentBanner.key];
mainContentBannerPreferences?.[flags.mainContentBanner.key];

if (
!flags.mainContentBanner ||
Expand Down
18 changes: 6 additions & 12 deletions packages/manager/src/components/MaskableText/MaskableText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ describe('MaskableText', () => {
text: plainText,
};

const preferences: ManagerPreferences = {
maskSensitiveData: true,
};
const preference: ManagerPreferences['maskSensitiveData'] = true;

const queryMocks = vi.hoisted(() => ({
usePreferences: vi.fn().mockReturnValue({}),
Expand All @@ -35,12 +33,12 @@ describe('MaskableText', () => {
});

queryMocks.usePreferences.mockReturnValue({
data: preferences,
data: preference,
});

it('should render masked text if the maskSensitiveData preference is enabled', () => {
queryMocks.usePreferences.mockReturnValue({
data: preferences,
data: preference,
});

const { getByText, queryByText } = renderWithTheme(
Expand All @@ -54,9 +52,7 @@ describe('MaskableText', () => {

it('should not render masked text if the maskSensitiveData preference is disabled', () => {
queryMocks.usePreferences.mockReturnValue({
data: {
maskSensitiveData: false,
},
data: false,
});

const { getByText, queryByText } = renderWithTheme(
Expand All @@ -70,9 +66,7 @@ describe('MaskableText', () => {

it("should render MaskableText's children if the maskSensitiveData preference is disabled and children are provided", () => {
queryMocks.usePreferences.mockReturnValue({
data: {
maskSensitiveData: false,
},
data: false,
});

const plainTextElement = <div>{plainText}</div>;
Expand All @@ -87,7 +81,7 @@ describe('MaskableText', () => {

it('should render a toggleable VisibilityTooltip if isToggleable is provided', async () => {
queryMocks.usePreferences.mockReturnValue({
data: preferences,
data: preference,
});

const { getByTestId, getByText } = renderWithTheme(
Expand Down
7 changes: 4 additions & 3 deletions packages/manager/src/components/MaskableText/MaskableText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ export interface MaskableTextProps {
}

export const MaskableText = (props: MaskableTextProps) => {
const { children, isToggleable = false, text, length } = props;
const { children, isToggleable = false, length, text } = props;

const { data: preferences } = usePreferences();
const maskedPreferenceSetting = preferences?.maskSensitiveData;
const { data: maskedPreferenceSetting } = usePreferences(
(preferences) => preferences?.maskSensitiveData
);

const [isMasked, setIsMasked] = React.useState(maskedPreferenceSetting);

Expand Down
13 changes: 7 additions & 6 deletions packages/manager/src/components/OrderBy.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
sortData,
} from './OrderBy';

import type { ManagerPreferences } from 'src/types/ManagerPreferences';

const a = {
age: 43,
hobbies: ['this', 'that', 'the other'],
Expand Down Expand Up @@ -61,14 +63,13 @@ describe('OrderBy', () => {
});

describe('getInitialValuesFromUserPreferences', () => {
const preferences = {
sortKeys: {
['listening-services']: {
order: 'desc' as any,
orderBy: 'test-order',
},
const preferences: ManagerPreferences['sortKeys'] = {
['listening-services']: {
order: 'desc',
orderBy: 'test-order',
},
};

it('should return values from query params if available', () => {
expect(
getInitialValuesFromUserPreferences(
Expand Down
12 changes: 7 additions & 5 deletions packages/manager/src/components/OrderBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export type CombinedProps<T> = Props<T>;
*/
export const getInitialValuesFromUserPreferences = (
preferenceKey: string,
preferences: ManagerPreferences,
preferences: ManagerPreferences['sortKeys'],
params: Record<string, string>,
defaultOrderBy?: string,
defaultOrder?: Order,
Expand Down Expand Up @@ -91,7 +91,7 @@ export const getInitialValuesFromUserPreferences = (
};
}
return (
preferences?.sortKeys?.[preferenceKey] ?? {
preferences?.[preferenceKey] ?? {
order: defaultOrder,
orderBy: defaultOrderBy,
}
Expand Down Expand Up @@ -156,15 +156,17 @@ export const sortData = <T,>(orderBy: string, order: Order) => {
};

export const OrderBy = <T,>(props: CombinedProps<T>) => {
const { data: preferences } = usePreferences();
const { data: sortPreferences } = usePreferences(
(preferences) => preferences?.sortKeys
);
const { mutateAsync: updatePreferences } = useMutatePreferences();
const location = useLocation();
const history = useHistory();
const params = getQueryParamsFromQueryString(location.search);

const initialValues = getInitialValuesFromUserPreferences(
props.preferenceKey ?? '',
preferences ?? {},
sortPreferences ?? {},
params,
props.orderBy,
props.order
Expand Down Expand Up @@ -210,7 +212,7 @@ export const OrderBy = <T,>(props: CombinedProps<T>) => {
if (props.preferenceKey) {
updatePreferences({
sortKeys: {
...(preferences?.sortKeys ?? {}),
...(sortPreferences ?? {}),
[props.preferenceKey]: { order, orderBy },
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ export const PreferenceToggle = <Key extends keyof ManagerPreferences>(
value,
} = props;

const { data: preferences } = usePreferences();
const { data: preference } = usePreferences(
(preferences) => preferences?.[preferenceKey]
);

const { mutateAsync: updateUserPreferences } = useMutatePreferences();

const togglePreference = () => {
let newPreferenceToSet: ManagerPreferences[Key];

if (preferences?.[preferenceKey] === undefined) {
if (preference === undefined) {
// Because we default to preferenceOptions[0], toggling with no preference should pick preferenceOptions[1]
newPreferenceToSet = preferenceOptions[1];
} else if (preferences[preferenceKey] === preferenceOptions[0]) {
} else if (preference === preferenceOptions[0]) {
newPreferenceToSet = preferenceOptions[1];
} else {
newPreferenceToSet = preferenceOptions[0];
Expand All @@ -64,7 +66,7 @@ export const PreferenceToggle = <Key extends keyof ManagerPreferences>(
};

return children({
preference: value ?? preferences?.[preferenceKey] ?? preferenceOptions[0]!,
preference: value ?? preference ?? preferenceOptions[0]!,
togglePreference,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,14 @@ export const TypeToConfirmDialog = (props: CombinedProps) => {

const [confirmText, setConfirmText] = React.useState('');

const { data: preferences } = usePreferences();
const { data: typeToConfirmPreference } = usePreferences(
(preferences) => preferences?.type_to_confirm
);

const isPrimaryButtonDisabled =
(preferences?.type_to_confirm !== false && confirmText !== entity.name) ||
(typeToConfirmPreference !== false && confirmText !== entity.name) ||
disableTypeToConfirmSubmit;

const isTypeToConfirmInputDisabled = disableTypeToConfirmInput;

React.useEffect(() => {
Expand Down Expand Up @@ -162,7 +166,7 @@ export const TypeToConfirmDialog = (props: CombinedProps) => {
textFieldStyle={textFieldStyle}
typographyStyle={typographyStyle}
value={confirmText}
visible={preferences?.type_to_confirm}
visible={typeToConfirmPreference}
/>
</ConfirmationDialog>
);
Expand Down
6 changes: 4 additions & 2 deletions packages/manager/src/features/Backups/BackupsCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const BackupsCTA = () => {
const { data: accountSettings } = useAccountSettings();
const { data: profile } = useProfile();

const { data: preferences } = usePreferences();
const { data: isBackupsBannerDismissed } = usePreferences(
(preferences) => preferences?.backups_cta_dismissed
);
const { mutateAsync: updatePreferences } = useMutatePreferences();

const [isBackupsDrawerOpen, setIsBackupsDrawerOpen] = React.useState(false);
Expand All @@ -36,7 +38,7 @@ export const BackupsCTA = () => {
profile?.restricted ||
accountSettings?.managed ||
areAllLinodesBackedUp ||
preferences?.backups_cta_dismissed
isBackupsBannerDismissed
) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ export const ContactInformation = React.memo((props: Props) => {

const { data: notifications } = useNotificationsQuery();

const { data: preferences } = usePreferences();
const { data: maskSensitiveDataPreference } = usePreferences(
(preferences) => preferences?.maskSensitiveData
);

const [focusEmail, setFocusEmail] = React.useState(false);

Expand Down Expand Up @@ -118,7 +120,7 @@ export const ContactInformation = React.memo((props: Props) => {
}, [editContactDrawerOpen, history.location.state]);

const [isContactInfoMasked, setIsContactInfoMasked] = useState(
preferences?.maskSensitiveData
maskSensitiveDataPreference
);

/**
Expand Down Expand Up @@ -176,7 +178,7 @@ export const ContactInformation = React.memo((props: Props) => {
{EDIT_BILLING_CONTACT}
</BillingActionButton>
)}
{preferences?.maskSensitiveData && (
{maskSensitiveDataPreference && (
<BillingActionButton
disableFocusRipple
disableRipple
Expand All @@ -195,7 +197,7 @@ export const ContactInformation = React.memo((props: Props) => {
)}
</Box>
</BillingBox>
{preferences?.maskSensitiveData && isContactInfoMasked ? (
{maskSensitiveDataPreference && isContactInfoMasked ? (
<Typography>
This data is sensitive and hidden for privacy. To unmask all
sensitive data by default, go to{' '}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ export const NodeRow = React.memo((props: NodeRowProps) => {
} = props;

const { data: events } = useInProgressEvents();
const { data: preferences } = usePreferences();
const { data: maskSensitiveDataPreference } = usePreferences(
(preferences) => preferences?.maskSensitiveData
);

const recentEvent = events?.find(
(event) =>
Expand Down Expand Up @@ -123,7 +125,7 @@ export const NodeRow = React.memo((props: NodeRowProps) => {
>
<CopyTooltip
copyableText
masked={Boolean(preferences?.maskSensitiveData)}
masked={Boolean(maskSensitiveDataPreference)}
maskedTextLength="ipv4"
text={displayIP}
/>
Expand Down
Loading

0 comments on commit 1fd49e8

Please sign in to comment.