spug/spug_web/src/pages/deploy/request/Ext1Console.js

132 lines
4.3 KiB
JavaScript

/**
* Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
* Copyright (c) <spug.dev@gmail.com>
* Released under the AGPL-3.0 License.
*/
import React, { useEffect } from 'react';
import { observer, useLocalStore } from 'mobx-react';
import { Card, Progress, Modal, Collapse, Steps } from 'antd';
import { ShrinkOutlined, CaretRightOutlined, LoadingOutlined, CloseOutlined } from '@ant-design/icons';
import OutView from './OutView';
import { http, X_TOKEN } from 'libs';
import styles from './index.module.less';
import store from './store';
function Ext1Console(props) {
const outputs = useLocalStore(() => ({}));
useEffect(props.request.mode === 'read' ? readDeploy : doDeploy, [])
function readDeploy() {
let socket;
http.get(`/api/deploy/request/${props.request.id}/`)
.then(res => {
Object.assign(outputs, res.outputs)
if (res.status === '2') {
socket = _makeSocket()
}
})
return () => socket && socket.close()
}
function doDeploy() {
let socket;
http.post(`/api/deploy/request/${props.request.id}/`)
.then(res => {
Object.assign(outputs, res.outputs)
socket = _makeSocket()
})
return () => socket && socket.close()
}
function _makeSocket() {
let index = 0;
const token = props.request.id;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/request/${token}/?x-token=${X_TOKEN}`);
socket.onopen = () => socket.send(String(index));
socket.onmessage = e => {
if (e.data === 'pong') {
socket.send(String(index))
} else {
index += 1;
const {key, data, step, status} = JSON.parse(e.data);
if (data !== undefined) outputs[key].data.push(data);
if (step !== undefined) outputs[key].step = step;
if (status !== undefined) outputs[key].status = status;
}
}
return socket
}
function StepItem(props) {
let icon = null;
if (props.step === props.item.step && props.item.status !== 'error') {
icon = <LoadingOutlined/>
}
return <Steps.Step {...props} icon={icon}/>
}
function switchMiniMode() {
const value = store.tabModes[props.request.id];
store.tabModes[props.request.id] = !value
}
return store.tabModes[props.request.id] ? (
<Card
className={styles.item}
bodyStyle={{padding: '8px 12px'}}
onClick={switchMiniMode}>
<div className={styles.header}>
<div className={styles.title}>{props.request.name}</div>
<CloseOutlined onClick={() => store.showConsole(props.request, true)}/>
</div>
{Object.values(outputs).map(item => (
<Progress
key={item.id}
percent={(item.step + 1) * 18}
status={item.step === 100 ? 'success' : item.status === 'error' ? 'exception' : 'active'}/>
))}
</Card>
) : (
<Modal
visible
width={1000}
footer={null}
maskClosable={false}
className={styles.console}
onCancel={() => store.showConsole(props.request, true)}
title={[
<span key="1">{props.request.name}</span>,
<div key="2" className={styles.miniIcon} onClick={switchMiniMode}>
<ShrinkOutlined/>
</div>
]}>
<Collapse
defaultActiveKey={'0'}
className={styles.collapse}
expandIcon={({isActive}) => <CaretRightOutlined style={{fontSize: 16}} rotate={isActive ? 90 : 0}/>}>
{Object.values(outputs).map((item, index) => (
<Collapse.Panel
key={index}
header={
<div className={styles.header}>
<b className={styles.title}>{item.title}</b>
<Steps size="small" className={styles.step} current={item.step} status={item.status}>
<StepItem title="等待调度" item={item} step={0}/>
<StepItem title="数据准备" item={item} step={1}/>
<StepItem title="发布前任务" item={item} step={2}/>
<StepItem title="执行发布" item={item} step={3}/>
<StepItem title="发布后任务" item={item} step={4}/>
</Steps>
</div>}>
<OutView records={item.data}/>
</Collapse.Panel>
))}
</Collapse>
</Modal>
)
}
export default observer(Ext1Console)