Skip to content

Commit

Permalink
feat:cronjob detail page (#3914)
Browse files Browse the repository at this point in the history
* feat:cronjob detail page

Signed-off-by: jingyang <3161362058@qq.com>

* fix

* fix

* sort job

* pod log

* code

---------

Signed-off-by: jingyang <3161362058@qq.com>
  • Loading branch information
zjy365 committed Sep 14, 2023
1 parent cbcec7e commit b837bd3
Show file tree
Hide file tree
Showing 39 changed files with 10,482 additions and 3,002 deletions.
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
});
}
}

0 comments on commit b837bd3

Please sign in to comment.