diff --git a/packages/api-v4/src/aglb/types.ts b/packages/api-v4/src/aglb/types.ts index c6a416f7a2f..7dcae7df052 100644 --- a/packages/api-v4/src/aglb/types.ts +++ b/packages/api-v4/src/aglb/types.ts @@ -131,7 +131,7 @@ export interface RuleCreatePayload { } export interface MatchCondition { - hostname: string; + hostname: string | null; match_field: MatchField; match_value: string; session_stickiness_cookie: string | null; @@ -159,8 +159,8 @@ interface HealthCheck { timeout: number; unhealthy_threshold: number; healthy_threshold: number; - path: string; - host: string; + path?: string | null; + host?: string | null; } export interface ServiceTarget extends ServiceTargetPayload { @@ -169,7 +169,7 @@ export interface ServiceTarget extends ServiceTargetPayload { export interface Endpoint { ip: string; - host?: string; + host?: string | null; port: number; rate_capacity: number; } diff --git a/packages/manager/.changeset/pr-9954-fixed-1701698397297.md b/packages/manager/.changeset/pr-9954-fixed-1701698397297.md new file mode 100644 index 00000000000..0bda884c125 --- /dev/null +++ b/packages/manager/.changeset/pr-9954-fixed-1701698397297.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +`TableCell` styling for `ActionMenu`s ([#9954](https://github.com/linode/manager/pull/9954)) diff --git a/packages/manager/.changeset/pr-9954-upcoming-features-1701698414248.md b/packages/manager/.changeset/pr-9954-upcoming-features-1701698414248.md new file mode 100644 index 00000000000..0cf3ef7f731 --- /dev/null +++ b/packages/manager/.changeset/pr-9954-upcoming-features-1701698414248.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +AGLB copy changes and improvments ([#9954](https://github.com/linode/manager/pull/9954)) diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts index 87cec38587f..b7be9ae8955 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts @@ -72,14 +72,14 @@ describe('Akamai Global Load Balancer landing page', () => { .should('be.visible') .closest('tr') .within(() => { - // Confirm that regions are listed for load balancer. - loadbalancerMock.regions.forEach((loadbalancerRegion: string) => { - const regionLabel = getRegionById(loadbalancerRegion).label; - cy.findByText(regionLabel, { exact: false }).should('be.visible'); - cy.findByText(loadbalancerRegion, { exact: false }).should( - 'be.visible' - ); - }); + // TODO: AGLB - Confirm that regions from the API are listed for load balancer + // loadbalancerMock.regions.forEach((loadbalancerRegion: string) => { + // const regionLabel = getRegionById(loadbalancerRegion).label; + // cy.findByText(regionLabel, { exact: false }).should('be.visible'); + // cy.findByText(loadbalancerRegion, { exact: false }).should( + // 'be.visible' + // ); + // }); cy.findByText(loadbalancerMock.hostname).should('be.visible'); @@ -94,14 +94,14 @@ describe('Akamai Global Load Balancer landing page', () => { .should('be.visible') .closest('tr') .within(() => { - // Confirm that regions are listed for load balancer. - loadbalancerMock.regions.forEach((loadbalancerRegion: string) => { - const regionLabel = getRegionById(loadbalancerRegion).label; - cy.findByText(regionLabel, { exact: false }).should('be.visible'); - cy.findByText(loadbalancerRegion, { exact: false }).should( - 'be.visible' - ); - }); + // TODO: AGLB - Confirm that regions from the API are listed for load balancer + // loadbalancerMock.regions.forEach((loadbalancerRegion: string) => { + // const regionLabel = getRegionById(loadbalancerRegion).label; + // cy.findByText(regionLabel, { exact: false }).should('be.visible'); + // cy.findByText(loadbalancerRegion, { exact: false }).should( + // 'be.visible' + // ); + // }); ui.actionMenu .findByTitle( diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts index 8b6309f18d6..890c89f7066 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts @@ -539,7 +539,7 @@ describe('Akamai Global Load Balancer routes page', () => { .findByTitle('Edit Rule') .should('be.visible') .within(() => { - cy.findByLabelText('Hostname') + cy.findByLabelText('Hostname (optional)') .should('have.value', routes[0].rules[0].match_condition.hostname) .clear() .type('example.com'); diff --git a/packages/manager/src/components/TableCell/TableCell.tsx b/packages/manager/src/components/TableCell/TableCell.tsx index bbcd7d7487e..159b10fcdde 100644 --- a/packages/manager/src/components/TableCell/TableCell.tsx +++ b/packages/manager/src/components/TableCell/TableCell.tsx @@ -10,14 +10,7 @@ import { TooltipIcon } from 'src/components/TooltipIcon'; const useStyles = makeStyles()((theme: Theme) => ({ actionCell: { - // Prevents Safari from adding margins to the ActionMenu button - '& > button': { - margin: 0, - }, - alignItems: 'center', - display: 'flex', - justifyContent: 'flex-end', - padding: 0, + textAlign: 'right', }, center: { '&:last-child': { diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/ConfigurationDetails.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/ConfigurationDetails.tsx index 5db9413b6e3..daad8310f82 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/ConfigurationDetails.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/ConfigurationDetails.tsx @@ -81,15 +81,16 @@ export const ConfigurationDetails = ({ index, name }: Props) => { - ({ - marginLeft: '0 !important', - marginRight: `${theme.spacing(1 / 2)} !important`, - })} - /> + ({ + marginLeft: '0 !important', + marginRight: theme.spacing(), + })} + component="span" + /> After the load balancer is created, and if the protocol is HTTPS, - upload TLS termination certificates. + upload TLS termination certificates.{' '} Learn more. diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/LoadBalancerRegions.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/LoadBalancerRegions.tsx index d1722ceda96..bdf4339f703 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/LoadBalancerRegions.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerCreate/LoadBalancerRegions.tsx @@ -17,9 +17,12 @@ export const LoadBalancerRegions = () => { Where this Load Balancer instance will be deployed. - Load Balancers will - be automatically provisioned in these 5 Regions. No charges with be - incurred. + + Load Balancers will be automatically provisioned in these 5 Regions. + No charges with be incurred. diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/CreateCertificateDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/CreateCertificateDrawer.tsx index 7ad54c050e8..a1e04d70220 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/CreateCertificateDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/CreateCertificateDrawer.tsx @@ -14,6 +14,7 @@ import { CERTIFICATES_COPY, exampleCert, exampleKey, + initialValues, labelMap, titleMap, } from './constants'; @@ -44,12 +45,7 @@ export const CreateCertificateDrawer = (props: Props) => { const formik = useFormik({ enableReinitialize: true, - initialValues: { - certificate: '', - key: '', - label: '', - type, - }, + initialValues: initialValues[type], async onSubmit(values) { try { await createCertificate(values); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/constants.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/constants.ts index b56aa642b9a..e1c6d48d616 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/constants.ts +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/constants.ts @@ -1,5 +1,19 @@ import type { Certificate } from '@linode/api-v4'; +export const initialValues = { + ca: { + certificate: '', + label: '', + type: 'ca', + }, + downstream: { + certificate: '', + key: '', + label: '', + type: 'downstream', + }, +} as const; + export const CERTIFICATES_COPY = { Create: { ca: diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/index.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/index.tsx index 3d59c93eb9c..fa7ab4db202 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/index.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Certificates/index.tsx @@ -38,7 +38,7 @@ export const LoadBalancerCertificates = () => { Upload certificates to your Load Balancer for use across your Configurations and Service Targets. - + null}> ({ ...t, routeName: `${url}/${t.path}` }))} /> diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/LoadBalancerSummary.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/LoadBalancerSummary.tsx index 281f4d35606..5899ffb2c63 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/LoadBalancerSummary.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/LoadBalancerSummary.tsx @@ -3,13 +3,14 @@ import React from 'react'; import { useParams } from 'react-router-dom'; import { Paper } from 'src/components/Paper'; +import { Stack } from 'src/components/Stack'; import { Typography } from 'src/components/Typography'; import { IPAddress } from 'src/features/Linodes/LinodesLanding/IPAddress'; import { useLoadBalancerQuery } from 'src/queries/aglb/loadbalancers'; -import { useRegionsQuery } from 'src/queries/regions'; +// import { useRegionsQuery } from 'src/queries/regions'; import { Ports } from '../LoadBalancerLanding/Ports'; -import { Stack } from 'src/components/Stack'; +import { LoadBalancerRegions } from './LoadBalancerRegions'; export const LoadBalancerSummary = () => { const { loadbalancerId } = useParams<{ loadbalancerId: string }>(); @@ -17,12 +18,20 @@ export const LoadBalancerSummary = () => { const id = Number(loadbalancerId); const { data: loadbalancer } = useLoadBalancerQuery(id); - const { data: regions } = useRegionsQuery(); + // const { data: regions } = useRegionsQuery(); const items = [ { title: 'Hostname', - value: , + value: loadbalancer?.hostname ? ( + + ) : ( + None + ), + }, + { + title: 'Load Balancer ID', + value: {loadbalancer?.id}, }, { title: 'Ports', @@ -30,17 +39,15 @@ export const LoadBalancerSummary = () => { }, { title: 'Regions', - value: ( - - {loadbalancer?.regions - .map((region) => regions?.find((r) => r.id === region)?.label) - .join(', ')} - - ), - }, - { - title: 'Load Balancer ID', - value: {loadbalancer?.id}, + value: , + // Uncomment the line below to show the regions returned by the API. + // value: ( + // + // {loadbalancer?.regions + // .map((region) => regions?.find((r) => r.id === region)?.label) + // .join(', ')} + // + // ), }, ]; @@ -50,7 +57,7 @@ export const LoadBalancerSummary = () => { {items.map(({ title, value }) => ( - + {title} {value} diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/CreateRouteDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/CreateRouteDrawer.tsx index 99a82d43fbb..6471e71731e 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/CreateRouteDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/CreateRouteDrawer.tsx @@ -61,7 +61,9 @@ export const CreateRouteDrawer = (props: Props) => { return (
- {generalError && } + {generalError && ( + + )} { newRules.splice(ruleIndex, 1); + const normalizedRules = newRules.map(getNormalizedRulePayload); + await mutateAsync({ - rules: newRules, + label: route.label, + protocol: route.protocol, + rules: normalizedRules, }); onClose(); }; diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx index 680c9da69ff..fee6152e6c2 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx @@ -22,11 +22,13 @@ import { getFormikErrorsFromAPIErrors } from 'src/utilities/formikErrorUtils'; import { ServiceTargetSelect } from '../ServiceTargets/ServiceTargetSelect'; import { MatchTypeInfo } from './MatchTypeInfo'; +import { ROUTE_COPY } from './constants'; import { TimeUnit, defaultServiceTarget, defaultTTL, getIsSessionStickinessEnabled, + getNormalizedRulePayload, initialValues, matchTypeOptions, matchValuePlaceholder, @@ -36,7 +38,6 @@ import { } from './utils'; import type { Route, RulePayload } from '@linode/api-v4'; -import { ROUTE_COPY } from './constants'; interface Props { loadbalancerId: number; @@ -62,8 +63,9 @@ export const RuleDrawer = (props: Props) => { const isEditMode = ruleIndexToEdit !== undefined; - const validationSchema = - route?.protocol === 'tcp' ? TCPRuleSchema : HTTPRuleSchema; + const protocol = route?.protocol ?? 'tcp'; + + const validationSchema = protocol === 'tcp' ? TCPRuleSchema : HTTPRuleSchema; const { error, @@ -83,9 +85,11 @@ export const RuleDrawer = (props: Props) => { try { const existingRules = route?.rules ?? []; + const normalizedRule: RulePayload = getNormalizedRulePayload(rule); + // If we are editing, update the rule with the form data. if (isEditMode) { - existingRules[ruleIndexToEdit] = rule; + existingRules[ruleIndexToEdit] = normalizedRule; } await updateRoute({ @@ -93,7 +97,9 @@ export const RuleDrawer = (props: Props) => { protocol: route?.protocol, // If we are editing, send the updated rules, otherwise // append a new rule to the end. - rules: isEditMode ? existingRules : [...existingRules, rule], + rules: isEditMode + ? existingRules + : [...existingRules, normalizedRule], }); onClose(); } catch (errors) { @@ -200,7 +206,7 @@ export const RuleDrawer = (props: Props) => { > - {ROUTE_COPY.Rule.Description} + {ROUTE_COPY.Rule.Description[protocol]} {generalErrors && } @@ -222,6 +228,7 @@ export const RuleDrawer = (props: Props) => { name="match_condition.hostname" onBlur={formik.handleBlur} onChange={formik.handleChange} + optional placeholder="www.example.com" value={formik.values.match_condition.hostname} /> @@ -332,10 +339,20 @@ export const RuleDrawer = (props: Props) => { : undefined } onChange={(serviceTarget) => { - formik.setFieldTouched(`service_targets[${index}].id`); + formik.setFieldTouched( + `service_targets[${index}].id`, + true, + false + ); formik.setFieldValue( `service_targets[${index}].id`, - serviceTarget?.id ?? -1 + serviceTarget?.id ?? -1, + true + ); + formik.setFieldValue( + `service_targets[${index}].label`, + serviceTarget?.label ?? '', + false ); }} loadbalancerId={loadbalancerId} diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/constants.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/constants.ts index 0e5a25e8512..76f87014622 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/constants.ts +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/constants.ts @@ -8,8 +8,12 @@ export const ROUTE_COPY = { 'TCP rules include the percentage of incoming requests that should be directed to each target.', }, Rule: { - Description: - 'Rules set the conditions that are used for target selection. TCP rules include the percentage of incoming requests that should be directed to each target.', + Description: { + http: + 'Rules set the conditions that are used for target selection. HTTP/S rules include Match Rules and the percentage of incoming requests that should be directed to each target.', + tcp: + 'Rules set the conditions that are used for target selection. TCP rules include the percentage of incoming requests that should be directed to each target.', + }, Hostname: 'The hostname of the target where the rule applies. If a hostname is not specified, the rule applies to all targets. Wildcards (*) are supported.', MatchRule: { diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.test.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.test.ts new file mode 100644 index 00000000000..29658494f67 --- /dev/null +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.test.ts @@ -0,0 +1,39 @@ +import { getNormalizedRulePayload } from './utils'; + +describe('getNormalizedRulePayload', () => { + it('should change empty strings to null', () => { + expect( + getNormalizedRulePayload({ + match_condition: { + hostname: '', + match_field: 'path_prefix', + match_value: '', + session_stickiness_cookie: null, + session_stickiness_ttl: null, + }, + service_targets: [ + { + id: 42, + label: 'test-1', + percentage: 100, + }, + ], + }) + ).toStrictEqual({ + match_condition: { + hostname: null, + match_field: 'path_prefix', + match_value: '', + session_stickiness_cookie: null, + session_stickiness_ttl: null, + }, + service_targets: [ + { + id: 42, + label: 'test-1', + percentage: 100, + }, + ], + }); + }); +}); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts index c3c52efff7f..1367c26260d 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts @@ -61,6 +61,20 @@ export const getIsSessionStickinessEnabled = (rule: Rule | RulePayload) => { ); }; +/** + * Converts some empty strings to `null` in RulePayload + * so that the API accepts the payload. + */ +export const getNormalizedRulePayload = (rule: RulePayload) => ({ + match_condition: { + ...rule.match_condition, + hostname: rule.match_condition.hostname + ? rule.match_condition.hostname + : null, + }, + service_targets: rule.service_targets, +}); + export const timeUnitFactorMap = { millisecond: 1, second: 1000, diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/RuleRow.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/RuleRow.tsx index 552bde34d07..a27a81788ed 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/RuleRow.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/RuleRow.tsx @@ -86,7 +86,9 @@ export const RuleRow = (props: RuleRowProps) => { }} aria-label={`Match value: ${rule.match_condition.match_value}`} > - {rule.match_condition.match_value} + {rule.match_condition.match_value + ? rule.match_condition.match_value + : 'None'} @@ -112,10 +114,8 @@ export const RuleRow = (props: RuleRowProps) => { - {rule.service_targets.map(({ id, label }) => ( -
- {label}:{id} -
+ {rule.service_targets.map(({ label }) => ( +
{label}
))} } diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx index e013c55a8b9..bdcf878bdf5 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx @@ -37,6 +37,7 @@ import { initialValues, protocolOptions, } from './constants'; +import { getNormalizedServiceTargetPayload } from './utils'; interface Props { loadbalancerId: number; @@ -65,12 +66,15 @@ export const ServiceTargetDrawer = (props: Props) => { const formik = useFormik({ enableReinitialize: true, initialValues: isEditMode ? serviceTarget : initialValues, - async onSubmit(values: ServiceTargetPayload) { + async onSubmit(values) { + const normalizedValues: ServiceTargetPayload = getNormalizedServiceTargetPayload( + values + ); try { if (isEditMode) { - await updateServiceTarget(values); + await updateServiceTarget(normalizedValues); } else { - await createServiceTarget(values); + await createServiceTarget(normalizedValues); } onClose(); } catch (errors) { @@ -148,10 +152,20 @@ export const ServiceTargetDrawer = (props: Props) => { )} {generalCreateErrors && ( - + )} {generalUpdateErrors && ( - + )} { + it('should change empty strings to null', () => { + expect( + getNormalizedServiceTargetPayload({ + certificate_id: null, + endpoints: [ + { + host: '', + ip: '139.144.129.228', + port: 80, + rate_capacity: 10000, + }, + ], + healthcheck: { + healthy_threshold: 3, + host: '', + interval: 10, + path: '', + protocol: 'http', + timeout: 5, + unhealthy_threshold: 3, + }, + label: 'test', + load_balancing_policy: 'round_robin', + percentage: 10, + protocol: 'https', + }) + ).toStrictEqual({ + certificate_id: null, + endpoints: [ + { + host: null, + ip: '139.144.129.228', + port: 80, + rate_capacity: 10000, + }, + ], + healthcheck: { + healthy_threshold: 3, + host: null, + interval: 10, + path: null, + protocol: 'http', + timeout: 5, + unhealthy_threshold: 3, + }, + label: 'test', + load_balancing_policy: 'round_robin', + percentage: 10, + protocol: 'https', + }); + }); +}); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/utils.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/utils.ts new file mode 100644 index 00000000000..82277317e3d --- /dev/null +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/utils.ts @@ -0,0 +1,24 @@ +import type { ServiceTargetPayload } from '@linode/api-v4'; + +/** + * Replaces empty strings with `null` in ServiceTargetPayload + * so that the API accepts the request. + */ +export const getNormalizedServiceTargetPayload = ( + serviceTarget: ServiceTargetPayload +) => ({ + ...serviceTarget, + endpoints: serviceTarget.endpoints.map((e) => ({ + ...e, + host: e.host ? e.host : null, + })), + healthcheck: { + ...serviceTarget.healthcheck, + host: serviceTarget.healthcheck.host + ? serviceTarget.healthcheck.host + : null, + path: serviceTarget.healthcheck.path + ? serviceTarget.healthcheck.path + : null, + }, +}); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Region.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Region.tsx index 4fe59db5990..521f7302e35 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Region.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Region.tsx @@ -33,11 +33,14 @@ export const Region = ({ loadbalancerId }: Props) => { return ( - + Regions - Load Balancer - regions can not be changed during beta. + {' '} + Load Balancer regions can not be changed during beta. diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/LoadBalancerRow.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/LoadBalancerRow.tsx index 79c1484343c..51701cd8a86 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/LoadBalancerRow.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/LoadBalancerRow.tsx @@ -3,12 +3,15 @@ import * as React from 'react'; import { Link } from 'react-router-dom'; import { Hidden } from 'src/components/Hidden'; +import { Stack } from 'src/components/Stack'; import { TableCell } from 'src/components/TableCell'; import { TableRow } from 'src/components/TableRow'; +import { Typography } from 'src/components/Typography'; +import { IPAddress } from 'src/features/Linodes/LinodesLanding/IPAddress'; +import { regions as alphaRegions } from '../LoadBalancerDetail/LoadBalancerRegions'; import { LoadBalancerActionsMenu } from './LoadBalancerActionsMenu'; import { Ports } from './Ports'; -import { RegionsCell } from './RegionsCell'; export interface LoadBalancerHandlers { onDelete: () => void; @@ -20,7 +23,7 @@ interface Props { } export const LoadBalancerRow = ({ handlers, loadBalancer }: Props) => { - const { hostname, id, label, regions } = loadBalancer; + const { hostname, id, label } = loadBalancer; return ( {
- {hostname} + + {hostname ? : 'None'} + - {regions.map((region) => ( + + {alphaRegions.map(({ id, label }) => ( + + {label} ({id}) + + ))} + + {/* Uncomment the code below to show the regions returned by the API */} + {/* {regions.map((region) => ( - ))} + ))} */} diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/Ports.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/Ports.tsx index 0d484733c35..23a8467352f 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/Ports.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerLanding/Ports.tsx @@ -21,6 +21,10 @@ export const Ports = ({ loadbalancerId }: PortProps) => { return ; } + if (ports?.length === 0) { + return None; + } + if (error || !ports) { return Unknown; } diff --git a/packages/validation/src/loadbalancers.schema.ts b/packages/validation/src/loadbalancers.schema.ts index cd02d0b72bd..c99a46218c7 100644 --- a/packages/validation/src/loadbalancers.schema.ts +++ b/packages/validation/src/loadbalancers.schema.ts @@ -40,7 +40,7 @@ export const CertificateConfigSchema = object({ export const EndpointSchema = object({ ip: string().required('IP is required.'), - host: string(), + host: string().nullable(), port: number() .required('Port is required.') .min(1, 'Port must be greater than 0.') @@ -54,8 +54,8 @@ const HealthCheckSchema = object({ timeout: number().min(0), unhealthy_threshold: number().min(0), healthy_threshold: number().min(0), - path: string(), - host: string(), + path: string().nullable(), + host: string().nullable(), }); export const CreateServiceTargetSchema = object({ @@ -101,7 +101,7 @@ const RouteServiceTargetSchema = object({ }); const TCPMatchConditionSchema = object({ - hostname: string(), + hostname: string().nullable(), }); const HTTPMatchConditionSchema = TCPMatchConditionSchema.concat(