Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Changed
---

Export `HostEndpoint` and rename `private_access` to `public_access` ([#13413](https://github.com/linode/manager/pull/13413))
4 changes: 2 additions & 2 deletions packages/api-v4/src/databases/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ export type HostEndpointRole =
| 'standby'
| 'standby-connection-pool';

interface HostEndpoint {
export interface HostEndpoint {
address: string;
port: number;
private_access: boolean;
public_access: boolean;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went ahead and updated the private_access field to public_access since it was soft approved

role: HostEndpointRole;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Use new hostname endpoint in Database Summary and Network tab ([#13413](https://github.com/linode/manager/pull/13413))
1 change: 1 addition & 0 deletions packages/manager/src/dev-tools/FeatureFlagTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const options: { flag: keyof Flags; label: string }[] = [
},
{ flag: 'gecko2', label: 'Gecko' },
{ flag: 'generationalPlansv2', label: 'Generational compute plans' },
{ flag: 'hostnameEndpoints', label: 'Hostname Endpoints' },
Copy link
Contributor

@smans-akamai smans-akamai Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this new feature flag be mentioned in the description? Maybe under the change list and verification steps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mentioned under the change list and verification steps

{ flag: 'limitsEvolution', label: 'Limits Evolution' },
{ flag: 'linodeDiskEncryption', label: 'Linode Disk Encryption (LDE)' },
{ flag: 'linodeInterfaces', label: 'Linode Interfaces' },
Expand Down
8 changes: 4 additions & 4 deletions packages/manager/src/factories/databases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const databaseInstanceFactory =
{
address: 'public-db-mysql-primary-0.b.linodeb.net',
role: 'primary',
private_access: false,
public_access: true,
port: 3306,
},
],
Expand All @@ -191,7 +191,7 @@ export const databaseInstanceFactory =
{
address: 'public-db-mysql-primary-0.b.linodeb.net',
role: 'primary',
private_access: false,
public_access: true,
port: 3306,
},
],
Expand Down Expand Up @@ -253,7 +253,7 @@ export const databaseFactory = Factory.Sync.makeFactory<Database>({
{
address: 'public-db-mysql-primary-0.b.linodeb.net',
role: 'primary',
private_access: false,
public_access: true,
port: 3306,
},
],
Expand All @@ -265,7 +265,7 @@ export const databaseFactory = Factory.Sync.makeFactory<Database>({
{
address: 'public-db-mysql-primary-0.b.linodeb.net',
role: 'primary',
private_access: false,
public_access: true,
port: 3306,
},
],
Expand Down
1 change: 1 addition & 0 deletions packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ export interface Flags {
gecko2: GeckoFeatureFlag;
generationalPlansv2: GenerationalPlansFlag;
gpuv2: GpuV2;
hostnameEndpoints: boolean;
iam: BaseFeatureFlag;
iamDelegation: BaseFeatureFlag;
iamLimitedAvailabilityBadges: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { TooltipIcon } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';

import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip';

import {
SUMMARY_HOST_TOOLTIP_COPY,
SUMMARY_PRIVATE_HOST_COPY,
} from '../constants';

import type { HostEndpoint } from '@linode/api-v4/lib/databases/types';

interface ConnectionDetailsHostDisplayProps {
host: HostEndpoint;
}

export const ConnectionDetailsHostDisplay = (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted from ConnectionDetailsHostRows and made more generic

props: ConnectionDetailsHostDisplayProps
) => {
const { host } = props;

return (
<>
{host?.address}
<StyledCopyTooltip text={host.address} />
<TooltipIcon
componentsProps={{
tooltip: {
style: {
minWidth: 285,
},
},
}}
status="info"
sxTooltipIcon={{
marginLeft: '4px',
padding: '0px',
}}
text={
!host?.public_access
? SUMMARY_PRIVATE_HOST_COPY
: SUMMARY_HOST_TOOLTIP_COPY
}
/>
</>
);
};

export const StyledCopyTooltip = styled(CopyTooltip, {
label: 'StyledCopyTooltip',
})(({ theme }) => ({
'& svg': {
height: theme.spacingFunction(16),
width: theme.spacingFunction(16),
},
'&:hover': {
backgroundColor: 'transparent',
},
display: 'inline-flex',
marginLeft: theme.spacingFunction(4),
}));
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
const LEGACY_PRIMARY = 'db-mysql-legacy-primary.net';
const LEGACY_SECONDARY = 'db-mysql-legacy-secondary.net';

/**
* @TODO - delete this file after API releases hostname endpoint changes

Check warning on line 21 in packages/manager/src/features/Databases/DatabaseDetail/ConnectionDetailsHostRows.test.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Complete the task associated to this "TODO" comment. Raw Output: {"ruleId":"sonarjs/todo-tag","severity":1,"message":"Complete the task associated to this \"TODO\" comment.","line":21,"column":5,"nodeType":null,"messageId":"completeTODO","endLine":21,"endColumn":9}
*/

describe('ConnectionDetailsHostRows', () => {
it('should display Host and Read-only Host fields for a default database with no VPC configured', () => {
const database = databaseFactory.build({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ interface ConnectionDetailsHostRowsProps {
type HostContentMode = 'default' | 'private' | 'public';

/**
* @deprecated Delete this file in favor of ConnectionDetailsHostRows2 after the API releases hostname endpoint changes.
*
* This component is responsible for conditionally rendering the Private Host, Public Host, and Read-only Host rows that get displayed in
* the Connection Details tables that appear in the Database Summary and Networking tabs */
export const ConnectionDetailsHostRows = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { screen } from '@testing-library/react';
import React from 'react';

import { databaseFactory } from 'src/factories/databases';
import { renderWithTheme } from 'src/utilities/testHelpers';

import { ConnectionDetailsHostRows2 } from './ConnectionDetailsHostRows2';

import type { Database } from '@linode/api-v4/lib/databases';

const DEFAULT_PRIMARY = 'db-mysql-default-primary.net';
const DEFAULT_STANDBY = 'db-mysql-default-standby.net';

const PRIVATE_PRIMARY = `private-${DEFAULT_PRIMARY}`;
const PRIVATE_STANDBY = `private-${DEFAULT_STANDBY}`;

describe('ConnectionDetailsHostRows2', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is a copy of ConnectionDetailsHostRows.test.tsx with updates to support endpoints field and minor clean up

it('should display Host and Read-only Host fields for a default database with no VPC configured', () => {
const database = databaseFactory.build({
hosts: {
primary: DEFAULT_PRIMARY,
standby: DEFAULT_STANDBY,
endpoints: [
{
role: 'primary',
address: DEFAULT_PRIMARY,
port: 15847,
public_access: true,
},
{
role: 'standby',
address: DEFAULT_STANDBY,
port: 15847,
public_access: true,
},
],
},
platform: 'rdbms-default',

Check warning on line 38 in packages/manager/src/features/Databases/DatabaseDetail/ConnectionDetailsHostRows2.test.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 5 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 5 times.","line":38,"column":17,"nodeType":"Literal","endLine":38,"endColumn":32}
private_network: null, // No VPC configured, so Host and Read-only Host fields render
}) as Database;

renderWithTheme(<ConnectionDetailsHostRows2 database={database} />);

expect(screen.getByText('Host')).toBeVisible();
expect(screen.getByText(DEFAULT_PRIMARY)).toBeVisible();

expect(screen.getByText('Read-only Host')).toBeVisible();
expect(screen.getByText(DEFAULT_STANDBY)).toBeVisible();
});

it('should display N/A for default DB with blank read-only Host field', () => {
const database = databaseFactory.build({
hosts: {
primary: DEFAULT_PRIMARY,
standby: undefined,

Check warning on line 55 in packages/manager/src/features/Databases/DatabaseDetail/ConnectionDetailsHostRows2.test.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Use null instead. Raw Output: {"ruleId":"sonarjs/no-undefined-assignment","severity":1,"message":"Use null instead.","line":55,"column":18,"nodeType":"Identifier","messageId":"useNull","endLine":55,"endColumn":27}
endpoints: [
{
role: 'primary',
address: DEFAULT_PRIMARY,
port: 15847,
public_access: true,
},
],
},
platform: 'rdbms-default',
});

renderWithTheme(<ConnectionDetailsHostRows2 database={database} />);

expect(screen.getByText('N/A')).toBeVisible();
});

it('should display provisioning text when hosts are not available', () => {
const database = databaseFactory.build({
hosts: undefined,

Check warning on line 75 in packages/manager/src/features/Databases/DatabaseDetail/ConnectionDetailsHostRows2.test.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Use null instead. Raw Output: {"ruleId":"sonarjs/no-undefined-assignment","severity":1,"message":"Use null instead.","line":75,"column":14,"nodeType":"Identifier","messageId":"useNull","endLine":75,"endColumn":23}
platform: 'rdbms-default',
}) as Database;

const { getByText } = renderWithTheme(
<ConnectionDetailsHostRows2 database={database} />
);

const hostNameProvisioningText = getByText(
'Your hostname will appear here once it is available.'
);

expect(hostNameProvisioningText).toBeInTheDocument();
});

it('should display Private variations of Host and Read-only fields when a VPC is configured with public access set to false', () => {
const database = databaseFactory.build({
hosts: {
primary: PRIVATE_PRIMARY,
standby: PRIVATE_STANDBY,
endpoints: [
{
role: 'primary',
address: PRIVATE_PRIMARY,
port: 15847,
public_access: false,
},
{
role: 'standby',
address: PRIVATE_STANDBY,
port: 15847,
public_access: false,
},
],
},
platform: 'rdbms-default',
private_network: {
public_access: false,
subnet_id: 1,
vpc_id: 123,
}, // VPC configuration with public access set to false
}) as Database;

renderWithTheme(<ConnectionDetailsHostRows2 database={database} />);

expect(screen.getByText('Private Host')).toBeVisible();
expect(screen.getByText(PRIVATE_PRIMARY)).toBeVisible();
expect(screen.getByText('Private Read-only Host')).toBeVisible();
expect(screen.getByText(PRIVATE_STANDBY)).toBeVisible();
});

it('should display Private and Public variations of Host and Read-only Host fields when a VPC is configured with public access set to true', () => {
const database = databaseFactory.build({
hosts: {
primary: PRIVATE_PRIMARY,
standby: PRIVATE_STANDBY,
endpoints: [
{
role: 'primary',
address: `public-${DEFAULT_PRIMARY}`,
port: 15847,
public_access: true,
},
{
role: 'standby',
address: `public-${DEFAULT_STANDBY}`,
port: 15847,
public_access: true,
},
{
role: 'primary',
address: PRIVATE_PRIMARY,
port: 15847,
public_access: false,
},
{
role: 'standby',
address: PRIVATE_STANDBY,
port: 15847,
public_access: false,
},
],
},
platform: 'rdbms-default',
private_network: {
public_access: true,
subnet_id: 1,
vpc_id: 123,
}, // VPC configuration with public access set to true
}) as Database;

renderWithTheme(<ConnectionDetailsHostRows2 database={database} />);

// Verify that Private and Public Host and Readonly-host fields are rendered
expect(screen.getByText('Private Host')).toBeVisible();
expect(screen.getByText('Public Host')).toBeVisible();
expect(screen.getByText('Private Read-only Host')).toBeVisible();
expect(screen.getByText('Public Read-only Host')).toBeVisible();

// Verify that the Private and Public hostname is rendered correctly
expect(screen.getByText(PRIVATE_PRIMARY)).toBeVisible();
expect(screen.getByText(`public-${DEFAULT_PRIMARY}`)).toBeVisible();

// Verify that the Private and Public read-only hostname is rendered correctly
expect(screen.getByText(PRIVATE_STANDBY)).toBeVisible();
expect(screen.getByText(`public-${DEFAULT_STANDBY}`)).toBeVisible();
});
});
Loading