diff --git a/packages/manager/.changeset/pr-13464-fixed-1772634680494.md b/packages/manager/.changeset/pr-13464-fixed-1772634680494.md new file mode 100644 index 00000000000..229fecf3f04 --- /dev/null +++ b/packages/manager/.changeset/pr-13464-fixed-1772634680494.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +IAM Parent/Child - SwitchAccount Drawer: hide search if no child account ([#13464](https://github.com/linode/manager/pull/13464)) diff --git a/packages/manager/src/assets/icons/no-results-state.svg b/packages/manager/src/assets/icons/no-results-state.svg new file mode 100644 index 00000000000..e7723054193 --- /dev/null +++ b/packages/manager/src/assets/icons/no-results-state.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/manager/src/features/Account/SwitchAccountDrawer.test.tsx b/packages/manager/src/features/Account/SwitchAccountDrawer.test.tsx index 36f4e9fcd7b..4ae55c8d34b 100644 --- a/packages/manager/src/features/Account/SwitchAccountDrawer.test.tsx +++ b/packages/manager/src/features/Account/SwitchAccountDrawer.test.tsx @@ -9,7 +9,11 @@ import { SwitchAccountDrawer } from './SwitchAccountDrawer'; const queryMocks = vi.hoisted(() => ({ useProfile: vi.fn().mockReturnValue({}), - useGetListMyDelegatedChildAccountsQuery: vi.fn().mockReturnValue({}), + useMyDelegatedChildAccountsQuery: vi.fn().mockReturnValue({}), + useChildAccountsInfiniteQuery: vi.fn().mockReturnValue({}), + useIsIAMDelegationEnabled: vi + .fn() + .mockReturnValue({ isIAMDelegationEnabled: true }), })); vi.mock('@linode/queries', async () => { @@ -17,8 +21,19 @@ vi.mock('@linode/queries', async () => { return { ...actual, useProfile: queryMocks.useProfile, - useGetListMyDelegatedChildAccountsQuery: - queryMocks.useGetListMyDelegatedChildAccountsQuery, + useMyDelegatedChildAccountsQuery: + queryMocks.useMyDelegatedChildAccountsQuery, + useChildAccountsInfiniteQuery: queryMocks.useChildAccountsInfiniteQuery, + }; +}); + +vi.mock('src/features/IAM/hooks/useIsIAMEnabled', async () => { + const actual = await vi.importActual( + 'src/features/IAM/hooks/useIsIAMEnabled' + ); + return { + ...actual, + useIsIAMDelegationEnabled: queryMocks.useIsIAMDelegationEnabled, }; }); @@ -29,16 +44,34 @@ const props = { }; describe('SwitchAccountDrawer', () => { + const accounts = accountFactory.buildList(5, { + company: 'Test Account 1', + }); + beforeEach(() => { queryMocks.useProfile.mockReturnValue({}); - queryMocks.useGetListMyDelegatedChildAccountsQuery.mockReturnValue({ - data: accountFactory.buildList(5, { - company: 'Test Account 1', - euuid: '123', - }), + queryMocks.useIsIAMDelegationEnabled.mockReturnValue({ + isIAMDelegationEnabled: true, + }); + queryMocks.useMyDelegatedChildAccountsQuery.mockReturnValue({ + data: { data: accounts, results: accounts.length, page: 1, pages: 1 }, isLoading: false, isRefetching: false, }); + queryMocks.useChildAccountsInfiniteQuery.mockReturnValue({ + data: { + pages: [ + { data: accounts, results: accounts.length, page: 1, pages: 1 }, + ], + pageParams: [], + }, + isInitialLoading: false, + isRefetching: false, + isFetchingNextPage: false, + hasNextPage: false, + fetchNextPage: vi.fn(), + refetch: vi.fn(), + }); }); it('should have a title', () => { @@ -94,4 +127,20 @@ describe('SwitchAccountDrawer', () => { expect(props.onClose).toHaveBeenCalledTimes(1); }); }); + + it('should display an empty state when no child accounts are found', async () => { + queryMocks.useMyDelegatedChildAccountsQuery.mockReturnValue({ + data: { data: [], results: 0, page: 1, pages: 1 }, + isLoading: false, + isRefetching: false, + }); + const { getByText } = renderWithTheme(); + + expect(getByText('You don’t have access to other accounts.')).toBeVisible(); + expect( + getByText( + 'You must be added to a delegation by an account administrator to have access to other accounts.' + ) + ).toBeVisible(); + }); }); diff --git a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx index 8faed748301..dea40764784 100644 --- a/packages/manager/src/features/Account/SwitchAccountDrawer.tsx +++ b/packages/manager/src/features/Account/SwitchAccountDrawer.tsx @@ -3,6 +3,7 @@ import { useMyDelegatedChildAccountsQuery, } from '@linode/queries'; import { + Box, Button, Drawer, LinkButton, @@ -14,6 +15,7 @@ import { import React, { useMemo, useState } from 'react'; import ErrorStateCloud from 'src/assets/icons/error-state-cloud.svg'; +import NoResultsState from 'src/assets/icons/no-results-state.svg'; import { DebouncedSearchTextField } from 'src/components/DebouncedSearchTextField'; import { useParentChildAuthentication } from 'src/features/Account/SwitchAccounts/useParentChildAuthentication'; import { useSwitchToParentAccount } from 'src/features/Account/SwitchAccounts/useSwitchToParentAccount'; @@ -217,6 +219,7 @@ export const SwitchAccountDrawer = (props: Props) => { const hasError = isIAMDelegationEnabled ? delegatedChildAccountsError : childAccountInfiniteError; + return ( {createTokenErrorReason && ( @@ -225,116 +228,144 @@ export const SwitchAccountDrawer = (props: Props) => { {isParentTokenError.length > 0 && ( )} - ({ - margin: `${theme.spacingFunction(24)} 0`, - })} - > - Select an account to view and manage its settings and configurations - {isProxyOrDelegateUserType && ( - <> - {' or '} - { - sendSwitchToParentAccountEvent(); - handleSwitchToParentAccount(); - }} - > - switch back to your account - - - )} - . - - - {hasError ? ( - - - Unable to load data. - - Try again or contact support if the issue persists. + {childAccounts && + childAccounts.length === 0 && + !Object.prototype.hasOwnProperty.call(filter, 'company') ? ( + + + + You don’t have access to other accounts. + + + You must be added to a delegation by an account administrator to + have access to other accounts. - + ) : ( <> - - {searchQuery && - childAccounts && - childAccounts.length === 0 && - !isLoading && ( - - No search results - + ({ + margin: `${theme.spacingFunction(24)} 0`, + })} + > + Select an account to view and manage its settings and configurations + {isProxyOrDelegateUserType && ( + <> + {' or '} + { + sendSwitchToParentAccountEvent(); + handleSwitchToParentAccount(); + }} + > + switch back to your account + + )} + . + - {isIAMDelegationEnabled && ( - - )} - {!isIAMDelegationEnabled && ( - + {hasError ? ( + + + Unable to load data. + + Try again or contact support if the issue persists. + + + + ) : ( + <> + {((childAccounts && childAccounts.length !== 0) || + searchQuery) && ( + + )} + {isIAMDelegationEnabled && + searchQuery && + childAccounts && + childAccounts.length === 0 && + !isLoading && ( + + No search results + + )} + + {isIAMDelegationEnabled && ( + + )} + {!isIAMDelegationEnabled && ( + + )} + )} )} diff --git a/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.test.tsx b/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.test.tsx index b7a4ec14655..e226097a2d2 100644 --- a/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.test.tsx +++ b/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.test.tsx @@ -28,7 +28,6 @@ const props: ChildAccountsTableProps = { setIsSwitchingChildAccounts: vi.fn(), totalResults: 0, userType: undefined, - filter: {}, isLoading: false, isSwitchingChildAccounts: false, onClose: vi.fn(), @@ -65,16 +64,4 @@ describe('ChildAccountsTable', () => { expect(getByTestId('child-accounts-table-pagination')).toBeVisible(); }); - - it('should display an empty state when no child accounts are found', async () => { - const { getByText } = renderWithTheme( - - ); - - expect( - getByText( - /You don't have access to other accounts. You must be added to a delegation by an account administrator to have access to other accounts./ - ) - ).toBeInTheDocument(); - }); }); diff --git a/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.tsx b/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.tsx index 31cd956fb29..524960b2cb0 100644 --- a/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.tsx +++ b/packages/manager/src/features/Account/SwitchAccounts/ChildAccountsTable.tsx @@ -1,4 +1,4 @@ -import { Box, CircleProgress, LinkButton, Notice, useTheme } from '@linode/ui'; +import { Box, CircleProgress, LinkButton, useTheme } from '@linode/ui'; import { Pagination } from 'akamai-cds-react-components/Pagination'; import { Table, @@ -10,12 +10,11 @@ import React from 'react'; import { MIN_PAGE_SIZE } from 'src/components/PaginationFooter/PaginationFooter.constants'; -import type { Account, Filter, UserType } from '@linode/api-v4'; +import type { Account, UserType } from '@linode/api-v4'; export interface ChildAccountsTableProps { childAccounts?: Account[]; currentTokenWithBearer?: string; - filter: Filter; isLoading: boolean; isSwitchingChildAccounts: boolean; onClose: () => void; @@ -43,7 +42,6 @@ export interface ChildAccountsTableProps { export const ChildAccountsTable = (props: ChildAccountsTableProps) => { const { - filter, childAccounts, currentTokenWithBearer, isLoading, @@ -76,19 +74,6 @@ export const ChildAccountsTable = (props: ChildAccountsTableProps) => { ); } - if ( - childAccounts && - childAccounts.length === 0 && - !Object.prototype.hasOwnProperty.call(filter, 'company') - ) { - return ( - - You don't have access to other accounts. You must be added to a - delegation by an account administrator to have access to other accounts. - - ); - } - return ( <>