Skip to content

Commit

Permalink
upcoming: [M3-7294] - AGLB Full Create Flow - Add Rule Support to Rou…
Browse files Browse the repository at this point in the history
…tes (#10035)

* add collapseable table

* remove old routes table and setup drawer handlers

* wire up add rule drawer

* wow this is gonna be so broken

* improve form experence

* yikes...

* add create mutation

* small fixes and tweaks

* Added changeset: Add Rule support to AGLB Full Create Flow

* remove crazy code that we won't need when the POST changes

---------

Co-authored-by: Banks Nussman <banks@nussman.us>
  • Loading branch information
bnussman-akamai and bnussman authored Jan 30, 2024
1 parent ddcc599 commit 9a14b92
Show file tree
Hide file tree
Showing 10 changed files with 811 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Add Rule support to AGLB Full Create Flow ([#10035](https://github.com/linode/manager/pull/10035))
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import type { Handlers } from './LoadBalancerConfigurations';

export const handlers: Handlers = {
handleAddRoute: vi.fn(),
handleAddRule: vi.fn(),
handleAddServiceTarget: vi.fn(),
handleCloseRuleDrawer: vi.fn(),
handleCloseServiceTargetDrawer: vi.fn(),
handleEditRoute: vi.fn(),
handleEditRule: vi.fn(),
handleEditServiceTarget: vi.fn(),
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import { useFormikContext } from 'formik';
import * as React from 'react';
import { useState } from 'react';
import * as React from 'react';

import { AddRouteDrawer } from './AddRouteDrawer';
import { EditRouteDrawer } from './EditRouteDrawer';
import { LoadBalancerConfiguration } from './LoadBalancerConfiguration';
import { RuleDrawer } from './RuleDrawer';
import { ServiceTargetDrawer } from './ServiceTargetDrawer';

import type { CreateLoadbalancerPayload } from '@linode/api-v4';

export interface Handlers {
handleAddRoute: (configurationIndex: number) => void;
handleAddRule: (configurationIndex: number, routeIndex: number) => void;
handleAddServiceTarget: (configurationIndex: number) => void;
handleCloseRuleDrawer: () => void;
handleCloseServiceTargetDrawer: () => void;
handleEditRoute: (index: number, configurationIndex: number) => void;
handleEditRule: (
configurationIndex: number,
routeIndex: number,
ruleIndex: number
) => void;
handleEditServiceTarget: (index: number, configurationIndex: number) => void;
}

Expand All @@ -25,12 +33,14 @@ export const LoadBalancerConfigurations = () => {
);
const [isAddRouteDrawerOpen, setIsAddRouteDrawerOpen] = useState(false);
const [isEditRouteDrawerOpen, setIsEditRouteDrawerOpen] = useState(false);
const [isRuleDrawerOpen, setIsRuleDrawerOpen] = useState(false);

const [
selectedServiceTargetIndex,
setSelectedServiceTargetIndex,
] = useState<number>();
const [selectedRouteIndex, setSelectedRouteIndex] = useState<number>();
const [selectedRuleIndex, setSelectedRuleIndex] = useState<number>();
const [
selectedConfigurationIndex,
setSelectedConfigurationIndex,
Expand Down Expand Up @@ -66,11 +76,36 @@ export const LoadBalancerConfigurations = () => {
setIsServiceTargetDrawerOpen(false);
};

const handleEditRule = (
configurationIndex: number,
routeIndex: number,
ruleIndex: number
) => {
setSelectedConfigurationIndex(configurationIndex);
setSelectedRouteIndex(routeIndex);
setSelectedRuleIndex(ruleIndex);
setIsRuleDrawerOpen(true);
};

const handleAddRule = (configurationIndex: number, routeIndex: number) => {
setSelectedConfigurationIndex(configurationIndex);
setSelectedRouteIndex(routeIndex);
setIsRuleDrawerOpen(true);
};

const handleCloseRuleDrawer = () => {
setSelectedRuleIndex(undefined);
setIsRuleDrawerOpen(false);
};

const handlers: Handlers = {
handleAddRoute,
handleAddRule,
handleAddServiceTarget,
handleCloseRuleDrawer,
handleCloseServiceTargetDrawer,
handleEditRoute,
handleEditRule,
handleEditServiceTarget,
};

Expand Down Expand Up @@ -106,6 +141,13 @@ export const LoadBalancerConfigurations = () => {
open={isEditRouteDrawerOpen}
routeIndex={selectedRouteIndex}
/>
<RuleDrawer
configurationIndex={selectedConfigurationIndex}
onClose={handleCloseRuleDrawer}
open={isRuleDrawerOpen}
routeIndex={selectedRouteIndex}
ruleIndexToEdit={selectedRuleIndex}
/>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@ import { useFormikContext } from 'formik';
import React, { useState } from 'react';

import { ActionMenu } from 'src/components/ActionMenu/ActionMenu';
import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import {
CollapsibleTable,
TableItem,
} from 'src/components/CollapsibleTable/CollapsibleTable';
import { Hidden } from 'src/components/Hidden';
import { IconButton } from 'src/components/IconButton';
import { InlineMenuAction } from 'src/components/InlineMenuAction/InlineMenuAction';
import { InputAdornment } from 'src/components/InputAdornment';
import { Stack } from 'src/components/Stack';
import { Table } from 'src/components/Table';
import { TableBody } from 'src/components/TableBody';
import { TableCell } from 'src/components/TableCell';
import { TableHead } from 'src/components/TableHead';
import { TableRow } from 'src/components/TableRow';
import { TableRowEmpty } from 'src/components/TableRowEmpty/TableRowEmpty';
import { TextField } from 'src/components/TextField';
import { Typography } from 'src/components/Typography';

import { RulesTable } from './RulesTable';

import type { Handlers } from './LoadBalancerConfigurations';
import type { LoadBalancerCreateFormData } from './LoadBalancerCreateFormWrapper';

Expand All @@ -35,13 +41,89 @@ export const Routes = ({ configurationIndex, handlers }: Props) => {
const configuration = values.configurations![configurationIndex];

const handleRemoveRoute = (index: number) => {
configuration.routes!.splice(index, 1);
setFieldValue(
`configurations[${configurationIndex}].routes`,
configuration.routes
);
const newRoutes = [...configuration.routes!];
newRoutes.splice(index, 1);
setFieldValue(`configurations[${configurationIndex}].routes`, newRoutes);
};

const getTableItems = (): TableItem[] => {
if (configuration.routes?.length === 0) {
return [];
}

return configuration
.routes!.filter((route) => {
if (query) {
return route.label.includes(query);
}
return true;
})
.map((route, index) => {
const OuterTableCells = (
<>
<Hidden mdDown>
<TableCell>{route.rules.length}</TableCell>
</Hidden>
<Hidden smDown>
<TableCell>{route.protocol.toLocaleUpperCase()}</TableCell>
</Hidden>
<TableCell actionCell>
<InlineMenuAction
onClick={() =>
handlers.handleAddRule(configurationIndex, index)
}
actionText="Add Rule"
/>
<ActionMenu
actionsList={[
{
onClick: () =>
handlers.handleEditRoute(index, configurationIndex),
title: 'Edit Label',
},
{
onClick: () => handleRemoveRoute(index),
title: 'Remove',
},
]}
ariaLabel={`Action Menu for Route ${route.label}`}
/>
</TableCell>
</>
);

const InnerTable = (
<RulesTable
onEditRule={(ruleIndex) =>
handlers.handleEditRule(configurationIndex, index, ruleIndex)
}
configurationIndex={configurationIndex}
routeIndex={index}
/>
);

return {
InnerTable,
OuterTableCells,
id: index,
label: route.label,
};
});
};

const RoutesTableRowHead = (
<TableRow>
<TableCell>Route Label</TableCell>
<Hidden mdDown>
<TableCell>Rules</TableCell>
</Hidden>
<Hidden smDown>
<TableCell>Protocol</TableCell>
</Hidden>
<TableCell></TableCell>
</TableRow>
);

return (
<Stack padding={1} spacing={1}>
<Typography variant="h2">Routes</Typography>
Expand Down Expand Up @@ -80,49 +162,13 @@ export const Routes = ({ configurationIndex, handlers }: Props) => {
value={query}
/>
</Stack>
<Table sx={{ width: '99%' }}>
<TableHead>
<TableRow>
<TableCell>Route Label</TableCell>
<TableCell>Rules</TableCell>
<TableCell></TableCell>
</TableRow>
</TableHead>
<TableBody>
{configuration.routes!.length === 0 && (
<TableRowEmpty colSpan={5} />
)}
{configuration.routes
?.filter((route) => {
if (query) {
return route.label.includes(query);
}
return true;
})
.map((route, index) => (
<TableRow key={route.label}>
<TableCell>{route.label}</TableCell>
<TableCell>{route.rules.length}</TableCell>
<TableCell actionCell>
<ActionMenu
actionsList={[
{
onClick: () =>
handlers.handleEditRoute(index, configurationIndex),
title: 'Edit Label',
},
{
onClick: () => handleRemoveRoute(index),
title: 'Remove',
},
]}
ariaLabel={`Action Menu for Route ${route.label}`}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<Box maxWidth="99%">
<CollapsibleTable
TableItems={getTableItems()}
TableRowEmpty={<TableRowEmpty colSpan={4} message={'No Routes'} />}
TableRowHead={RoutesTableRowHead}
/>
</Box>
</Stack>
</Stack>
);
Expand Down
Loading

0 comments on commit 9a14b92

Please sign in to comment.