From b0004ccef029dc9fb2990304939ce6c75440a2b7 Mon Sep 17 00:00:00 2001 From: Jaalah Ramos Date: Tue, 27 Feb 2024 15:53:02 -0500 Subject: [PATCH 1/6] Fix account switching --- .../features/Account/SwitchAccountDrawer.tsx | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx index 3391402a690..4f48ad84043 100644 --- a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx +++ b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx @@ -1,6 +1,5 @@ import { createChildAccountPersonalAccessToken } from '@linode/api-v4'; import React from 'react'; -import { useHistory } from 'react-router-dom'; import { StyledLinkButton } from 'src/components/Button/StyledLinkButton'; import { Drawer } from 'src/components/Drawer'; @@ -18,6 +17,7 @@ import { getStorage } from 'src/utilities/storage'; import { ChildAccountList } from './SwitchAccounts/ChildAccountList'; +import type { Token } from '@linode/api-v4'; import type { APIError, ChildAccountPayload, UserType } from '@linode/api-v4'; import type { State as AuthState } from 'src/store/authentication'; @@ -38,7 +38,8 @@ export const SwitchAccountDrawer = (props: Props) => { ); const currentTokenWithBearer = useCurrentToken() ?? ''; - const history = useHistory(); + const currentParentToken = + getStorage('authentication/parent_token/token') ?? ''; const handleClose = React.useCallback(() => { onClose(); @@ -76,11 +77,9 @@ export const SwitchAccountDrawer = (props: Props) => { [] ); - // Navigate to the current location, triggering a re-render without a full page reload. const refreshPage = React.useCallback(() => { - // TODO: Parent/Child: We need to test this against the real API. - history.push(history.location.pathname); - }, [history]); + location.reload(); + }, []); const handleSwitchToChildAccount = React.useCallback( async ({ @@ -97,17 +96,13 @@ export const SwitchAccountDrawer = (props: Props) => { isProxyUser: boolean; }) => { try { - // TODO: Parent/Child: FOR MSW ONLY, REMOVE WHEN API IS READY - // ================================================================ - // throw new Error( - // `Account switching failed. Try again.` - // ); - // ================================================================ - // We don't need to worry about this if we're a proxy user. if (!isProxyUser) { - const parentToken = { + const parentToken: Token = { + created: getStorage('authentication/created'), expiry: getStorage('authentication/expire'), + id: getStorage('authentication/id'), + label: getStorage('authentication/label'), scopes: getStorage('authentication/scopes'), token: currentTokenWithBearer ?? '', }; @@ -128,7 +123,10 @@ export const SwitchAccountDrawer = (props: Props) => { setTokenInLocalStorage({ prefix: 'authentication/proxy_token', - token: proxyToken, + token: { + ...proxyToken, + token: `Bearer ${proxyToken.token}`, + }, }); updateCurrentTokenBasedOnUserType({ @@ -139,16 +137,6 @@ export const SwitchAccountDrawer = (props: Props) => { refreshPage(); } catch (error) { setIsProxyTokenError(error as APIError[]); - - // TODO: Parent/Child: FOR MSW ONLY, REMOVE WHEN API IS READY - // ================================================================ - // setIsProxyTokenError([ - // { - // field: 'token', - // reason: error.message, - // }, - // ]); - // ================================================================ } }, [getProxyToken, refreshPage] @@ -168,7 +156,8 @@ export const SwitchAccountDrawer = (props: Props) => { updateCurrentTokenBasedOnUserType({ userType: 'parent' }); handleClose(); - }, [handleClose, isProxyUser]); + refreshPage(); + }, [handleClose, refreshPage]); return ( @@ -201,7 +190,9 @@ export const SwitchAccountDrawer = (props: Props) => { . Date: Tue, 27 Feb 2024 16:16:49 -0500 Subject: [PATCH 2/6] Added changeset: Fix Account Switching --- .../.changeset/pr-10234-upcoming-features-1709068609413.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-10234-upcoming-features-1709068609413.md diff --git a/packages/manager/.changeset/pr-10234-upcoming-features-1709068609413.md b/packages/manager/.changeset/pr-10234-upcoming-features-1709068609413.md new file mode 100644 index 00000000000..b41a933532d --- /dev/null +++ b/packages/manager/.changeset/pr-10234-upcoming-features-1709068609413.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Fix Account Switching ([#10234](https://github.com/linode/manager/pull/10234)) From 24f8d6d7000fc5b2248723f0802bcf8a22306d08 Mon Sep 17 00:00:00 2001 From: Jaalah Ramos Date: Tue, 27 Feb 2024 16:19:24 -0500 Subject: [PATCH 3/6] Added changeset: Fix to ensure ChildAccountList receives proper account token --- .../.changeset/pr-10234-upcoming-features-1709068764309.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-10234-upcoming-features-1709068764309.md diff --git a/packages/manager/.changeset/pr-10234-upcoming-features-1709068764309.md b/packages/manager/.changeset/pr-10234-upcoming-features-1709068764309.md new file mode 100644 index 00000000000..ec7f0726d34 --- /dev/null +++ b/packages/manager/.changeset/pr-10234-upcoming-features-1709068764309.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Fix to ensure ChildAccountList receives proper account token ([#10234](https://github.com/linode/manager/pull/10234)) From 3b830e8dbaac6e1592b42c7beb22d46702e19688 Mon Sep 17 00:00:00 2001 From: Jaalah Ramos <125309814+jaalah-akamai@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:01:13 -0500 Subject: [PATCH 4/6] Update packages/manager/src/features/Account/SwitchAccountDrawer.tsx Co-authored-by: Mariah Jacobs <114685994+mjac0bs@users.noreply.github.com> --- packages/manager/src/features/Account/SwitchAccountDrawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx index 4f48ad84043..ab56a87695e 100644 --- a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx +++ b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx @@ -191,7 +191,7 @@ export const SwitchAccountDrawer = (props: Props) => { Date: Tue, 27 Feb 2024 17:01:18 -0500 Subject: [PATCH 5/6] Update packages/manager/src/features/Account/SwitchAccountDrawer.tsx Co-authored-by: Mariah Jacobs <114685994+mjac0bs@users.noreply.github.com> --- packages/manager/src/features/Account/SwitchAccountDrawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx index ab56a87695e..216ccece28a 100644 --- a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx +++ b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx @@ -38,7 +38,7 @@ export const SwitchAccountDrawer = (props: Props) => { ); const currentTokenWithBearer = useCurrentToken() ?? ''; - const currentParentToken = + const currentParentTokenWithBearer = getStorage('authentication/parent_token/token') ?? ''; const handleClose = React.useCallback(() => { From a2c03dea7090e61c73d6f6148206b34575e5d701 Mon Sep 17 00:00:00 2001 From: Joe D'Amore Date: Tue, 27 Feb 2024 17:05:12 -0500 Subject: [PATCH 6/6] Update account switching test to reflect bug fixes --- .../parentChild/account-switching.spec.ts | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/packages/manager/cypress/e2e/core/parentChild/account-switching.spec.ts b/packages/manager/cypress/e2e/core/parentChild/account-switching.spec.ts index 60c6488ef30..52b053af660 100644 --- a/packages/manager/cypress/e2e/core/parentChild/account-switching.spec.ts +++ b/packages/manager/cypress/e2e/core/parentChild/account-switching.spec.ts @@ -57,7 +57,7 @@ const assertAuthLocalStorage = ( expiry: string, scopes: string ) => { - assertLocalStorageValue('authentication/token', token); + assertLocalStorageValue('authentication/token', `Bearer ${token}`); assertLocalStorageValue('authentication/expire', expiry); assertLocalStorageValue('authentication/scopes', scopes); }; @@ -126,6 +126,23 @@ describe('Parent/Child account switching', () => { .should('be.enabled') .click(); + // Prepare up mocks in advance of the account switch. As soon as the child account is clicked, + // Cloud will replace its stored token with the token provided by the API and then reload. + // From that point forward, we will not have a valid test account token stored in local storage, + // so all non-intercepted API requests will respond with a 401 status code and we will get booted to login. + // We'll mitigate this by broadly mocking ALL API-v4 requests, then applying more specific mocks to the + // individual requests as needed. + mockAllApiRequests(); + mockGetLinodes([]); + mockGetRegions([]); + mockGetEvents([]); + mockGetNotifications([]); + mockGetAccount(mockChildAccount); + mockGetProfile(mockParentProfile); + mockGetUser(mockParentUser); + + // Mock the account switch itself -- we have to do this after the mocks above + // to ensure that it is applied. mockCreateChildAccountToken(mockChildAccount, mockChildAccountToken).as( 'switchAccount' ); @@ -147,24 +164,6 @@ describe('Parent/Child account switching', () => { mockChildAccountToken.scopes ); - // From this point forward, we will not have a valid test account token stored in local storage, - // so all non-intercepted API requests will respond with a 401 status code and we will get booted to login. - // We'll mitigate this by broadly mocking ALL API-v4 requests, then applying more specific mocks to the - // individual requests as needed. - mockAllApiRequests(); - mockGetLinodes([]); - mockGetRegions([]); - mockGetEvents([]); - mockGetNotifications([]); - - mockGetAccount(mockChildAccount); - mockGetProfile(mockParentProfile); - mockGetUser(mockParentUser); - - // TODO Remove the call to `cy.reload()` once Cloud Manager automatically updates itself upon account switching. - // TODO Add assertions for toast upon account switch. This might involve improving mocks for events/notifications. - cy.reload(); - // Confirm expected username and company are shown in user menu button. assertUserMenuButton( mockParentProfile.username, @@ -205,6 +204,21 @@ describe('Parent/Child account switching', () => { .click(); }); + // Prepare up mocks in advance of the account switch. As soon as the child account is clicked, + // Cloud will replace its stored token with the token provided by the API and then reload. + // From that point forward, we will not have a valid test account token stored in local storage, + // so all non-intercepted API requests will respond with a 401 status code and we will get booted to login. + // We'll mitigate this by broadly mocking ALL API-v4 requests, then applying more specific mocks to the + // individual requests as needed. + mockAllApiRequests(); + mockGetLinodes([]); + mockGetRegions([]); + mockGetEvents([]); + mockGetNotifications([]); + mockGetAccount(mockChildAccount); + mockGetProfile(mockParentProfile); + mockGetUser(mockParentUser); + // Click mock company name in "Switch Account" drawer. mockCreateChildAccountToken(mockChildAccount, mockChildAccountToken).as( 'switchAccount' @@ -227,23 +241,6 @@ describe('Parent/Child account switching', () => { mockChildAccountToken.scopes ); - // From this point forward, we will not have a valid test account token stored in local storage, - // so all non-intercepted API requests will respond with a 401 status code and we will get booted to login. - // We'll mitigate this by broadly mocking ALL API-v4 requests, then applying more specific mocks to the - // individual requests as needed. - mockAllApiRequests(); - mockGetLinodes([]); - mockGetRegions([]); - mockGetEvents([]); - mockGetNotifications([]); - mockGetAccount(mockChildAccount); - mockGetProfile(mockParentProfile); - mockGetUser(mockParentUser); - - // TODO Remove the call to `cy.reload()` once Cloud Manager automatically updates itself upon account switching. - // TODO Add assertions for toast upon account switch. This might involve improving mocks for events/notifications. - cy.reload(); - // Confirm expected username and company are shown in user menu button. assertUserMenuButton( mockParentProfile.username,