mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-29 02:56:08 +08:00
支持批量创建同名称环境变量,日志和脚本管理PC页支持宽度拖拽
This commit is contained in:
parent
30cea84886
commit
3525b1d92a
|
@ -25,11 +25,13 @@ export default (app: Router) => {
|
||||||
route.post(
|
route.post(
|
||||||
'/envs',
|
'/envs',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.array().items(
|
||||||
value: Joi.string().required(),
|
Joi.object({
|
||||||
name: Joi.string().required(),
|
value: Joi.string().required(),
|
||||||
remarks: Joi.string().optional(),
|
name: Joi.string().required(),
|
||||||
}),
|
remarks: Joi.string().optional().allow(''),
|
||||||
|
}),
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
|
|
|
@ -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();
|
const envs = await this.envs();
|
||||||
let position = initEnvPosition;
|
let position = initEnvPosition;
|
||||||
if (envs && envs.length > 0 && envs[envs.length - 1].position) {
|
if (envs && envs.length > 0 && envs[envs.length - 1].position) {
|
||||||
position = envs[envs.length - 1].position;
|
position = envs[envs.length - 1].position;
|
||||||
}
|
}
|
||||||
const tab = new Env({ ...payload, position: position / 2 });
|
const tabs = payloads.map((x) => {
|
||||||
const doc = await this.insert(tab);
|
position = position / 2;
|
||||||
|
const tab = new Env({ ...x, position });
|
||||||
|
return tab;
|
||||||
|
});
|
||||||
|
const docs = await this.insert(tabs);
|
||||||
await this.set_envs();
|
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) => {
|
return new Promise((resolve) => {
|
||||||
this.cronDb.insert(payload, (err, doc) => {
|
this.cronDb.insert(payloads, (err, docs) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
} else {
|
} else {
|
||||||
resolve(doc);
|
resolve(docs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -191,7 +191,7 @@ input:-webkit-autofill:active {
|
||||||
}
|
}
|
||||||
|
|
||||||
.Resizer {
|
.Resizer {
|
||||||
background: #000;
|
background: #fff;
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
|
@ -200,6 +200,8 @@ input:-webkit-autofill:active {
|
||||||
-moz-background-clip: padding;
|
-moz-background-clip: padding;
|
||||||
-webkit-background-clip: padding;
|
-webkit-background-clip: padding;
|
||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
|
border-left: 5px solid rgba(42, 161, 255, 0);
|
||||||
|
border-right: 5px solid rgba(42, 161, 255, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Resizer:hover {
|
.Resizer:hover {
|
||||||
|
@ -210,29 +212,22 @@ input:-webkit-autofill:active {
|
||||||
.Resizer.horizontal {
|
.Resizer.horizontal {
|
||||||
height: 11px;
|
height: 11px;
|
||||||
margin: -5px 0;
|
margin: -5px 0;
|
||||||
border-top: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
border-bottom: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
cursor: row-resize;
|
cursor: row-resize;
|
||||||
width: 100%;
|
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 {
|
.Resizer.vertical {
|
||||||
width: 11px;
|
width: 11px;
|
||||||
margin: 0 -5px;
|
margin: 0 -5px;
|
||||||
border-left: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
border-right: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Resizer.horizontal:hover,
|
||||||
.Resizer.vertical:hover {
|
.Resizer.vertical:hover {
|
||||||
border-left: 5px solid rgba(0, 0, 0, 0.5);
|
border-left-color: rgba(42, 161, 255, 0.5);
|
||||||
border-right: 5px solid rgba(0, 0, 0, 0.5);
|
border-right-color: rgba(42, 161, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Resizer.disabled {
|
.Resizer.disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
3
src/pages/env/index.tsx
vendored
3
src/pages/env/index.tsx
vendored
|
@ -317,7 +317,8 @@ const Env = () => {
|
||||||
const result = [...value];
|
const result = [...value];
|
||||||
const index = value.findIndex((x) => x._id === env._id);
|
const index = value.findIndex((x) => x._id === env._id);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
result.push(env);
|
env = Array.isArray(env) ? env : [env];
|
||||||
|
result.push(...env);
|
||||||
} else {
|
} else {
|
||||||
result.splice(index, 1, {
|
result.splice(index, 1, {
|
||||||
...env,
|
...env,
|
||||||
|
|
23
src/pages/env/modal.tsx
vendored
23
src/pages/env/modal.tsx
vendored
|
@ -1,5 +1,5 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
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 { request } from '@/utils/http';
|
||||||
import config from '@/utils/config';
|
import config from '@/utils/config';
|
||||||
|
|
||||||
|
@ -17,8 +17,19 @@ const EnvModal = ({
|
||||||
|
|
||||||
const handleOk = async (values: any) => {
|
const handleOk = async (values: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
const { value, split, name, remarks } = values;
|
||||||
const method = env ? 'put' : 'post';
|
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`, {
|
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
|
||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
|
@ -61,6 +72,14 @@ const EnvModal = ({
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入环境变量名称" />
|
<Input placeholder="请输入环境变量名称" />
|
||||||
</Form.Item>
|
</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
|
<Form.Item
|
||||||
name="value"
|
name="value"
|
||||||
label="值"
|
label="值"
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
height: calc(100vh - 128px);
|
height: calc(100vh - 128px);
|
||||||
height: calc(100vh - var(--vh-offset, 0px) - 128px);
|
height: calc(100vh - var(--vh-offset, 0px) - 128px);
|
||||||
width: @tree-width;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
@ -20,4 +19,5 @@
|
||||||
|
|
||||||
.log-container {
|
.log-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { request } from '@/utils/http';
|
||||||
import styles from './index.module.less';
|
import styles from './index.module.less';
|
||||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||||
import { useCtx, useTheme } from '@/utils/hooks';
|
import { useCtx, useTheme } from '@/utils/hooks';
|
||||||
|
import SplitPane from 'react-split-pane';
|
||||||
|
|
||||||
function getFilterData(keyword: string, data: any) {
|
function getFilterData(keyword: string, data: any) {
|
||||||
const expandedKeys: string[] = [];
|
const expandedKeys: string[] = [];
|
||||||
|
@ -133,24 +134,40 @@ const Log = () => {
|
||||||
>
|
>
|
||||||
<div className={`${styles['log-container']} log-container`}>
|
<div className={`${styles['log-container']} log-container`}>
|
||||||
{!isPhone && (
|
{!isPhone && (
|
||||||
<div className={styles['left-tree-container']}>
|
<SplitPane split="vertical" size={200} maxSize={-100}>
|
||||||
<Input.Search
|
<div className={styles['left-tree-container']}>
|
||||||
className={styles['left-tree-search']}
|
<Input.Search
|
||||||
onChange={onSearch}
|
className={styles['left-tree-search']}
|
||||||
></Input.Search>
|
onChange={onSearch}
|
||||||
<div className={styles['left-tree-scroller']} ref={treeDom}>
|
></Input.Search>
|
||||||
<Tree
|
<div className={styles['left-tree-scroller']} ref={treeDom}>
|
||||||
className={styles['left-tree']}
|
<Tree
|
||||||
treeData={filterData}
|
className={styles['left-tree']}
|
||||||
showIcon={true}
|
treeData={filterData}
|
||||||
height={height}
|
showIcon={true}
|
||||||
showLine={{ showLeafIcon: true }}
|
height={height}
|
||||||
onSelect={onTreeSelect}
|
showLine={{ showLeafIcon: true }}
|
||||||
></Tree>
|
onSelect={onTreeSelect}
|
||||||
|
></Tree>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Editor
|
||||||
|
language="shell"
|
||||||
|
theme={theme}
|
||||||
|
value={value}
|
||||||
|
options={{
|
||||||
|
readOnly: true,
|
||||||
|
fontSize: 12,
|
||||||
|
lineNumbersMinChars: 3,
|
||||||
|
fontFamily: 'Source Code Pro',
|
||||||
|
folding: false,
|
||||||
|
glyphMargin: false,
|
||||||
|
wordWrap: 'on',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SplitPane>
|
||||||
)}
|
)}
|
||||||
{isPhone ? (
|
{isPhone && (
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
value={value}
|
value={value}
|
||||||
options={{
|
options={{
|
||||||
|
@ -165,21 +182,6 @@ const Log = () => {
|
||||||
}}
|
}}
|
||||||
onChange={(editor, data, value) => {}}
|
onChange={(editor, data, value) => {}}
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<Editor
|
|
||||||
language="shell"
|
|
||||||
theme={theme}
|
|
||||||
value={value}
|
|
||||||
options={{
|
|
||||||
readOnly: true,
|
|
||||||
fontSize: 12,
|
|
||||||
lineNumbersMinChars: 3,
|
|
||||||
fontFamily: 'Source Code Pro',
|
|
||||||
folding: false,
|
|
||||||
glyphMargin: false,
|
|
||||||
wordWrap: 'on',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
height: calc(100vh - 128px);
|
height: calc(100vh - 128px);
|
||||||
height: calc(100vh - var(--vh-offset, 0px) - 128px);
|
height: calc(100vh - var(--vh-offset, 0px) - 128px);
|
||||||
width: @tree-width;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
@ -20,4 +19,5 @@
|
||||||
|
|
||||||
.log-container {
|
.log-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import styles from './index.module.less';
|
||||||
import EditModal from './editModal';
|
import EditModal from './editModal';
|
||||||
import { Controlled as CodeMirror } from 'react-codemirror2';
|
import { Controlled as CodeMirror } from 'react-codemirror2';
|
||||||
import { useCtx, useTheme } from '@/utils/hooks';
|
import { useCtx, useTheme } from '@/utils/hooks';
|
||||||
|
import SplitPane from 'react-split-pane';
|
||||||
|
|
||||||
function getFilterData(keyword: string, data: any) {
|
function getFilterData(keyword: string, data: any) {
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
|
@ -122,24 +123,38 @@ const Script = () => {
|
||||||
>
|
>
|
||||||
<div className={`${styles['log-container']} log-container`}>
|
<div className={`${styles['log-container']} log-container`}>
|
||||||
{!isPhone && (
|
{!isPhone && (
|
||||||
<div className={styles['left-tree-container']}>
|
<SplitPane split="vertical" size={200} maxSize={-100}>
|
||||||
<Input.Search
|
<div className={styles['left-tree-container']}>
|
||||||
className={styles['left-tree-search']}
|
<Input.Search
|
||||||
onChange={onSearch}
|
className={styles['left-tree-search']}
|
||||||
></Input.Search>
|
onChange={onSearch}
|
||||||
<div className={styles['left-tree-scroller']} ref={treeDom}>
|
></Input.Search>
|
||||||
<Tree
|
<div className={styles['left-tree-scroller']} ref={treeDom}>
|
||||||
className={styles['left-tree']}
|
<Tree
|
||||||
treeData={filterData}
|
className={styles['left-tree']}
|
||||||
showIcon={true}
|
treeData={filterData}
|
||||||
height={height}
|
showIcon={true}
|
||||||
showLine={{ showLeafIcon: true }}
|
height={height}
|
||||||
onSelect={onTreeSelect}
|
showLine={{ showLeafIcon: true }}
|
||||||
></Tree>
|
onSelect={onTreeSelect}
|
||||||
|
></Tree>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Editor
|
||||||
|
language={mode}
|
||||||
|
value={value}
|
||||||
|
theme={theme}
|
||||||
|
options={{
|
||||||
|
readOnly: true,
|
||||||
|
fontSize: 12,
|
||||||
|
lineNumbersMinChars: 3,
|
||||||
|
folding: false,
|
||||||
|
glyphMargin: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SplitPane>
|
||||||
)}
|
)}
|
||||||
{isPhone ? (
|
{isPhone && (
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
value={value}
|
value={value}
|
||||||
options={{
|
options={{
|
||||||
|
@ -155,19 +170,6 @@ const Script = () => {
|
||||||
}}
|
}}
|
||||||
onChange={(editor, data, value) => {}}
|
onChange={(editor, data, value) => {}}
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<Editor
|
|
||||||
language={mode}
|
|
||||||
value={value}
|
|
||||||
theme={theme}
|
|
||||||
options={{
|
|
||||||
readOnly: true,
|
|
||||||
fontSize: 12,
|
|
||||||
lineNumbersMinChars: 3,
|
|
||||||
folding: false,
|
|
||||||
glyphMargin: false,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<EditModal
|
<EditModal
|
||||||
visible={isLogModalVisible}
|
visible={isLogModalVisible}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user