1.add application list page (#779)

2.ignore the deleted applicationconfig resource instead return nil
3.code style fix
This commit is contained in:
majian
2020-12-17 09:22:38 -08:00
committed by GitHub
parent 0fab691ba3
commit c09e4df452
10 changed files with 185 additions and 7 deletions
+6
View File
@@ -3,6 +3,12 @@
path: '/',
redirect: `/System`,
},
{
name: 'applications',
icon: 'appstore',
path: `/applications`,
component: './Application',
},
{
name: 'system',
icon: 'setting',
@@ -1,7 +1,6 @@
import React from 'react';
import { Menu, message, Spin, Typography } from 'antd';
import classNames from 'classnames';
import { useModel } from 'umi';
import { DownOutlined } from '@ant-design/icons';
+1
View File
@@ -2,4 +2,5 @@ export default {
'menu.home': 'Home',
'menu.system': 'System',
'menu.system.environment': 'Environment',
'menu.applications': 'Applications',
};
+1
View File
@@ -2,4 +2,5 @@ export default {
'menu.home': '首页',
'menu.system': '系统',
'menu.system.environment': '环境',
'menu.applications': '应用列表',
};
+125
View File
@@ -0,0 +1,125 @@
import React, { useCallback } from 'react';
import { Button, Card, message, Popconfirm, Space, Table } from 'antd';
import { Link, useModel, useRequest } from 'umi';
import { deleteApplication, getApplications } from '@/services/application';
import compatibleDayjs from '@/utils/compatibleDayjs';
import { PlusOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-layout';
export default () => {
const { currentEnvironment } = useModel('useEnvironmentModel');
const { data, loading, run: loadApps } = useRequest(
async () => {
if (currentEnvironment?.envName == null) {
return { code: 200, data: [] } as API.VelaResponse<Array<API.Application>>;
}
return getApplications(currentEnvironment.envName);
},
{
refreshDeps: [currentEnvironment],
},
);
// delete application
const remove = useCallback(
async (appName: string) => {
const envName = currentEnvironment?.envName;
if (envName == null) {
throw new Error('Unable to determine the current environment name.');
}
const response = await deleteApplication(envName, appName);
loadApps();
return response;
},
[currentEnvironment],
);
return (
<PageContainer>
<Card>
<div style={{ marginBottom: '10px' }}>
<Space>
<Button type="primary" icon={<PlusOutlined />}>
Create
</Button>
</Space>
</div>
<Table
dataSource={data ?? []}
rowKey={(record) => record.name}
loading={loading ? { delay: 300 } : undefined}
columns={[
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (text, record) => {
return (
<Link
to={{
pathname: `${window.routerBase}applications/${record.name}`,
}}
>
{text}
</Link>
);
},
},
{
title: 'Status',
dataIndex: 'status',
key: 'status',
render: (text) => {
return text;
},
},
{
title: 'Created Time',
dataIndex: 'createdTime',
key: 'createdTime',
render: (text) => {
return compatibleDayjs(text).format('YYYY-MM-DD HH:mm:ss');
},
},
{
title: 'Actions',
dataIndex: 'Actions',
key: 'Actions',
render: (text, { name }) => {
return (
<Space>
<Popconfirm
title="Are you sure to delete this application?"
onConfirm={() => {
remove(name).then(({ code, data: content }) => {
if (code === 200) {
message.success({
content,
key: 'remove',
});
} else {
message.error({
content,
key: 'remove',
});
}
});
}}
>
<Button type="link" size="small" danger>
Delete
</Button>
</Popconfirm>
</Space>
);
},
},
]}
/>
</Card>
</PageContainer>
);
};
@@ -98,7 +98,7 @@ export default (): React.ReactNode => {
},
},
{
title: 'Operations',
title: 'Actions',
dataIndex: 'current',
render: (current, { envName, namespace }) => {
const active = current === '*';
@@ -113,7 +113,7 @@ export default (): React.ReactNode => {
switchCurrenrt({ envName });
}}
>
switch
Switch
</Button>
<Button
size="small"
@@ -128,7 +128,7 @@ export default (): React.ReactNode => {
})
}
>
update
Update
</Button>
{defaultEnv ? undefined : (
<Popconfirm
@@ -143,7 +143,7 @@ export default (): React.ReactNode => {
}}
>
<Button type="link" size="small" danger>
remove
Remove
</Button>
</Popconfirm>
)}
+8 -2
View File
@@ -8,7 +8,7 @@ declare namespace API {
name: string;
status?: string;
components?: ComponentMeta[];
createdTime?: Date;
createdTime?: string;
}
export interface ComponentMeta {
@@ -19,7 +19,7 @@ declare namespace API {
traits?: any[]; // ComponentTrait
traitsNames?: string[];
app: string;
createdTime?: Date;
createdTime?: string;
}
interface Environment {
@@ -33,4 +33,10 @@ declare namespace API {
interface EnvironmentBody {
namespace: string;
}
interface Application {
name: string;
status: string;
createdTime: string;
}
}
+22
View File
@@ -0,0 +1,22 @@
import { request } from 'umi';
const BASE_PATH = '/api/envs';
/*
* application list: get /api/envs/{env}/apps
*/
export async function getApplications(
envName: string,
): Promise<API.VelaResponse<API.Application[]>> {
return request(`${BASE_PATH}/${envName}/apps`);
}
/*
* delete application: delete /api/envs/{env}/apps/{app}
*/
export async function deleteApplication(
envName: string,
appName: string,
): Promise<API.VelaResponse<string>> {
return request(`${BASE_PATH}/${envName}/apps/${appName}`, { method: 'delete' });
}
+14
View File
@@ -0,0 +1,14 @@
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
dayjs.extend(customParseFormat);
dayjs.extend(utc);
dayjs.extend(timezone);
const FORMAT = 'YYYY-MM-DD HH:mm:ss ZZ';
export default function compatibleDayjs(date: string) {
return dayjs(date, FORMAT).tz();
}
+4
View File
@@ -76,6 +76,10 @@ func ListApplications(ctx context.Context, c client.Client, opt Option) ([]apis.
}
for _, a := range appConfigList.Items {
// ignore the deleted resource
if a.GetDeletionGracePeriodSeconds() != nil {
continue
}
applicationMeta, err := RetrieveApplicationStatusByName(ctx, c, a.Name, a.Namespace)
if err != nil {
return applicationMetaList, nil