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:cronjob detail page #3914

Merged
merged 6 commits into from Sep 14, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11,363 changes: 8,693 additions & 2,670 deletions frontend/pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions frontend/providers/cronjob/package.json
Expand Up @@ -22,6 +22,8 @@
"@tanstack/react-query": "^4.29.25",
"ansi_up": "^5.2.1",
"axios": "^1.4.0",
"cron-parser": "^4.9.0",
"cronstrue": "^2.32.0",
"date-fns": "^2.30.0",
"dayjs": "^1.11.9",
"echarts": "^5.4.3",
Expand Down
37 changes: 31 additions & 6 deletions frontend/providers/cronjob/public/locales/en/common.json
Expand Up @@ -73,7 +73,7 @@
"Connection Info": "Connection",
"Direct Connection": "connect",
"Delete Warning": "Delete Warning",
"Delete Hint": "Do you want to delete this database if you are sure? If you do this, all data for the database will be deleted.",
"Delete Hint": "Are you sure you want to delete this CronJob? If you perform this operation, the related Job will be deleted.",
"Please Enter": "Please Enter",
"Confirm Delete": "Confirm",
"Confirm Restart Pod": "Confirm Restart Pod?",
Expand Down Expand Up @@ -121,8 +121,10 @@
"Database Usage": "Database Usage",
"Disk": "Disk",
"Schedule": "Schedule",
"Last Schedule Time": "Last Schedule Time",
"Last Successful Time": "Last Successful Time",
"Last Schedule": "Last Schedule",
"Last Schedule Time": "Schedule Time:",
"Last Successful Time": "Successful Time:",
"Next Execution Time": "Next Execution Time",
"job": {
"list": "Cron Job List",
"create": "Create Job",
Expand All @@ -148,7 +150,8 @@
"Backup": "Backup",
"Success": "Success",
"Have Error": "Failed",
"Logs": "Logs"
"Logs": "Logs",
"Error": "Error"
},
"Form": {
"Image": "Image",
Expand All @@ -164,6 +167,28 @@
"Command": "Command",
"Parameters": "Parameters",
"Time": "Time",
"Image Address": "Image Address"
}
"Image Address": "Image Address",
"URL": "URL",
"Cron Expression": "Cron Expression",
"Example": "Example: */1 * * * * means executing tasks every minute",
"Visit Url": "Visit Url",
"Execution Image": "Execution Image",
"Expansion and Contraction Launchpad": "Expansion and Contraction Launchpad",
"App Name": "App Name",
"Replicas": "Replicas",
"JobNamePlaceholder": "Starts with a letter and can contain only lowercase letters, digits, and hyphens (-)"
},
"every five minutes": "every five minutes",
"per hour": "per hour",
"8 am every day": "8 am every day",
"examples": "examples",
"Not allowed to change app name": "Not allowed to change app name",
"The user name cannot be empty": "The user name cannot be empty",
"Executed": "Executed",
"Historical Mission": "Historical Mission",
"pause_message": "Are you sure to pause the cronjob?",
"Basic Information": "Basic Information",
"Succeeded": "Succeeded",
"Failures": "Failures",
"Log": "Log"
}
39 changes: 32 additions & 7 deletions frontend/providers/cronjob/public/locales/zh/common.json
Expand Up @@ -80,7 +80,7 @@
"Connection Info": "连接信息",
"Direct Connection": "一键连接",
"Delete Warning": "删除警告",
"Delete Hint": "如果确认要删除这个数据库吗?如果执行此操作,将删除该数据库的所有数据。",
"Delete Hint": "确认要删除这个CronJob吗?如果执行此操作,将删除相关Job。",
"Please Enter": "请输入",
"Confirm Delete": "确认删除",
"Confirm Restart Pod": "请确认重启 Pod?",
Expand Down Expand Up @@ -167,9 +167,11 @@
"InnoDB Buffer Pool": "InnoDB 缓冲池",
"Database Usage": "数据库用量",
"Disk": "磁盘空间",
"Schedule": "表达式",
"Last Schedule Time": "最后调度时间",
"Last Successful Time": "上一次成功时间",
"Schedule": "执行周期",
"Last Schedule": "上次执行",
"Last Schedule Time": "执行时间:",
"Last Successful Time": "成功时间:",
"Next Execution Time": "下次执行时间",
"job": {
"list": "任务列表",
"create": "新建任务",
Expand All @@ -195,7 +197,8 @@
"Backup": "备份",
"Success": "成功",
"Have Error": "出现异常",
"Logs": "日志"
"Logs": "日志",
"Error": "失败"
},
"Form": {
"Image": "镜像源",
Expand All @@ -211,6 +214,28 @@
"Command": "运行命令",
"Parameters": "命令参数",
"Time": "时间",
"Image Address": "镜像仓库地址"
}
"Image Address": "镜像仓库地址",
"URL": "URL",
"Cron Expression": "Cron 表达式",
"Example": "例: */1 * * * * 表示每分钟执行任务",
"Visit Url": "访问url",
"Execution Image": "执行镜像",
"Expansion and Contraction Launchpad": "扩缩容 Launchpad",
"App Name": "App 名称",
"Replicas": "副本数",
"JobNamePlaceholder": "以字母开头,只能包含小写字母、数字和连字符 (-)"
},
"every five minutes": "每五分钟",
"per hour": "每小时",
"8 am every day": "每天上午8点",
"examples": "更多示例",
"Not allowed to change app name": "不允许更改应用程序名称",
"The user name cannot be empty": "用户名不能为空",
"Executed": "执行于",
"Historical Mission": "历史任务",
"pause_message": "确定暂停cronjob吗",
"Basic Information": "基础信息",
"Succeeded": "成功数",
"Failures": "失败数",
"Log": "日志"
}
14 changes: 14 additions & 0 deletions frontend/providers/cronjob/src/api/app.ts
@@ -0,0 +1,14 @@
import { GET } from '@/services/request';
import { adaptAppListItem, adaptServiceAccountList } from '@/utils/adapt';
import { V1Deployment, V1ServiceAccount } from '@kubernetes/client-node';

