Implement application creation page

To fix #680
This commit is contained in:
zzxwill
2021-02-05 17:48:27 +08:00
parent f2bd881d27
commit 8af08075df
9 changed files with 231 additions and 24 deletions
+6
View File
@@ -9,6 +9,12 @@
path: `/applications`,
component: './Application',
},
/* Application Create should be moved to /Application */
{
name: 'create_application',
path: '/applications/create',
component: './CreateApplication'
},
{
name: 'capability',
icon: 'AppstoreAddOutlined',
+4 -1
View File
@@ -54,6 +54,7 @@
"@umijs/route-utils": "^1.0.33",
"antd": "^4.9.4",
"classnames": "^2.2.6",
"form-render": "^0.9.0",
"dayjs": "^1.9.7",
"lodash": "^4.17.11",
"moment": "^2.25.3",
@@ -63,6 +64,7 @@
"react-dev-inspector": "^1.1.1",
"react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4",
"react-router-dom": "^5.2.0",
"umi": "^3.2.14",
"umi-request": "^1.0.8",
"use-merge-value": "^1.0.1"
@@ -100,7 +102,8 @@
"pro-download": "1.0.1",
"puppeteer-core": "^5.0.0",
"stylelint": "^13.0.0",
"typescript": "^4.1.2"
"typescript": "^4.1.2",
"webpack-plugin-fr-theme": "^0.2.0"
},
"engines": {
"node": ">=10.0.0"
+1 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import * as api from '@/services/traits';
import * as api from '@/services/capability';
interface State {
loading?: boolean;
+1 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import * as api from '@/services/workloads';
import * as api from '@/services/capability';
interface State {
loading?: boolean;
+4 -1
View File
@@ -6,6 +6,8 @@ import { Link, useModel, useRequest } from 'umi';
import { deleteApplication, getApplications } from '@/services/application';
import { PlusOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-layout';
// @ts-ignore
import { Link as ReactLink } from "react-router-dom";
export default () => {
const { currentEnvironment } = useModel('useEnvironmentModel');
@@ -42,7 +44,8 @@ export default () => {
<div style={{ marginBottom: '10px' }}>
<Space>
<Button type="primary" icon={<PlusOutlined />}>
Create
<ReactLink to="/applications/create"> Create</ReactLink>
</Button>
</Space>
</div>
@@ -0,0 +1,192 @@
import React, {useState} from 'react';
import {Input, Dropdown, Menu, Button, Divider, Row, Col} from 'antd';
import {useModel} from "@@/plugin-model/useModel";
import {DownOutlined, UserOutlined} from '@ant-design/icons';
import FormRender from 'form-render/lib/antd';
import {getCapabilityOpenAPISchema} from "@/services/capability";
// prevent Ant design style from being overridden
import 'antd/dist/antd.css';
export default (): React.ReactNode => {
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {workloadsLoading, workloadList} = useModel('useWorkloadsModel');
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {traitsLoading, traitsList} = useModel('useTraitsModel');
const workloadMenuList = workloadList?.map((i) =>
<Menu.Item key={i.name} icon={<UserOutlined/>} onClick={() => handleMenuClick("workload_type", i.name)}>
{i.name}
</Menu.Item>
)
const traitMenuList = traitsList?.map((i) =>
<Menu.Item key={i.name} icon={<UserOutlined/>} onClick={() => handleMenuClick("trait", i.name)}>
{i.name}
</Menu.Item>
)
const workloadsMenu = (
<Menu>
{workloadMenuList}
</Menu>
);
const traitsMenu = (
<Menu>
{traitMenuList}
</Menu>
);
// Capability parameters form render
const [formData, setData] = useState({});
// schema is OpenAPI Schema JSON data
const [workloadSchema, setWorkloadSchema] = useState({})
const [traitSchema, setTraitSchema] = useState({})
const [valid, setValid] = useState([]);
function handleMenuClick(capabilityType: string, capabilityName: string) {
console.log('click', capabilityName);
getCapabilityOpenAPISchema(capabilityName).then((result) => {
const data = JSON.parse(result.data)
if (capabilityType === "workload_type") {
setWorkloadSchema(data)
} else if (capabilityType === "trait") {
setTraitSchema(data)
}
})
}
const onSubmit = () => {
// valid == 0: validation passed
if (valid.length > 0) {
alert(`invalid${valid.toString()}`);
} else {
alert(JSON.stringify(formData, null, 2));
}
};
return (
<div style={{maxWidth: 600}}>
<Row>
<Col span="4">
Application
</Col>
<Col span="20"/>
</Row>
<Row>
<Col span="4">
Name:
</Col>
<Col span="8">
<Input placeholder="Basic usage"/>
</Col>
<Col span="12"/>
</Row>
<Row>
<Col span="24">
<Divider/>
</Col>
</Row>
<Row>
<Col span="4">
Services
</Col>
<Col span="20"/>
</Row>
<Row>
<Col span="4">
Name:
</Col>
<Col span="8">
<Input placeholder="Basic usage"/>
</Col>
<Col span="12"/>
</Row>
<Row>
<Col span="4">
Type:
</Col>
<Col span="20">
<Dropdown overlay={workloadsMenu}>
<a className="ant-dropdown-link">
Select <DownOutlined/>
</a>
</Dropdown>
</Col>
</Row>
<Row>
<Col span="4">
Settings:
</Col>
<Col span="20">
<FormRender
schema={workloadSchema}
formData={formData}
onChange={setData}
onValidate={setValid}
displayType="column"
/>
</Col>
</Row>
<Row>
<Col span="24">
<Divider/>
</Col>
</Row>
<Row>
<Col span="4">
Traits
</Col>
<Col span="20"/>
</Row>
<Row>
<Col span="4">
Type:
</Col>
<Col span="20">
<Dropdown overlay={traitsMenu}>
<a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
Select <DownOutlined/>
</a>
</Dropdown>
</Col>
</Row>
<Row>
<Col span="4">
Properties:
</Col>
<Col span="20">
<FormRender
schema={traitSchema}
formData={formData}
onChange={setData}
onValidate={setValid}
displayType="column"
/>
</Col>
</Row>
<Row>
<Col span="8"/>
<Col span="8">
<Button onClick={onSubmit} type="primary">Submit</Button>
</Col>
<Col span="8"/>
</Row>
</div>
);
};
+23
View File
@@ -0,0 +1,23 @@
import { request } from 'umi';
/*
* workload type list: get /api/workloads/
*/
export async function getWorkloads(): Promise<API.VelaResponse<API.Workloads[]>> {
return request( '/api/workloads');
}
/*
* trait list: get /api/traits/
*/
export async function getTraits(): Promise<API.VelaResponse<API.Traits[]>> {
return request('/api/traits');
}
export async function getCapabilityOpenAPISchema(
capabilityName: string,
): Promise<API.VelaResponse<string>> {
return request(`/api/definitions/${capabilityName}`, { method: 'get' });
}
-10
View File
@@ -1,10 +0,0 @@
import { request } from 'umi';
const BASE_PATH = '/api/traits';
/*
* trait 列表: get /api/traits/
*/
export async function getTraits(): Promise<API.VelaResponse<API.Traits[]>> {
return request(BASE_PATH);
}
-10
View File
@@ -1,10 +0,0 @@
import { request } from 'umi';
const BASE_PATH = '/api/workloads';
/*
* workload 列表: get /api/workloads/
*/
export async function getWorkloads(): Promise<API.VelaResponse<API.Workloads[]>> {
return request(BASE_PATH);
}