Skip to content

Commit 8455fa6

Browse files
bnussman-akamaibnussman
authored andcommitted
feat: [M3-7026] - AGLB Details - Service Targets Tab (linode#9577)
* initial build * add cert field * Added changeset: Add AGLB Details - Service Targets Tab * make more responsive * improve search * feedback --------- Co-authored-by: Banks Nussman <banks@nussman.us>
1 parent fe09eb9 commit 8455fa6

File tree

12 files changed

+203
-444
lines changed

12 files changed

+203
-444
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
Add AGLB Details - Service Targets Tab ([#9577](https://github.com/linode/manager/pull/9577))

packages/manager/src/features/LoadBalancers/LoadBalancerDetail/LoadBalancerDetail.tsx

+11-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ const LoadBalancerSummary = React.lazy(() =>
1616
}))
1717
);
1818

19+
const LoadBalancerServiceTargets = React.lazy(() =>
20+
import('./LoadBalancerServiceTargets').then((module) => ({
21+
default: module.LoadBalancerServiceTargets,
22+
}))
23+
);
24+
1925
const LoadBalancerCertificates = React.lazy(() =>
2026
import('./LoadBalancerCertificates').then((module) => ({
2127
default: module.LoadBalancerCertificates,
@@ -93,7 +99,11 @@ const LoadBalancerDetailLanding = () => {
9399
</SafeTabPanel>
94100
<SafeTabPanel index={1}>1</SafeTabPanel>
95101
<SafeTabPanel index={2}>2</SafeTabPanel>
96-
<SafeTabPanel index={3}>3</SafeTabPanel>
102+
<SafeTabPanel index={3}>
103+
<React.Suspense fallback={<SuspenseLoader />}>
104+
<LoadBalancerServiceTargets />
105+
</React.Suspense>
106+
</SafeTabPanel>
97107
<SafeTabPanel index={4}>
98108
<React.Suspense fallback={<SuspenseLoader />}>
99109
<LoadBalancerCertificates />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import CloseIcon from '@mui/icons-material/Close';
2+
import { Hidden, IconButton } from '@mui/material';
3+
import Stack from '@mui/material/Stack';
4+
import React, { useState } from 'react';
5+
import { useParams } from 'react-router-dom';
6+
7+
import { ActionMenu } from 'src/components/ActionMenu';
8+
import { Box } from 'src/components/Box';
9+
import { Button } from 'src/components/Button/Button';
10+
import { CircleProgress } from 'src/components/CircleProgress';
11+
import { InputAdornment } from 'src/components/InputAdornment';
12+
import { Link } from 'src/components/Link';
13+
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
14+
import { StatusIcon } from 'src/components/StatusIcon/StatusIcon';
15+
import { Table } from 'src/components/Table';
16+
import { TableBody } from 'src/components/TableBody';
17+
import { TableCell } from 'src/components/TableCell';
18+
import { TableHead } from 'src/components/TableHead';
19+
import { TableRow } from 'src/components/TableRow';
20+
import { TableRowEmpty } from 'src/components/TableRowEmpty/TableRowEmpty';
21+
import { TableRowError } from 'src/components/TableRowError/TableRowError';
22+
import { TableSortCell } from 'src/components/TableSortCell';
23+
import { TextField } from 'src/components/TextField';
24+
import { Typography } from 'src/components/Typography';
25+
import { useOrder } from 'src/hooks/useOrder';
26+
import { usePagination } from 'src/hooks/usePagination';
27+
import { useLoadBalancerServiceTargetsQuery } from 'src/queries/aglb/serviceTargets';
28+
29+
import type { Filter } from '@linode/api-v4';
30+
31+
const PREFERENCE_KEY = 'loadbalancer-service-targets';
32+
33+
export const LoadBalancerServiceTargets = () => {
34+
const { loadbalancerId } = useParams<{ loadbalancerId: string }>();
35+
36+
const [query, setQuery] = useState<string>();
37+
38+
const pagination = usePagination(1, PREFERENCE_KEY);
39+
40+
const { handleOrderChange, order, orderBy } = useOrder(
41+
{
42+
order: 'desc',
43+
orderBy: 'label',
44+
},
45+
`${PREFERENCE_KEY}-order`
46+
);
47+
48+
const filter: Filter = {
49+
['+order']: order,
50+
['+order_by']: orderBy,
51+
};
52+
53+
// If the user types in a search query, filter results by label.
54+
if (query) {
55+
filter['label'] = { '+contains': query };
56+
}
57+
58+
const { data, error, isLoading } = useLoadBalancerServiceTargetsQuery(
59+
Number(loadbalancerId),
60+
{
61+
page: pagination.page,
62+
page_size: pagination.pageSize,
63+
},
64+
filter
65+
);
66+
67+
if (isLoading) {
68+
return <CircleProgress />;
69+
}
70+
71+
return (
72+
<>
73+
<Stack
74+
alignItems="flex-end"
75+
direction="row"
76+
flexWrap="wrap"
77+
gap={2}
78+
mb={2}
79+
mt={1.5}
80+
>
81+
<TextField
82+
InputProps={{
83+
endAdornment: (
84+
<InputAdornment position="end">
85+
<IconButton
86+
aria-label="Clear"
87+
onClick={() => setQuery('')}
88+
size="small"
89+
sx={{ padding: 'unset' }}
90+
>
91+
<CloseIcon
92+
color="inherit"
93+
sx={{ color: '#aaa !important' }}
94+
/>
95+
</IconButton>
96+
</InputAdornment>
97+
),
98+
}}
99+
hideLabel
100+
label="Filter"
101+
onChange={(e) => setQuery(e.target.value)}
102+
placeholder="Filter"
103+
style={{ minWidth: '320px' }}
104+
value={query}
105+
/>
106+
<Box flexGrow={1} />
107+
<Button buttonType="primary">Create Service Target</Button>
108+
</Stack>
109+
<Table>
110+
<TableHead>
111+
<TableRow>
112+
<TableSortCell
113+
active={orderBy === 'label'}
114+
direction={order}
115+
handleClick={handleOrderChange}
116+
label="label"
117+
>
118+
Label
119+
</TableSortCell>
120+
<TableCell>Endpoints</TableCell>
121+
<Hidden smDown>
122+
<TableCell>Algorithm</TableCell>
123+
</Hidden>
124+
<Hidden mdDown>
125+
<TableCell>Certificate</TableCell>
126+
</Hidden>
127+
<Hidden lgDown>
128+
<TableCell>Health Checks</TableCell>
129+
</Hidden>
130+
<TableCell></TableCell>
131+
</TableRow>
132+
</TableHead>
133+
<TableBody>
134+
{error && <TableRowError colSpan={6} message={error?.[0]?.reason} />}
135+
{data?.results === 0 && <TableRowEmpty colSpan={6} />}
136+
{data?.data.map((serviceTarget) => (
137+
<TableRow key={serviceTarget.label}>
138+
<TableCell>
139+
<Link to={String(serviceTarget.id)}>{serviceTarget.label}</Link>
140+
</TableCell>
141+
<TableCell>
142+
<Stack alignItems="center" direction="row" spacing={0.5}>
143+
<StatusIcon status="active" />
144+
<Typography noWrap>4 up</Typography>
145+
<Typography>&mdash;</Typography>
146+
<StatusIcon status="error" />
147+
<Typography noWrap>6 down</Typography>
148+
</Stack>
149+
</TableCell>
150+
<Hidden smDown>
151+
<TableCell sx={{ textTransform: 'capitalize' }}>
152+
{serviceTarget.load_balancing_policy.replace('_', ' ')}
153+
</TableCell>
154+
</Hidden>
155+
<Hidden mdDown>
156+
<TableCell>{serviceTarget.ca_certificate}</TableCell>
157+
</Hidden>
158+
<Hidden lgDown>
159+
<TableCell>
160+
{serviceTarget.healthcheck.interval !== 0 ? 'Yes' : 'No'}
161+
</TableCell>
162+
</Hidden>
163+
<TableCell actionCell>
164+
<ActionMenu
165+
actionsList={[
166+
{ onClick: () => null, title: 'Edit' },
167+
{ onClick: () => null, title: 'Clone Service Target' },
168+
{ onClick: () => null, title: 'Delete' },
169+
]}
170+
ariaLabel={`Action Menu for service target ${serviceTarget.label}`}
171+
/>
172+
</TableCell>
173+
</TableRow>
174+
))}
175+
</TableBody>
176+
</Table>
177+
<PaginationFooter
178+
count={data?.results ?? 0}
179+
handlePageChange={pagination.handlePageChange}
180+
handleSizeChange={pagination.handlePageSizeChange}
181+
page={pagination.page}
182+
pageSize={pagination.pageSize}
183+
/>
184+
</>
185+
);
186+
};

packages/manager/src/features/LoadBalancers/Routes/RouteCreate/RouteCreate.tsx

-14
This file was deleted.

packages/manager/src/features/LoadBalancers/Routes/RouteLanding/RouteLanding.tsx

-14
This file was deleted.

packages/manager/src/features/LoadBalancers/ServiceTargets/ServiceTargetCreate/ServiceTargetCreate.tsx

-14
This file was deleted.

packages/manager/src/features/LoadBalancers/ServiceTargets/ServiceTargetLanding/ServiceTargetActionMenu.test.tsx

-46
This file was deleted.

packages/manager/src/features/LoadBalancers/ServiceTargets/ServiceTargetLanding/ServiceTargetActionMenu.tsx

-41
This file was deleted.

0 commit comments

Comments
 (0)