- 增加资产附加属性功能
This commit is contained in:
parent
4085677c5a
commit
622fa65241
3
main.go
3
main.go
@ -122,6 +122,9 @@ func Run() error {
|
|||||||
if err := global.DB.AutoMigrate(&model.Asset{}); err != nil {
|
if err := global.DB.AutoMigrate(&model.Asset{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := global.DB.AutoMigrate(&model.AssetAttribute{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := global.DB.AutoMigrate(&model.Session{}); err != nil {
|
if err := global.DB.AutoMigrate(&model.Session{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,31 @@ func AssetUpdateEndpoint(c echo.Context) error {
|
|||||||
return Success(c, nil)
|
return Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AssetGetAttributeEndpoint(c echo.Context) error {
|
||||||
|
|
||||||
|
assetId := c.Param("id")
|
||||||
|
attributeMap, err := model.FindAssetAttrMapByAssetId(assetId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return Success(c, attributeMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AssetUpdateAttributeEndpoint(c echo.Context) error {
|
||||||
|
m := echo.Map{}
|
||||||
|
if err := c.Bind(&m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
assetId := c.Param("id")
|
||||||
|
protocol := c.QueryParam("protocol")
|
||||||
|
err := model.UpdateAssetAttributes(assetId, protocol, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return Success(c, "")
|
||||||
|
}
|
||||||
|
|
||||||
func AssetDeleteEndpoint(c echo.Context) error {
|
func AssetDeleteEndpoint(c echo.Context) error {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
split := strings.Split(id, ",")
|
split := strings.Split(id, ",")
|
||||||
|
@ -74,6 +74,8 @@ func SetupRoutes() *echo.Echo {
|
|||||||
assets.GET("/paging", AssetPagingEndpoint)
|
assets.GET("/paging", AssetPagingEndpoint)
|
||||||
assets.POST("/:id/tcping", AssetTcpingEndpoint)
|
assets.POST("/:id/tcping", AssetTcpingEndpoint)
|
||||||
assets.PUT("/:id", AssetUpdateEndpoint)
|
assets.PUT("/:id", AssetUpdateEndpoint)
|
||||||
|
assets.GET("/:id/attributes", AssetGetAttributeEndpoint)
|
||||||
|
assets.PUT("/:id/attributes", AssetUpdateAttributeEndpoint)
|
||||||
assets.DELETE("/:id", AssetDeleteEndpoint)
|
assets.DELETE("/:id", AssetDeleteEndpoint)
|
||||||
assets.GET("/:id", AssetGetEndpoint)
|
assets.GET("/:id", AssetGetEndpoint)
|
||||||
assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint))
|
assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint))
|
||||||
|
@ -124,6 +124,15 @@ func TunEndpoint(c echo.Context) error {
|
|||||||
|
|
||||||
configuration.SetParameter("hostname", session.IP)
|
configuration.SetParameter("hostname", session.IP)
|
||||||
configuration.SetParameter("port", strconv.Itoa(session.Port))
|
configuration.SetParameter("port", strconv.Itoa(session.Port))
|
||||||
|
|
||||||
|
// 加载资产配置的属性,优先级比全局配置的高,因此最后加载,覆盖掉全局配置
|
||||||
|
attributes, _ := model.FindAssetAttributeByAssetId(session.AssetId)
|
||||||
|
if len(attributes) > 0 {
|
||||||
|
for i := range attributes {
|
||||||
|
attribute := attributes[i]
|
||||||
|
configuration.SetParameter(attribute.Name, attribute.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for name := range configuration.Parameters {
|
for name := range configuration.Parameters {
|
||||||
// 替换数据库空格字符串占位符为真正的空格
|
// 替换数据库空格字符串占位符为真正的空格
|
||||||
|
@ -18,6 +18,8 @@ const (
|
|||||||
FontName = "font-name"
|
FontName = "font-name"
|
||||||
FontSize = "font-size"
|
FontSize = "font-size"
|
||||||
ColorScheme = "color-scheme"
|
ColorScheme = "color-scheme"
|
||||||
|
Backspace = "backspace"
|
||||||
|
TerminalType = "terminal-type"
|
||||||
|
|
||||||
EnableDrive = "enable-drive"
|
EnableDrive = "enable-drive"
|
||||||
DriveName = "drive-name"
|
DriveName = "drive-name"
|
||||||
@ -31,6 +33,17 @@ const (
|
|||||||
DisableBitmapCaching = "disable-bitmap-caching"
|
DisableBitmapCaching = "disable-bitmap-caching"
|
||||||
DisableOffscreenCaching = "disable-offscreen-caching"
|
DisableOffscreenCaching = "disable-offscreen-caching"
|
||||||
DisableGlyphCaching = "disable-glyph-caching"
|
DisableGlyphCaching = "disable-glyph-caching"
|
||||||
|
|
||||||
|
ColorDepth = "color-depth"
|
||||||
|
Cursor = "cursor"
|
||||||
|
SwapRedBlue = "swap-red-blue"
|
||||||
|
DestHost = "dest-host"
|
||||||
|
DestPort = "dest-port"
|
||||||
|
|
||||||
|
UsernameRegex = "username-regex"
|
||||||
|
PasswordRegex = "password-regex"
|
||||||
|
LoginSuccessRegex = "login-success-regex"
|
||||||
|
LoginFailureRegex = "login-failure-regex"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Delimiter = ';'
|
const Delimiter = ';'
|
||||||
|
@ -1 +1,108 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"next-terminal/pkg/global"
|
||||||
|
"next-terminal/pkg/guacd"
|
||||||
|
"next-terminal/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AssetAttribute struct {
|
||||||
|
Id string `gorm:"index" json:"id"`
|
||||||
|
AssetId string `gorm:"index" json:"assetId"`
|
||||||
|
Name string `gorm:"index" json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AssetAttribute) TableName() string {
|
||||||
|
return "asset_attributes"
|
||||||
|
}
|
||||||
|
|
||||||
|
var SSHParameterNames = []string{guacd.FontName, guacd.FontSize, guacd.ColorScheme, guacd.Backspace, guacd.TerminalType}
|
||||||
|
var RDPParameterNames = []string{guacd.EnableWallpaper, guacd.EnableTheming, guacd.EnableFontSmoothing, guacd.EnableFullWindowDrag, guacd.EnableDesktopComposition, guacd.EnableMenuAnimations, guacd.DisableBitmapCaching, guacd.DisableOffscreenCaching, guacd.DisableGlyphCaching}
|
||||||
|
var VNCParameterNames = []string{guacd.ColorDepth, guacd.Cursor, guacd.SwapRedBlue, guacd.DestHost, guacd.DestPort}
|
||||||
|
var TelnetParameterNames = []string{guacd.FontName, guacd.FontSize, guacd.ColorScheme, guacd.Backspace, guacd.TerminalType, guacd.UsernameRegex, guacd.PasswordRegex, guacd.LoginSuccessRegex, guacd.LoginFailureRegex}
|
||||||
|
|
||||||
|
func UpdateAssetAttributes(assetId, protocol string, m echo.Map) error {
|
||||||
|
var data []AssetAttribute
|
||||||
|
var parameterNames []string
|
||||||
|
switch protocol {
|
||||||
|
case "ssh":
|
||||||
|
parameterNames = SSHParameterNames
|
||||||
|
case "rdp":
|
||||||
|
parameterNames = RDPParameterNames
|
||||||
|
case "vnc":
|
||||||
|
parameterNames = VNCParameterNames
|
||||||
|
case "telnet":
|
||||||
|
parameterNames = TelnetParameterNames
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range parameterNames {
|
||||||
|
name := parameterNames[i]
|
||||||
|
if m[name] != nil && m[name] != "" {
|
||||||
|
data = append(data, genAttribute(assetId, name, m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
err := tx.Where("asset_id = ?", assetId).Delete(&AssetAttribute{}).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.CreateInBatches(&data, len(data)).Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func genAttribute(assetId, name string, m echo.Map) AssetAttribute {
|
||||||
|
value := fmt.Sprintf("%v", m[name])
|
||||||
|
attribute := AssetAttribute{
|
||||||
|
Id: utils.Sign([]string{assetId, name}),
|
||||||
|
AssetId: assetId,
|
||||||
|
Name: name,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
return attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindAssetAttributeByAssetId(assetId string) (o []AssetAttribute, err error) {
|
||||||
|
err = global.DB.Where("asset_id = ?", assetId).Find(&o).Error
|
||||||
|
if o == nil {
|
||||||
|
o = make([]AssetAttribute, 0)
|
||||||
|
}
|
||||||
|
return o, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindAssetAttrMapByAssetId(assetId string) (map[string]interface{}, error) {
|
||||||
|
asset, err := FindAssetById(assetId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
attributes, err := FindAssetAttributeByAssetId(assetId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameterNames []string
|
||||||
|
switch asset.Protocol {
|
||||||
|
case "ssh":
|
||||||
|
parameterNames = SSHParameterNames
|
||||||
|
case "rdp":
|
||||||
|
parameterNames = RDPParameterNames
|
||||||
|
case "vnc":
|
||||||
|
parameterNames = VNCParameterNames
|
||||||
|
}
|
||||||
|
propertiesMap := FindAllPropertiesMap()
|
||||||
|
var attributeMap = make(map[string]interface{})
|
||||||
|
for name := range propertiesMap {
|
||||||
|
if utils.Contains(parameterNames, name) {
|
||||||
|
attributeMap[name] = propertiesMap[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range attributes {
|
||||||
|
attributeMap[attributes[i].Name] = attributes[i].Value
|
||||||
|
}
|
||||||
|
return attributeMap, nil
|
||||||
|
}
|
||||||
|
@ -40,6 +40,10 @@ import {
|
|||||||
import {PROTOCOL_COLORS} from "../../common/constants";
|
import {PROTOCOL_COLORS} from "../../common/constants";
|
||||||
import Logout from "../user/Logout";
|
import Logout from "../user/Logout";
|
||||||
import {hasPermission, isAdmin} from "../../service/permission";
|
import {hasPermission, isAdmin} from "../../service/permission";
|
||||||
|
import AssetSSHAttributeModal from "./AssetSSHAttributeModal";
|
||||||
|
import AssetRDPAttributeModal from "./AssetRDPAttributeModal";
|
||||||
|
import AssetVNCAttributeModal from "./AssetVNCAttributeModal";
|
||||||
|
import AssetTelnetAttributeModal from "./AssetTelnetAttributeModal";
|
||||||
|
|
||||||
const confirm = Modal.confirm;
|
const confirm = Modal.confirm;
|
||||||
const {Search} = Input;
|
const {Search} = Input;
|
||||||
@ -85,6 +89,8 @@ class Asset extends Component {
|
|||||||
users: [],
|
users: [],
|
||||||
selected: {},
|
selected: {},
|
||||||
selectedSharers: [],
|
selectedSharers: [],
|
||||||
|
attrVisible: false,
|
||||||
|
attributes: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
@ -224,6 +230,34 @@ class Asset extends Component {
|
|||||||
await this.showModal('复制资产', result.data);
|
await this.showModal('复制资产', result.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async attr(record) {
|
||||||
|
let result = await request.get(`/assets/${record['id']}/attributes`);
|
||||||
|
if (result.code !== 1) {
|
||||||
|
message.error(result.message, 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-extend-native
|
||||||
|
String.prototype.bool = function () {
|
||||||
|
return (/^true$/i).test(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
let attributes = result['data'];
|
||||||
|
for (const key in attributes) {
|
||||||
|
if (!attributes.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (key === 'swap-red-blue') {
|
||||||
|
attributes[key] = attributes[key].bool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selected: record,
|
||||||
|
attrVisible: true,
|
||||||
|
attributes: attributes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async showModal(title, asset = {}) {
|
async showModal(title, asset = {}) {
|
||||||
// 并行请求
|
// 并行请求
|
||||||
let getCredentials = request.get('/credentials');
|
let getCredentials = request.get('/credentials');
|
||||||
@ -413,6 +447,38 @@ class Asset extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUpdateAttr = async (formData) => {
|
||||||
|
// 弹窗 form 传来的数据
|
||||||
|
this.setState({
|
||||||
|
modalConfirmLoading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
let selected = this.state.selected;
|
||||||
|
let result = await request.put(`/assets/${selected['id']}/attributes?protocol=${selected['protocol']}`, formData);
|
||||||
|
if (result['code'] !== 1) {
|
||||||
|
message.error(result['message'], 10);
|
||||||
|
} else {
|
||||||
|
message.success('操作成功');
|
||||||
|
this.setState({
|
||||||
|
attrVisible: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.setState({
|
||||||
|
modalConfirmLoading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancelUpdateAttr = () => {
|
||||||
|
this.setState({
|
||||||
|
attrVisible: false,
|
||||||
|
selected: {},
|
||||||
|
attributes: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const columns = [{
|
const columns = [{
|
||||||
@ -484,8 +550,14 @@ class Asset extends Component {
|
|||||||
onClick={() => this.copy(record.id)}>复制</Button>
|
onClick={() => this.copy(record.id)}>复制</Button>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
||||||
{isAdmin() ?
|
|
||||||
<Menu.Item key="3">
|
<Menu.Item key="3">
|
||||||
|
<Button type="text" size='small'
|
||||||
|
disabled={!hasPermission(record['owner'])}
|
||||||
|
onClick={() => this.attr(record)}>属性</Button>
|
||||||
|
</Menu.Item>
|
||||||
|
|
||||||
|
{isAdmin() ?
|
||||||
|
<Menu.Item key="4">
|
||||||
<Button type="text" size='small'
|
<Button type="text" size='small'
|
||||||
disabled={!hasPermission(record['owner'])}
|
disabled={!hasPermission(record['owner'])}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -507,7 +579,7 @@ class Asset extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<Menu.Item key="4">
|
<Menu.Item key="5">
|
||||||
<Button type="text" size='small'
|
<Button type="text" size='small'
|
||||||
disabled={!hasPermission(record['owner'])}
|
disabled={!hasPermission(record['owner'])}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
@ -516,7 +588,7 @@ class Asset extends Component {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
||||||
<Menu.Divider/>
|
<Menu.Divider/>
|
||||||
<Menu.Item key="5">
|
<Menu.Item key="6">
|
||||||
<Button type="text" size='small' danger
|
<Button type="text" size='small' danger
|
||||||
disabled={!hasPermission(record['owner'])}
|
disabled={!hasPermission(record['owner'])}
|
||||||
onClick={() => this.showDeleteConfirm(record.id, record.name)}>删除</Button>
|
onClick={() => this.showDeleteConfirm(record.id, record.name)}>删除</Button>
|
||||||
@ -692,7 +764,6 @@ class Asset extends Component {
|
|||||||
{
|
{
|
||||||
this.state.modalVisible ?
|
this.state.modalVisible ?
|
||||||
<AssetModal
|
<AssetModal
|
||||||
modalFormRef={this.modalFormRef}
|
|
||||||
visible={this.state.modalVisible}
|
visible={this.state.modalVisible}
|
||||||
title={this.state.modalTitle}
|
title={this.state.modalTitle}
|
||||||
handleOk={this.handleOk}
|
handleOk={this.handleOk}
|
||||||
@ -823,6 +894,49 @@ class Asset extends Component {
|
|||||||
</Modal> : undefined
|
</Modal> : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.attrVisible && this.state.selected['protocol'] === 'ssh' ?
|
||||||
|
<AssetSSHAttributeModal
|
||||||
|
handleOk={this.handleUpdateAttr}
|
||||||
|
handleCancel={this.handleCancelUpdateAttr}
|
||||||
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
|
attributes={this.state.attributes}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.attrVisible && this.state.selected['protocol'] === 'rdp' ?
|
||||||
|
<AssetRDPAttributeModal
|
||||||
|
handleOk={this.handleUpdateAttr}
|
||||||
|
handleCancel={this.handleCancelUpdateAttr}
|
||||||
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
|
attributes={this.state.attributes}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.attrVisible && this.state.selected['protocol'] === 'vnc' ?
|
||||||
|
<AssetVNCAttributeModal
|
||||||
|
handleOk={this.handleUpdateAttr}
|
||||||
|
handleCancel={this.handleCancelUpdateAttr}
|
||||||
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
|
attributes={this.state.attributes}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.attrVisible && this.state.selected['protocol'] === 'telnet' ?
|
||||||
|
<AssetTelnetAttributeModal
|
||||||
|
handleOk={this.handleUpdateAttr}
|
||||||
|
handleCancel={this.handleCancelUpdateAttr}
|
||||||
|
confirmLoading={this.state.modalConfirmLoading}
|
||||||
|
attributes={this.state.attributes}
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
</Content>
|
</Content>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
205
web/src/components/asset/AssetRDPAttributeModal.js
Normal file
205
web/src/components/asset/AssetRDPAttributeModal.js
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Collapse, Form, Input, Modal, Switch, Tooltip, Typography} from "antd/lib/index";
|
||||||
|
import {ExclamationCircleOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const {Panel} = Collapse;
|
||||||
|
const formLayout = {
|
||||||
|
labelCol: {span: 6},
|
||||||
|
wrapperCol: {span: 14},
|
||||||
|
};
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {span: 12},
|
||||||
|
wrapperCol: {span: 12},
|
||||||
|
};
|
||||||
|
|
||||||
|
const AssetRDPAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={'属性'}
|
||||||
|
visible={true}
|
||||||
|
maskClosable={false}
|
||||||
|
centered={true}
|
||||||
|
onOk={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then(values => {
|
||||||
|
form.resetFields();
|
||||||
|
handleOk(values);
|
||||||
|
})
|
||||||
|
.catch(info => {
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
confirmLoading={confirmLoading}
|
||||||
|
okText='确定'
|
||||||
|
cancelText='取消'
|
||||||
|
>
|
||||||
|
|
||||||
|
<Form form={form} {...formLayout} initialValues={attributes}>
|
||||||
|
|
||||||
|
<Collapse defaultActiveKey={['remote-app']} ghost>
|
||||||
|
<Panel header={<Text strong>Remote App</Text>} key="remote-app">
|
||||||
|
<Form.Item
|
||||||
|
name="remote-app"
|
||||||
|
label={<Tooltip title="指定在远程桌面上启动的RemoteApp。
|
||||||
|
如果您的远程桌面服务器支持该应用程序,则该应用程序(且仅该应用程序)对用户可见。
|
||||||
|
|
||||||
|
Windows需要对远程应用程序的名称使用特殊的符号。
|
||||||
|
远程应用程序的名称必须以两个竖条作为前缀。
|
||||||
|
例如,如果您已经在您的服务器上为notepad.exe创建了一个远程应用程序,并将其命名为“notepad”,则您将该参数设置为:“||notepad”。">
|
||||||
|
程序 <ExclamationCircleOutlined/>
|
||||||
|
</Tooltip>}
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="remote app"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="remote-app-dir"
|
||||||
|
label={<Tooltip title="remote app的工作目录,如果未配置remote app,此参数无效。">工作目录
|
||||||
|
<ExclamationCircleOutlined/></Tooltip>}
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="remote app的工作目录"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="remote-app-args"
|
||||||
|
label={<Tooltip title="remote app的命令行参数,如果未配置remote app,此参数无效。">参数
|
||||||
|
<ExclamationCircleOutlined/></Tooltip>}
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="remote app的命令行参数"/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
<Panel header={<Text strong>性能</Text>} key="2">
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-wallpaper"
|
||||||
|
label="启用桌面墙纸"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-theming"
|
||||||
|
label="启用桌面主题"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-font-smoothing"
|
||||||
|
label="启用字体平滑(ClearType)"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-full-window-drag"
|
||||||
|
label="启用全窗口拖拽"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-desktop-composition"
|
||||||
|
label="启用桌面合成效果(Aero)"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="enable-menu-animations"
|
||||||
|
label="启用菜单动画"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="disable-bitmap-caching"
|
||||||
|
label="禁用位图缓存"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="disable-offscreen-caching"
|
||||||
|
label="禁用离屏缓存"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="disable-glyph-caching"
|
||||||
|
label="禁用字形缓存"
|
||||||
|
valuePropName="checked"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
</Collapse>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssetRDPAttributeModal;
|
107
web/src/components/asset/AssetSSHAttributeModal.js
Normal file
107
web/src/components/asset/AssetSSHAttributeModal.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Collapse, Form, Input, Modal, Select, Typography} from "antd/lib/index";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {Panel} = Collapse;
|
||||||
|
const {Text} = Typography;
|
||||||
|
|
||||||
|
const AssetSSHAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {span: 6},
|
||||||
|
wrapperCol: {span: 14},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={'属性'}
|
||||||
|
visible={true}
|
||||||
|
maskClosable={false}
|
||||||
|
centered={true}
|
||||||
|
onOk={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then(values => {
|
||||||
|
form.resetFields();
|
||||||
|
handleOk(values);
|
||||||
|
})
|
||||||
|
.catch(info => {
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
confirmLoading={confirmLoading}
|
||||||
|
okText='确定'
|
||||||
|
cancelText='取消'
|
||||||
|
>
|
||||||
|
|
||||||
|
<Form form={form} {...formItemLayout} initialValues={attributes}>
|
||||||
|
<Collapse defaultActiveKey={['显示设置']} ghost>
|
||||||
|
<Panel header={<Text strong>显示设置</Text>} key="显示设置">
|
||||||
|
<Form.Item
|
||||||
|
name="color-scheme"
|
||||||
|
label="配色方案"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="gray-black">黑底灰字</Option>
|
||||||
|
<Option value="green-black">黑底绿字</Option>
|
||||||
|
<Option value="white-black">黑底白字</Option>
|
||||||
|
<Option value="black-white">白底黑字</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="font-name"
|
||||||
|
label="字体名称"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="为空时使用系统默认字体"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="font-size"
|
||||||
|
label="字体大小"
|
||||||
|
>
|
||||||
|
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
<Panel header={<Text strong>控制终端行为</Text>} key="控制终端行为">
|
||||||
|
<Form.Item
|
||||||
|
name="backspace"
|
||||||
|
label="退格键映射"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="string:127">删除键(Ctrl-?)</Option>
|
||||||
|
<Option value="string:8">退格键(Ctrl-H)</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="terminal-type"
|
||||||
|
label="终端类型"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="ansi">ansi</Option>
|
||||||
|
<Option value="linux">linux</Option>
|
||||||
|
<Option value="vt100">vt100</Option>
|
||||||
|
<Option value="vt220">vt220</Option>
|
||||||
|
<Option value="xterm">xterm</Option>
|
||||||
|
<Option value="xterm-256color">xterm-256color</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssetSSHAttributeModal;
|
133
web/src/components/asset/AssetTelnetAttributeModal.js
Normal file
133
web/src/components/asset/AssetTelnetAttributeModal.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Collapse, Form, Input, Modal, Select, Typography} from "antd/lib/index";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {Panel} = Collapse;
|
||||||
|
const {Text} = Typography;
|
||||||
|
|
||||||
|
const AssetTelnetAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {span: 8},
|
||||||
|
wrapperCol: {span: 14},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={'属性'}
|
||||||
|
visible={true}
|
||||||
|
maskClosable={false}
|
||||||
|
centered={true}
|
||||||
|
onOk={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then(values => {
|
||||||
|
form.resetFields();
|
||||||
|
handleOk(values);
|
||||||
|
})
|
||||||
|
.catch(info => {
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
confirmLoading={confirmLoading}
|
||||||
|
okText='确定'
|
||||||
|
cancelText='取消'
|
||||||
|
>
|
||||||
|
|
||||||
|
<Form form={form} {...formItemLayout} initialValues={attributes}>
|
||||||
|
<Collapse defaultActiveKey={['认证']} ghost>
|
||||||
|
<Panel header={<Text strong>认证</Text>} key="认证">
|
||||||
|
<Form.Item
|
||||||
|
name="username-regex"
|
||||||
|
label="用户名正则表达式"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder=""/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="password-regex"
|
||||||
|
label="密码正则表达式"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder=""/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="login-success-regex"
|
||||||
|
label="登录成功正则表达式"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder=""/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="login-failure-regex"
|
||||||
|
label="登录失败正则表达式"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder=""/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
<Panel header={<Text strong>显示设置</Text>} key="显示设置">
|
||||||
|
<Form.Item
|
||||||
|
name="color-scheme"
|
||||||
|
label="配色方案"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="gray-black">黑底灰字</Option>
|
||||||
|
<Option value="green-black">黑底绿字</Option>
|
||||||
|
<Option value="white-black">黑底白字</Option>
|
||||||
|
<Option value="black-white">白底黑字</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="font-name"
|
||||||
|
label="字体名称"
|
||||||
|
>
|
||||||
|
<Input type='text' placeholder="为空时使用系统默认字体"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="font-size"
|
||||||
|
label="字体大小"
|
||||||
|
>
|
||||||
|
<Input type='number' placeholder="为空时使用系统默认字体大小" min={8} max={96}/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
<Panel header={<Text strong>控制终端行为</Text>} key="控制终端行为">
|
||||||
|
<Form.Item
|
||||||
|
name="backspace"
|
||||||
|
label="退格键映射"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="string:127">删除键(Ctrl-?)</Option>
|
||||||
|
<Option value="string:8">退格键(Ctrl-H)</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="terminal-type"
|
||||||
|
label="终端类型"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="ansi">ansi</Option>
|
||||||
|
<Option value="linux">linux</Option>
|
||||||
|
<Option value="vt100">vt100</Option>
|
||||||
|
<Option value="vt220">vt220</Option>
|
||||||
|
<Option value="xterm">xterm</Option>
|
||||||
|
<Option value="xterm-256color">xterm-256color</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssetTelnetAttributeModal;
|
97
web/src/components/asset/AssetVNCAttributeModal.js
Normal file
97
web/src/components/asset/AssetVNCAttributeModal.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Collapse, Form, Input, Modal, Select, Switch, Tooltip, Typography} from "antd/lib/index";
|
||||||
|
import {ExclamationCircleOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {Panel} = Collapse;
|
||||||
|
const formLayout = {
|
||||||
|
labelCol: {span: 6},
|
||||||
|
wrapperCol: {span: 14},
|
||||||
|
};
|
||||||
|
|
||||||
|
const AssetRDPAttributeModal = function ({handleOk, handleCancel, confirmLoading, attributes}) {
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={'属性'}
|
||||||
|
visible={true}
|
||||||
|
maskClosable={false}
|
||||||
|
centered={true}
|
||||||
|
onOk={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then(values => {
|
||||||
|
form.resetFields();
|
||||||
|
handleOk(values);
|
||||||
|
})
|
||||||
|
.catch(info => {
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
confirmLoading={confirmLoading}
|
||||||
|
okText='确定'
|
||||||
|
cancelText='取消'
|
||||||
|
>
|
||||||
|
|
||||||
|
<Form form={form} {...formLayout} initialValues={attributes}>
|
||||||
|
|
||||||
|
<Collapse defaultActiveKey={['显示设置']} ghost>
|
||||||
|
<Panel header={<Text strong>显示设置</Text>} key="显示设置">
|
||||||
|
<Form.Item
|
||||||
|
name="color-depth"
|
||||||
|
label="色彩深度"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="string:16">低色(16位)</Option>
|
||||||
|
<Option value="string:24">真彩(24位)</Option>
|
||||||
|
<Option value="string:32">真彩(32位)</Option>
|
||||||
|
<Option value="string:8">256色</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="cursor"
|
||||||
|
label="光标"
|
||||||
|
initialValue=""
|
||||||
|
>
|
||||||
|
<Select onChange={null}>
|
||||||
|
<Option value="">默认</Option>
|
||||||
|
<Option value="string:local">本地</Option>
|
||||||
|
<Option value="string:remote">远程</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="swap-red-blue"
|
||||||
|
label="交换红蓝成分"
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="开启" unCheckedChildren="关闭"/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
<Panel header={<Text strong>VNC中继</Text>} key="2">
|
||||||
|
<Form.Item label={<Tooltip title="连接到VNC代理(例如UltraVNC Repeater)时要请求的目标主机。">目标主机
|
||||||
|
<ExclamationCircleOutlined/></Tooltip>}
|
||||||
|
name='dest-host'>
|
||||||
|
<Input placeholder="目标主机"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={<Tooltip title="连接到VNC代理(例如UltraVNC Repeater)时要请求的目标端口。">目标端口
|
||||||
|
<ExclamationCircleOutlined/></Tooltip>}
|
||||||
|
name='dest-port'>
|
||||||
|
<Input type='number' min={1} max={65535}
|
||||||
|
placeholder='目标端口'/>
|
||||||
|
</Form.Item>
|
||||||
|
</Panel>
|
||||||
|
</Collapse>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssetRDPAttributeModal;
|
@ -312,6 +312,26 @@ class Setting extends Component {
|
|||||||
|
|
||||||
<Title level={3}>SSH配置</Title>
|
<Title level={3}>SSH配置</Title>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
{...formItemLayout}
|
||||||
|
name="color-scheme"
|
||||||
|
label="配色方案"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '配色方案',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
initialValue="gray-black"
|
||||||
|
>
|
||||||
|
<Select style={{width: 120}} onChange={null}>
|
||||||
|
<Option value="gray-black">黑底灰字</Option>
|
||||||
|
<Option value="green-black">黑底绿字</Option>
|
||||||
|
<Option value="white-black">黑底白字</Option>
|
||||||
|
<Option value="black-white">白底黑字</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...formItemLayout}
|
{...formItemLayout}
|
||||||
name="font-name"
|
name="font-name"
|
||||||
@ -340,26 +360,6 @@ class Setting extends Component {
|
|||||||
<Input type='number' placeholder="请输入字体大小"/>
|
<Input type='number' placeholder="请输入字体大小"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
{...formItemLayout}
|
|
||||||
name="color-scheme"
|
|
||||||
label="颜色主题"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '颜色主题',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
initialValue="gray-black"
|
|
||||||
>
|
|
||||||
<Select style={{width: 120}} onChange={null}>
|
|
||||||
<Option value="gray-black">黑底灰字</Option>
|
|
||||||
<Option value="green-black">黑底绿字</Option>
|
|
||||||
<Option value="white-black">黑底白字</Option>
|
|
||||||
<Option value="black-white">白底黑字</Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item {...formTailLayout}>
|
<Form.Item {...formTailLayout}>
|
||||||
<Button type="primary" htmlType="submit">
|
<Button type="primary" htmlType="submit">
|
||||||
更新
|
更新
|
||||||
|
Loading…
Reference in New Issue
Block a user