export const getMyApps = () =>
GET<V1Deployment[]>('/api/launchpad/getApps').then((res) => res.map(adaptAppListItem));

export const getMyServiceAccount = () =>
GET<V1ServiceAccount[]>('/api/launchpad/getServiceAccount').then((res) =>
res.map(adaptServiceAccountList)
);

export const getAppByName = (name: string) =>
GET<V1Deployment>(`/api/launchpad/getAppByAppName?appName=${name}`);
32 changes: 26 additions & 6 deletions frontend/providers/cronjob/src/api/job.ts
@@ -1,16 +1,23 @@
import { DELETE, GET, POST } from '@/services/request';
import { adaptJobDetail, adaptJobList } from '@/utils/adapt';
import {
adaptCronJobDetail,
adaptCronJobList,
adaptEvents,
adaptJobDetail,
adaptJobItemList
} from '@/utils/adapt';
import { V1PodList } from '@kubernetes/client-node';

export const applyYamlList = (yamlList: string[], type: 'create' | 'replace' | 'update') =>
POST('/api/applyYamlList', { yamlList, type });

export const getMyJobList = () =>
GET('/api/cronjob/getJobList').then((data) => data.map(adaptJobList));
export const getCronJobList = () =>
GET('/api/cronjob/getCronJobList').then((data) => data.map(adaptCronJobList));

export const getJobByName = (name: string) =>
GET(`/api/cronjob/getByName?name=${name}`).then(adaptJobDetail);
export const getCronJobByName = (name: string) =>
GET(`/api/cronjob/getByName?name=${name}`).then(adaptCronJobDetail);

export const delJobByName = (name: string) => DELETE('/api/cronjob/delByName', { name });
export const delCronJobByName = (name: string) => DELETE('/api/cronjob/delByName', { name });

