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-8007] - DBaaS enhancements summary and settings #10939

Merged
merged 1 commit into from
Sep 18, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Upcoming Features
---

DBaaS V2 readonly hosts ([#10939](https://github.com/linode/manager/pull/10939))
1 change: 0 additions & 1 deletion packages/api-v4/src/regions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export type Capabilities =
| 'Kubernetes'
| 'Linodes'
| 'Managed Databases'
| 'Managed Databases Beta'
| 'Metadata'
| 'NodeBalancers'
| 'Object Storage'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

DBaaS V2 enhancements to the Summary and Settings tabs ([#10939](https://github.com/linode/manager/pull/10939))
5 changes: 3 additions & 2 deletions packages/manager/src/factories/databases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ export const databaseInstanceFactory = Factory.Sync.makeFactory<DatabaseInstance
created: '2021-12-09T17:15:12',
engine: Factory.each((i) => ['mysql', 'postgresql'][i % 2] as Engine),
hosts: {
primary: 'db-primary-0.b.linodeb.net',
secondary: 'db-secondary-0.b.linodeb.net',
primary: 'db-mysql-primary-0.b.linodeb.net',
secondary: 'db-mysql-secondary-0.b.linodeb.net',
},
id: Factory.each((i) => i),
instance_uri: '',
Expand Down Expand Up @@ -222,6 +222,7 @@ export const databaseFactory = Factory.Sync.makeFactory<Database>({
members: {
'2.2.2.2': 'primary',
},
platform: pickRandom(['rdbms-legacy', 'rdbms-default']),
port: 3306,
region: 'us-east',
ssl_connection: false,
Expand Down
Copy link
Member

Choose a reason for hiding this comment

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

Nice job on this test. Clean and concise 🧼

Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,30 @@ describe('DatabaseSettings Component', () => {
expect(button).toBeEnabled();
}
});

it('Should render Maintenance Window with radio buttons', () => {
const database = databaseFactory.build({
platform: 'rdbms-legacy',
});
const { getByRole, queryByText } = renderWithTheme(
<DatabaseSettings database={database} />
);
const radioInput = getByRole('radiogroup');
expect(radioInput).toHaveTextContent('Monthly');
expect(radioInput).toHaveTextContent('Weekly');
expect(queryByText('Maintenance Window')).toBeTruthy();
});

it('Should render Weekly Maintenance Window', () => {
const database = databaseFactory.build({
platform: 'rdbms-default',
});
const { queryByText } = renderWithTheme(
<DatabaseSettings database={database} />
);

expect(queryByText('Monthly')).toBeNull();
expect(queryByText('Weekly')).toBeNull();
expect(queryByText('Set a Weekly Maintenance Window')).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ export const DatabaseSettings: React.FC<Props> = (props) => {
</Typography>
);

const resetRootPasswordCopy =
'Resetting your root password will automatically generate a new password. You can view the updated password on your database cluster summary page. ';
const isLegacy = database.platform === 'rdbms-legacy';

const deleteClusterCopy =
'Deleting a database cluster is permanent and cannot be undone.';
const resetRootPasswordCopy = isLegacy
? 'Resetting your root password will automatically generate a new password. You can view the updated password on your database cluster summary page. '
: 'Reset your root password if someone should no longer have access to the root user or if you believe your password may have been compromised. This will automatically generate a new password that you’ll be able to see on your database cluster summary page.';

const deleteClusterCopy = isLegacy
? 'Deleting a database cluster is permanent and cannot be undone.'
: 'Permanently remove an unused database cluster.';

const [isDeleteDialogOpen, setIsDeleteDialogOpen] = React.useState(false);
const [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import { FormControlLabel } from 'src/components/FormControlLabel';
import { RadioGroup } from 'src/components/RadioGroup';
import { useDatabaseMutation } from 'src/queries/databases/databases';

// import { updateDatabaseSchema } from '@linode/validation/src/databases.schema';

const useStyles = makeStyles()((theme: Theme) => ({
formControlDropdown: {
'& label': {
Expand Down Expand Up @@ -173,22 +171,30 @@ export const MaintenanceWindow = (props: Props) => {
onSubmit: handleSaveMaintenanceWindow,
});

const isLegacy = database.platform === 'rdbms-legacy';

const typographyDatabase =
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: I think we normally use capitalized snake case for copy constants, but someone correct me if I'm wrong!

Suggested change
const typographyDatabase =
const TYPOGRAPHY_DATABASE =

these constants could also be moved to the top of the scope, outside the component. Alternatively, you could do something like you did with the copies in DatabaseSettings:

const typographyDatabase = isLegacy ? ... : ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure, other places have camelCase for text copy. Personally, I'd do CAPS for const but not sure the standard.

'Select when you want the required OS and DB engine updates to take place. The maintenance may cause downtime on clusters with less than 3 nodes (non high-availability clusters).';

const typographyLegacyDatabase =
"OS and DB engine updates will be performed on the schedule below. Select the frequency, day, and time you'd prefer maintenance to occur.";

return (
<form onSubmit={handleSubmit}>
<div className={classes.topSection}>
<div className={classes.sectionTitleAndText}>
<Typography className={classes.sectionTitle} variant="h3">
Maintenance Window
{isLegacy
? 'Maintenance Window'
: 'Set a Weekly Maintenance Window'}
Copy link
Member

Choose a reason for hiding this comment

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

All other headings on this page don't use verbs. I'd prefer if we keep headings consistent, but that's just my opinion.

Suggested change
: 'Set a Weekly Maintenance Window'}
: 'Weekly Maintenance Window'}

</Typography>
{maintenanceUpdateError ? (
<Notice spacingTop={8} variant="error">
{maintenanceUpdateError[0].reason}
</Notice>
) : null}
<Typography className={classes.sectionText}>
OS and DB engine updates will be performed on the schedule below.
Select the frequency, day, and time you&rsquo;d prefer maintenance
to occur.{' '}
{isLegacy ? typographyLegacyDatabase : typographyDatabase}
{database.cluster_size !== 3
? 'For non-HA plans, expect downtime during this window.'
: null}
Expand Down Expand Up @@ -261,7 +267,7 @@ export const MaintenanceWindow = (props: Props) => {
/>
<TooltipIcon
sxTooltipIcon={{
marginTop: '1.25rem',
marginTop: '1.75rem',
padding: '0px 8px',
}}
text={
Expand All @@ -277,44 +283,46 @@ export const MaintenanceWindow = (props: Props) => {
</div>
</FormControl>
</div>
<FormControl
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setFormTouched(true);
setFieldValue('frequency', e.target.value);
if (e.target.value === 'weekly') {
// If the frequency is weekly, set the 'week_of_month' field to null since that should only be specified for a monthly frequency.
setFieldValue('week_of_month', null);
}
{isLegacy && (
<FormControl
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setFormTouched(true);
setFieldValue('frequency', e.target.value);
if (e.target.value === 'weekly') {
// If the frequency is weekly, set the 'week_of_month' field to null since that should only be specified for a monthly frequency.
setFieldValue('week_of_month', null);
}

if (e.target.value === 'monthly') {
const dayOfWeek =
daySelectionMap.find(
(option) => option.value === values.day_of_week
) ?? daySelectionMap[0];
if (e.target.value === 'monthly') {
const dayOfWeek =
daySelectionMap.find(
(option) => option.value === values.day_of_week
) ?? daySelectionMap[0];

weekSelectionModifier(dayOfWeek.label, weekSelectionMap);
setFieldValue(
'week_of_month',
modifiedWeekSelectionMap[0].value
);
}
}}
disabled={disabled}
>
<RadioGroup
style={{ marginBottom: 0, marginTop: 0 }}
value={values.frequency}
weekSelectionModifier(dayOfWeek.label, weekSelectionMap);
setFieldValue(
'week_of_month',
modifiedWeekSelectionMap[0].value
);
}
}}
disabled={disabled}
>
{maintenanceFrequencyMap.map((option) => (
<FormControlLabel
control={<Radio />}
key={option.value}
label={option.key}
value={option.value}
/>
))}
</RadioGroup>
</FormControl>
<RadioGroup
style={{ marginBottom: 0, marginTop: 0 }}
value={values.frequency}
>
{maintenanceFrequencyMap.map((option) => (
<FormControlLabel
control={<Radio />}
key={option.value}
label={option.key}
value={option.value}
/>
))}
</RadioGroup>
</FormControl>
)}
<div>
{values.frequency === 'monthly' ? (
<FormControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,12 @@ export const DatabaseSummaryConnectionDetails = (props: Props) => {
{database.hosts.secondary ? (
<Box alignItems="center" display="flex" flexDirection="row">
<Typography>
<span>private network host</span> = {database.hosts.secondary}
{database.platform === 'rdbms-default' ? (
<span>read-only host</span>
) : (
<span>private network host</span>
)}
= {database.hosts.secondary}
</Typography>
<CopyTooltip
className={classes.inlineCopyToolTip}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel';
import { TabLinkList } from 'src/components/Tabs/TabLinkList';
import { TabPanels } from 'src/components/Tabs/TabPanels';
import { Tabs } from 'src/components/Tabs/Tabs';
import DatabaseLogo from 'src/features/Databases/DatabaseLanding/DatabaseLogo';
import { useEditableLabelState } from 'src/hooks/useEditableLabelState';
import { useFlags } from 'src/hooks/useFlags';
import { useIsResourceRestricted } from 'src/hooks/useIsResourceRestricted';
Expand Down Expand Up @@ -199,6 +200,7 @@ export const DatabaseDetail = () => {
</SafeTabPanel>
</TabPanels>
</Tabs>
{database.platform === 'rdbms-default' && <DatabaseLogo />}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { TableCell } from '@mui/material';
import React from 'react';

import { Hidden } from 'src/components/Hidden';
Expand Down Expand Up @@ -60,8 +59,14 @@ const DatabaseLandingTable = ({
Status
</TableSortCell>
{isNewDatabase && (
/* TODO add back TableSortCell once API is updated to support sort by Plan */
<TableCell>Plan</TableCell>
<TableSortCell
active={orderBy === 'plan'}
direction={order}
handleClick={handleOrderChange}
label="plan"
>
Plan
</TableSortCell>
)}
<Hidden smDown>
<TableSortCell
Expand Down
6 changes: 6 additions & 0 deletions packages/manager/src/mocks/serverHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ const databases = [
label: `Nanode 1 GB`,
memory: 1024,
}),
databaseTypeFactory.build({
class: 'nanode',
id: 'g6-standard-1',
label: `Linode 2 GB`,
memory: 2048,
}),
...databaseTypeFactory.buildList(7, { class: 'standard' }),
];
const dedicatedTypes = databaseTypeFactory.buildList(7, {
Expand Down
2 changes: 1 addition & 1 deletion packages/validation/src/databases.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const createDatabaseSchema = object({
region: string().required('Region is required'),
type: string().required('Type is required'),
cluster_size: number()
.oneOf([1, 3], 'Nodes are required')
.oneOf([1, 2, 3], 'Nodes are required')
.required('Nodes are required'),
replication_type: string().when('engine', {
is: (engine: string) => Boolean(engine.match(/mysql|postgres/g)),
Expand Down
Loading