Skip to content

Commit 872f923

Browse files
add ChildAccountsTable component for IAM
1 parent 280ee59 commit 872f923

File tree

3 files changed

+114
-118
lines changed

3 files changed

+114
-118
lines changed

packages/manager/src/features/Account/SwitchAccountDrawer.tsx

Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@ import {
22
useChildAccountsInfiniteQuery,
33
useMyDelegatedChildAccountsQuery,
44
} from '@linode/queries';
5-
import { Drawer, LinkButton, Notice, Typography } from '@linode/ui';
5+
import {
6+
Button,
7+
Drawer,
8+
LinkButton,
9+
Notice,
10+
Stack,
11+
Typography,
12+
useTheme,
13+
} from '@linode/ui';
614
import React, { useMemo, useState } from 'react';
715

16+
import ErrorStateCloud from 'src/assets/icons/error-state-cloud.svg';
817
import { DebouncedSearchTextField } from 'src/components/DebouncedSearchTextField';
918
import { PARENT_USER_SESSION_EXPIRED } from 'src/features/Account/constants';
1019
import { useParentChildAuthentication } from 'src/features/Account/SwitchAccounts/useParentChildAuthentication';
@@ -35,11 +44,14 @@ interface HandleSwitchToChildAccountProps {
3544

3645
export const SwitchAccountDrawer = (props: Props) => {
3746
const { onClose, open, userType } = props;
47+
const theme = useTheme();
3848
const [isSubmitting, setSubmitting] = React.useState<boolean>(false);
3949
const [isParentTokenError, setIsParentTokenError] = React.useState<
4050
APIError[]
4151
>([]);
4252
const [searchQuery, setSearchQuery] = React.useState<string>('');
53+
const [page, setPage] = useState(1);
54+
const [pageSize, setPageSize] = useState(25);
4355
const { isIAMDelegationEnabled } = useIsIAMDelegationEnabled();
4456
const isParentUserType = userType === 'parent';
4557
const isProxyUserType = userType === 'proxy';
@@ -92,15 +104,14 @@ export const SwitchAccountDrawer = (props: Props) => {
92104
isRefetching: allChildAccountsIsRefetching,
93105
refetch: refetchAllChildAccounts,
94106
} = useMyDelegatedChildAccountsQuery({
95-
params: {},
107+
params: {
108+
page,
109+
page_size: pageSize,
110+
},
96111
filter,
97112
enabled: isIAMDelegationEnabled && isParentUserType,
98113
});
99114

100-
const refetchFn = isIAMDelegationEnabled
101-
? refetchAllChildAccounts
102-
: refetchChildAccounts;
103-
104115
const handleSwitchToChildAccount = React.useCallback(
105116
async ({
106117
currentTokenWithBearer,
@@ -190,6 +201,17 @@ export const SwitchAccountDrawer = (props: Props) => {
190201
const [isSwitchingChildAccounts, setIsSwitchingChildAccounts] =
191202
useState<boolean>(false);
192203

204+
const isLoading =
205+
isInitialLoading ||
206+
isSubmitting ||
207+
isSwitchingChildAccounts ||
208+
isRefetching ||
209+
allChildAccountsLoading ||
210+
allChildAccountsIsRefetching;
211+
212+
const refetchFn = isIAMDelegationEnabled
213+
? refetchAllChildAccounts
214+
: refetchChildAccounts;
193215
const handleClose = () => {
194216
setIsSwitchingChildAccounts(false);
195217
setSearchQuery('');
@@ -203,6 +225,15 @@ export const SwitchAccountDrawer = (props: Props) => {
203225
return data?.pages.flatMap((page) => page.data);
204226
}, [isIAMDelegationEnabled, allChildAccounts, data]);
205227

228+
const handlePageChange = (newPage: number) => {
229+
setPage(newPage);
230+
};
231+
232+
const handlePageSizeChange = (newPageSize: number) => {
233+
setPageSize(newPageSize);
234+
setPage(1); // Reset to first page when page size changes
235+
};
236+
206237
return (
207238
<Drawer onClose={handleClose} open={open} title="Switch Account">
208239
{createTokenErrorReason && (
@@ -234,50 +265,67 @@ export const SwitchAccountDrawer = (props: Props) => {
234265
)}
235266
.
236267
</Typography>
237-
{isIAMDelegationEnabled && allChildAccounts && (
268+
269+
{(childAccountInfiniteError || allChildAccountsError) && (
270+
<Stack alignItems="center" gap={1} justifyContent="center">
271+
<ErrorStateCloud />
272+
<Typography>Unable to load data.</Typography>
273+
<Typography>
274+
Try again or contact support if the issue persists.
275+
</Typography>
276+
<Button
277+
buttonType="primary"
278+
onClick={() => refetchFn()}
279+
sx={(theme) => ({
280+
marginTop: theme.spacingFunction(16),
281+
})}
282+
>
283+
Try again
284+
</Button>
285+
</Stack>
286+
)}
287+
{!(childAccountInfiniteError || allChildAccountsError) && (
238288
<>
239289
<DebouncedSearchTextField
240290
clearable
241291
debounceTime={250}
242292
hideLabel
243-
key={`iam-search-${searchQuery}`}
293+
key={`switch-search-${searchQuery}`}
244294
label="Search"
245295
onSearch={setSearchQuery}
246296
placeholder="Search"
247-
sx={{ marginBottom: 2 }}
297+
sx={{ marginBottom: theme.spacingFunction(12) }}
248298
value={searchQuery}
249299
/>
250-
{searchQuery && childAccounts && childAccounts.length === 0 && (
251-
<Typography sx={{ fontStyle: 'italic' }}>
252-
No search results
253-
</Typography>
254-
)}
300+
{searchQuery &&
301+
childAccounts &&
302+
childAccounts.length === 0 &&
303+
!isLoading && (
304+
<Typography
305+
sx={{
306+
fontStyle: 'italic',
307+
marginTop: theme.spacingFunction(6),
308+
}}
309+
>
310+
No search results
311+
</Typography>
312+
)}
255313
</>
256314
)}
257315
{isIAMDelegationEnabled && (
258316
<ChildAccountsTable
259317
childAccounts={childAccounts}
260318
currentTokenWithBearer={currentTokenWithBearer}
261-
errors={{
262-
childAccountInfiniteError,
263-
allChildAccountsError: allChildAccountsError?.[0]
264-
? new Error(allChildAccountsError[0].reason)
265-
: null,
266-
}}
267-
filter={filter}
268-
isLoading={
269-
isInitialLoading ||
270-
isSubmitting ||
271-
isSwitchingChildAccounts ||
272-
isRefetching ||
273-
allChildAccountsLoading ||
274-
allChildAccountsIsRefetching
275-
}
319+
isLoading={isLoading}
276320
isSwitchingChildAccounts={isSwitchingChildAccounts}
277321
onClose={onClose}
322+
onPageChange={handlePageChange}
323+
onPageSizeChange={handlePageSizeChange}
278324
onSwitchAccount={handleSwitchToChildAccount}
279-
refetchFn={refetchFn}
325+
page={page}
326+
pageSize={pageSize}
280327
setIsSwitchingChildAccounts={setIsSwitchingChildAccounts}
328+
totalResults={allChildAccounts?.results || 0}
281329
userType={userType}
282330
/>
283331
)}
@@ -299,14 +347,7 @@ export const SwitchAccountDrawer = (props: Props) => {
299347
filter={filter}
300348
hasNextPage={hasNextPage}
301349
isFetchingNextPage={isFetchingNextPage}
302-
isLoading={
303-
isInitialLoading ||
304-
isSubmitting ||
305-
isSwitchingChildAccounts ||
306-
isRefetching ||
307-
allChildAccountsLoading ||
308-
allChildAccountsIsRefetching
309-
}
350+
isLoading={isLoading}
310351
isSwitchingChildAccounts={isSwitchingChildAccounts}
311352
onClose={onClose}
312353
onSwitchAccount={handleSwitchToChildAccount}

packages/manager/src/features/Account/SwitchAccounts/ChildAccountList.tsx

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1-
import {
2-
Box,
3-
Button,
4-
CircleProgress,
5-
LinkButton,
6-
Notice,
7-
Stack,
8-
Typography,
9-
} from '@linode/ui';
1+
import { Box, CircleProgress, LinkButton, Notice, Stack } from '@linode/ui';
102
import React from 'react';
113
import { Waypoint } from 'react-waypoint';
124

13-
import ErrorStateCloud from 'src/assets/icons/error-state-cloud.svg';
145
import { useIsIAMDelegationEnabled } from 'src/features/IAM/hooks/useIsIAMEnabled';
156

167
import type { ChildAccount, Filter, UserType } from '@linode/api-v4';
@@ -52,39 +43,12 @@ export const ChildAccountList = React.memo(
5243
onClose,
5344
onSwitchAccount,
5445
userType,
55-
refetchFn,
56-
errors,
5746
hasNextPage,
5847
fetchNextPage,
5948
isFetchingNextPage,
6049
}: ChildAccountListProps) => {
6150
const { isIAMDelegationEnabled } = useIsIAMDelegationEnabled();
6251

63-
const hasError = isIAMDelegationEnabled
64-
? errors.allChildAccountsError
65-
: errors.childAccountInfiniteError;
66-
67-
if (hasError) {
68-
return (
69-
<Stack alignItems="center" gap={1} justifyContent="center">
70-
<ErrorStateCloud />
71-
<Typography>Unable to load data.</Typography>
72-
<Typography>
73-
Try again or contact support if the issue persists.
74-
</Typography>
75-
<Button
76-
buttonType="primary"
77-
onClick={() => refetchFn()}
78-
sx={(theme) => ({
79-
marginTop: theme.spacingFunction(16),
80-
})}
81-
>
82-
Try again
83-
</Button>
84-
</Stack>
85-
);
86-
}
87-
8852
if (isLoading) {
8953
return (
9054
<Box display="flex" justifyContent="center">
Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { LinkButton } from '@linode/ui';
1+
import { Box, CircleProgress, LinkButton, useTheme } from '@linode/ui';
2+
import { Pagination } from 'akamai-cds-react-components';
23
import {
34
Table,
45
TableBody,
@@ -7,22 +8,16 @@ import {
78
} from 'akamai-cds-react-components/Table';
89
import React from 'react';
910

10-
import { TableRowError } from 'src/components/TableRowError/TableRowError';
11-
import { TableRowLoading } from 'src/components/TableRowLoading/TableRowLoading';
12-
13-
import type { Account, Filter, UserType } from '@linode/api-v4';
11+
import type { Account, UserType } from '@linode/api-v4';
1412

1513
interface ChildAccountsTableProps {
1614
childAccounts?: Account[];
1715
currentTokenWithBearer?: string;
18-
errors: {
19-
allChildAccountsError: Error | null;
20-
childAccountInfiniteError: boolean;
21-
};
22-
filter: Filter;
2316
isLoading: boolean;
2417
isSwitchingChildAccounts: boolean;
2518
onClose: () => void;
19+
onPageChange: (page: number) => void;
20+
onPageSizeChange: (pageSize: number) => void;
2621
onSwitchAccount: ({
2722
currentTokenWithBearer,
2823
euuid,
@@ -36,51 +31,44 @@ interface ChildAccountsTableProps {
3631
onClose: (e: React.SyntheticEvent<HTMLElement>) => void;
3732
userType: undefined | UserType;
3833
}) => void;
39-
refetchFn: () => void;
34+
page: number;
35+
pageSize: number;
4036
setIsSwitchingChildAccounts: (value: boolean) => void;
37+
totalResults: number;
4138
userType: undefined | UserType;
4239
}
4340

4441
export const ChildAccountsTable = (props: ChildAccountsTableProps) => {
4542
const {
4643
childAccounts,
4744
currentTokenWithBearer,
48-
errors,
4945
isLoading,
5046
isSwitchingChildAccounts,
5147
onClose,
5248
onSwitchAccount,
5349
setIsSwitchingChildAccounts,
5450
userType,
51+
page,
52+
pageSize,
53+
totalResults,
54+
onPageChange,
55+
onPageSizeChange,
5556
} = props;
5657

57-
// const [page, setPage] = useState(1);
58-
// const [pageSize, setPageSize] = useState(25);
59-
60-
// const handlePageChange = (newPage: number) => {
61-
// setPage(newPage);
62-
// };
63-
64-
// const handlePageSizeChange = (newPageSize: number) => {
65-
// setPageSize(newPageSize);
66-
// setPage(1); // Reset to first page when page size changes
67-
// };
58+
const theme = useTheme();
59+
const handlePageChange = (newPage: number) => {
60+
onPageChange(newPage);
61+
};
6862

69-
// const startIndex = (page - 1) * pageSize;
70-
// const endIndex = startIndex + pageSize;
71-
// const paginatedAccounts = childAccounts?.slice(startIndex, endIndex) || [];
72-
// const totalCount = childAccounts?.length || 0;
63+
const handlePageSizeChange = (newPageSize: number) => {
64+
onPageSizeChange(newPageSize);
65+
};
7366

7467
if (isLoading) {
75-
return <TableRowLoading columns={2} />;
76-
}
77-
78-
if (errors.allChildAccountsError) {
7968
return (
80-
<TableRowError
81-
colSpan={2}
82-
message={errors.allChildAccountsError.message}
83-
/>
69+
<Box display="flex" justifyContent="center">
70+
<CircleProgress size="md" />
71+
</Box>
8472
);
8573
}
8674

@@ -112,18 +100,21 @@ export const ChildAccountsTable = (props: ChildAccountsTableProps) => {
112100
))}
113101
</TableBody>
114102
</Table>
115-
{/* {totalCount > pageSize && (
103+
{totalResults > pageSize && (
116104
<Pagination
117-
count={totalCount}
118-
onPageChange={(_, newPage) => handlePageChange(newPage)}
119-
onRowsPerPageChange={(event) =>
120-
handlePageSizeChange(parseInt(event.target.value, 10))
105+
count={totalResults}
106+
onPageChange={(e: CustomEvent<number>) =>
107+
handlePageChange(Number(e.detail))
121108
}
109+
onPageSizeChange={(
110+
e: CustomEvent<{ page: number; pageSize: number }>
111+
) => handlePageSizeChange(Number(e.detail.pageSize))}
122112
page={page}
123-
rowsPerPage={pageSize}
124-
rowsPerPageOptions={[25, 50, 100]}
113+
pageSize={pageSize}
114+
pageSizes={[25, 50, 75, 100]}
115+
style={{ marginTop: theme.spacingFunction(12) }}
125116
/>
126-
)} */}
117+
)}
127118
</>
128119
);
129120
};

0 commit comments

Comments
 (0)