export const updateCronJobStatus = ({
jobName,
Expand All @@ -19,3 +26,16 @@ export const updateCronJobStatus = ({
jobName: string;
type: 'Stop' | 'Start';
}) => POST('/api/cronjob/startAndStop', { jobName, type });

export const getJobList = (name: string) =>
GET(`/api/job/list?cronJobName=${name}`).then(adaptJobItemList);

export const getJobEvents = (name: string) => GET(`/api/job/event?name=${name}`).then(adaptEvents);

export const getPodLogs = (podName: string) => GET<string>(`/api/getPodLogs?podName=${podName}`);

export const getJobPodList = (jobNames: string[]) =>
POST<V1PodList>(`/api/getJobPodList`, { jobNames });

export const getJobListEventsAndLogs = (cronJobName: string) =>
getJobList(cronJobName).then(adaptJobDetail);
6 changes: 3 additions & 3 deletions frontend/providers/cronjob/src/components/Slider/index.tsx
Expand Up @@ -32,19 +32,19 @@ const MySlider = ({
}, [activeVal, markList]);

return (
<Slider max={max} min={min} step={step} size={'lg'} value={value} onChange={setVal}>
<Slider w="500px" max={max} min={min} step={step} size={'lg'} value={value} onChange={setVal}>
{markList.map((item, i) => (
<SliderMark
key={item.value}
value={i}
mt={3}
fontSize={'sm'}
transform={'translateX(-50%)'}
transform={'translateX(-20%)'}
{...(activeVal === item.value
? { color: 'myGray.900', fontWeight: 'bold' }
: { color: 'myGray.500' })}
>
<Box px={3} cursor={'pointer'}>
<Box minW={'40px'} cursor={'pointer'}>
{item.label}
</Box>
</SliderMark>
Expand Down
6 changes: 4 additions & 2 deletions frontend/providers/cronjob/src/components/Table/index.tsx
Expand Up @@ -23,7 +23,9 @@ const Table = ({ columns, data }: Props) => {
py={3}
bg={'white'}
key={item.key}
color={'myGray.500'}
fontSize={'12px'}
fontWeight={500}
color={'#485058'}
whiteSpace={'nowrap'}
_first={{
borderLeftRadius: 'md',
Expand All @@ -45,7 +47,7 @@ const Table = ({ columns, data }: Props) => {
px={3}
py={4}
fontSize={'sm'}
color={'myGray.600'}
color={'#363C42'}
borderBottom={'1px solid'}
borderBottomColor={index1 !== data.length - 1 ? 'myGray.100' : 'transparent'}
borderTopLeftRadius={index1 === 0 && index2 === 0 ? 'md' : ''}
Expand Down
62 changes: 34 additions & 28 deletions frontend/providers/cronjob/src/constants/job.ts
@@ -1,8 +1,9 @@
import { CronJobEditType } from '@/types/job';

export const JobTypeList = [
{ id: 'test', label: 'test' },
{ id: 'test2', label: 'test2' }
export const CronJobTypeList = [
{ id: 'url', label: 'Form.Visit Url' },
{ id: 'launchpad', label: 'Form.Expansion and Contraction Launchpad' },
{ id: 'image', label: 'Form.Execution Image' }
];

export const SelectTimeList = <
Expand All @@ -29,31 +30,6 @@ export const WeekSelectList = [
{ label: 'Sunday', id: '0' }
];

export const DefaultJobEditValue: CronJobEditType = {
jobType: '',
jobName: '',
schedule: '* * * * *',
imageName: '',
runCMD: '',
cmdParam: '',
secret: {
use: false,
username: '',
password: '',
serverAddress: 'docker.io'
},
envs: [
{
key: 'TZ',
value: 'Asia/Shanghai'
}
],
scheduleType: 'hour',
week: [],
hour: '*',
minute: '*'
};

export enum StatusEnum {
Running = 'Running',
Creating = 'Creating',
Expand Down Expand Up @@ -163,3 +139,33 @@ export const CronJobStatusMap = {
dotColor: '#787A90'
}
};

export const DefaultJobEditValue: CronJobEditType = {
jobType: 'launchpad',
jobName: '',
schedule: '* * * * *',
imageName: '',
runCMD: '',
cmdParam: '',
secret: {
use: false,
username: '',
password: '',
serverAddress: 'docker.io'
},
envs: [],
url: '',
enableNumberCopies: true,
enableResources: true,
replicas: 1,
cpu: 0,
memory: 0,
launchpadName: '',
launchpadId: '',
serviceAccountName: '',
status: CronJobStatusMap['Running'],
isPause: false,
creatTime: '',
_schedule: '',
nextExecutionTime: ''
};
Expand Up @@ -9,7 +9,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { namespace, k8sBatch } = await getK8s({
kubeconfig: await authSession(req)
});
const response: any = await k8sBatch.listNamespacedCronJob(namespace);
const response = await k8sBatch.listNamespacedCronJob(namespace);

jsonRes(res, { data: response?.body?.items });
} catch (err: any) {
Expand Down
35 changes: 35 additions & 0 deletions frontend/providers/cronjob/src/pages/api/getJobPodList.ts
@@ -0,0 +1,35 @@
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { ApiResp } from '@/services/kubernet';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
try {
const { jobNames } = req.body as {
jobNames: string[];
};
const labelSelector = jobNames.join(',');
const { k8sCore, namespace } = await getK8s({
kubeconfig: await authSession(req)
});

const response = await k8sCore.listNamespacedPod(
namespace,
undefined,
undefined,
undefined,
undefined,
`job-name in (${labelSelector})`
);

return jsonRes(res, {
data: response.body
});
} catch (err: any) {
jsonRes(res, {
code: 500,
error: err
});
}
}