U 优化批量执行UX

pull/418/head
vapao 2021-12-09 22:23:50 +08:00
parent 38b77c77bb
commit ddd1cb8cc1
5 changed files with 31 additions and 17 deletions

View File

@ -38,7 +38,7 @@ class Job:
def _handle_command(self, command, interpreter):
if interpreter == 'python':
return f'python << EOF\n{command}\nEOF'
return f'python << EOF\n# -*- coding: UTF-8 -*-\n{command}\nEOF'
return command
def send(self, data):
@ -53,7 +53,7 @@ class Job:
if not self.token:
with self.ssh:
return self.ssh.exec_command(self.command, self.env)
self.send('\r\33[K\x1b[36m### Executing ...\x1b[0m\r\n')
self.send('\r\n\x1b[36m### Executing ...\x1b[0m\r\n')
code = -1
try:
with self.ssh:

View File

@ -36,7 +36,7 @@ function OutView(props) {
term.loadAddon(fitPlugin)
term.open(el.current)
fitPlugin.fit()
term.write('WebSocket connecting ... ')
term.write('\x1b[36m### WebSocket connecting ...\x1b[0m')
const resize = () => fitPlugin.fit();
window.addEventListener('resize', resize)
setTerm(term)
@ -49,7 +49,11 @@ function OutView(props) {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/exec/${store.token}/?x-token=${X_TOKEN}`);
socket.onopen = () => {
term.write('\r\x1b[K\x1b[36m### Waiting for scheduling ...\x1b[0m')
const message = '\r\x1b[K\x1b[36m### Waiting for scheduling ...\x1b[0m'
for (let key of Object.keys(store.outputs)) {
store.outputs[key].data = message
}
term.write(message)
socket.send('ok');
}
socket.onmessage = e => {

View File

@ -5,7 +5,7 @@
*/
import React, { useState, useEffect } from 'react';
import { observer } from 'mobx-react';
import { PlusOutlined, ThunderboltOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { PlusOutlined, ThunderboltOutlined, BulbOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { Form, Button, Alert, Radio, Tooltip } from 'antd';
import { ACEditor, AuthDiv, Breadcrumb } from 'components';
import Selector from 'pages/host/Selector';
@ -68,14 +68,19 @@ function TaskIndex() {
<div className={style.index} hidden={store.showConsole}>
<Form layout="vertical" className={style.left}>
<Form.Item required label="目标主机">
{store.host_ids.length > 0 && (
<Alert style={{width: 200}} type="info" message={`已选择 ${store.host_ids.length} 台主机`}/>
{store.host_ids.length > 0 ? (
<Alert
type="info"
className={style.area}
message={<div>已选择 <b style={{fontSize: 18, color: '#1890ff'}}>{store.host_ids.length}</b> </div>}
onClick={() => store.showHost = true}/>
) : (
<Button icon={<PlusOutlined/>} onClick={() => store.showHost = true}>
从主机列表中选择
</Button>
)}
</Form.Item>
<Button
style={{marginBottom: 24}}
icon={<PlusOutlined/>}
onClick={() => store.showHost = true}>从主机列表中选择</Button>
<Form.Item required label="执行命令" style={{position: 'relative'}}>
<Radio.Group
buttonStyle="solid"
@ -86,12 +91,10 @@ function TaskIndex() {
<Radio.Button value="python">Python</Radio.Button>
</Radio.Group>
<a href="https://spug.cc/docs/batch-exec" target="_blank" rel="noopener noreferrer"
className={style.tips}>全局变量</a>
className={style.tips}><BulbOutlined/> 使用全局变量</a>
<Button style={{float: 'right'}} icon={<PlusOutlined/>} onClick={store.switchTemplate}>从执行模版中选择</Button>
<ACEditor className={style.editor} mode={interpreter} value={command} width="100%" onChange={setCommand}/>
</Form.Item>
<Form.Item>
<Button icon={<PlusOutlined/>} onClick={store.switchTemplate}>从执行模版中选择</Button>
</Form.Item>
<Button loading={loading} icon={<ThunderboltOutlined/>} type="primary" onClick={handleSubmit}>开始执行</Button>
</Form>

View File

@ -8,14 +8,21 @@
padding: 24px;
width: 60%;
.area {
cursor: pointer;
width: 200px;
height: 32px;
}
.tips {
position: absolute;
top: 10px;
left: 180px;
color: #999;
}
.editor {
height: calc(100vh - 588px) !important;
height: calc(100vh - 482px) !important;
}
}

View File

@ -67,7 +67,7 @@ class Store {
const host = hostStore.idMap[id];
this.outputs[host.id] = {
title: `${host.name}(${host.hostname}:${host.port})`,
data: '',
data: '\x1b[36m### WebSocket connecting ...\x1b[0m',
status: -2
}
}