Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [UIE-8006] - DBaaS 2.0 Create #10872

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions packages/api-v4/src/databases/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export interface DatabaseEngine {
}

export type DatabaseStatus =
| 'active'
| 'degraded'
| 'failed'
| 'provisioning'
| 'resizing'
| 'active'
| 'suspending'
| 'suspended'
| 'resuming'
| 'restoring'
| 'failed'
| 'degraded';
| 'resuming'
| 'suspended'
| 'suspending';

export type DatabaseBackupType = 'snapshot' | 'auto';

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

DBaaS V2 create enhancements ([#10872](https://github.com/linode/manager/pull/10872))
109 changes: 107 additions & 2 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { renderWithTheme, wrapWithTheme } from 'src/utilities/testHelpers';

import PrimaryNav from './PrimaryNav';

import type { Flags } from 'src/featureFlags';

const props = {
closeMenu: vi.fn(),
isCollapsed: false,
Expand Down Expand Up @@ -54,7 +56,7 @@ describe('PrimaryNav', () => {
expect(getByTestId(queryString).getAttribute('aria-current')).toBe('false');
});

it('should show Databases menu item if the user has the account capability', async () => {
it('should show Databases menu item if the user has the account capability V1', async () => {
const account = accountFactory.build({
capabilities: ['Managed Databases'],
});
Expand All @@ -65,7 +67,110 @@ describe('PrimaryNav', () => {
})
);

const { findByText } = renderWithTheme(<PrimaryNav {...props} />);
const flags: Partial<Flags> = {
dbaasV2: {
beta: true,
enabled: true,
},
};

const { findByText, queryByTestId } = renderWithTheme(
<PrimaryNav {...props} />,
{
flags,
}
);

const databaseNavItem = await findByText('Databases');

expect(databaseNavItem).toBeVisible();
expect(queryByTestId('betaChip')).toBeNull();
});

it('should show Databases menu item if the user has the account capability V2 Beta', async () => {
const account = accountFactory.build({
capabilities: ['Managed Databases V2'],
});

server.use(
http.get('*/account', () => {
return HttpResponse.json(account);
})
);

const flags: Partial<Flags> = {
dbaasV2: {
beta: true,
enabled: true,
},
};

const { findByTestId, findByText } = renderWithTheme(
<PrimaryNav {...props} />,
{
flags,
}
);

const databaseNavItem = await findByText('Databases');
const betaChip = await findByTestId('betaChip');

expect(databaseNavItem).toBeVisible();
expect(betaChip).toBeVisible();
});

it('should show Databases menu item if the user has the account capability V2', async () => {
const account = accountFactory.build({
capabilities: ['Managed Databases V2'],
});

server.use(
http.get('*/account', () => {
return HttpResponse.json(account);
})
);

const flags: Partial<Flags> = {
dbaasV2: {
beta: false,
enabled: true,
},
};

const { findByText, queryByTestId } = renderWithTheme(
<PrimaryNav {...props} />,
{
flags,
}
);

const databaseNavItem = await findByText('Databases');

expect(databaseNavItem).toBeVisible();
expect(queryByTestId('betaChip')).toBeNull();
});

it('should show Databases menu item if the user has the account capability V2', async () => {
const account = accountFactory.build({
capabilities: ['Managed Databases V2'],
});

server.use(
http.get('*/account', () => {
return HttpResponse.json(account);
})
);

const flags: Partial<Flags> = {
dbaasV2: {
beta: true,
enabled: true,
},
};

const { findByText } = renderWithTheme(<PrimaryNav {...props} />, {
flags,
});

const databaseNavItem = await findByText('Databases');

Expand Down
6 changes: 3 additions & 3 deletions packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
const { isACLPEnabled } = useIsACLPEnabled();

const { isPlacementGroupsEnabled } = useIsPlacementGroupsEnabled();
const { isDatabasesEnabled } = useIsDatabasesEnabled();
const { isDatabasesEnabled, isDatabasesV2Beta } = useIsDatabasesEnabled();

const prefetchMarketplace = () => {
if (!enableMarketplacePrefetch) {
Expand Down Expand Up @@ -187,7 +187,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
hide: !isDatabasesEnabled,
href: '/databases',
icon: <Database />,
isBeta: flags.dbaasV2?.beta,
isBeta: isDatabasesV2Beta,
},
{
activeLinks: ['/kubernetes/create'],
Expand Down Expand Up @@ -247,9 +247,9 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
[
isDatabasesEnabled,
isDatabasesV2Beta,
isManaged,
allowMarketplacePrefetch,
flags.dbaasV2,
isPlacementGroupsEnabled,
flags.placementGroups,
isACLPEnabled,
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/components/TabbedPanel/TabbedPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface TabbedPanelProps {
copy?: string;
docsLink?: JSX.Element;
error?: JSX.Element | string;
handleTabChange?: () => void;
handleTabChange?: (index: number) => void;
header: string;
initTab?: number;
innerClass?: string;
Expand Down Expand Up @@ -66,7 +66,7 @@ const TabbedPanel = React.memo((props: TabbedPanelProps) => {
const tabChangeHandler = (index: number) => {
setTabIndex(index);
if (handleTabChange) {
handleTabChange();
handleTabChange(index);
}
};

Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/factories/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const accountFactory = Factory.Sync.makeFactory<Account>({
'Linodes',
'LKE HA Control Planes',
'Machine Images',
'Managed Databases V2',
corya-akamai marked this conversation as resolved.
Show resolved Hide resolved
'Managed Databases',
'NodeBalancers',
'Object Storage Access Key Regions',
'Object Storage Endpoint Types',
Expand Down
10 changes: 6 additions & 4 deletions packages/manager/src/factories/databases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ import type {
PostgresReplicationType,
} from '@linode/api-v4/lib/databases/types';

// These are not all of the possible statuses, but these are some common ones.
export const possibleStatuses: DatabaseStatus[] = [
'provisioning',
'active',
'failed',
'degraded',
'restoring',
'failed',
'provisioning',
'resizing',
'restoring',
'resuming',
'suspended',
'suspending',
];

export const possibleMySQLReplicationTypes: MySQLReplicationType[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import { createMemoryHistory } from 'history';
import * as React from 'react';
import { Router } from 'react-router-dom';

import { databaseTypeFactory } from 'src/factories';
import { accountFactory, databaseTypeFactory } from 'src/factories';
import { makeResourcePage } from 'src/mocks/serverHandlers';
import { HttpResponse, http, server } from 'src/mocks/testServer';
import { renderWithTheme } from 'src/utilities/testHelpers';
import { mockMatchMedia } from 'src/utilities/testHelpers';
import { mockMatchMedia, renderWithTheme } from 'src/utilities/testHelpers';

import DatabaseCreate from './DatabaseCreate';

Expand Down Expand Up @@ -79,4 +78,80 @@ describe('Database Create', () => {
expect(nodeRadioBtns).toHaveTextContent('$60/month $0.09/hr');
expect(nodeRadioBtns).toHaveTextContent('$140/month $0.21/hr');
});

it('should display the correct nodes for account with Managed Databases', async () => {
server.use(
http.get('*/account', () => {
const account = accountFactory.build({
capabilities: ['Managed Databases'],
});
return HttpResponse.json(account);
})
);

// Mock route history so the Plan Selection table displays prices without requiring a region in the DB Create flow.
const history = createMemoryHistory();
history.push('databases/create');

const { getAllByText, getByTestId } = renderWithTheme(
<Router history={history}>
<DatabaseCreate />
</Router>
);

await waitForElementToBeRemoved(getByTestId(loadingTestId));

// default to $0 if no plan is selected
const nodeRadioBtns = getByTestId('database-nodes');
expect(nodeRadioBtns).toHaveTextContent('$0/month $0/hr');

// update node pricing if a plan is selected
const radioBtn = getAllByText('Nanode 1 GB')[0];
fireEvent.click(radioBtn);
expect(nodeRadioBtns).toHaveTextContent('$60/month $0.09/hr');
expect(nodeRadioBtns).not.toHaveTextContent('$100/month $0.15/hr');
expect(nodeRadioBtns).toHaveTextContent('$140/month $0.21/hr');
});

it('should display the correct nodes for account with Managed Databases V2', async () => {
server.use(
http.get('*/account', () => {
const account = accountFactory.build({
capabilities: ['Managed Databases V2'],
});
return HttpResponse.json(account);
})
);

// Mock route history so the Plan Selection table displays prices without requiring a region in the DB Create flow.
const history = createMemoryHistory();
history.push('databases/create');

const flags = {
dbaasV2: {
beta: true,
enabled: true,
},
};

const { getAllByText, getByTestId } = renderWithTheme(
<Router history={history}>
<DatabaseCreate />
</Router>,
{ flags }
);

await waitForElementToBeRemoved(getByTestId(loadingTestId));

// default to $0 if no plan is selected
const nodeRadioBtns = getByTestId('database-nodes');
expect(nodeRadioBtns).toHaveTextContent('$0/month $0/hr');

// update node pricing if a plan is selected
const radioBtn = getAllByText('Nanode 1 GB')[0];
fireEvent.click(radioBtn);
expect(nodeRadioBtns).toHaveTextContent('$60/month $0.09/hr');
expect(nodeRadioBtns).toHaveTextContent('$100/month $0.15/hr');
expect(nodeRadioBtns).toHaveTextContent('$140/month $0.21/hr');
});
});
Loading
Loading