From 2a25b1087445b0d9f8d1c089da16b0e89b8ff2b2 Mon Sep 17 00:00:00 2001 From: wenxin <85589661@qq.com> Date: Tue, 25 Aug 2020 09:32:59 +0800 Subject: [PATCH 1/2] Complete env page structure --- dashboard/config/config.js | 17 ++- dashboard/src/locales/en-US/menu.js | 2 + dashboard/src/models/env.js | 10 +- dashboard/src/pages/System/Env/index.jsx | 175 ++++++++++++++++++++++ dashboard/src/pages/System/Env/index.less | 3 + 5 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 dashboard/src/pages/System/Env/index.jsx create mode 100644 dashboard/src/pages/System/Env/index.less diff --git a/dashboard/config/config.js b/dashboard/config/config.js index a0e979634..9f0c725aa 100644 --- a/dashboard/config/config.js +++ b/dashboard/config/config.js @@ -1,9 +1,9 @@ // https://umijs.org/config/ -import { defineConfig } from 'umi'; +import {defineConfig} from 'umi'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; -const { REACT_APP_ENV } = process.env; +const {REACT_APP_ENV} = process.env; export default defineConfig({ hash: true, antd: {}, @@ -121,6 +121,19 @@ export default defineConfig({ path: '/Capability', component: './Capability', }, + { + path: '/System', + name: 'System', + icon: 'table', + routes: [ + { + name: 'Env', + icon: 'table', + path: '/System/Env', + component: './System/Env', + } + ] + }, { name: 'Capability.Detail', hideInMenu: true, diff --git a/dashboard/src/locales/en-US/menu.js b/dashboard/src/locales/en-US/menu.js index 728f5cfae..342dc6f76 100644 --- a/dashboard/src/locales/en-US/menu.js +++ b/dashboard/src/locales/en-US/menu.js @@ -11,6 +11,8 @@ export default { 'menu.ApplicationList.CreateApplication': 'CreateApplication', 'menu.Capability': 'Capability', 'menu.Capability.Detail': 'Detail', + 'menu.System': 'System', + 'menu.System.Env': 'Env', 'menu.Workload': 'Workloads', 'menu.Workload.Deployment': 'Deployment', 'menu.Workload.Containerized': 'Containerized', diff --git a/dashboard/src/models/env.js b/dashboard/src/models/env.js index 938b8fd5f..a75fc69d2 100644 --- a/dashboard/src/models/env.js +++ b/dashboard/src/models/env.js @@ -1,4 +1,4 @@ -import { getEnvs, switchEnv } from '@/services/env'; +import {getEnvs, switchEnv, initialEnvs} from '@/services/env'; const TestModel = { namespace: 'envs', @@ -6,14 +6,18 @@ const TestModel = { // initailState: '8880' }, effects: { - *getEnvs({ payload }, { call }) { + * getEnvs({payload}, {call}) { const res = yield call(getEnvs, payload); return res; }, - *switchEnv({ payload }, { call }) { + * switchEnv({payload}, {call}) { const res = yield call(switchEnv, payload); return res; }, + * initialEnvs({payload}, {call}) { + const res = yield call(initialEnvs, payload) + return res; + } }, reducers: {}, }; diff --git a/dashboard/src/pages/System/Env/index.jsx b/dashboard/src/pages/System/Env/index.jsx new file mode 100644 index 000000000..540b791d5 --- /dev/null +++ b/dashboard/src/pages/System/Env/index.jsx @@ -0,0 +1,175 @@ +import React from 'react'; +import {PageContainer} from '@ant-design/pro-layout'; +import {Button, Table, Space, Modal, Form, Input} from 'antd'; +import {ExclamationCircleOutlined} from '@ant-design/icons'; +import {Link} from 'umi'; +import './index.less'; +import {connect} from "dva"; + +const {confirm} = Modal; + +function showDeleteConfirm(record) { + confirm({ + title: `Are you sure delete env ${record.name}?`, + icon: , + width: 500, + okText: 'Yes', + okType: 'danger', + cancelText: 'No', + onOk() { + console.log('OK'); + } + }); +} + +function specifyNamespace(record) { + +} + +const layout = { + labelCol: { + span: 6, + }, + wrapperCol: { + span: 18, + }, +}; + +const columns = [ + { + title: 'Env', + dataIndex: 'name', + key: 'name' + }, + { + title: 'Namespace', + dataIndex: 'namespace', + key: 'namespace', + }, + { + title: 'Operations', + dataIndex: 'Operations', + key: 'Operations', + render: (text, record) => { + return ( + + + + + ); + }, + }, +]; + +@connect(() => ({})) +class TableList extends React.PureComponent { + formRef = React.createRef(); + + constructor(props) { + super(props); + this.state = { + visible: false, + envs: [] + }; + } + + showModal = () => { + this.setState({ + visible: true, + }); + }; + + handleOk = async (values) => { + await this.formRef.current.validateFields(); + this.setState({ + visible: false, + }); + // const fieldsValue = await this.formRef.current.validateFields(); + // fieldsValue为通过验证的数据,现在可进行提交 + // console.log(fieldsValue) + }; + + handleTest = async () => { + await this.formRef.current.validateFields(); + this.setState({ + visible: false, + }); + }; + + handleCancel = () => { + this.setState({ + visible: false, + }); + }; + + getInitalData = async () => { + const envs = await this.props.dispatch({ + type: 'envs/getEnvs', + }); + this.setState({ + envs + }); + } + + componentDidMount() { + this.getInitalData(); + } + + render() { + return ( + +
+ + + +
+ + Test + , + , + ]} + > +
+ + + + + + +
+
+ record.name} + columns={columns} dataSource={this.state.envs}/> + + ); + } +} + +export default TableList; diff --git a/dashboard/src/pages/System/Env/index.less b/dashboard/src/pages/System/Env/index.less new file mode 100644 index 000000000..44a919ec1 --- /dev/null +++ b/dashboard/src/pages/System/Env/index.less @@ -0,0 +1,3 @@ +p { + margin: 0; +} From d341862694cd7c8a03a82e903d283d102648ca2a Mon Sep 17 00:00:00 2001 From: xiaoyuaiheshui <714545064@qq.com> Date: Fri, 28 Aug 2020 17:39:20 +0800 Subject: [PATCH 2/2] Complete env page interface docking and page status 77 --- dashboard/config/config.js | 8 +- .../GlobalHeader/WorkSpaceDropDown.css | 96 ++++++ .../GlobalHeader/WorkSpaceDropDown.jsx | 48 ++- .../GlobalHeader/workSpaceDropDown.jsx | 84 ----- dashboard/src/models/env.js | 41 ++- dashboard/src/pages/System/Env/index.jsx | 319 ++++++++++-------- dashboard/src/services/env.js | 13 +- 7 files changed, 351 insertions(+), 258 deletions(-) create mode 100644 dashboard/src/components/GlobalHeader/WorkSpaceDropDown.css delete mode 100644 dashboard/src/components/GlobalHeader/workSpaceDropDown.jsx diff --git a/dashboard/config/config.js b/dashboard/config/config.js index 9f0c725aa..ecf767d93 100644 --- a/dashboard/config/config.js +++ b/dashboard/config/config.js @@ -1,9 +1,9 @@ // https://umijs.org/config/ -import {defineConfig} from 'umi'; +import { defineConfig } from 'umi'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; -const {REACT_APP_ENV} = process.env; +const { REACT_APP_ENV } = process.env; export default defineConfig({ hash: true, antd: {}, @@ -131,8 +131,8 @@ export default defineConfig({ icon: 'table', path: '/System/Env', component: './System/Env', - } - ] + }, + ], }, { name: 'Capability.Detail', diff --git a/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.css b/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.css new file mode 100644 index 000000000..fa0c32508 --- /dev/null +++ b/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.css @@ -0,0 +1,96 @@ +.ant-pro-global-header-layout-side { + padding-right: 0; +} +.ant-dropdown-menu-item, +.ant-dropdown-menu-submenu-title { + clear: both; + margin: 0; + padding: 5px 20px; + color: deepskyblue; + font-weight: normal; + font-size: 14px; + line-height: 22px; + white-space: nowrap; + cursor: pointer; + transition: all 0.3s; + border-top: 1px solid #dee4e6; +} + +.ant-dropdown-menu-item:nth-child(1) { + border-top: 1px solid #fff; +} + +.ant-dropdown-menu-item-active { + background: rgb(0, 21, 41) !important; +} + +.ant-dropdown-menu-item-active .box1 { + color: white; +} + +.ant-dropdown-menu-item-active .box2 { + color: white; +} + +.box { + display: flex; + width: 100%; + flex-direction: column; +} + +.box1 { + font-size: 16px; + color: #5095d4; +} + +.box2 { + font-size: 12px; + color: #8d959b; +} + +.ant-dropdown-trigger { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + height: 100%; +} + +.drop-box { + display: flex; + flex-direction: row; + align-items: center; + justify-content: left; + height: 100%; + background: rgb(0, 21, 41); + padding: 0 20px; +} + +.btn-box { + display: flex; + flex-direction: column; + align-items: space-between; + overflow: hidden; + margin-right: 20px; + min-width: 120px; +} + +.btn-top { + display: flex; + height: 20px; + line-height: 20px; + font-size: 20px; + color: white; +} + +.btn-bottom { + display: flex; + height: 20px; + line-height: 20px; + font-size: 12px; + color: #8d959b; +} +.btn-outlined { + fontsize: 15px; + color: #fff; +} diff --git a/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.jsx b/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.jsx index 7f1e364ec..e8659219b 100644 --- a/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.jsx +++ b/dashboard/src/components/GlobalHeader/WorkSpaceDropDown.jsx @@ -1,29 +1,32 @@ -import { Menu, Dropdown, Button, message } from 'antd'; +import { Menu, Dropdown, message } from 'antd'; import { DownOutlined } from '@ant-design/icons'; import React from 'react'; import { connect } from 'dva'; +import './WorkSpaceDropDown.css'; -@connect(() => ({})) +@connect((env) => ({ envs: env.envs })) export default class WorkSpaceDropDown extends React.Component { constructor(props) { super(props); this.state = { workSpaceName: '', envs: [], + namespace: '', }; } async componentDidMount() { const envs = await this.props.dispatch({ - type: 'envs/getEnvs', // applist对应models层的命名空间namespace + type: 'envs/getEnvs', }); if (envs) { - const { name = 'test' } = envs.find((a) => { - return a.current === '*'; + const { name, namespace } = envs.find((env) => { + return env.current === '*'; }); this.setState({ - envs, + envs: envs, workSpaceName: name, + namespace: namespace, }); this.props.dispatch({ type: 'globalData/currentEnv', @@ -48,6 +51,7 @@ export default class WorkSpaceDropDown extends React.Component { this.setState( { workSpaceName: e.key, + namespace: e.item.props.title, }, () => { // 值切换存储 @@ -59,25 +63,37 @@ export default class WorkSpaceDropDown extends React.Component { }); }, ); + await this.props.dispatch({ + type: 'envs/getEnvs', // applist对应models层的命名空间namespace + }); }; render() { + const { envs } = this.props; const menu = ( - {/* default - oam-system - linkerd - rio-system */} - {this.state.envs.map((item) => { - return {item.name}; - })} + {envs.envs && + envs.envs.map((item) => { + return ( + +
+
{item.name}
+
{item.namespace}
+
+
+ ); + })}
); return ( - +
+
+
{this.state.workSpaceName}
+
{this.state.namespace}
+
+ +
); } diff --git a/dashboard/src/components/GlobalHeader/workSpaceDropDown.jsx b/dashboard/src/components/GlobalHeader/workSpaceDropDown.jsx deleted file mode 100644 index 7f1e364ec..000000000 --- a/dashboard/src/components/GlobalHeader/workSpaceDropDown.jsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Menu, Dropdown, Button, message } from 'antd'; -import { DownOutlined } from '@ant-design/icons'; -import React from 'react'; -import { connect } from 'dva'; - -@connect(() => ({})) -export default class WorkSpaceDropDown extends React.Component { - constructor(props) { - super(props); - this.state = { - workSpaceName: '', - envs: [], - }; - } - - async componentDidMount() { - const envs = await this.props.dispatch({ - type: 'envs/getEnvs', // applist对应models层的命名空间namespace - }); - if (envs) { - const { name = 'test' } = envs.find((a) => { - return a.current === '*'; - }); - this.setState({ - envs, - workSpaceName: name, - }); - this.props.dispatch({ - type: 'globalData/currentEnv', - payload: { - currentEnv: name, - }, - }); - } - } - - handleMenuClick = async (e) => { - // 发送切换envs的接口 - const switchResult = await this.props.dispatch({ - type: 'envs/switchEnv', - payload: { - currentEnv: e.key, - }, - }); - if (switchResult) { - message.success(switchResult); - } - this.setState( - { - workSpaceName: e.key, - }, - () => { - // 值切换存储 - this.props.dispatch({ - type: 'globalData/currentEnv', - payload: { - currentEnv: e.key, - }, - }); - }, - ); - }; - - render() { - const menu = ( - - {/* default - oam-system - linkerd - rio-system */} - {this.state.envs.map((item) => { - return {item.name}; - })} - - ); - return ( - - - - ); - } -} diff --git a/dashboard/src/models/env.js b/dashboard/src/models/env.js index a75fc69d2..9753deac4 100644 --- a/dashboard/src/models/env.js +++ b/dashboard/src/models/env.js @@ -1,24 +1,49 @@ -import {getEnvs, switchEnv, initialEnvs} from '@/services/env'; +import { getEnvs, switchEnv, initialEnvs, deleteEnv } from '@/services/env'; const TestModel = { namespace: 'envs', state: { - // initailState: '8880' + envs: undefined, }, effects: { - * getEnvs({payload}, {call}) { + *getEnvs({ payload }, { call, put }) { const res = yield call(getEnvs, payload); + yield put({ + type: 'onGetEnvsSuccess', + payload: res, + }); return res; }, - * switchEnv({payload}, {call}) { + *switchEnv({ payload }, { call }) { const res = yield call(switchEnv, payload); return res; }, - * initialEnvs({payload}, {call}) { - const res = yield call(initialEnvs, payload) + *initialEnvs({ payload }, { call, put }) { + yield call(initialEnvs, payload); + const res = yield call(getEnvs, payload); + yield put({ + type: 'onGetEnvsSuccess', + payload: res, + }); return res; - } + }, + *deleteEnv({ payload }, { call, put }) { + yield call(deleteEnv, payload); + const res = yield call(getEnvs); + yield put({ + type: 'onGetEnvsSuccess', + payload: res, + }); + return res; + }, + }, + reducers: { + onGetEnvsSuccess(state, { payload }) { + return { + ...state, + envs: payload, + }; + }, }, - reducers: {}, }; export default TestModel; diff --git a/dashboard/src/pages/System/Env/index.jsx b/dashboard/src/pages/System/Env/index.jsx index 540b791d5..c146bffcd 100644 --- a/dashboard/src/pages/System/Env/index.jsx +++ b/dashboard/src/pages/System/Env/index.jsx @@ -1,30 +1,12 @@ -import React from 'react'; -import {PageContainer} from '@ant-design/pro-layout'; -import {Button, Table, Space, Modal, Form, Input} from 'antd'; -import {ExclamationCircleOutlined} from '@ant-design/icons'; -import {Link} from 'umi'; +import React, { useEffect, useState } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Table, Space, Modal, Form, Input, Tooltip } from 'antd'; +import { ExclamationCircleOutlined } from '@ant-design/icons'; import './index.less'; -import {connect} from "dva"; +import { connect } from 'dva'; +import * as _ from 'lodash'; -const {confirm} = Modal; - -function showDeleteConfirm(record) { - confirm({ - title: `Are you sure delete env ${record.name}?`, - icon: , - width: 500, - okText: 'Yes', - okType: 'danger', - cancelText: 'No', - onOk() { - console.log('OK'); - } - }); -} - -function specifyNamespace(record) { - -} +const { confirm } = Modal; const layout = { labelCol: { @@ -35,141 +17,188 @@ const layout = { }, }; -const columns = [ - { - title: 'Env', - dataIndex: 'name', - key: 'name' - }, - { - title: 'Namespace', - dataIndex: 'namespace', - key: 'namespace', - }, - { - title: 'Operations', - dataIndex: 'Operations', - key: 'Operations', - render: (text, record) => { - return ( - - - - - ); - }, - }, -]; +const TableList = (props) => { + const { dispatch } = props; + const tableEnvs = _.get(props, 'getEnvs.envs', []); + const [form] = Form.useForm(); + const [visible, setVisible] = useState(false); + const [env, setEnv] = useState([]); -@connect(() => ({})) -class TableList extends React.PureComponent { - formRef = React.createRef(); + const showModal = () => { + setVisible(true); + }; - constructor(props) { - super(props); - this.state = { - visible: false, - envs: [] - }; - } + const handleOk = async () => { + const fieldsValue = await form.validateFields(); + await dispatch({ + type: 'envs/initialEnvs', + payload: { + params: fieldsValue, + }, + }); + setEnv(null); + form.resetFields(); + setVisible(false); + }; - showModal = () => { - this.setState({ - visible: true, + const handleCancel = () => { + setEnv(null); + setVisible(false); + form.resetFields(); + }; + + const deleteEnv = async (record) => { + await dispatch({ + type: 'envs/deleteEnv', + payload: { + envName: record.name, + }, }); }; - handleOk = async (values) => { - await this.formRef.current.validateFields(); - this.setState({ - visible: false, - }); - // const fieldsValue = await this.formRef.current.validateFields(); - // fieldsValue为通过验证的数据,现在可进行提交 - // console.log(fieldsValue) - }; - - handleTest = async () => { - await this.formRef.current.validateFields(); - this.setState({ - visible: false, + const showDeleteConfirm = (record) => { + confirm({ + title: `Are you sure delete env ${record.name}?`, + icon: , + width: 500, + okText: 'Yes', + okType: 'danger', + cancelText: 'No', + onOk() { + deleteEnv(record); + }, }); }; - handleCancel = () => { - this.setState({ - visible: false, + const specifyNamespace = (record) => { + form.setFieldsValue({ + name: record.name, + namespace: record.namespace, }); + setEnv(record); + setVisible(true); }; - getInitalData = async () => { - const envs = await this.props.dispatch({ + const getInitialData = async () => { + await dispatch({ type: 'envs/getEnvs', }); - this.setState({ - envs - }); - } + }; + useEffect(() => { + getInitialData(); + }, []); - componentDidMount() { - this.getInitalData(); - } - - render() { - return ( - -
+ const columns = [ + { + title: 'Env', + dataIndex: 'name', + key: 'name', + render: (text) => { + if (text.length > 20) { + return {text.substr(0, 20)}...; + } + return text; + }, + }, + { + title: 'Namespace', + dataIndex: 'namespace', + key: 'namespace', + render: (text) => { + if (text.length > 20) { + return {text.substr(0, 20)}...; + } + return text; + }, + }, + { + title: 'Current', + dataIndex: 'current', + align: 'center', + key: 'current', + render: (text) => { + return text === '*' ? 'active' : ''; + }, + }, + { + title: 'Operations', + dataIndex: 'Operations', + key: 'Operations', + render: (text, record) => { + return ( - + -
- - Test - , - , - ]} - > -
- - - - - - - -
-
record.name} - columns={columns} dataSource={this.state.envs}/> - - ); - } -} - -export default TableList; + ); + }, + }, + ]; + return ( + +
+ + + +
+ + {env && env.name ? 'Update' : 'Create'} + , + ]} + > +
+ + + + + + + +
+
record.name} columns={columns} dataSource={tableEnvs} /> + + ); +}; +export default connect((env) => { + return { + getEnvs: env.envs, + }; +})(TableList); diff --git a/dashboard/src/services/env.js b/dashboard/src/services/env.js index 7e091aced..7967b52e4 100644 --- a/dashboard/src/services/env.js +++ b/dashboard/src/services/env.js @@ -1,24 +1,34 @@ import request from '@/utils/request'; + /* * 初始化 env:Post /api/envs/ */ -export async function initialEnvs() { +export async function initialEnvs({ params }) { return request('/api/envs/', { method: 'post', + data: { + ...params, + }, + headers: { + 'Content-Type': 'application/json', + }, }); } + /* * env 列表:Get /api/envs/ */ export async function getEnvs() { return request('/api/envs/'); } + /* * 查询 env:Get /api/envs/:envName */ export async function searchEnvs({ envName }) { return request(`/api/envs/${envName}`); } + /* * 删除 env:Delete /api/envs/:envName */ @@ -27,6 +37,7 @@ export async function deleteEnv({ envName }) { method: 'delete', }); } + /* * 切换 env:Patch /api/envs/:envName */