From dc7340e24aa397435836eb6ae93e7acaabaf9072 Mon Sep 17 00:00:00 2001 From: vapao Date: Fri, 21 Oct 2022 16:47:41 +0800 Subject: [PATCH 01/36] =?UTF-8?q?U=20=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=88=86=E5=8F=91=E5=9C=A8=E6=96=87=E4=BB=B6=E8=BF=87=E5=A4=9A?= =?UTF-8?q?=E6=97=B6=E5=B1=95=E7=A4=BA=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/exec/task/index.module.less | 1 + spug_web/src/pages/exec/transfer/Output.js | 3 ++- spug_web/src/pages/exec/transfer/index.js | 11 +++++++---- spug_web/src/pages/exec/transfer/index.module.less | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/spug_web/src/pages/exec/task/index.module.less b/spug_web/src/pages/exec/task/index.module.less index e6add70..2a229b5 100644 --- a/spug_web/src/pages/exec/task/index.module.less +++ b/spug_web/src/pages/exec/task/index.module.less @@ -8,6 +8,7 @@ .left { padding: 24px; width: 60%; + border-right: 1px solid #dfdfdf; .area { cursor: pointer; diff --git a/spug_web/src/pages/exec/transfer/Output.js b/spug_web/src/pages/exec/transfer/Output.js index e4262bb..ffc8f69 100644 --- a/spug_web/src/pages/exec/transfer/Output.js +++ b/spug_web/src/pages/exec/transfer/Output.js @@ -32,7 +32,8 @@ function OutView(props) { store.tag = '' gCurrent = current term.setOption('disableStdin', true) - term.setOption('fontSize', gStore.terminal.fontSize) + term.setOption('fontSize', 14) + term.setOption('lineHeight', 1.2) term.setOption('fontFamily', gStore.terminal.fontFamily) term.setOption('theme', {background: '#2b2b2b', foreground: '#A9B7C6', cursor: '#2b2b2b'}) term.attachCustomKeyEventHandler((arg) => { diff --git a/spug_web/src/pages/exec/transfer/index.js b/spug_web/src/pages/exec/transfer/index.js index 853a167..b564b64 100644 --- a/spug_web/src/pages/exec/transfer/index.js +++ b/spug_web/src/pages/exec/transfer/index.js @@ -121,11 +121,13 @@ function TransferIndex() { + { + return { + onClick: () => handleClickRow(record) + } + }} + rowSelection={{ + selectedRowKeys, + hideSelectAll: props.onlyOne, + onSelect: handleClickRow, + onSelectAll: handleSelectAll + }}> + + ( + + + + + )}/> + +
+ + + + ) -}) \ No newline at end of file +} + +HostSelector.defaultProps = { + value: [], + type: 'text' +} + +export default observer(HostSelector) \ No newline at end of file diff --git a/spug_web/src/pages/host/index.module.less b/spug_web/src/pages/host/index.module.less index c502150..230f13a 100644 --- a/spug_web/src/pages/host/index.module.less +++ b/spug_web/src/pages/host/index.module.less @@ -26,21 +26,6 @@ } } -.selector { - :global(.ant-modal-footer) { - border-top: none - } - - .gTitle { - height: 44px; - line-height: 44px; - padding-left: 12px; - font-weight: bold; - margin-bottom: 12px; - background: #fafafa; - } -} - .formAddress1 { display: inline-block; diff --git a/spug_web/src/pages/host/selector.module.less b/spug_web/src/pages/host/selector.module.less new file mode 100644 index 0000000..b469812 --- /dev/null +++ b/spug_web/src/pages/host/selector.module.less @@ -0,0 +1,46 @@ +.modal { + :global(.ant-modal-footer) { + border-top: none + } + + .gTitle { + height: 44px; + line-height: 44px; + padding-left: 12px; + font-weight: bold; + margin-bottom: 12px; + background: #fafafa; + } +} + +.area { + cursor: pointer; + width: 200px; + height: 32px; +} + +.treeNode { + display: flex; + flex-direction: row; + align-items: center; + + .title { + margin-left: 8px; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-all; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + } + + .number { + width: 30px; + text-align: right; + } +} + + + + diff --git a/spug_web/src/pages/monitor/Step1.js b/spug_web/src/pages/monitor/Step1.js index b7ce777..1dd1e19 100644 --- a/spug_web/src/pages/monitor/Step1.js +++ b/spug_web/src/pages/monitor/Step1.js @@ -8,7 +8,7 @@ import { observer } from 'mobx-react'; import { ExclamationCircleOutlined } from '@ant-design/icons'; import { Modal, Form, Input, Select, Button, message } from 'antd'; import TemplateSelector from '../exec/task/TemplateSelector'; -import Selector from 'pages/host/Selector'; +import HostSelector from 'pages/host/Selector'; import { LinkButton, ACEditor } from 'components'; import { http, cleanCommand } from 'libs'; import store from './store'; @@ -22,7 +22,6 @@ const helpMap = { export default observer(function () { const [loading, setLoading] = useState(false); const [showTmp, setShowTmp] = useState(false); - const [showSelector, setShowSelector] = useState(false); function handleTest() { setLoading(true) @@ -131,10 +130,7 @@ export default observer(function () { notFoundContent={null}/> - {store.record.targets?.length > 0 && ( - 已选择 {store.record.targets.length} 台 - )} - + store.record.targets = ids}/> Tips: 仅测试第一个监控地址 {showTmp && store.record.extra = body} onCancel={() => setShowTmp(false)}/>} - setShowSelector(false)} - onOk={(_, ids) => store.record.targets = ids}/> ) }) \ No newline at end of file diff --git a/spug_web/src/pages/schedule/Step2.js b/spug_web/src/pages/schedule/Step2.js index e092573..f0a781b 100644 --- a/spug_web/src/pages/schedule/Step2.js +++ b/spug_web/src/pages/schedule/Step2.js @@ -3,7 +3,7 @@ * Copyright (c) * Released under the AGPL-3.0 License. */ -import React, { useState } from 'react'; +import React from 'react'; import { observer } from 'mobx-react'; import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import { Form, Select, Button } from 'antd'; @@ -13,7 +13,12 @@ import hostStore from 'pages/host/store'; import styles from './index.module.css'; export default observer(function () { - const [visible, setVisible] = useState(false) + function handleChange(_, ids) { + if (store.targets.includes('local')) { + ids.unshift('local') + } + store.targets = ids + } return ( @@ -43,15 +48,10 @@ export default observer(function () { ))} - + x !== 'local')} onChange={handleChange}> + + - setVisible(false)} - onOk={(_, ids) => store.targets = ids}/> - info.host_ids = ids}/> + info.host_ids = ids}/> diff --git a/spug_web/src/pages/exec/transfer/index.js b/spug_web/src/pages/exec/transfer/index.js index 9eb82ad..66663de 100644 --- a/spug_web/src/pages/exec/transfer/index.js +++ b/spug_web/src/pages/exec/transfer/index.js @@ -120,7 +120,7 @@ function TransferIndex() { 上传本地文件 - makeFile(row)}> + makeFile(row)}> 添加主机文件 )}> @@ -144,7 +144,7 @@ function TransferIndex() { setDir(e.target.value)} placeholder="请输入目标路径"/> - x.id)} onChange={(_, __, rows) => setHosts(rows)}/> + x.id)} onChange={rows => setHosts(rows)}/> diff --git a/spug_web/src/pages/host/Selector.js b/spug_web/src/pages/host/Selector.js index da1c4c5..f2ab447 100644 --- a/spug_web/src/pages/host/Selector.js +++ b/spug_web/src/pages/host/Selector.js @@ -62,20 +62,17 @@ function HostSelector(props) { } function handleSubmit() { - if (props.onChange) { - setLoading(true); - let res - const selectedRows = store.rawRecords.filter(x => selectedRowKeys.includes(x.id)) - if (props.onlyOne) { - res = props.onChange(store.group, selectedRowKeys[0], selectedRows[0]) - } else { - res = props.onChange(store.group, selectedRowKeys, selectedRows); - } - if (res && res.then) { - res.then(handleClose, () => setLoading(false)) - } else { - handleClose() - } + if (props.mode === 'ids') { + props.onChange(props.onlyOne ? selectedRowKeys[0] : selectedRowKeys) + handleClose() + } else if (props.mode === 'rows') { + const value = store.rawRecords.filter(x => selectedRowKeys.includes(x.id)) + props.onChange(props.onlyOne ? value[0] : value) + handleClose() + } else if (props.mode === 'group') { + setLoading(true) + props.onChange(store.group, selectedRowKeys) + .then(handleClose, () => setLoading(false)) } } @@ -112,34 +109,39 @@ function HostSelector(props) { setSelectedRowKeys([]) setLoading(false) setVisible(false) + if (props.onCancel) { + props.onCancel() + } } return (
- {props.children ? ( -
setVisible(true)}>{props.children}
- ) : ( - props.type === 'button' ? ( - props.value.length > 0 ? ( - 已选择 {props.value.length} 台主机
} - onClick={() => setVisible(true)}/> - ) : ( - - )) : ( -
- {props.value.length > 0 && 已选择 {props.value.length} 台} - -
+ {props.mode !== 'group' && ( + props.children ? ( +
setVisible(true)}>{props.children}
+ ) : ( + props.type === 'button' ? ( + props.value.length > 0 ? ( + 已选择 {props.value.length} 台主机} + onClick={() => setVisible(true)}/> + ) : ( + + )) : ( +
+ {props.value.length > 0 && 已选择 {props.value.length} 台} + +
+ ) ) )} null } export default observer(HostSelector) \ No newline at end of file diff --git a/spug_web/src/pages/host/index.js b/spug_web/src/pages/host/index.js index fc43907..abbe600 100644 --- a/spug_web/src/pages/host/index.js +++ b/spug_web/src/pages/host/index.js @@ -51,9 +51,10 @@ export default observer(function () { {store.syncVisible && } {store.selectorVisible && store.selectorVisible = false} - onOk={store.updateGroup} + onChange={store.updateGroup} />} ); diff --git a/spug_web/src/pages/monitor/Step1.js b/spug_web/src/pages/monitor/Step1.js index 1dd1e19..007cb2b 100644 --- a/spug_web/src/pages/monitor/Step1.js +++ b/spug_web/src/pages/monitor/Step1.js @@ -130,7 +130,7 @@ export default observer(function () { notFoundContent={null}/> - store.record.targets = ids}/> + store.record.targets = ids}/> Date: Wed, 29 Mar 2023 18:31:40 +0800 Subject: [PATCH 19/36] =?UTF-8?q?=E4=BF=AE=E5=A4=8DTOKEN=5FTTL=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=97=A0=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_api/libs/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spug_api/libs/middleware.py b/spug_api/libs/middleware.py index aa412b2..1a3a614 100644 --- a/spug_api/libs/middleware.py +++ b/spug_api/libs/middleware.py @@ -37,7 +37,7 @@ class AuthenticationMiddleware(MiddlewareMixin): if user and user.token_expired >= time.time() and user.is_active: if x_real_ip == user.last_ip or AppSetting.get_default('bind_ip') is False: request.user = user - user.token_expired = time.time() + 8 * 60 * 60 + user.token_expired = time.time() + settings.TOKEN_TTL user.save() return None response = json_response(error="验证失败,请重新登录") -- Gitee From 5e87b8763d77d6a40fee8f2e0c5174764e16b4a8 Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:35:00 +0800 Subject: [PATCH 20/36] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=BB=E6=9C=BA?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_api/apps/host/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spug_api/apps/host/views.py b/spug_api/apps/host/views.py index 377da26..db5036e 100644 --- a/spug_api/apps/host/views.py +++ b/spug_api/apps/host/views.py @@ -9,6 +9,7 @@ from apps.setting.utils import AppSetting from apps.account.utils import get_host_perms from apps.host.models import Host, Group from apps.host.utils import batch_sync_host, _sync_host_extend +from apps.exec.models import ExecTemplate from apps.app.models import Deploy from apps.schedule.models import Task from apps.monitor.models import Detection @@ -117,6 +118,9 @@ class HostView(View): detection = Detection.objects.filter(type__in=('3', '4'), targets__regex=regex).first() if detection: return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机') + tpl = ExecTemplate.objects.filter(host_ids__regex=regex).first() + if tpl: + return json_response(error=f'执行模板【{tpl.name}】关联了该主机,请解除关联后再尝试删除该主机') Host.objects.filter(id__in=host_ids).delete() return json_response(error=error) -- Gitee From 393e36e0cfcd9812c307e6e9d34dde61f405eb21 Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:38:09 +0800 Subject: [PATCH 21/36] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=A8=A1=E6=9D=BF=E5=8F=AF=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E5=B7=B2=E9=80=89=E6=8B=A9=E7=9A=84=E4=B8=BB=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/exec/template/Form.js | 2 +- spug_web/src/pages/host/Selector.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/spug_web/src/pages/exec/template/Form.js b/spug_web/src/pages/exec/template/Form.js index c67c9b5..aa40bfa 100644 --- a/spug_web/src/pages/exec/template/Form.js +++ b/spug_web/src/pages/exec/template/Form.js @@ -135,7 +135,7 @@ export default observer(function () { - info.host_ids = ids}/> + info.host_ids = ids}/> diff --git a/spug_web/src/pages/host/Selector.js b/spug_web/src/pages/host/Selector.js index f2ab447..c424352 100644 --- a/spug_web/src/pages/host/Selector.js +++ b/spug_web/src/pages/host/Selector.js @@ -146,7 +146,7 @@ function HostSelector(props) { className={styles.modal} title={props.title || '主机列表'} onOk={handleSubmit} - okButtonProps={{disabled: selectedRowKeys.length === 0}} + okButtonProps={{disabled: selectedRowKeys.length === 0 && !props.nullable}} confirmLoading={loading} onCancel={handleClose}> @@ -209,6 +209,7 @@ HostSelector.defaultProps = { value: [], type: 'text', mode: 'ids', + nullable: false, onChange: () => null } -- Gitee From 29b8add6555d79430660e8066c66480e33f9a2c5 Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:39:47 +0800 Subject: [PATCH 22/36] =?UTF-8?q?Web=E7=BB=88=E7=AB=AF=E5=8F=AF=E7=82=B9?= =?UTF-8?q?=E5=87=BBlogo=E5=8C=BA=E5=9F=9F=E5=9C=A8=E6=96=B0=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E4=B8=AD=E6=89=93=E5=BC=80=E4=B8=BB=E6=9C=BA=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/ssh/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spug_web/src/pages/ssh/index.js b/spug_web/src/pages/ssh/index.js index df5525d..fed510b 100644 --- a/spug_web/src/pages/ssh/index.js +++ b/spug_web/src/pages/ssh/index.js @@ -221,9 +221,9 @@ function WebSSH(props) { return hasPermission('host.console.view|host.console.list') ? (
posX = 0} onMouseMove={handleMouseMove}>
-
+ logo -
+
} -- Gitee From cc6df9ca98553a3b36cc24ffda595261eb111e1f Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:40:32 +0800 Subject: [PATCH 23/36] =?UTF-8?q?Header=E5=A2=9E=E5=8A=A0web=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=E5=85=A5=E5=8F=A3=E5=B0=8F=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/layout/Header.js | 12 ++++++++++-- spug_web/src/layout/Notification.js | 6 +++--- spug_web/src/layout/avatar.png | Bin 12259 -> 1794 bytes spug_web/src/layout/layout.module.less | 20 +++++++++++++++----- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/spug_web/src/layout/Header.js b/spug_web/src/layout/Header.js index 628cc6d..efd3365 100644 --- a/spug_web/src/layout/Header.js +++ b/spug_web/src/layout/Header.js @@ -6,7 +6,8 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { Layout, Dropdown, Menu, Avatar } from 'antd'; -import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined } from '@ant-design/icons'; +import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined, CodeOutlined } from '@ant-design/icons'; +import { AuthDiv } from 'components'; import Notification from './Notification'; import styles from './layout.module.less'; import http from '../libs/http'; @@ -20,6 +21,10 @@ export default function (props) { http.get('/api/account/logout/') } + function openTerminal() { + window.open('/ssh') + } + const UserMenu = ( @@ -42,7 +47,10 @@ export default function (props) {
-
+ + + +
diff --git a/spug_web/src/layout/Notification.js b/spug_web/src/layout/Notification.js index 24395be..329544c 100644 --- a/spug_web/src/layout/Notification.js +++ b/spug_web/src/layout/Notification.js @@ -106,7 +106,7 @@ export default function () { const count = notifies.length - reads.length; return ( -
+
@@ -133,11 +133,11 @@ export default function () { )}> - +
0 ? count : 0}> - +
) diff --git a/spug_web/src/layout/avatar.png b/spug_web/src/layout/avatar.png index 64669bd69aba9b58a9f166123ad5ce166ce610bc..d8b1c8a606f7aa340a6634a2d3df680d8051d127 100644 GIT binary patch literal 1794 zcmV+d2mSboP)Px*yh%hsRCwC$SZkUNdJePo6w^^5n^rCr_R{dGh4RlP6D}h}7P@Rs0;a4|qS9^>4#TtW@=V zmx9r)_8m|j=B9M8XJ?94!EmT!rSPpQvz9hb2@*LiO2pkkDrN_?3xFul{B8-gUCHD;_x#Cwa_D7q%>Rmav- zaRI#buZfC{K_VU*7znEfzIn8WD$&G~0LD1);boL=G>@lrz_1R`-{wDK?#`}Wb=W|A z+H_WjM`>#Y_MV4*=aBx}1;Q*oC`|I12+^N748e`UV`4V1!}vopSLQC(&mWhm@l~aG z0~EN6jZtKr089OSELPSMH5TI=v5zPXPhmg)le*Ob8nie+3o}c&eds%cNE!GVUN6`f5C8w6d{j?DSJW-Y)3_&D)KC?BXEqO zv{4`CpYG~u99K=VdLk}^j1>$l6q5u77=|;jqA_8rI$8sli78mifN>qB=+WR&^N^5ZLS-D6_Z(Lg%Lr z=S^r?uTZ5fdcVj`L1GWR&FSM(kmZwuG+%`EF0cacB-c%WFR2AnYsLJ!kU_BW+qQj{ zzr9)O$yT=x^)>koiFARPMN^CLn9D>Uzn)(;Z{4{uNVVV0$ zc@UG3*>b>H51tGDNbhYTCgg8SZQ&wr*39P)MRs(4c>=p0q{_?4TaQyX%a^Ern7JI! zwi$!va_S^i@sz{#ovHYo3PJ6LK$@w~&S9RujC^d6+G+e_UY+ND6$v*xMfLB8x* zMY-aaIj!3u14X?V&nv6qsgs~pJquaZ(3B5U93_GccD!8z+%!5Y9gJC>M?|b98PAJt za@rIvCjw-oy;`QnYRp~7aw-LkfROfkS)_(Jn}k*-7sM7=%fv+SZlK)iT)l?$-zD}S z415YoZ8ZgxJ=n&$Jg=K#C)t4FST1j_DnCALOf)TbEx6B(0PtVnx1v~FxQ#x;LfF_n zUDi_-qK!RCS8Mhlw>w)a${GPS@3Hs_9VcdQxl;uDuH|;N!``Yd6dYr{-l zPiyuJ4-cC7DsF)Zv*t;)Oq@@xkA50mp5I9zTpF20Z8rkJ#f_e$H0(Wj^5n^rCr_R{ kdGh4RlP6D}JPix|2d2X^pN-``yZ`_I07*qoM6N<$g5mvJ7ytkO literal 12259 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 Date: Wed, 29 Mar 2023 18:41:36 +0800 Subject: [PATCH 24/36] =?UTF-8?q?=E7=9B=91=E6=8E=A7=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E5=9C=B0=E5=9D=80=E6=94=AF=E6=8C=81=E9=80=97?= =?UTF-8?q?=E5=8F=B7=E7=A9=BA=E6=A0=BC=E8=87=AA=E5=8A=A8=E5=88=86=E9=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/monitor/Step1.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spug_web/src/pages/monitor/Step1.js b/spug_web/src/pages/monitor/Step1.js index 007cb2b..9c14ac2 100644 --- a/spug_web/src/pages/monitor/Step1.js +++ b/spug_web/src/pages/monitor/Step1.js @@ -83,7 +83,7 @@ export default observer(function () { } function getStyle(t) { - return t.includes(store.record.type) ? {display: 'flex'} : {display: 'none'} + return t.includes(store.record.type) ? {} : {display: 'none'} } const {name, desc, type, targets, extra, group} = store.record; @@ -117,6 +117,7 @@ export default observer(function () { store.record.targets = v} placeholder="IP或域名,支持多个地址,每输入完成一个后按回车确认" notFoundContent={null}/> -- Gitee From a283c34b475f266f031c49cb7619e96f412f9e44 Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:43:51 +0800 Subject: [PATCH 25/36] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E9=80=89=E6=8B=A9=E5=BA=94=E7=94=A8=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/components/AppSelector.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spug_web/src/components/AppSelector.js b/spug_web/src/components/AppSelector.js index 6777afa..add1539 100644 --- a/spug_web/src/components/AppSelector.js +++ b/spug_web/src/components/AppSelector.js @@ -56,9 +56,8 @@ export default observer(function AppSelector(props) { mode="inline" selectedKeys={[String(env_id)]} style={{border: 'none'}} - onSelect={({selectedKeys}) => setEnvId(selectedKeys[0])}> - {envStore.records.map(item => {item.name})} - + items={envStore.records.map(x => ({key: x.id, label: x.name, title: x.name}))} + onSelect={({selectedKeys}) => setEnvId(selectedKeys[0])}/>
-- Gitee From a891b0989d4dc75faab7d556373cdc2e814bc34e Mon Sep 17 00:00:00 2001 From: vapao Date: Wed, 29 Mar 2023 18:44:38 +0800 Subject: [PATCH 26/36] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=94=AF=E6=8C=81=E6=92=A4=E9=94=80=E4=B8=BB?= =?UTF-8?q?=E6=9C=BA=E6=8E=88=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/system/role/HostPerm.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spug_web/src/pages/system/role/HostPerm.js b/spug_web/src/pages/system/role/HostPerm.js index 4a2e93d..6287a5c 100644 --- a/spug_web/src/pages/system/role/HostPerm.js +++ b/spug_web/src/pages/system/role/HostPerm.js @@ -59,6 +59,7 @@ export default observer(function () {
Date: Wed, 29 Mar 2023 18:47:43 +0800 Subject: [PATCH 27/36] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9F=90=E4=BA=9B?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E4=B8=BB=E6=9C=BA=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6=E6=9C=AA=E5=B1=95=E7=A4=BA=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spug_web/src/pages/host/Selector.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spug_web/src/pages/host/Selector.js b/spug_web/src/pages/host/Selector.js index c424352..54b750d 100644 --- a/spug_web/src/pages/host/Selector.js +++ b/spug_web/src/pages/host/Selector.js @@ -24,7 +24,7 @@ function HostSelector(props) { hStore.initial().then(() => { store.rawRecords = hStore.rawRecords; store.rawTreeData = hStore.rawTreeData; - store.group = store.treeData[0] + store.group = store.treeData[0] || {} }) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) @@ -166,7 +166,7 @@ function HostSelector(props) {
- store.f_word = e.target.value}/>