Skip to content

Commit

Permalink
auto backup (#3486)
Browse files Browse the repository at this point in the history
* auto backup

* i18n
  • Loading branch information
c121914yu authored Jul 11, 2023
1 parent 7df69f2 commit b695d97
Show file tree
Hide file tree
Showing 21 changed files with 691 additions and 122 deletions.
1 change: 1 addition & 0 deletions frontend/providers/dbprovider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"unlink-sdk": "yalc remove --all && pnpm install sealos-desktop-sdk"
},
"dependencies": {
"@chakra-ui/anatomy": "^2.1.1",
"@chakra-ui/icons": "^2.0.17",
"@chakra-ui/react": "^2.5.1",
"@chakra-ui/system": "^2.5.5",
Expand Down
9 changes: 9 additions & 0 deletions frontend/providers/dbprovider/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion frontend/providers/dbprovider/public/locales/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,21 @@
"Auto Backup": "自动备份",
"Containers": "容器",
"Redis does not support backup at this time": "Redis 暂时不支持备份",
"The multi-replica Redis includes High Availability (HA) nodes. Please note, the anticipated price already encompasses the cost for the HA nodes.": "Redis 多副本包含 HA 节点,请悉知,预估价格已包含 HA 节点费用"
"The multi-replica Redis includes High Availability (HA) nodes. Please note, the anticipated price already encompasses the cost for the HA nodes.": "Redis 多副本包含 HA 节点,请悉知,预估价格已包含 HA 节点费用",
"CronExpression": "循环周期",
"Monday": "周一",
"Tuesday": "周二",
"Wednesday": "周三",
"Thursday": "周四",
"Friday": "周五",
"Saturday": "周六",
"Sunday": "周日",
"Start Hour": "小时",
"Start Minute": "分钟",
"Save": "保存",
"Hour": "小时",
"Day": "",
"Week": "",
"SaveTime": "保留时间",
"Set auto backup successful": "设置自动备份任务成功"
}
7 changes: 6 additions & 1 deletion frontend/providers/dbprovider/src/api/backup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { GET, POST, DELETE } from '@/services/request';
import type { Props as CreateBackupPros } from '@/pages/api/backup/create';
import { adaptBackup } from '@/utils/adapt';
import { BackupItemType } from '@/types/db';
import { AutoBackupFormType } from '@/types/backup';
import type { Props as UpdatePolicyProps } from '@/pages/api/backup/updatePolicy';

export const getBackupPolicy = (data: { dbName: string; dbType: string }) =>
GET<AutoBackupFormType>(`/api/backup/policy`, data);
export const createBackup = (data: CreateBackupPros) => POST('/api/backup/create', data);
export const getBackupList = (dbName: string) =>
GET('/api/backup/getBackupList', { dbName }).then((res) => res.map(adaptBackup));

export const deleteBackup = (backupName: string) =>
DELETE(`/api/backup/delBackup?backupName=${backupName}`);
export const updateBackupPolicy = (data: UpdatePolicyProps) =>
POST<AutoBackupFormType>(`/api/backup/updatePolicy`, data);
40 changes: 30 additions & 10 deletions frontend/providers/dbprovider/src/components/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { Menu, MenuButton, MenuList, MenuItem, Button, useDisclosure } from '@chakra-ui/react';
import { Menu, MenuButton, MenuList, MenuItem, Button, useDisclosure, Box } from '@chakra-ui/react';
import type { ButtonProps } from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { useTranslation } from 'next-i18next';

interface Props extends ButtonProps {
isDisabled?: boolean;
Expand All @@ -12,6 +13,7 @@ interface Props extends ButtonProps {
id: string;
}[];
width?: number | string;
icon?: React.ReactNode;
onchange?: (val: string) => void;
}

