This is the 16th day of my participation in the First Challenge 2022.

Hello ~ I’m Milo! I am building an open source interface testing platform from 0 to 1, and also writing a set of corresponding tutorials, I hope you can support more. Welcome to follow my public account Milo test diary, get the latest article tutorial!

review

In the last section we looked at perfecting profile capabilities and being able to manage our user avatars using OSS.

Remember our configuration.json file (system configuration file)?

In this section, we will talk about the system configuration function, which is the ability to configure configuration.json in the front page.

Recall the details

Previously we wrote configuration management functionality, although there are updates, but no actual use.

Oss that read oss type and account password, as well as the email section useful.

With an actual method, writing the CURD interface is much easier.

implementation

The back-end logic

  • Edit section

    We need to make some adjustments to the editing, note that ensure_ASCII is turned off and indent is indent when writing the JSON file.

  • The new app/routers/config/system. Py files
from fastapi import Depends

from app.core.configuration import SystemConfiguration
from app.handler.fatcory import PityResponse
from app.routers import Permission
from app.routers.config.gconfig import router
from config import Config


@router.get("/system", description="Get system configuration")
def get_system_config(_=Depends(Permission(Config.ADMIN))) :
    configuration = SystemConfiguration.get_config()
    return PityResponse.success(configuration)


@router.post("/system/update", description="Update system Configuration")
def get_system_config(data: dict, _=Depends(Permission(Config.ADMIN))) :
    SystemConfiguration.update_config(data)
    return PityResponse.success()

Copy the code

/config/system is the interface to get the configuration and /config/system/update is the interface to modify the configuration.

Finally, we can register the route in app/init.py.

The front-end logic

  • Write the service layer

Write the interfaces that call fetch/update separately.

  • Write the model layer

Add two new methods in models/gconfig.js that call the two interfaces just written in the Service layer.

  • Write the view layer

    First we split the page into three tabs:

  1. oss
  2. email
  3. yapi

This corresponds to 3 sub-components. Let’s take a look at the ideal renderings:

So we create a new SRC/pages/Config/SystemConfig JSX file:

import {PageContainer} from "@ant-design/pro-layout";
import {Button, Card, Col, Form, message, Row, Spin, Tabs} from "antd";
import OssConfig from "@/components/System/OssConfig";
import EmailConfig from "@/components/System/EmailConfig";
import YapiConfig from "@/components/System/YapiConfig";
import {SaveOutlined} from "@ant-design/icons";
import {connect} from "umi";
import {useEffect} from "react";

const {TabPane} = Tabs;

const SystemConfig = ({dispatch, gconfig, loading}) = > {

  const [form] = Form.useForm()
  const {configuration} = gconfig;

  const onSetField = () = > {
    const {email, oss, yapi} = configuration;
    form.setFieldsValue(email);
    form.setFieldsValue(oss);
    form.setFieldsValue(yapi);
  }

  useEffect(() = > {
    dispatch({
      type: 'gconfig/fetchSystemConfig'
    })
  }, [])

  useEffect(() = > {
    // Change the form data in batches
    onSetField()
  }, [configuration])

  const onSubmit = async() = > {let values;
    try {
      values = await form.validateFields();
    } catch (e) {
      message.info("There are required fields left unfilled, please check.")
      return;
    }
    const requestData = {
      email: {
        "sender": values.sender,
        "password": values.password,
        "host": values.host,
        "to": values.to
      },
      yapi: {
        "token": values.token,
      },
      oss: {
        "oss_type": values.oss_type,
        "access_key_id": values.access_key_id,
        "access_key_secret": values.access_key_secret,
        "bucket": values.bucket,
        "endpoint": values.endpoint
      }
    }
    dispatch({
      type: "gconfig/updateConfiguration".payload: requestData,
    })
  }

  return (
    <PageContainer title="System Settings" breadcrumb={null}>
      <Spin spinning={loading.effects['gconfig/updateConfiguration'] | |loading.effects['gconfig/fetchSystemConfig']} >
        <Card>
          <Row>
            <Col span={24}>
              <Tabs tabPosition="left">
                <TabPane key="1" tab="Mail Settings" forceRender>
                  <EmailConfig form={form}/>
                </TabPane>
                <TabPane key="2" tab="The OSS setting" forceRender>
                  <OssConfig form={form}/>
                </TabPane>
                <TabPane key="3" tab="Yapi Settings" forceRender>
                  <YapiConfig form={form}/>
                </TabPane>
              </Tabs>
            </Col>
          </Row>
          <Row>
            <div style={{margin: '16px auto'}} >
              <Button type="primary" icon={<SaveOutlined/>} the onClick = {onSubmit} > save</Button>
            </div>
          </Row>
        </Card>
      </Spin>
    </PageContainer>)}export default connect(({gconfig, loading}) = > ({gconfig, loading}))(SystemConfig);

