支持批量创建同名称环境变量,日志和脚本管理PC页支持宽度拖拽

This commit is contained in:
hanhh 2021-08-17 18:34:55 +08:00
parent 594e871744
commit 2d6da9ebfe
9 changed files with 114 additions and 89 deletions

View File

@ -25,11 +25,13 @@ export default (app: Router) => {
route.post(
'/envs',
celebrate({
body: Joi.object({
body: Joi.array().items(
Joi.object({
value: Joi.string().required(),
name: Joi.string().required(),
remarks: Joi.string().optional(),
remarks: Joi.string().optional().allow(''),
}),
),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');

View File

@ -16,25 +16,29 @@ export default class EnvService {
});
}
public async create(payload: Env): Promise<Env> {
public async create(payloads: Env[]): Promise<Env[]> {
const envs = await this.envs();
let position = initEnvPosition;
if (envs && envs.length > 0 && envs[envs.length - 1].position) {
position = envs[envs.length - 1].position;
}
const tab = new Env({ ...payload, position: position / 2 });
const doc = await this.insert(tab);
const tabs = payloads.map((x) => {
position = position / 2;
const tab = new Env({ ...x, position });
return tab;
});
const docs = await this.insert(tabs);
await this.set_envs();
return doc;
return docs;
}
public async insert(payload: Env): Promise<Env> {
public async insert(payloads: Env[]): Promise<Env[]> {
return new Promise((resolve) => {
this.cronDb.insert(payload, (err, doc) => {
this.cronDb.insert(payloads, (err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(doc);
resolve(docs);
}
});
});

View File

@ -191,7 +191,7 @@ input:-webkit-autofill:active {
}
.Resizer {
background: #000;
background: #fff;
opacity: 0.2;
z-index: 1;
-moz-box-sizing: border-box;
@ -200,6 +200,8 @@ input:-webkit-autofill:active {
-moz-background-clip: padding;
-webkit-background-clip: padding;
background-clip: padding-box;
border-left: 5px solid rgba(42, 161, 255, 0);
border-right: 5px solid rgba(42, 161, 255, 0);
}
.Resizer:hover {
@ -210,29 +212,22 @@ input:-webkit-autofill:active {
.Resizer.horizontal {
height: 11px;
margin: -5px 0;
border-top: 5px solid rgba(255, 255, 255, 0);
border-bottom: 5px solid rgba(255, 255, 255, 0);
cursor: row-resize;
width: 100%;
}
.Resizer.horizontal:hover {
border-top: 5px solid rgba(0, 0, 0, 0.5);
border-bottom: 5px solid rgba(0, 0, 0, 0.5);
}
.Resizer.vertical {
width: 11px;
margin: 0 -5px;
border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0);
cursor: col-resize;
}
.Resizer.horizontal:hover,
.Resizer.vertical:hover {
border-left: 5px solid rgba(0, 0, 0, 0.5);
border-right: 5px solid rgba(0, 0, 0, 0.5);
border-left-color: rgba(42, 161, 255, 0.5);
border-right-color: rgba(42, 161, 255, 0.5);
}
.Resizer.disabled {
cursor: not-allowed;
}

View File

@ -317,7 +317,8 @@ const Env = () => {
const result = [...value];
const index = value.findIndex((x) => x._id === env._id);
if (index === -1) {
result.push(env);
env = Array.isArray(env) ? env : [env];
result.push(...env);
} else {
result.splice(index, 1, {
...env,

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Modal, message, Input, Form } from 'antd';
import { Modal, message, Input, Form, Radio } from 'antd';
import { request } from '@/utils/http';
import config from '@/utils/config';
@ -17,8 +17,19 @@ const EnvModal = ({
const handleOk = async (values: any) => {
setLoading(true);
const { value, split, name, remarks } = values;
const method = env ? 'put' : 'post';
const payload = env ? { ...values, _id: env._id } : values;
let payload = env ? { ...values, _id: env._id } : values;
if (!env && split === '1') {
const symbol = value.includes('&') ? '&' : '\n';
payload = value.split(symbol).map((x: any) => {
return {
name: name,
value: x,
remarks: remarks,
};
});
}
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
data: payload,
});
@ -61,6 +72,14 @@ const EnvModal = ({
>
<Input placeholder="请输入环境变量名称" />
</Form.Item>
{!env && (
<Form.Item name="split" label="自动拆分" initialValue="0">
<Radio.Group>
<Radio value="1"></Radio>
<Radio value="0"></Radio>
</Radio.Group>
</Form.Item>
)}
<Form.Item
name="value"
label="值"

View File

@ -7,7 +7,6 @@
background-color: #fff;
height: calc(100vh - 128px);
height: calc(100vh - var(--vh-offset, 0px) - 128px);
width: @tree-width;
display: flex;
flex-direction: column;
}
@ -20,4 +19,5 @@
.log-container {
display: flex;
position: relative;
}

View File

@ -7,6 +7,7 @@ import { request } from '@/utils/http';
import styles from './index.module.less';
import { Controlled as CodeMirror } from 'react-codemirror2';
import { useCtx, useTheme } from '@/utils/hooks';
import SplitPane from 'react-split-pane';
function getFilterData(keyword: string, data: any) {
const expandedKeys: string[] = [];
@ -133,6 +134,7 @@ const Log = () => {
>
<div className={`${styles['log-container']} log-container`}>
{!isPhone && (
<SplitPane split="vertical" size={200} maxSize={-100}>
<div className={styles['left-tree-container']}>
<Input.Search
className={styles['left-tree-search']}
@ -149,23 +151,6 @@ const Log = () => {
></Tree>
</div>
</div>
)}
{isPhone ? (
<CodeMirror
value={value}
options={{
lineNumbers: true,
lineWrapping: true,
styleActiveLine: true,
matchBrackets: true,
readOnly: true,
}}
onBeforeChange={(editor, data, value) => {
setValue(value);
}}
onChange={(editor, data, value) => {}}
/>
) : (
<Editor
language="shell"
theme={theme}
@ -180,6 +165,23 @@ const Log = () => {
wordWrap: 'on',
}}
/>
</SplitPane>
)}
{isPhone && (
<CodeMirror
value={value}
options={{
lineNumbers: true,
lineWrapping: true,
styleActiveLine: true,
matchBrackets: true,
readOnly: true,
}}
onBeforeChange={(editor, data, value) => {
setValue(value);
}}
onChange={(editor, data, value) => {}}
/>
)}
</div>
</PageContainer>

View File

@ -7,7 +7,6 @@
background-color: #fff;
height: calc(100vh - 128px);
height: calc(100vh - var(--vh-offset, 0px) - 128px);
width: @tree-width;
display: flex;
flex-direction: column;
}
@ -20,4 +19,5 @@
.log-container {
display: flex;
position: relative;
}

View File

@ -8,6 +8,7 @@ import styles from './index.module.less';
import EditModal from './editModal';
import { Controlled as CodeMirror } from 'react-codemirror2';
import { useCtx, useTheme } from '@/utils/hooks';
import SplitPane from 'react-split-pane';
function getFilterData(keyword: string, data: any) {
if (keyword) {
@ -122,6 +123,7 @@ const Script = () => {
>
<div className={`${styles['log-container']} log-container`}>
{!isPhone && (
<SplitPane split="vertical" size={200} maxSize={-100}>
<div className={styles['left-tree-container']}>
<Input.Search
className={styles['left-tree-search']}
@ -138,8 +140,21 @@ const Script = () => {
></Tree>
</div>
</div>
<Editor
language={mode}
value={value}
theme={theme}
options={{
readOnly: true,
fontSize: 12,
lineNumbersMinChars: 3,
folding: false,
glyphMargin: false,
}}
/>
</SplitPane>
)}
{isPhone ? (
{isPhone && (
<CodeMirror
value={value}
options={{
@ -155,19 +170,6 @@ const Script = () => {
}}
onChange={(editor, data, value) => {}}
/>
) : (
<Editor
language={mode}
value={value}
theme={theme}
options={{
readOnly: true,
fontSize: 12,
lineNumbersMinChars: 3,
folding: false,
glyphMargin: false,
}}
/>
)}
<EditModal
visible={isLogModalVisible}