Expand All @@ -22,23 +24,35 @@ const MySelect = ({
width = 'auto',
list,
onchange,
icon = <ChevronDownIcon />,
...props
}: Props) => {
const { t } = useTranslation();

const menuItemStyles = {
borderRadius: 'sm',
py: 2,
display: 'flex',
alignItems: 'center',
transform: 'translate3d(0,0,0)',
cursor: 'pointer',
px: 3,
_hover: {
backgroundColor: 'myWhite.600'
}
};
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<Menu autoSelect={false} onOpen={() => !isDisabled && onOpen()} onClose={onClose}>
<MenuButton as={'span'}>
<Menu
isOpen={isOpen}
autoSelect={false}
onOpen={() => !isDisabled && onOpen()}
onClose={onClose}
>
<MenuButton as={'div'}>
<Button
position={'relative'}
width={width}
px={3}
display={'flex'}
Expand All @@ -49,15 +63,18 @@ const MySelect = ({
? {
boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'myBlue.600',
bg: 'transparent'
bg: 'transparent',
color: 'myGray.800'
}
: {
bg: 'myWhite.300'
})}
{...props}
>
{list?.find((item) => item.id === value)?.label || placeholder}
<ChevronDownIcon />
{t(list?.find((item) => item.id === value)?.label || placeholder || '')}
<Box position={'absolute'} right={3}>
{icon}
</Box>
</Button>
</MenuButton>
{!isDisabled && (
Expand All @@ -69,9 +86,11 @@ const MySelect = ({
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
}
zIndex={99}
maxH={'300px'}
overflow={'overlay'}
>
{list?.map((item) => (
<MenuItem
<Box
key={item.id}
{...menuItemStyles}
{...(value === item.id
Expand All @@ -83,15 +102,16 @@ const MySelect = ({
if (onchange && value !== item.id) {
onchange(item.id);
}
onClose();
}}
>
{item.label}
</MenuItem>
{t(item.label)}
</Box>
))}
</MenuList>
)}
</Menu>
);
};

export default MySelect;
export default React.memo(MySelect);
20 changes: 18 additions & 2 deletions frontend/providers/dbprovider/src/components/Tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
};
}
}, [size]);
const activeIndex = useMemo(
() => list.findIndex((item) => item.id === activeId),
[activeId, list]
);
return (
<Grid
border={'1px solid #DEE0E2'}
Expand All @@ -46,12 +50,24 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
fontSize={sizeMap.fontSize}
{...props}
>
{list.map((item) => (
{list.map((item, i) => (
<Box
key={item.id}
py={sizeMap.inlineP}
borderRadius={'sm'}
position={'relative'}
textAlign={'center'}
zIndex={1}
_before={{
content: '""',
position: 'absolute',
right: '0',
top: '50%',
transform: 'translateY(-50%)',
w: i === list.length - 1 || i === activeIndex || i === activeIndex - 1 ? '0' : '1px',
h: '10px',
bg: '#DEE0E2'
}}
{...(activeId === item.id
? {
boxShadow: '0px 2px 2px rgba(137, 156, 171, 0.25)',
Expand All @@ -66,7 +82,7 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
onChange(item.id);
}}
>
{t(item.label)}
<Box>{t(item.label)}</Box>
</Box>
))}
</Grid>
Expand Down
2 changes: 1 addition & 1 deletion frontend/providers/dbprovider/src/constants/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export const DBBackupPolicyNameMap = {
export const defaultDBEditValue: DBEditType = {
dbType: DBTypeEnum.postgresql,
dbVersion: '',
dbName: 'dbname',
dbName: '',
replicas: 1,
cpu: CpuSlideMarkList[1].value,
memory: MemorySlideMarkList[1].value,
Expand Down
39 changes: 36 additions & 3 deletions frontend/providers/dbprovider/src/constants/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ import {
extendTheme
} from '@chakra-ui/react';
// @ts-ignore
import { selectAnatomy, switchAnatomy, numberInputAnatomy } from '@chakra-ui/anatomy';
import {
selectAnatomy,
switchAnatomy,
numberInputAnatomy,
checkboxAnatomy
} from '@chakra-ui/anatomy';
const { definePartsStyle: selectPart, defineMultiStyleConfig: selectMultiStyle } =
createMultiStyleConfigHelpers(selectAnatomy.keys);
const { definePartsStyle: switchPart, defineMultiStyleConfig: switchMultiStyle } =
createMultiStyleConfigHelpers(switchAnatomy.keys);
const { definePartsStyle: numInputPart, defineMultiStyleConfig: numInputMultiStyle } =
createMultiStyleConfigHelpers(numberInputAnatomy.keys);
const { definePartsStyle: checkboxPart, defineMultiStyleConfig: checkboxStyle } =
createMultiStyleConfigHelpers(checkboxAnatomy.keys);

const Button = defineStyleConfig({
baseStyle: {
Expand Down Expand Up @@ -181,7 +188,17 @@ const Switch = switchMultiStyle({
bg: 'myGray.700'
}
}
})
}),
variants: {
deepLight: {
track: {
bg: 'myGray.200',
_checked: {
bg: 'myGray.700'
}
}
}
}
});

const Tooltip = defineStyleConfig({
Expand All @@ -194,6 +211,21 @@ const Tooltip = defineStyleConfig({
}
});

const Checkbox = checkboxStyle({
baseStyle: checkboxPart({
control: defineStyle({
_checked: {
bg: 'black',
borderColor: 'black',
_hover: {
bg: 'black !important',
borderColor: 'black !important'
}
}
})
})
});

export const theme = extendTheme({
styles: {
global: {
Expand Down Expand Up @@ -305,6 +337,7 @@ export const theme = extendTheme({
Select,
Switch,
Textarea,
NumberInput
NumberInput,
Checkbox
}
});
22 changes: 9 additions & 13 deletions frontend/providers/dbprovider/src/pages/api/backup/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import { ApiResp } from '@/services/kubernet';
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { json2Backup } from '@/utils/json2Yaml';
import { json2ManualBackup } from '@/utils/json2Yaml';
import { DBBackupPolicyNameMap, DBTypeEnum } from '@/constants/db';

export type Props = {
backupName: string;
dbName: string;
remark?: string;
dbType: `${DBTypeEnum}`;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
const { backupName, dbName, remark } = req.body as Props;
const { backupName, dbName, remark, dbType } = req.body as Props;

if (!dbName || !backupName) {
if (!dbName || !backupName || !dbType) {
jsonRes(res, {
code: 500,
error: 'params error'
Expand All @@ -24,7 +26,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<

const group = 'dataprotection.kubeblocks.io';
const version = 'v1alpha1';
const labelKey = 'app.kubernetes.io/instance';
const plural = 'backuppolicies';

try {
Expand All @@ -33,27 +34,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});

// get backup backupolicies.dataprotection.kubeblocks.io
const { body } = (await k8sCustomObjects.listNamespacedCustomObject(
const { body } = (await k8sCustomObjects.getNamespacedCustomObject(
group,
version,
namespace,
plural,
undefined,
undefined,
undefined,
undefined,
`${labelKey}=${dbName}`
`${dbName}-${DBBackupPolicyNameMap[dbType]}-backup-policy`
)) as { body: any };

const backupPolicyName = body?.items?.[0]?.metadata?.name;
const backupPolicyName = body?.metadata?.name;

if (!backupPolicyName) {
throw new Error('Cannot find backup policy');
}

const backupCr = json2Backup({
const backupCr = json2ManualBackup({
name: backupName,
dbName,
backupPolicyName,
remark
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export async function getBackups({ dbName, req }: Props & { req: NextApiRequest
undefined,
undefined,
undefined,
`${crLabelKey}=${dbName}`
`app.kubernetes.io/instance=${dbName}`
)) as { body: { items: any[] } };

return body?.items || [];
Expand Down
Loading

0 comments on commit b695d97

Please sign in to comment.