Copy the code

Each TAB type corresponds to a different component. Each TAB type corresponds to a different component.

Create JSX for the following three components in SRC/Components /System respectively:

  • Mail component emailconfig.jsx:
import {Col, Form, Input, Row} from "antd";
import {CONFIG} from "@/consts/config";

export default ({form}) => {
  return (
    <Row gutter={8}>
      <Col span={4} />
      <Col span={16}>
        <Form form={form} {. CONFIG.LAYOUT} >
          <Form.Item label="Sender" name="sender" rules={[{required: true.message:'Please enter sender email '}]}>
            <Input placeholder="Please enter sender email"/>
          </Form.Item>
          <Form.Item label="host" name="host" rules={[{required: true.message:'Please enter a serverhost'}}] >
            <Input placeholder="Please enter server host"/>
          </Form.Item>
          <Form.Item label="Mailbox Key" name="password" rules={[{required: true.message:'Please enter email key '}]}>
            <Input placeholder="Please enter your mailbox key"/>
          </Form.Item>
          <Form.Item label="Name of Recipient" name="to" rules={[{required: true.message:'Please enter recipient name '}]}>
            <Input placeholder="Please enter recipient name"/>
          </Form.Item>
        </Form>
      </Col>
      <Col span={4} />
    </Row>)}Copy the code
  • Yapi component YapiConfig JSX
import {Button, Col, Form, Input, Row} from "antd";
import {CONFIG} from "@/consts/config";

export default ({form}) => {
  return (
    <Row gutter={8}>
      <Col span={4} />
      <Col span={16}>
        <Form form={form} {. CONFIG.LAYOUT} >
          <Form.Item label="token" name="token">
            <Input placeholder="Please enter yAPI token"/>
          </Form.Item>
        </Form>
      </Col>
      <Col span={4} />
    </Row>)}Copy the code
  • OssConfig.jsx
import {Col, Form, Input, Row, Select} from "antd";
import {CONFIG} from "@/consts/config";

export default ({form}) => {
  return (
    <Row gutter={8}>
      <Col span={4} />
      <Col span={16}>
        <Form form={form} {. CONFIG.LAYOUT} >
          <Form.Item label="Type" name="oss_type" rules={[{required: true.message:'please selectossType '}}] >
            <Select placeholder="Please select oss type">
              <Select.Option value="aliyun">Ali cloud</Select.Option>
              <Select.Option value="gitee">gitee</Select.Option>
              <Select.Option value="cos">Tencent cloud</Select.Option>
              <Select.Option value="qiniu">Seven NiuYun</Select.Option>
            </Select>
          </Form.Item>
          <Form.Item label="access_id" name="access_key_id" rules={[{required: true.message:'please enteraccess_key_id'}}] >
            <Input placeholder="Please enter access_key_id"/>
          </Form.Item>
          <Form.Item label="access_secret" name="access_key_secret" rules={[{required: true.message:'please enteraccess_secret'}}] >
            <Input placeholder="Please enter access_secret"/>
          </Form.Item>
          <Form.Item label="bucket" name="bucket" rules={[{required: true.message:'please enterbucket'}}] >
            <Input placeholder="Please enter bucket"/>
          </Form.Item>
          <Form.Item label="endpoint" name="endpoint">
            <Input placeholder="Please enter endpoint, leave it blank."/>
          </Form.Item>
        </Form>
      </Col>
      <Col span={4} />
    </Row>)}Copy the code

Note that when the save button is pressed, three components need to be retrieved, so each component accepts the form from the parent component.

ForceRender can force every TAB page to be rendered, even if it has not been opened.

Final rendering

conclusion

The system Settings only have these functions for the time being, and we may have configuration items including theme, JIRA account password and so on in the future.