mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-06 16:54:33 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5800837ed5 | |||
| aecdd7852b | |||
| d68c5b85bd |
@@ -44,7 +44,6 @@ export default (app: Router) => {
|
||||
.required()
|
||||
.pattern(/^[a-zA-Z_][0-9a-zA-Z_]*$/),
|
||||
remarks: Joi.string().optional().allow(''),
|
||||
labels: Joi.array().items(Joi.string()).optional(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
@@ -71,7 +70,6 @@ export default (app: Router) => {
|
||||
name: Joi.string().required(),
|
||||
remarks: Joi.string().optional().allow('').allow(null),
|
||||
id: Joi.number().required(),
|
||||
labels: Joi.array().items(Joi.string()).optional(),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
@@ -232,46 +230,6 @@ export default (app: Router) => {
|
||||
},
|
||||
);
|
||||
|
||||
route.post(
|
||||
'/labels',
|
||||
celebrate({
|
||||
body: Joi.object({
|
||||
ids: Joi.array().items(Joi.number().required()),
|
||||
labels: Joi.array().items(Joi.string().required()),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger: Logger = Container.get('logger');
|
||||
try {
|
||||
const envService = Container.get(EnvService);
|
||||
const data = await envService.addLabels(req.body.ids, req.body.labels);
|
||||
return res.send({ code: 200, data });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
route.delete(
|
||||
'/labels',
|
||||
celebrate({
|
||||
body: Joi.object({
|
||||
ids: Joi.array().items(Joi.number().required()),
|
||||
labels: Joi.array().items(Joi.string().required()),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger: Logger = Container.get('logger');
|
||||
try {
|
||||
const envService = Container.get(EnvService);
|
||||
const data = await envService.removeLabels(req.body.ids, req.body.labels);
|
||||
return res.send({ code: 200, data });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
route.post(
|
||||
'/upload',
|
||||
upload.single('env'),
|
||||
|
||||
@@ -10,7 +10,6 @@ export class Env {
|
||||
name?: string;
|
||||
remarks?: string;
|
||||
isPinned?: 1 | 0;
|
||||
labels?: string[];
|
||||
|
||||
constructor(options: Env) {
|
||||
this.value = options.value;
|
||||
@@ -24,7 +23,6 @@ export class Env {
|
||||
this.name = options.name;
|
||||
this.remarks = options.remarks || '';
|
||||
this.isPinned = options.isPinned || 0;
|
||||
this.labels = options.labels || [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,5 +45,4 @@ export const EnvModel = sequelize.define<EnvInstance>('Env', {
|
||||
name: { type: DataTypes.STRING, unique: 'compositeIndex' },
|
||||
remarks: DataTypes.STRING,
|
||||
isPinned: DataTypes.NUMBER,
|
||||
labels: DataTypes.JSON,
|
||||
});
|
||||
|
||||
@@ -116,6 +116,9 @@ export class EmailNotification extends NotificationBaseInfo {
|
||||
public emailUser: string = '';
|
||||
public emailPass: string = '';
|
||||
public emailTo: string = '';
|
||||
public emailHost: string = '';
|
||||
public emailPort: string = '';
|
||||
public emailSecure: string = '';
|
||||
}
|
||||
|
||||
export class PushMeNotification extends NotificationBaseInfo {
|
||||
|
||||
@@ -199,34 +199,6 @@ export default class EnvService {
|
||||
await EnvModel.update({ isPinned: 0 }, { where: { id: ids } });
|
||||
}
|
||||
|
||||
public async addLabels(ids: number[], labels: string[]) {
|
||||
const docs = await EnvModel.findAll({ where: { id: ids } });
|
||||
await sequelize.transaction(async (t) => {
|
||||
for (const doc of docs) {
|
||||
const env = doc.get({ plain: true });
|
||||
await EnvModel.update(
|
||||
{ labels: Array.from(new Set((env.labels || []).concat(labels))) },
|
||||
{ where: { id: env.id }, transaction: t },
|
||||
);
|
||||
}
|
||||
});
|
||||
return await EnvModel.findAll({ where: { id: ids } });
|
||||
}
|
||||
|
||||
public async removeLabels(ids: number[], labels: string[]) {
|
||||
const docs = await EnvModel.findAll({ where: { id: ids } });
|
||||
await sequelize.transaction(async (t) => {
|
||||
for (const doc of docs) {
|
||||
const env = doc.get({ plain: true });
|
||||
await EnvModel.update(
|
||||
{ labels: (env.labels || []).filter((label: string) => !labels.includes(label)) },
|
||||
{ where: { id: env.id }, transaction: t },
|
||||
);
|
||||
}
|
||||
});
|
||||
return await EnvModel.findAll({ where: { id: ids } });
|
||||
}
|
||||
|
||||
public async set_envs() {
|
||||
const envs = await this.envs('', {
|
||||
name: { [Op.not]: null },
|
||||
|
||||
+34
-4
@@ -590,16 +590,46 @@ export default class NotificationService {
|
||||
}
|
||||
|
||||
private async email() {
|
||||
const { emailPass, emailService, emailUser, emailTo } = this.params;
|
||||
const {
|
||||
emailPass,
|
||||
emailService,
|
||||
emailUser,
|
||||
emailTo,
|
||||
emailHost,
|
||||
emailPort,
|
||||
emailSecure,
|
||||
} = this.params;
|
||||
|
||||
try {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: emailService,
|
||||
const transportConfig: {
|
||||
service?: string;
|
||||
host?: string;
|
||||
port?: number;
|
||||
secure?: boolean;
|
||||
auth: { user: string; pass: string };
|
||||
} = {
|
||||
auth: {
|
||||
user: emailUser,
|
||||
pass: emailPass,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (emailHost) {
|
||||
transportConfig.host = emailHost;
|
||||
const parsedPort = emailPort ? parseInt(emailPort, 10) : NaN;
|
||||
transportConfig.port =
|
||||
!isNaN(parsedPort) && parsedPort >= 1 && parsedPort <= 65535
|
||||
? parsedPort
|
||||
: 465;
|
||||
transportConfig.secure =
|
||||
emailSecure !== undefined && emailSecure !== ''
|
||||
? emailSecure === 'true'
|
||||
: transportConfig.port === 465;
|
||||
} else {
|
||||
transportConfig.service = emailService;
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport(transportConfig);
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: `"青龙快讯" <${emailUser}>`,
|
||||
|
||||
@@ -84,6 +84,6 @@ COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
WORKDIR ${QL_DIR}
|
||||
|
||||
HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:${QlPort:-5700}/api/health || exit 1
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["./docker/docker-entrypoint.sh"]
|
||||
|
||||
+1
-1
@@ -84,6 +84,6 @@ COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
WORKDIR ${QL_DIR}
|
||||
|
||||
HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:${QlPort:-5700}/api/health || exit 1
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["./docker/docker-entrypoint.sh"]
|
||||
|
||||
+23
-23
@@ -55,12 +55,15 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.10.0",
|
||||
"@grpc/grpc-js": "^1.14.0",
|
||||
"@grpc/proto-loader": "^0.8.0",
|
||||
"@keyv/sqlite": "^4.0.1",
|
||||
"@otplib/preset-default": "^12.0.1",
|
||||
"body-parser": "^1.20.3",
|
||||
"celebrate": "^15.0.3",
|
||||
"chokidar": "^4.0.1",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"cron-parser": "^5.4.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
@@ -70,69 +73,66 @@
|
||||
"express-jwt": "^8.4.1",
|
||||
"express-rate-limit": "^7.4.1",
|
||||
"express-urlrewrite": "^2.0.3",
|
||||
"undici": "^7.9.0",
|
||||
"helmet": "^8.1.0",
|
||||
"hpagent": "^1.2.0",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"ip2region": "2.3.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"keyv": "^5.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"multer": "2.1.1",
|
||||
"multer": "^2.1.1",
|
||||
"node-schedule": "^2.1.0",
|
||||
"nodemailer": "^8.0.1",
|
||||
"nodemailer": "^6.9.16",
|
||||
"p-queue-cjs": "7.3.4",
|
||||
"@bufbuild/protobuf": "^2.10.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"ps-tree": "^1.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"request-ip": "3.3.0",
|
||||
"sequelize": "^6.37.5",
|
||||
"sockjs": "^0.3.24",
|
||||
"sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
|
||||
"toad-scheduler": "^3.0.1",
|
||||
"typedi": "^0.10.0",
|
||||
"undici": "^7.9.0",
|
||||
"uuid": "^11.0.3",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
"request-ip": "3.3.0",
|
||||
"ip2region": "2.3.0",
|
||||
"keyv": "^5.2.3",
|
||||
"@keyv/sqlite": "^4.0.1",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"compression": "^1.7.4",
|
||||
"helmet": "^8.1.0"
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"moment": "2.30.1",
|
||||
"@ant-design/icons": "^5.0.1",
|
||||
"@ant-design/pro-layout": "6.38.22",
|
||||
"@codemirror/view": "^6.34.1",
|
||||
"@codemirror/state": "^6.4.1",
|
||||
"@codemirror/view": "^6.34.1",
|
||||
"@monaco-editor/react": "4.2.1",
|
||||
"@react-hook/resize-observer": "^2.0.2",
|
||||
"react-router-dom": "6.26.1",
|
||||
"@types/body-parser": "^1.19.2",
|
||||
"@types/compression": "^1.7.2",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/express-jwt": "^6.0.4",
|
||||
"@types/file-saver": "2.0.2",
|
||||
"@types/helmet": "^4.0.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/jsonwebtoken": "^8.5.8",
|
||||
"@types/lodash": "^4.14.185",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/multer": "^2.1.0",
|
||||
"@types/node": "^17.0.21",
|
||||
"@types/node-schedule": "^1.3.2",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/proper-lockfile": "^4.1.4",
|
||||
"@types/ps-tree": "^1.1.6",
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react": "^18.0.20",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/request-ip": "0.0.41",
|
||||
"@types/serve-handler": "^6.1.1",
|
||||
"@types/sockjs": "^0.3.33",
|
||||
"@types/sockjs-client": "^1.5.1",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/request-ip": "0.0.41",
|
||||
"@types/proper-lockfile": "^4.1.4",
|
||||
"@types/ps-tree": "^1.1.6",
|
||||
"@uiw/codemirror-extensions-langs": "^4.21.9",
|
||||
"@uiw/react-codemirror": "^4.21.9",
|
||||
"@umijs/max": "^4.4.4",
|
||||
@@ -144,9 +144,9 @@
|
||||
"axios": "^1.4.0",
|
||||
"compression-webpack-plugin": "9.2.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"react-hotkeys-hook": "^4.6.1",
|
||||
"file-saver": "2.0.2",
|
||||
"lint-staged": "^13.0.3",
|
||||
"moment": "2.30.1",
|
||||
"monaco-editor": "0.33.0",
|
||||
"nodemon": "^3.0.1",
|
||||
"prettier": "^2.5.1",
|
||||
@@ -162,7 +162,9 @@
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-hotkeys-hook": "^4.6.1",
|
||||
"react-intl-universal": "^2.12.0",
|
||||
"react-router-dom": "6.26.1",
|
||||
"react-split-pane": "^0.1.92",
|
||||
"sockjs-client": "^1.6.0",
|
||||
"ts-node": "^10.9.2",
|
||||
@@ -170,8 +172,6 @@
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "5.2.2",
|
||||
"vh-check": "^2.0.5",
|
||||
"virtualizedtableforantd4": "1.3.0",
|
||||
"@types/compression": "^1.7.2",
|
||||
"@types/helmet": "^4.0.0"
|
||||
"virtualizedtableforantd4": "1.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+259
-568
File diff suppressed because it is too large
Load Diff
@@ -390,7 +390,11 @@
|
||||
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "Version, you can specify 'pro' for the Professional version and 'personal' for the Personal version. If left blank, it will default to the Professional version.",
|
||||
"飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "Feishu group bot: https://www.feishu.cn/hc/zh-CN/articles/360024984973",
|
||||
"飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "Feishu group bot signature secret, obtained after enabling signature verification in security settings",
|
||||
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填": "Email service name, e.g., 126, 163, Gmail, QQ, etc. Supported list: https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json. Can be left blank if emailHost is set",
|
||||
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "Email service name, e.g., 126, 163, Gmail, QQ, etc. Supported list: https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json",
|
||||
"自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com": "Custom SMTP server address. When set, the server configuration in emailService will be ignored. E.g., smtp.qiye.aliyun.com",
|
||||
"自定义SMTP端口号,默认465": "Custom SMTP port number, default is 465",
|
||||
"是否使用SSL/TLS,端口为465时默认为true,否则默认为false": "Whether to use SSL/TLS. Defaults to true when port is 465, otherwise false",
|
||||
"邮箱地址": "Email Address",
|
||||
"SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "The SMTP login password may also be a special passphrase, depending on the specific email service provider's instructions",
|
||||
"PushMe的Key,https://push.i-i.me/": "PushMe key, https://push.i-i.me/",
|
||||
|
||||
@@ -390,7 +390,11 @@
|
||||
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版",
|
||||
"飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973": "飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973",
|
||||
"飞书群组机器人加签密钥,安全设置中开启签名校验后获得": "飞书群组机器人加签密钥,安全设置中开启签名校验后获得",
|
||||
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填": "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填",
|
||||
"邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json": "邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json",
|
||||
"自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com": "自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com",
|
||||
"自定义SMTP端口号,默认465": "自定义SMTP端口号,默认465",
|
||||
"是否使用SSL/TLS,端口为465时默认为true,否则默认为false": "是否使用SSL/TLS,端口为465时默认为true,否则默认为false",
|
||||
"邮箱地址": "邮箱地址",
|
||||
"SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定": "SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定",
|
||||
"PushMe的Key,https://push.i-i.me/": "PushMe的Key,https://push.i-i.me/",
|
||||
|
||||
Vendored
+1
-34
@@ -36,7 +36,7 @@ import { useVT } from 'virtualizedtableforantd4';
|
||||
import Copy from '../../components/copy';
|
||||
import EditNameModal from './editNameModal';
|
||||
import './index.less';
|
||||
import EnvModal, { EnvLabelModal } from './modal';
|
||||
import EnvModal from './modal';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
const { Search } = Input;
|
||||
@@ -121,22 +121,6 @@ const Env = () => {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: intl.get('标签'),
|
||||
dataIndex: 'labels',
|
||||
key: 'labels',
|
||||
render: (labels: string[], record: any) => {
|
||||
return (
|
||||
<Space size={[0, 4]} wrap>
|
||||
{labels?.filter((label) => label).map((label) => (
|
||||
<Tag key={label} color="blue">
|
||||
{label}
|
||||
</Tag>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: intl.get('更新时间'),
|
||||
dataIndex: 'timestamp',
|
||||
@@ -254,7 +238,6 @@ const Env = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditNameModalVisible, setIsEditNameModalVisible] = useState(false);
|
||||
const [isLabelModalVisible, setIsLabelModalVisible] = useState(false);
|
||||
const [editedEnv, setEditedEnv] = useState();
|
||||
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
@@ -639,13 +622,6 @@ const Env = () => {
|
||||
>
|
||||
{intl.get('批量修改变量名称')}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginBottom: 5, marginLeft: 8 }}
|
||||
onClick={() => setIsLabelModalVisible(true)}
|
||||
>
|
||||
{intl.get('批量修改标签')}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginBottom: 5, marginLeft: 8 }}
|
||||
@@ -724,15 +700,6 @@ const Env = () => {
|
||||
ids={selectedRowIds}
|
||||
/>
|
||||
)}
|
||||
{isLabelModalVisible && (
|
||||
<EnvLabelModal
|
||||
handleCancel={(needUpdate) => {
|
||||
setIsLabelModalVisible(false);
|
||||
if (needUpdate) getEnvs();
|
||||
}}
|
||||
ids={selectedRowIds}
|
||||
/>
|
||||
)}
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Vendored
+4
-78
@@ -1,9 +1,8 @@
|
||||
import intl from 'react-intl-universal';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, message, Input, Form, Radio, Button } from 'antd';
|
||||
import { Modal, message, Input, Form, Radio } from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
import config from '@/utils/config';
|
||||
import EditableTagGroup from '@/components/tag';
|
||||
|
||||
const EnvModal = ({
|
||||
env,
|
||||
@@ -17,7 +16,7 @@ const EnvModal = ({
|
||||
|
||||
const handleOk = async (values: any) => {
|
||||
setLoading(true);
|
||||
const { value, split, name, remarks, labels } = values;
|
||||
const { value, split, name, remarks } = values;
|
||||
const method = env ? 'put' : 'post';
|
||||
let payload;
|
||||
if (!env) {
|
||||
@@ -28,11 +27,10 @@ const EnvModal = ({
|
||||
name: name,
|
||||
value: x,
|
||||
remarks: remarks,
|
||||
labels: labels || [],
|
||||
};
|
||||
});
|
||||
} else {
|
||||
payload = [{ value, name, remarks, labels: labels || [] }];
|
||||
payload = [{ value, name, remarks }];
|
||||
}
|
||||
} else {
|
||||
payload = { ...values, id: env.id };
|
||||
@@ -125,81 +123,9 @@ const EnvModal = ({
|
||||
<Form.Item name="remarks" label={intl.get('备注')}>
|
||||
<Input placeholder={intl.get('请输入备注')} />
|
||||
</Form.Item>
|
||||
<Form.Item name="labels" label={intl.get('标签')}>
|
||||
<EditableTagGroup />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export { EnvModal as default };
|
||||
export const EnvLabelModal = ({
|
||||
ids,
|
||||
handleCancel,
|
||||
}: {
|
||||
ids: Array<string>;
|
||||
handleCancel: (needUpdate?: boolean) => void;
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const update = async (action: 'delete' | 'post') => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(async (values) => {
|
||||
setLoading(true);
|
||||
const payload = { ids, labels: values.labels };
|
||||
try {
|
||||
const { code, data } = await request[action](
|
||||
`${config.apiPrefix}envs/labels`,
|
||||
payload,
|
||||
);
|
||||
|
||||
if (code === 200) {
|
||||
message.success(
|
||||
action === 'post'
|
||||
? intl.get('添加Labels成功')
|
||||
: intl.get('删除Labels成功'),
|
||||
);
|
||||
handleCancel(true);
|
||||
}
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((info) => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
<Button key="cancel" onClick={() => handleCancel(false)}>{intl.get('取消')}</Button>,
|
||||
<Button key="delete" type="primary" danger onClick={() => update('delete')}>
|
||||
{intl.get('删除')}
|
||||
</Button>,
|
||||
<Button key="add" type="primary" onClick={() => update('post')}>
|
||||
{intl.get('添加')}
|
||||
</Button>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={intl.get('批量修改标签')}
|
||||
open={true}
|
||||
footer={buttons}
|
||||
centered
|
||||
maskClosable={false}
|
||||
forceRender
|
||||
onCancel={() => handleCancel(false)}
|
||||
confirmLoading={loading}
|
||||
>
|
||||
<Form form={form} layout="vertical" name="form_in_env_label_modal">
|
||||
<Form.Item name="labels" label={intl.get('标签')}>
|
||||
<EditableTagGroup />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
export default EnvModal;
|
||||
|
||||
+19
-2
@@ -406,9 +406,26 @@ export default {
|
||||
{
|
||||
label: 'emailService',
|
||||
tip: intl.get(
|
||||
'邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json',
|
||||
'邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json,设置emailHost后此项可不填',
|
||||
),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: 'emailHost',
|
||||
tip: intl.get(
|
||||
'自定义SMTP服务器地址,设置后将忽略emailService中的服务器配置,如smtp.qiye.aliyun.com',
|
||||
),
|
||||
},
|
||||
{
|
||||
label: 'emailPort',
|
||||
tip: intl.get('自定义SMTP端口号,默认465'),
|
||||
},
|
||||
{
|
||||
label: 'emailSecure',
|
||||
tip: intl.get('是否使用SSL/TLS,端口为465时默认为true,否则默认为false'),
|
||||
items: [
|
||||
{ value: 'true', label: 'true' },
|
||||
{ value: 'false', label: 'false' },
|
||||
],
|
||||
},
|
||||
{ label: 'emailUser', tip: intl.get('邮箱认证地址'), required: true },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user