Compare commits

..

371 Commits

Author SHA1 Message Date
ibuler
1e777ea67d perf: remove check 2024-12-10 17:28:58 +08:00
ibuler
a290e15b90 perf: 修改抽屉,传递动作 2023-11-08 19:18:49 +08:00
“huailei000”
b47f396cd4 perf: 详情暂时不显示更新按钮 2023-11-08 18:22:35 +08:00
“huailei000”
085554ef7f perf: 优化资产授权报错 2023-11-08 17:15:05 +08:00
feng
a62884564c perf: 在线用户根据websocket添加用户是否活跃状态 2023-11-08 17:03:01 +08:00
fit2bot
a9c0d0677c feat: 右侧抽屉创建 (#3436)
* stash

* perf: 验证用户和网域

* perf: 优化 drawer

* perf: 优化创建后 list reload

* perf: 优化创建

* perf: 替换账号管理相关页面创建、更新组件

* perf: 替换权限管理相关页面组件

* perf: 优化资产这里

* perf: 修改 reload

* perf: 替换权限管理-用户登录页面组件

* perf: 修改资产这里

* perf: 优化一点

* perf: 优化平台列表创建、更新抽屉组件不能正常显示问题

* perf: 优化平台列表创建时表单初始化数据不准确问题

* perf: 优化创建、更新平台表单报错问题

* perf: 优化列表克隆问题

* perf: 优化创建资产时抽屉组件偶尔不显示问题

* perf: 优化工作台创建、更新组件

* perf: GenericCreateUpdateDrawer 组件增加参数visible控制显示隐藏

* perf: 优化visible判断

* perf: 优化资产创建、更新

* perf: 增加el-drawer组件补丁,防止在抽屉里复制拖拽至遮罩层会使抽屉关闭问题

* perf: 优化角色列表创建、更新报错问题;优化关闭抽屉控制台报错问题

* perf: 优化作业管理创建、更新

* perf: 优化工单创建

* perf: 优化远程应用创建、更新

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: wangruidong <940853815@qq.com>
Co-authored-by: huailei <31801270+huailei000@users.noreply.github.com>
2023-11-08 11:21:39 +08:00
“huailei000”
5449d74d53 perf: 优化select2组件远程搜索结果为空时是否开启远程搜索状态没有动态更新问题;创建工单搜索资产时不显示问题 2023-11-08 10:21:15 +08:00
jiangweidong
dc401f80b9 fix: 解决更新云同步任务时,优先级无法更新问题 2023-11-07 17:18:45 +08:00
wangruidong
379cd2386a perf: 账号备份增加sftp方式 2023-11-07 15:37:04 +08:00
wangruidong
4e7bdb9c69 perf: 对象存储增加sftp 2023-11-07 15:37:04 +08:00
feng626
41449fb538 Merge pull request #3485 from jumpserver/pr@dev@gather_account
feat: 账号收集添加资产账号信息变化通知
2023-11-07 13:00:45 +08:00
feng626
a75488217c Merge pull request #3495 from jumpserver/pr@dev@su_from
fix: 账号 切换自 翻译修复
2023-11-07 11:09:18 +08:00
feng
8e32792696 fix: 账号 切换自 翻译修复 2023-11-07 11:08:28 +08:00
feng626
b47caf0287 Merge pull request #3493 from jumpserver/pr@dev@account_change_push
fix: 改密 推送 详情里执行任务的权限不对
2023-11-06 18:05:39 +08:00
feng
715ae856f0 fix: 改密 推送 详情里执行任务的权限不对 2023-11-06 18:01:39 +08:00
“huailei000”
19ae27e6c2 perf: ztree父节点是选中状态,点击展开后子节点默认显示选中状态 2023-11-06 16:22:11 +08:00
halo
2132bacff5 feat: 工作台支持配置显示系统工具 2023-11-03 17:34:14 +08:00
老广
e57c5a20d0 Merge pull request #3487 from jumpserver/pr@dev@perf_add_ip_group_access
perf: 更新字段修改
2023-11-02 15:39:48 +08:00
老广
3d35f0aafe Merge pull request #3488 from jumpserver/pr@dev@perf_tag_input
perf: 优化 tab input
2023-11-02 15:38:52 +08:00
ibuler
68ac03db9e perf: 优化 tab input 2023-11-02 15:33:30 +08:00
wangruidong
7b5471a451 perf: 更新字段修改 2023-11-02 15:16:58 +08:00
ibuler
7f052ac85e perf: 优化 tag input 2023-11-02 11:07:20 +08:00
feng
64e75eb9ff feat: 账号收集添加资产账号信息变化通知 2023-11-02 10:50:18 +08:00
ibuler
8e75e5d5e3 perf: 优化 json field m2m 2023-11-02 10:36:00 +08:00
“huailei000”
1810e6833c perf: 公告支持markdown预览 2023-11-01 01:19:09 -05:00
wangruidong
8c7c012785 perf: 添加访问IP控制 2023-10-31 02:45:03 -05:00
feng626
378d82518a Merge pull request #3479 from jumpserver/pr@dev@change_secret_records
feat: 改密记录 推送记录可单独执行
2023-10-31 14:10:53 +08:00
wangruidong
728b04c8e3 perf: 修改语言位置 2023-10-30 21:54:40 -05:00
老广
b8611f095a Merge pull request #3478 from jumpserver/pr@dev@feat_apple_host_support_same_account
feat: 发布机支持使用同名账号连接
2023-10-31 10:19:30 +08:00
feng
f49a1184e2 feat: 改密记录 推送记录可单独执行 2023-10-30 18:42:14 +08:00
dependabot[bot]
77a4441018 build(deps): bump browserify-sign from 4.2.1 to 4.2.2
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: browserify-sign
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 14:30:10 +08:00
ibuler
18f1f0de79 feat: 发布机支持使用同名账号连接 2023-10-30 11:37:22 +08:00
dependabot[bot]
d252c7dd08 build(deps): bump @babel/traverse from 7.20.1 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.20.1 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 10:38:38 +08:00
dependabot[bot]
e5547f8a4c build(deps): bump crypto-js from 4.1.1 to 4.2.0
Bumps [crypto-js](https://github.com/brix/crypto-js) from 4.1.1 to 4.2.0.
- [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0)

---
updated-dependencies:
- dependency-name: crypto-js
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 10:37:50 +08:00
jiangweidong
63d6578991 fix: 云账号详情页面更新报错 2023-10-30 10:30:12 +08:00
ibuler
da00ae84a8 perf: 资产授权添加协议 2023-10-30 10:14:01 +08:00
ibuler
74a905ee85 perf: 资产授权添加协议 2023-10-30 10:14:01 +08:00
“huailei000”
a03e985df3 perf: table tooltip 修改鼠标移上图标显示 2023-10-25 16:53:58 +08:00
吴小白
2d6005a4e0 perf: 优化构建 2023-10-25 16:38:41 +08:00
“huailei000”
c4ca28d2d9 perf: 优化table组件内容溢出省略时,鼠标可以移入tooltip 2023-10-25 16:37:59 +08:00
wangruidong
3934c17f52 perf: 增加语言切换功能 2023-10-25 03:03:17 -05:00
“huailei000”
51717f8583 perf: 优化创建api key后关闭弹窗列表不刷新问题 2023-10-25 10:47:17 +08:00
“huailei000”
67e99702c1 perf: 远程应用名称不能包含() 2023-10-24 19:30:50 +08:00
feng626
27ce5a3785 Merge pull request #3462 from jumpserver/pr@dev@account_change_secret
fix: 修改账号改密执行权限
2023-10-24 10:51:35 +08:00
feng
49122bb213 fix: 修改账号改密执行权限 2023-10-24 10:49:41 +08:00
halo
263c4d3f89 fix: 修复权限树自动选择的问题 2023-10-23 04:29:49 -05:00
wangruidong
2ed203dc32 perf: 添加作业中心执行历史配置字段 2023-10-23 04:23:15 -05:00
“huailei000”
742a06ea2d perf: 优化LDAP用户列表导入全部用户失败后没有提示信息问题 2023-10-20 16:15:20 +08:00
“huailei000”
1ad4e2c62e perf: 调整账号列表页面默认激活的tab 2023-10-19 19:15:24 +08:00
jiangweidong
7e29a3e836 fix: 新创建的云同步任务策略为空的问题 2023-10-19 03:57:31 -05:00
“huailei000”
3a66e8323c perf:优化折线图显示不准确问题 2023-10-19 14:38:03 +08:00
feng626
4852e3d26a Merge pull request #3446 from jumpserver/pr@dev@profile
perf: 修改profile icon
2023-10-19 10:44:23 +08:00
feng
80509dc15f perf: 修改profile icon 2023-10-19 10:43:32 +08:00
“huailei000”
601bd4740c perf: 优化账号推送,推送参数不准确问题 2023-10-18 05:53:42 -05:00
老广
62be5885db Merge pull request #3444 from jumpserver/pr@dev@perf_date_expired
perf: 优化日期,去掉 nwaring
2023-10-18 05:53:02 -05:00
ibuler
62e49567cc perf: 优化日期,去掉 nwaring 2023-10-18 18:51:46 +08:00
feng626
f2eff11d66 Merge pull request #3443 from jumpserver/pr@dev@command_filter_acl
fix: 命令过滤,点击命令组跳转到了规则基本信息,而不是命令组那里
2023-10-18 18:46:28 +08:00
feng
ae61586f95 fix: 命令过滤,点击命令组跳转到了规则基本信息,而不是命令组那里 2023-10-18 18:43:46 +08:00
“huailei000”
a08fbc3b77 perf: 优化table组件在有查询条件的情况下列表会重复请求接口的问题 2023-10-18 04:31:22 -05:00
ibuler
53d130f1cf perf: 优化个人设置 2023-10-18 04:30:39 -05:00
ibuler
c05992ce50 perf: 修改许可证 2023-10-18 04:30:18 -05:00
feng626
52522b7095 Merge pull request #3441 from jumpserver/pr@dev@session_ticket
perf: 资产登录工单 去掉session信息
2023-10-18 17:07:34 +08:00
feng
af3f6c5900 perf: 资产登录工单 去掉session信息 2023-10-18 17:06:46 +08:00
ibuler
7b15ca4955 perf: 优化角色创建时权限没有提示 2023-10-17 02:23:35 -05:00
“huailei000”
031016330a perf: 优化查看账号密码控制台报错问题 2023-10-16 15:03:00 +08:00
老广
e274640d2e Merge pull request #3433 from jumpserver/pr@dev@refactor_confirm
perf: 优化确认操作
2023-10-13 17:27:27 +08:00
ibuler
bd3352424c perf: 优化用户确认 2023-10-13 17:24:45 +08:00
ibuler
f8ec2bce0c merge: with dev 2023-10-13 17:06:01 +08:00
ibuler
81f34f0154 perf: remove debug 2023-10-13 17:01:38 +08:00
ibuler
759e205bfb perf: 优化确认操作 2023-10-13 16:55:21 +08:00
halo
fc5029e88a feat: 增加DB2图标 2023-10-13 02:59:35 -05:00
Bai
6fa8052878 fix: 修复连接令牌过期按钮被禁用的问题 2023-10-13 01:36:27 -05:00
feng626
0dc62712d4 Merge pull request #3431 from jumpserver/pr@dev@ticket
perf: 工单配置社区版隐藏
2023-10-13 11:18:43 +08:00
feng
23b08590cf perf: 工单配置社区版隐藏 2023-10-13 11:05:23 +08:00
feng626
8d8ab483e1 Merge pull request #3430 from jumpserver/pr@dev@platform
perf: 资产批量更新平台字段,根据平台约束协议自动生效
2023-10-12 18:11:37 +08:00
feng
fb757686e3 perf: 资产批量更新平台字段,根据平台约束协议自动生效 2023-10-12 16:56:43 +08:00
“huailei000”
6a8161dcaf perf:创建api key,弹窗关闭后刷新列表 2023-10-12 15:51:09 +08:00
ibuler
ae2391f07f perf: 优化数据库必填 2023-10-12 14:50:30 +08:00
ibuler
50a9ce35ad perf: 重构用户确认 2023-10-12 13:57:41 +08:00
“huailei000”
2d2a4be3a2 perf: 优化账号收集、账号改密、账号备份多次点击执行次数不能正常跳转到执行列表问题 2023-10-11 21:58:25 -05:00
Bai
e055429ff2 perf: 优化用户详情 phone 显示 2023-10-11 04:48:54 -05:00
“huailei000”
8727bac560 perf: 登录资产复核增加跳转会话入口 2023-10-11 04:26:04 -05:00
ibuler
fd018dc5ac perf: 仅本地用户允许使用 passkey 2023-10-11 04:24:38 -05:00
“huailei000”
4c3673aef2 perf: 优化账号模版同步更新账号信息 2023-10-11 04:23:29 -05:00
feng626
4eb61373e0 Merge pull request #3423 from jumpserver/pr@dev@profile
perf: 左上角profile accesskey 改成个人设置
2023-10-11 14:21:34 +08:00
feng
8e8dd38e2e perf: 左上角profile accesskey 改成个人设置 2023-10-11 14:21:00 +08:00
jiangweidong
f8b7720e2c feat: 支持自定义短信认证(文件) 2023-10-10 22:19:57 -05:00
ibuler
50af6fe017 perf: 优化确认的 dialog 2023-10-10 18:24:14 +08:00
feng626
8bc617c4a7 Merge pull request #3421 from jumpserver/pr@dev@user_notice
perf: 用户首次登录 条款和条件 提示优化
2023-10-10 18:23:47 +08:00
feng
f75d69601b perf: 用户首次登录 条款和条件 提示优化 2023-10-10 18:22:35 +08:00
Aaron3S
f54d819ec8 feat: 快捷命令增加设置执行目录 2023-10-10 07:49:57 +05:00
Eric
c50db4089c perf: 隐藏设置 terminal_theme_name 2023-10-10 07:42:12 +05:00
feng626
a6d7cc1215 Merge pull request #3416 from jumpserver/pr@dev@asset_notice
feat: 登录资产消息提示
2023-10-07 17:46:39 +08:00
feng
f6a2fcbbea feat: 登录资产消息提示 2023-10-07 17:44:27 +08:00
feng
071822e665 fix: 系统设置 邮件设置 不能设置后缀 2023-09-27 13:17:52 +05:00
“huailei000”
063dc9f8e1 perf: 优化资产授权详情、账号改密详情中已经添加了的资产没有给出标记还能重复选择的问题 2023-09-27 13:16:39 +05:00
“huailei000”
66e90f189c perf: 列表搜索框退格键可以删除搜索条件 2023-09-26 15:11:56 +08:00
feng626
bdd1a86568 Merge pull request #3410 from jumpserver/pr@dev@user_login_reminder
feat: 用户登录提醒
2023-09-25 16:26:10 +08:00
feng
01d0c9a0c2 feat: 用户登录提醒 2023-09-25 16:24:56 +08:00
“huailei000”
d42bd25371 perf: 修复平台列表导出模版错误问题 2023-09-21 16:18:29 +08:00
“huailei000”
2d07b10961 perf: 调整仪表盘翻译 2023-09-21 15:30:17 +08:00
ibuler
77fb9ef528 perf: 优化 passkey 报错 2023-09-21 12:23:50 +08:00
“huailei000”
b5950b795b fix: 修复组织角色添加用户报错问题 2023-09-20 18:42:08 +08:00
fit2bot
097817e02c perf: 修改模版平台参数无法设置 (#3402)
* perf: 修改模版平台参数无法设置

* perf: remove debug

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-09-20 14:09:31 +08:00
“huailei000”
cf7a77ce2e perf: 优化账号推送参数设置弹窗不能打开问题 2023-09-20 11:32:48 +08:00
feng626
e72850bff8 Merge pull request #3400 from jumpserver/pr@dev@user_setting
perf: 用户个人设置加上密钥是否设置
2023-09-19 16:30:31 +08:00
feng
4669cbfc83 perf: 用户个人设置加上密钥是否设置 2023-09-19 16:29:58 +08:00
Bai
cf8ad2a581 perf: 优化 es host help_text 提示 # 不支持 # 字符 2023-09-19 15:31:38 +08:00
“huailei000”
b776d0157b perf: 优化工单详情信息显示 2023-09-19 15:28:39 +08:00
“huailei000”
9aaee957af perf: 资产授权列表-指定账号字段不计算到账号个数里 2023-09-19 14:24:35 +08:00
老广
0bc681ea08 Merge pull request #3396 from jumpserver/pr@dev@perf_account_template_auto_push
perf: 修复自动推送按钮在不是 password 和 ssh_key 时禁用
2023-09-19 11:30:04 +08:00
ibuler
ea89ce1796 perf: 修复自动推送按钮在不是 password 和 ssh_key 时禁用 2023-09-19 11:17:22 +08:00
老广
e8a37a9c5b Merge pull request #3395 from jumpserver/pr@dev@perf_change_accont_template_password_rules
perf: 修改密码规则
2023-09-19 11:00:42 +08:00
ibuler
1350573ee2 perf: 修改翻译 2023-09-19 10:58:47 +08:00
ibuler
ba83bb14f3 perf: 修改密码规则 2023-09-18 19:33:47 +08:00
“huailei000”
7ae5adf49c perf: 在资产列表的资产树选择完节点后,创建资产能自动选择节点 2023-09-18 14:31:26 +08:00
ibuler
85a1385b4b perf: 优化创建用户默认角色 2023-09-18 14:02:03 +08:00
feng626
4da8eb12dc Merge pull request #3392 from jumpserver/pr@dev@push_now
perf: windows 账号 密钥类型为ssh 隐藏自动推送
2023-09-17 18:26:43 +08:00
feng
bf1be51c39 perf: windows 账号 密钥类型为ssh 隐藏自动推送 2023-09-17 18:25:33 +08:00
feng
3bbe9eccc1 perf: 修改usersession api 2023-09-15 17:25:41 +08:00
Bai
65e84b9b41 fix: 修改资产授权默认过期时间为 70 years 2023-09-15 14:27:40 +08:00
ibuler
0619900fd7 perf: 修改短信 sms 2023-09-15 14:26:49 +08:00
feng626
9ecc759dac Merge pull request #3390 from jumpserver/pr@dev@user_session
perf: 在线用户列表默认显示 认证方式
2023-09-15 10:50:24 +08:00
feng
946787e876 perf: 在线用户列表默认显示 认证方式 2023-09-15 10:49:28 +08:00
feng
54c30fcc0d feat: 用户在线session 控制 2023-09-14 16:25:51 +08:00
Aaron3S
83d730cf0f feat: 支持 ansible raw 模块 2023-09-13 19:30:10 +08:00
“huailei000”
7f7173432d perf: 优化crontab,周日的值修改为0 2023-09-13 19:26:56 +08:00
Bai
c1e5f1c1ce fix: 修复角色详情用户Name显示问题 2023-09-12 15:53:35 +08:00
fit2bot
ca3a99a5cf perf: 修改 passkey (#3382)
* perf: 修改 passkey

* perf: 完成 passkey

* perf: 修改 passkey icon

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-09-11 18:34:44 +08:00
feng626
95831c3ff7 Merge pull request #3383 from jumpserver/pr@dev@tranlate
perf: 翻译
2023-09-11 15:31:49 +08:00
feng
b5abf3e6ad perf: 翻译 2023-09-11 15:31:05 +08:00
feng626
9e4f519fc5 Merge pull request #3381 from jumpserver/pr@dev@usersetting
feat: 个人设置
2023-09-11 14:37:52 +08:00
feng
b712ec4183 feat: 个人设置 2023-09-10 15:44:05 +08:00
jiangweidong
35936ad01e feat: 系统工具支持traceroute (#3379) 2023-09-06 10:31:21 +08:00
ibuler
de5aed0f58 perf: 修改 protocol 说明 2023-09-04 13:50:26 +08:00
老广
5cb8cec835 Merge pull request #3376 from jumpserver/pr@dev@perf_session_list
perf: 优化会话列表
2023-08-31 17:11:50 +08:00
feng626
d66b2a8a87 Merge pull request #3362 from jumpserver/pr@dev@unlockip
feat: 可查看全局被限制的ip 并且可以解锁
2023-08-30 17:31:37 +08:00
feng
d06637afd4 feat: 可查看全局被限制的ip 并且可以解锁 2023-08-30 17:30:53 +08:00
“huailei000”
b27d88859f perf: 优化系统设置-邮件设置提交后页面空白问题 2023-08-30 16:40:10 +08:00
feng626
61580e096b Merge pull request #3377 from jumpserver/pr@dev@mysql_ssl
feat: mysql 证书
2023-08-30 15:16:05 +08:00
feng
da5d67ccbe feat: mysql 证书 2023-08-30 15:14:01 +08:00
ibuler
85a88616b0 perf: 优化会话列表 2023-08-30 14:34:16 +08:00
老广
3d3dfcafd3 Merge pull request #3374 from jumpserver/pr@dev@perf_route_children
perf: 修改路由 children active menu
2023-08-29 19:20:17 +08:00
ibuler
d51e025f04 perf: 修改路由 children active menu 2023-08-29 19:17:57 +08:00
老广
e78d201bd5 Merge pull request #3373 from jumpserver/pr@dev@feat_settings_tool_ping_telnet_multi
feat: telnet、ping支持批量测试,增加IP格式提示
2023-08-29 19:06:20 +08:00
老广
e1836eb1c6 Merge pull request #3372 from jumpserver/pr@dev@perf_change_some_helptext
perf: 修改云同步说明文案
2023-08-29 18:23:37 +08:00
ibuler
085447255b perf: 修改一些提示文案 2023-08-29 18:22:39 +08:00
jiangweidong
e3da28221e feat: telnet、ping支持批量测试,增加IP格式提示 2023-08-29 17:50:26 +08:00
ibuler
b276bbad34 perf: 修改云同步说明文案 2023-08-29 17:39:53 +08:00
老广
f534b292ce Merge pull request #3371 from jumpserver/pr@dev@perf_cloud_sync
perf: 优化同步
2023-08-29 16:25:13 +08:00
ibuler
a02e5363e0 perf: 修改云同步 2023-08-29 16:18:39 +08:00
ibuler
a0dbb3d7b0 perf: 优化同步 2023-08-29 16:14:35 +08:00
老广
b6e955f4b7 Merge pull request #3367 from jumpserver/pr@dev@perf_cloud_sync_None_err
fix: 策略删除动作和规则时提示404
2023-08-29 11:26:38 +08:00
老广
902662681c Merge pull request #3370 from jumpserver/pr@dev@perf_applet_host_tip
perf: 修改发布机的说明
2023-08-29 11:25:07 +08:00
ibuler
0196d42ffc perf: 修改发布机的说明 2023-08-29 11:24:09 +08:00
“huailei000”
a0a7590769 perf: 优化资产授权用户、资产选择之后下拉菜单选项还能继续选择问题 2023-08-29 10:23:08 +08:00
老广
b18c045a1b Merge pull request #3369 from jumpserver/pr@dev@perf_template
perf: 修改账号模版
2023-08-28 15:44:10 +08:00
ibuler
e0411010d1 perf: 修改账号模版 2023-08-28 15:19:20 +08:00
jiangweidong
757c48ebc8 fix: 策略删除时提示404 2023-08-25 14:02:23 +08:00
老广
38ea835df5 Merge pull request #3361 from jumpserver/pr@dev@perf_change_icon
perf: 修改一些 icon
2023-08-25 10:26:09 +08:00
老广
869b94d365 Merge pull request #3363 from jumpserver/pr@dev@perf_announcement_markdown
perf: 公告支持markdown语法
2023-08-25 10:25:42 +08:00
老广
25a8f43345 Merge pull request #3364 from jumpserver/pr@dev@fix_dynamic_input_glint_quit_problem
fix: 解决自动化动态列表组件添加内容会频闪退闪的问题
2023-08-25 10:25:09 +08:00
jiangweidong
7f2cb97bd7 perf: 去掉多余的内容 2023-08-25 10:06:28 +08:00
jiangweidong
580c005bc6 fix: 解决自动化动态列表组件添加内容会频闪闪退的问题 2023-08-25 10:02:51 +08:00
“huailei000”
e22d46bb38 perf: 公告支持markdown语法 2023-08-23 19:16:36 +08:00
ibuler
8d7dd81ebd perf: 修改一些 icon 2023-08-21 15:13:00 +08:00
老广
d5aa439fee Merge pull request #3359 from jumpserver/pr@dev@add_tips
perf: 添加 DOMAINS 不设置 报错的提示
2023-08-18 15:02:55 +08:00
ibuler
095492e5a3 perf: 添加 DOMAINS 不设置 报错的提示 2023-08-18 07:02:09 +00:00
feng
a4e2cadedd perf: vault 为企业版 2023-08-17 16:18:25 +05:00
feng626
29b35ff2a9 Merge pull request #3354 from jumpserver/pr@dev@vault
perf: 优化功能设置顺序
2023-08-17 16:21:55 +08:00
feng
4b137f855e perf: 优化功能设置顺序 2023-08-17 16:18:58 +08:00
feng626
d836b46966 Merge pull request #3353 from jumpserver/pr@dev@label
fix: 标签跳转问题
2023-08-17 15:13:30 +08:00
feng
f9d7d68c77 fix: 标签跳转问题 2023-08-17 15:12:43 +08:00
Eric
cafc5879a0 perf: 发布机可支持添加网域 2023-08-17 14:27:09 +08:00
feng626
2ec88c3591 Merge pull request #3351 from jumpserver/pr@dev@vault
perf:  优化 vault 配置
2023-08-17 12:12:46 +08:00
feng
c37212a5ce perf: 优化 vault 配置 2023-08-17 11:42:55 +08:00
“huailei000”
f9c334b003 fix: 修复当列表有额外查询参数时,导致导出选项判断不准确问题 2023-08-16 17:06:37 +08:00
老广
d43d4137d7 Merge pull request #3347 from jumpserver/pr@dev@fix_accountadd
fix: 修复账号列表添加账号时会明文显示的问题
2023-08-16 10:51:07 +08:00
Bai
614565ba9c fix: 修复账号列表添加账号时会明文显示的问题 2023-08-16 10:44:46 +08:00
老广
575015616f Merge pull request #3337 from jumpserver/pr@dev@revert_build
revert: 还原构建
2023-08-15 18:39:13 +08:00
老广
26fac22b82 Merge pull request #3346 from jumpserver/pr@dev@perf_setting
perf: 再次修改设置
2023-08-15 17:02:25 +08:00
ibuler
40b7c62099 merge: with dev 2023-08-15 17:01:41 +08:00
ibuler
017486e961 perf: 再次修改设置 2023-08-15 16:59:28 +08:00
“huailei000”
7bb4567345 perf: 优化系统设置-基本设置控制台报错问题 2023-08-15 14:38:36 +08:00
老广
76c78df007 Merge pull request #3344 from jumpserver/pr@dev@perf_setting
perf: 修改系统设置布局
2023-08-15 13:53:15 +08:00
ibuler
ff6ac297b9 perf: 整理完成 2023-08-15 13:49:08 +08:00
ibuler
6b953506e4 perf: 修改系统设置布局 2023-08-14 19:41:47 +08:00
feng626
7ec130f033 Merge pull request #3343 from jumpserver/pr@dev@automation
perf: automation 任务详情添加id
2023-08-14 18:50:42 +08:00
feng
2f9e00de2e perf: automation 任务详情添加id 2023-08-14 18:49:27 +08:00
“huailei000”
e479dbfcb5 perf: 优化命令存储-主机helptext 2023-08-14 16:54:20 +08:00
feng626
1e5b6f970d Merge pull request #3340 from jumpserver/pr@dev@perm
perf: 角色权限选择工作台时自动关联connectiontoken权限
2023-08-14 16:37:28 +08:00
feng
e7222fb63c perf: 角色权限选择工作台时自动关联connectiontoken权限 2023-08-14 16:29:18 +08:00
feng626
f9617a92a8 Merge pull request #3339 from jumpserver/pr@dev@applet_host
perf: applethost 搜索框优化
2023-08-14 14:24:56 +08:00
feng
38e1b070cf perf: applethost 搜索框优化 2023-08-14 14:23:58 +08:00
feng626
f75d97305f Merge pull request #3338 from jumpserver/pr@dev@applethost
perf: 远程应用批量部署多选优化
2023-08-14 11:25:54 +08:00
feng
7df0cc78b1 perf: 远程应用批量部署多选优化 2023-08-14 11:24:24 +08:00
吴小白
a8a90930b9 revert: 还原构建 2023-08-14 11:23:18 +08:00
Eric
69dbf2f5da perf: 优化会话暂停的组件判断 2023-08-11 13:45:55 +05:00
feng626
fc8339d659 Merge pull request #3334 from jumpserver/pr@dev@vault
perf: 优化vault配置界面
2023-08-11 16:01:41 +08:00
feng
eada8d319d perf: 优化vault配置界面 2023-08-11 15:55:46 +08:00
“huailei000”
11940428a0 perf: 优化组件监控 2023-08-11 14:38:28 +08:00
老广
af2544e24b Merge pull request #3331 from jumpserver/pr@dev@perf_change_edtion
perf: 修改 applet 翻译
2023-08-10 17:32:36 +08:00
ibuler
4546952388 perf: 修改 applet 翻译 2023-08-10 17:30:50 +08:00
老广
a0c849f29d Merge pull request #3330 from jumpserver/pr@dev@applet_add_enterprise
perf: applet 添加 entperpise 标记
2023-08-10 15:32:31 +08:00
ibuler
fb9cd1614a perf: applet 添加 entperpise 标记 2023-08-10 14:40:46 +08:00
“huailei000”
c1543183a2 perf: 优化组件监控组件 2023-08-10 09:09:13 +05:00
Aaron3S
03dc3e993c feat: 增加批量sql支持 2023-08-09 19:43:46 +08:00
Aaron3S
8719ffee8e feat: 增加批量sql支持 2023-08-09 19:43:46 +08:00
Eric
cc60f2c1f5 perf: 优化代码 2023-08-09 19:43:25 +08:00
Eric
f042692dbf perf: 工单会话暂停控制 2023-08-09 19:43:25 +08:00
Eric
3d8dc619ad perf: 支持其他组件的暂停会话 2023-08-09 19:43:25 +08:00
Bai
b223c73a47 perf: 优化账号列表显示其他字段 2023-08-09 17:05:48 +08:00
Eric
53e313517d feat: 支持最大会话连接时长 2023-08-09 10:38:22 +08:00
老广
56bea8eaf4 Merge pull request #3324 from jumpserver/pr@dev@perf_ztree_chk_css
perf: 优化 ztree chk 样式
2023-08-08 17:13:09 +08:00
老广
992025e618 Merge pull request #3323 from jumpserver/pr@dev@perf_dashboard_data
perf: 优化首页 rank 的宽度
2023-08-08 17:12:48 +08:00
ibuler
205d301578 perf: 优化 ztree chk 样式 2023-08-08 17:08:49 +08:00
ibuler
4daccc9df3 perf: 优化首页 rank 的宽度 2023-08-08 16:37:05 +08:00
老广
ac802fff59 Merge pull request #3319 from jumpserver/pr@dev@perf_ticket_session
perf: 优化工单方式打开会话监控
2023-08-08 16:18:16 +08:00
老广
a6b0da60a3 Merge pull request #3320 from jumpserver/pr@dev@fix_msg_subscribe_for_xss
fix: 修复系统设置 > 消息订阅 > 修改订阅人 因为用户名导致的 xss
2023-08-08 16:17:49 +08:00
ibuler
45c860797a fix: 修复系统设置 > 消息订阅 > 修改订阅人 因为用户名导致的 xss 2023-08-08 11:07:34 +08:00
Eric
e636aa24c8 perf: 优化工单方式打开会话监控 2023-08-08 10:37:24 +08:00
老广
86b37eeeba Merge pull request #3318 from jumpserver/pr@dev@perf_org_delete
perf: System 组织不允许删除
2023-08-08 10:28:16 +08:00
ibuler
61cf9e7f14 perf: System 组织不允许删除 2023-08-08 10:27:26 +08:00
fit2bot
344e49e7ec perf: 同名账号定义一些策略 (#3311)
* perf: 同名账号定义一些策略

* perf: 修改虚拟账号

* perf: 修改更新后的 route

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-08-08 10:16:52 +08:00
老广
3ebdacafd0 Merge pull request #3316 from jumpserver/pr@dev@fix_strategy_cannot_export
fix: 云同步策略不支持导出
2023-08-08 09:57:06 +08:00
“huailei000”
e1ae467823 feat: 创建资产-选择模版添加搜索功能 2023-08-07 18:21:58 +08:00
jiangweidong
65c1ab450b fix: 云同步策略不支持导出 2023-08-07 17:55:54 +08:00
feng626
cbe3efdb18 Merge pull request #3309 from jumpserver/pr@dev@account_backup
feat: 账号备份密钥拆分
2023-08-07 15:50:36 +08:00
feng
e5eaa5bcfa feat: 账号备份密钥拆分 2023-08-07 15:47:25 +08:00
fit2bot
df687c0c06 perf: TagInput 组件增加替换显示密码功能;命令存储-主机不明文显示密码 (#3301)
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: huailei <31801270+huailei000@users.noreply.github.com>
2023-08-07 15:03:05 +08:00
feng626
1cc00517f5 Merge pull request #3314 from jumpserver/pr@dev@check_unused_users
feat: 检测不常用账号
2023-08-07 14:45:03 +08:00
jiangweidong
f3a6d6c02b perf: 优化批量审批翻译 2023-08-07 14:19:56 +08:00
feng
7bf33a9011 feat: 检测不常用账号 2023-08-07 11:35:06 +08:00
ibuler
7948a59b80 perf: 去掉 telnet 的全员设置 2023-08-07 10:37:33 +08:00
jiangweidong
af9f715357 feat: 云同步增加同步策略 (#3264)
* feat: 云同步逻辑更新

* feat: 云同步增加同步策略

* perf: 优化

* perf: 优化提交逻辑,平台和网域只允许设置一次

* perf: 策略抽离,有列表、详情、同步任务可便捷添加策略

* fix: 修改组件层级关系

* perf: 去掉不需要的

* perf: 优化变量名称、策略添加优先级
2023-08-07 10:33:04 +08:00
吴小白
202f8a357c perf: 更新 node 16.17.1 2023-08-07 10:20:13 +08:00
jiangweidong
3e75c781b3 feat: 系统工具改为异步,增加tcpdump工具 2023-08-07 10:19:48 +08:00
吴小白
3c3ed27eb2 Merge pull request #3310 from jumpserver/pr@dev@fix_build
fix: 修正构建错误
2023-08-04 17:59:54 +08:00
吴小白
fd0e23e35f perf: 更新 node 16.5 2023-08-04 17:55:04 +08:00
吴小白
c09a2df142 fix: 修正构建错误 2023-08-04 17:35:50 +08:00
“huailei000”
36737a6f25 perf: 命令记录列表增加账号字段 2023-08-03 16:19:21 +08:00
feng626
e4af9ccc1e Merge pull request #3304 from jumpserver/pr@dev@task_search
perf: 任务添加显示项 过滤项
2023-08-02 17:51:43 +08:00
feng
3c256c6fdc perf: 任务添加显示项 过滤项 2023-08-02 17:49:47 +08:00
“huailei000”
1e36f59b23 perf: 最近会话连接资产时增加login_account参数 2023-08-02 16:48:35 +08:00
feng626
aec6ee8376 Merge pull request #3302 from jumpserver/pr@dev@applet_host_deployment
feat: 批量部署发布机
2023-08-01 17:42:28 +08:00
feng
526b049495 feat: 批量部署发布机 2023-08-01 17:38:31 +08:00
Eric
5bef5a59a9 perf: 完善工单 session 变化 2023-08-01 17:26:15 +08:00
Eric
1e371a4e32 perf: 优化 session 的状态 2023-08-01 17:26:15 +08:00
Eric
0f6fd0ed70 feat: 支持暂停会话操作 2023-08-01 17:26:15 +08:00
feng626
fc1aefbb54 Merge pull request #3251 from jumpserver/pr@dev@vault
feat: vault 添加系统配置
2023-07-31 17:57:41 +08:00
feng
7561f1224d perf: merge dev 2023-07-31 17:56:20 +08:00
老广
0932132add Merge pull request #3299 from jumpserver/pr@dev@refactor_path
perf: 修改一些组件路径,原来的太难找了
2023-07-31 14:50:21 +08:00
ibuler
8492882633 perf: 修改一些组件路径,原来的太难找了 2023-07-31 14:45:27 +08:00
老广
11698255f6 Merge pull request #3297 from jumpserver/pr@dev@perf_tmp_passwd_icon
perf: 修改临时密码的 icon
2023-07-31 10:53:48 +08:00
ibuler
53eee6c857 perf: 修改临时密码的 icon 2023-07-31 10:34:40 +08:00
老广
f2bc4d6f22 Merge pull request #3296 from jumpserver/pr@dev@perf_applet_host_account_create
perf: 修改隐藏
2023-07-28 16:16:54 +08:00
ibuler
e50b16b13b perf: 修改隐藏 2023-07-28 16:16:03 +08:00
老广
232c30cadb Merge pull request #3295 from jumpserver/pr@dev@perf_applet_host_account_create
perf: 修改应用发布机账号生成
2023-07-28 11:07:38 +08:00
jiangweidong
3142da16ae feat: 支持批量审批工单 (#3273) 2023-07-28 10:49:11 +08:00
ibuler
741f8b847e Merge branch 'dev' into pr@dev@perf_applet_host_account_create 2023-07-28 10:44:05 +08:00
ibuler
b6d00a1784 perf: 修改应用发布机账号生成 2023-07-28 10:42:54 +08:00
jiangweidong
2f122f7fbe feat: 系统工具增加服务器时间及nmap工具 (#3289) 2023-07-28 10:42:28 +08:00
feng626
c3c46b759e Merge pull request #3294 from jumpserver/pr@dev@ldap
perf: 优化ldap交互
2023-07-27 19:14:55 +08:00
feng
a1c4013a69 perf: 优化ldap交互 2023-07-27 19:12:20 +08:00
老广
8aa9690a61 Merge pull request #3293 from jumpserver/pr@dev@perf_same_ztree
perf: 统一 ztree css
2023-07-27 18:37:29 +08:00
ibuler
30c0100a0b perf: 统一 ztree css 2023-07-27 18:18:52 +08:00
fit2bot
134dd17f3f perf: 添加应用市场链接 (#3292)
* perf: 添加应用市场链接

* perf: 修改版本号

* perf: 修改高度

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-07-27 16:52:58 +08:00
feng626
505642baec Merge pull request #3291 from jumpserver/pr@dev@asset_perm_account
perf: 修改AccountFormatter 请求方法为post
2023-07-27 14:04:14 +08:00
feng
c08964ee34 perf: 修改AccountFormatter 请求方法为post 2023-07-27 14:03:14 +08:00
老广
9df443667c Merge pull request #3290 from jumpserver/pr@dev@perf_protocols
perf: 修改 protocols 显示
2023-07-26 18:39:51 +08:00
ibuler
8fd8e9c1d4 perf: 修改 protocols 显示 2023-07-26 18:33:34 +08:00
feng
aa3ab5e138 perf: 配置信息修改 2023-07-24 19:43:46 +08:00
“huailei000”
a7df8706e5 perf: 工作台概况会话添加连接方式 2023-07-24 19:20:24 +08:00
“huailei000”
c200781322 perf: 修改github配置 2023-07-21 14:59:04 +08:00
老广
75c7778a10 Merge pull request #3261 from jumpserver/dependabot/npm_and_yarn/semver-5.7.2
build(deps): bump semver from 5.7.1 to 5.7.2
2023-07-21 10:28:11 +08:00
老广
c30e919573 Merge pull request #3271 from jumpserver/dependabot/npm_and_yarn/word-wrap-1.2.4
build(deps): bump word-wrap from 1.2.3 to 1.2.4
2023-07-21 10:27:45 +08:00
老广
ffff648e6d Merge pull request #3284 from jumpserver/pr@dev@perf_account_default_show
perf: 优化账号,默认实现是否激活
2023-07-21 10:27:19 +08:00
ibuler
981e676fa2 perf: 优化账号,默认实现是否激活 2023-07-20 20:22:36 +08:00
ibuler
664855d4b0 perf: 优化从 url 中获取端口 2023-07-20 17:37:58 +08:00
老广
c79637095a Merge pull request #3281 from jumpserver/pr@dev@remove_debug_msg
perf: 去掉 debug msg
2023-07-20 16:42:25 +08:00
ibuler
2a96abdd4a perf: 去掉 debug msg 2023-07-20 16:25:11 +08:00
老广
9541b97b23 Merge pull request #3280 from jumpserver/pr@dev@perf_add_debug
perf: 修改 debug msg
2023-07-20 16:11:00 +08:00
ibuler
52518a9ff3 perf: 修改 debug msg 2023-07-20 16:08:11 +08:00
“huailei000”
24a1c11288 perf: 优化账号详情推送弹窗点击关闭图标下次点击不能正常打开问题 2023-07-20 15:58:37 +08:00
老广
313aebaf50 Merge pull request #3278 from jumpserver/pr@dev@perf_add_debug_msg
perf: 添加 setTimeout
2023-07-20 15:21:57 +08:00
ibuler
5c6373e689 perf: 添加 setTimeout 2023-07-20 15:20:41 +08:00
老广
09fe3ea107 Merge pull request #3277 from jumpserver/pr@dev@perf_add_debug_msg
perf: 添加 debug msg
2023-07-20 15:06:10 +08:00
ibuler
ccf081b608 perf: 添加 debug msg 2023-07-20 15:04:44 +08:00
Bai
80ce3293a1 fix: 优化导入组件导入数据时全部使用 patch 方法; 解决一些表格数据库不全时引来的问题; 2023-07-19 19:58:40 +08:00
“huailei000”
4ed282ff2b perf: 优化连续批量更新用户报错问题 2023-07-19 19:50:18 +08:00
老广
dd8957cb69 Merge pull request #3274 from jumpserver/pr@dev@perf_protocol_setting_reset
perf: 优化 nestfield 重置不会变更的问题
2023-07-19 19:42:24 +08:00
ibuler
36c687b854 perf: 精简写法 2023-07-19 19:30:51 +08:00
ibuler
e22ecb6fe8 perf: 优化 nestfield 重置不会变更的问题 2023-07-19 18:46:20 +08:00
ibuler
b77440284f perf: 优化 Platform 中自动化 select 的宽度 2023-07-19 08:38:03 +05:00
老广
93d866328c Merge pull request #3270 from jumpserver/pr@dev@perf_domain_platform
perf: 优化网关更新时协议显示
2023-07-19 10:18:33 +08:00
dependabot[bot]
42c7b278c5 build(deps): bump word-wrap from 1.2.3 to 1.2.4
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 21:21:13 +00:00
“huailei000”
14ba501f2b perf: 优化网关更新时协议显示 2023-07-18 19:57:31 +08:00
ibuler
f072546083 perf: 优化账号模版表单,在弹窗中新窗口打开 2023-07-18 18:12:54 +08:00
“huailei000”
8f9ebcdfa9 perf: 界面设置上传组件控制上传类型 2023-07-18 18:10:58 +08:00
老广
7b76917768 Merge pull request #3267 from jumpserver/pr@dev@perf_promise
perf: 修改 资产详情的 card 和 账号模版密文类型
2023-07-18 10:34:10 +08:00
ibuler
e4d4bc84b6 perf: 修改 资产详情的 card 和 账号模版密文类型 2023-07-18 10:24:03 +08:00
老广
62cf19e70e Merge pull request #3263 from jumpserver/pr@dev@perf_connection_action
perf: 优化一些 rbac 权限位,着重 connection token 的
2023-07-17 10:24:59 +08:00
老广
2cb36f89f0 Merge pull request #3265 from jumpserver/pr@dev@perf_can_unbind_from_other_source
perf: 用户在认证方式和用户来源一致时,无法解绑此类认证
2023-07-17 10:24:16 +08:00
老广
9946ad75ad Merge pull request #3266 from jumpserver/pr@dev@perf_promise
perf: 修改平台 protocols 的下拉选择,可以更改
2023-07-17 10:21:16 +08:00
ibuler
abd8919225 perf: 修改平台 protocols 的下拉选择,可以更改 2023-07-17 10:11:54 +08:00
jiangweidong
6e5e760689 perf: 用户在认证方式和用户来源一致时,无法解绑此类认证 2023-07-14 18:21:45 +08:00
ibuler
1235895973 perf: 优化一些 rbac 权限位,着重 connection token 的 2023-07-13 16:01:03 +08:00
“huailei000”
59f9025e42 perf: 调整用户登录、连接方式文案 2023-07-13 10:57:45 +08:00
Bai
d06bda6d40 perf: 优化 is_active 到 Other 中 2023-07-12 20:33:21 +08:00
fangfang.dong
a8099089b2 feat: 系统设置 - 终端设置 - 端点规则: 新增字段is_active控制是否启用 2023-07-12 20:33:21 +08:00
dependabot[bot]
fd0c14e1c0 build(deps): bump semver from 5.7.1 to 5.7.2
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 12:33:01 +00:00
Aaron3S
9a04c81238 feat: 增加两个组件的名称 2023-07-11 19:16:18 +08:00
老广
f1b3e5038f Merge pull request #3259 from jumpserver/pr@dev@perf_protocol_setting
perf: 修改账号配置
2023-07-11 17:28:42 +08:00
ibuler
f6fe08607b perf: 修改账号配置 2023-07-11 17:27:16 +08:00
老广
6f2ca3e26a Merge pull request #3258 from jumpserver/pr@dev@add_gpt_add_default_addr
perf: 优化修改默认值
2023-07-11 14:48:50 +08:00
ibuler
3ed9ac0d9b perf: 优化修改默认值 2023-07-11 14:47:07 +08:00
老广
821ed14f40 Merge pull request #3257 from jumpserver/pr@dev@add_gpt_proxy
perf: gpt 添加 proxy
2023-07-11 14:40:21 +08:00
老广
6f0ee734e5 Merge pull request #3255 from jumpserver/pr@dev@feat_acl_command_warning
feat: 新增危险命令告警类型: Warning
2023-07-11 12:20:14 +08:00
老广
9a5b174eb1 Merge pull request #3242 from jumpserver/pr@dev@perf_component_jsoneditor
perf: json编辑器组件增加参数控制是否可拖拽;默认可以拖拽高度
2023-07-11 12:19:29 +08:00
老广
c27e1c97f2 Merge pull request #3241 from jumpserver/pr@dev@perf_component_weekcronselect
perf: 优化时间选择组件,鼠标指针超出容器时页面显示错乱问题
2023-07-11 12:17:27 +08:00
ibuler
1b4e01d19e perf: gpt 添加 proxy 2023-07-11 11:47:41 +08:00
老广
28c836b1f6 Merge pull request #3249 from jumpserver/pr@dev@feat_chatgpt_support
feat: 支持 chatgpt 资产
2023-07-11 09:58:04 +08:00
fangfang.dong
fc85eaf6b9 feat: 新增危险命令告警类型: Warning 2023-07-10 16:22:22 +08:00
老广
678d17a4e7 Merge pull request #3256 from jumpserver/pr@dev@perf_platform_protocol
perf: 优化 protocol setting
2023-07-07 19:02:27 +08:00
ibuler
ddf9780f9c perf: 优化 protocol setting 2023-07-07 18:51:20 +08:00
fangfang.dong
d47bd4acad feat: 新增危险命令告警类型: Warning 2023-07-07 15:22:25 +08:00
jiangweidong
09dabb5d3f feat: 云同步支持UCloud公有云 (#3253) 2023-07-04 18:24:50 +08:00
Eric_Lee
9eea051884 Merge pull request #3254 from jumpserver/revert-3250-pr@dev@perf_xrdp_rdp7
Revert "perf: 新增 xrdp 协议 rdp7 端口 3390"
2023-07-04 18:02:19 +08:00
老广
f6a3eb1349 Revert "perf: 新增 xrdp 协议 rdp7 端口 3390" 2023-07-04 17:36:21 +08:00
feng
433f3a34cb perf: 改密与推送保持一致 2023-07-04 17:34:51 +08:00
老广
aa790944f6 Merge pull request #3246 from jumpserver/pr@dev@feat_support_anonymous_account
feat: 支持授权匿名账号
2023-07-04 11:46:49 +08:00
ibuler
57167fc821 perf: 优化修改 chatgpt 支持 2023-07-04 09:53:28 +08:00
feng
fb70719cba feat: vault 添加系统配置 2023-07-04 00:55:45 +08:00
ibuler
5988892840 perf: 修改端口可以从 url 中获取 2023-07-03 19:44:53 +08:00
老广
af11e1bf0c Merge pull request #3244 from jumpserver/pr@dev@perf_permission_joblog
perf: 作业日志增加权限位控制
2023-07-03 16:36:03 +08:00
老广
09416b13d3 Merge pull request #3245 from jumpserver/pr@dev@perf_route_user_roles
perf: 点击角色列表组织默认切换到全局组织,在角色列表不能点击切换组织
2023-07-03 16:35:30 +08:00
老广
478745f534 Merge pull request #3250 from jumpserver/pr@dev@perf_xrdp_rdp7
perf: 新增 xrdp 协议 rdp7 端口 3390
2023-07-03 16:29:45 +08:00
ibuler
3de2bf73ea perf: 修改 i18n 2023-07-03 11:24:36 +08:00
Eric
3b877739a3 perf: endpoint 增加 rdp7_port 2023-06-30 18:41:49 +08:00
ibuler
06899d6932 perf: 修改 chatgpt 支持 2023-06-30 18:31:50 +08:00
Eric
6f3d21bb77 perf: 新增 xrdp 协议 rdp7 端口 3390 2023-06-30 18:12:00 +08:00
ibuler
b7da517ad7 feat: 支持 chatgpt 资产 2023-06-30 17:34:45 +08:00
“huailei000”
598b6b12e8 perf: 点击角色列表组织默认切换到全局组织,在角色列表不能点击切换组织 2023-06-30 15:59:31 +08:00
ibuler
400ceac737 perf: 修改协议设置 2023-06-30 15:55:20 +08:00
老广
34de6d8775 Merge pull request #3247 from jumpserver/pr@dev@perf_dev_env
perf: 调整 luna 的 proxy 的配置,支持 luna 录像播放
2023-06-30 15:53:11 +08:00
Eric
080542633a perf: 调整 luna 的 proxy 的配置,支持 luna 录像播放 2023-06-29 15:20:14 +08:00
ibuler
653f26137b perf: 修改翻译 2023-06-27 16:45:40 +08:00
ibuler
c86f0cc08d feat: 支持授权匿名账号 2023-06-27 16:41:27 +08:00
“huailei000”
541c6c5fe5 perf: json编辑器组件增加参数控制是否可拖拽;默认可以拖拽高度 2023-06-27 15:58:33 +08:00
“huailei000”
c36a210cd4 perf: 作业日志增加权限位控制 2023-06-25 15:56:41 +08:00
“huailei000”
b9f26df5e6 perf: 优化时间选择组件,鼠标指针超出容器时页面显示错乱问题 2023-06-21 18:28:32 +08:00
老广
dd0baa7b00 Merge pull request #3239 from jumpserver/pr@dev@perf_sql_display
perf: 修改 sql 显示
2023-06-21 14:35:26 +08:00
ibuler
524105278b perf: 修改 sql 显示 2023-06-21 14:08:11 +08:00
老广
2656546e3b Merge pull request #3236 from jumpserver/pr@dev@feat_assets_detail
feat: 控制台 - 资产管理 - 资产详情 新增标签增删功能
2023-06-21 13:37:34 +08:00
ibuler
ecaf1ceace pref: 添加 sql debug 2023-06-21 12:03:26 +08:00
“huailei000”
cf515a18de perf: 替换批量更新图标 2023-06-21 11:18:13 +08:00
Eric
a0ab7d3f32 perf: 修复 terminal 显示问题 2023-06-21 11:17:38 +08:00
fangfang.dong
467c3f7288 feat: 控制台 - 资产管理 - 资产详情 新增标签增删功能 2023-06-20 17:35:49 +08:00
老广
f68eaee8c8 Merge pull request #3231 from jumpserver/pr@dev@perf_org_change_global
perf: 优化手动切换到全局后,点击菜单回到上个非全局组织的问题
2023-06-20 16:01:31 +08:00
老广
163f661386 Merge pull request #3232 from jumpserver/pr@dev@applet_host_add_help_text
perf: 添加应用发布机说明,可以通过标签选择
2023-06-20 15:45:04 +08:00
老广
e54bc076d6 Merge pull request #3233 from jumpserver/pr@dev@perf_help_text
perf: 优化一些说明文案
2023-06-20 15:44:33 +08:00
ibuler
1fbf04ae51 perf: 优化一些说明文案 2023-06-20 15:21:41 +08:00
ibuler
f002c4aa3d perf: 添加应用发布机说明,可以通过标签选择 2023-06-20 14:19:43 +08:00
ibuler
f67bd39067 perf: 添加应用发布机说明,可以通过标签选择 2023-06-20 14:14:39 +08:00
ibuler
5c60624b2d perf: 优化手动切换到全局后,点击菜单回到上个非全局组织的问题 2023-06-19 18:48:21 +08:00
fangfang.dong
488684f293 fix: 修复创建用户时 先输入密码再选择来源为LDAP 密码项仍可输入未隐藏的BUG 2023-06-19 17:10:14 +08:00
Bai
5c511345bf fix: 修复 Endpoint Host 被禁用的问题 2023-06-19 16:37:40 +08:00
老广
be85a91ccd Merge pull request #3224 from jumpserver/pr@dev@change_attr_form
perf: 优化 attr form 字段选择
2023-06-15 18:31:43 +08:00
ibuler
94a02a2e7e perf: 修改冲突 2023-06-15 18:30:46 +08:00
ibuler
e60a33a2b1 perf: 修改 json attr form 表单 2023-06-15 18:28:16 +08:00
“huailei000”
a787737290 perf: 优化同步设置组织下拉框显示过长问题 2023-06-15 15:10:53 +08:00
522 changed files with 12191 additions and 6025 deletions

View File

@@ -33,17 +33,27 @@ jobs:
tag: ${{ steps.get_version.outputs.TAG }}
- uses: actions/setup-node@v2
with:
node-version: '14.16'
build-and-release:
needs: create-realese
name: Build and Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build it and upload
uses: jumpserver/action-build-upload-assets@node10
node-version: '16.20'
- name: Install dependencies
run: yarn install
- name: Build web
run: |
sed -i "s@version-dev@${{ steps.get_version.outputs.TAG }}@g" src/layout/components/NavHeader/About.vue
yarn build
- name: Create Upload Assets
run: |
rm -rf build/*
mv lina lina-${{ steps.get_version.outputs.VERSION }}
tar -czf lina-${{ steps.get_version.outputs.VERSION }}.tar.gz lina-${{ steps.get_version.outputs.VERSION }}
echo $(md5sum lina-${{ steps.get_version.outputs.VERSION }}.tar.gz | awk '{print $1}') > build/lina-${{ steps.get_version.outputs.VERSION }}.tar.gz.md5
mv lina-${{ steps.get_version.outputs.VERSION }}.tar.gz build/
- name: Release Upload Assets
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
files: |
build/lina-${{ steps.get_version.outputs.TAG }}.tar.gz
build/lina-${{ steps.get_version.outputs.TAG }}.tar.gz.md5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-realese.outputs.upload_url }}

View File

@@ -1,13 +1,28 @@
FROM node:14.16 as stage-build
FROM node:16.20-bullseye-slim as stage-build
ARG TARGETARCH
ARG DEPENDENCIES=" \
g++ \
make \
python3"
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=lina \
sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& apt-get update \
&& apt-get install -y --no-install-recommends ${DEPENDENCIES} \
&& echo "no" | dpkg-reconfigure dash \
&& rm -rf /var/lib/apt/lists/*
ARG NPM_REGISTRY="https://registry.npmmirror.com"
WORKDIR /data
RUN set -ex \
&& npm config set registry ${NPM_REGISTRY} \
&& yarn config set registry ${NPM_REGISTRY}
WORKDIR /data
ADD package.json yarn.lock /data
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn,sharing=locked,id=lina \
yarn install
@@ -19,6 +34,6 @@ RUN --mount=type=cache,target=/usr/local/share/.cache/yarn,sharing=locked,id=lin
sed -i "s@version-dev@${VERSION}@g" src/layout/components/NavHeader/About.vue \
&& yarn build
FROM nginx:1.24
FROM nginx:1.24-bullseye
COPY --from=stage-build /data/lina /opt/lina
COPY nginx.conf /etc/nginx/conf.d/default.conf

1
GITSHA
View File

@@ -1 +0,0 @@
58feba889adc1068882aa0ae7a26292e3610b65d

View File

@@ -5,11 +5,10 @@
"author": "Pan <panfree23@gmail.com>",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"dev": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"serve": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"build": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"fix": "eslint --ext .js,.vue --fix src",

View File

@@ -44,3 +44,11 @@ export function renameFile(playbookId, node) {
data: node
})
}
export function createJob(form) {
return request({
url: '/api/v1/ops/jobs/',
method: 'post',
data: form
})
}

View File

@@ -8,24 +8,11 @@ export function terminateSession(data) {
})
}
export function getSessionDetail(id) {
export function toggleLockSession(data) {
return request({
url: `/api/v1/terminal/sessions/${id}/`,
method: 'get'
})
}
export function getSessionCommands(id) {
return request({
url: `/api/v1/terminal/commands/?session_id=${id}`,
method: 'get'
})
}
export function getTerminalDetail(id) {
return request({
url: `/api/v1/terminal/terminals/${id}/`,
method: 'get'
url: '/api/v1/terminal/tasks/toggle-lock-session/',
method: 'post',
data: data
})
}

View File

@@ -8,12 +8,12 @@
</template>
<script>
import AutoDataForm from '@/components/AutoDataForm'
import { UpdateToken, UploadSecret } from '@/components/FormFields'
import Select2 from '@/components/FormFields/Select2'
import AssetSelect from '@/components/AssetSelect'
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
import { UpdateToken, UploadSecret } from '@/components/Form/FormFields'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import AssetSelect from '@/components/Apps/AssetSelect/index.vue'
import { encryptPassword } from '@/utils/crypto'
import { Required, RequiredChange } from '@/components/DataForm/rules'
import { Required, RequiredChange } from '@/components/Form/DataForm/rules'
import AutomationParamsForm from '@/views/assets/Platform/AutomationParamsSetting.vue'
export default {
@@ -55,7 +55,7 @@ export default {
protocols: [
{
name: 'ssh',
secret_types: ['password', 'ssh_key', 'token', 'access_key']
secret_types: ['password', 'ssh_key', 'token', 'access_key', 'api_key']
}
]
},
@@ -67,8 +67,8 @@ export default {
[this.$t('accounts.AccountTemplate'), ['template']],
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username']],
[this.$t('assets.Secret'), [
'secret_type', 'secret', 'ssh_key',
'token', 'access_key', 'passphrase'
'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key'
]],
[this.$t('common.Other'), ['push_now', 'params', 'on_invalid', 'is_active', 'comment']]
],
@@ -173,7 +173,7 @@ export default {
return this.platform || this.asset || this.addTemplate
}
},
secret: {
password: {
label: this.$t('assets.Password'),
component: UpdateToken,
hidden: (formValue) => formValue.secret_type !== 'password' || this.addTemplate
@@ -199,6 +199,12 @@ export default {
component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'access_key' || this.addTemplate
},
api_key: {
id: 'api_key',
label: this.$t('assets.ApiKey'),
component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'api_key' || this.addTemplate
},
secret_type: {
type: 'radio-group',
options: [],
@@ -208,11 +214,12 @@ export default {
},
push_now: {
helpText: this.$t('accounts.AccountPush.WindowsPushHelpText'),
hidden: () => {
hidden: (formValue) => {
const automation = this.iPlatform.automation || {}
return !automation.push_account_enabled ||
!automation.ansible_enabled ||
!this.$hasPerm('accounts.push_account') ||
(formValue.secret_type === 'ssh_key' && this.iPlatform.type.value === 'windows') ||
this.addTemplate
}
},
@@ -276,6 +283,10 @@ export default {
{
label: this.$t('assets.AccessKey'),
value: 'access_key'
},
{
label: this.$t('assets.ApiKey'),
value: 'api_key'
}
]
const secretTypes = []
@@ -290,11 +301,13 @@ export default {
})
},
confirm(form) {
const secretType = form.secret_type || ''
if (secretType !== 'password') {
form.secret = form[secretType]
}
const secretType = form.secret_type || 'password'
form.secret = form[secretType]
form.secret = this.encryptPassword ? encryptPassword(form.secret) : form.secret
//
delete form[secretType]
if (!form.secret) {
delete form['secret']
}

View File

@@ -1,16 +1,5 @@
<template>
<Dialog
v-if="iVisible"
:close-on-click-modal="false"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
:title="title"
:visible.sync="iVisible"
v-bind="$attrs"
width="70%"
v-on="$listeners"
>
<GenericCreateUpdateDrawer v-bind="$attrs">
<AccountCreateUpdateForm
v-if="!loading"
ref="form"
@@ -20,18 +9,18 @@
@add="addAccount"
@edit="editAccount"
/>
</Dialog>
</GenericCreateUpdateDrawer>
</template>
<script>
import Dialog from '@/components/Dialog'
import AccountCreateUpdateForm from '@/components/AccountCreateUpdateForm'
import GenericCreateUpdateDrawer from '@/layout/components/GenericCreateUpdateDrawer/index.vue'
import AccountCreateUpdateForm from '@/components/Apps/AccountCreateUpdateForm/index.vue'
export default {
name: 'CreateAccountDialog',
components: {
Dialog,
AccountCreateUpdateForm
AccountCreateUpdateForm,
GenericCreateUpdateDrawer
},
props: {
visible: {

View File

@@ -14,21 +14,11 @@
@updateAuthDone="onUpdateAuthDone"
/>
<AccountCreateUpdate
v-if="showAddDialog"
:account="account"
:url="url"
:asset="iAsset"
:title="accountCreateUpdateTitle"
:visible.sync="showAddDialog"
@add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)"
/>
<AccountCreateUpdate
v-if="showAddTemplateDialog"
:account="account"
:add-template="true"
:asset="iAsset"
:add-template="addTemplate"
:title="accountCreateUpdateTitle"
:visible.sync="showAddTemplateDialog"
@add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)"
/>
@@ -41,11 +31,11 @@
</template>
<script>
import ListTable from '@/components/ListTable/index'
import { ActionsFormatter } from '@/components/TableFormatters'
import ViewSecret from './ViewSecret'
import UpdateSecretInfo from './UpdateSecretInfo'
import AccountCreateUpdate from './AccountCreateUpdate'
import ListTable from '@/components/Table/ListTable/index.vue'
import { ActionsFormatter } from '@/components/Table/TableFormatters'
import ViewSecret from './ViewSecret.vue'
import UpdateSecretInfo from './UpdateSecretInfo.vue'
import AccountCreateUpdate from './AccountCreateUpdate.vue'
import { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms'
import ResultDialog from './BulkCreateResultDialog.vue'
@@ -111,7 +101,7 @@ export default {
type: Array,
default: () => ([
'name', 'username', 'asset', 'privileged',
'secret_type', 'date_updated'
'secret_type', 'is_active', 'date_updated'
])
},
headerExtraActions: {
@@ -128,6 +118,7 @@ export default {
showAddDialog: false,
showAddTemplateDialog: false,
createAccountResults: [],
addTemplate: false,
accountCreateUpdateTitle: this.$t('assets.AddAccount'),
iAsset: this.asset,
account: {},
@@ -142,10 +133,6 @@ export default {
order: '-date_updated'
},
columnsExclude: ['spec_info'],
columns: [
'name', 'username', 'asset', 'privileged',
'secret_type', 'source', 'actions'
],
columnsShow: {
min: ['name', 'username', 'actions'],
default: this.columnsDefault
@@ -262,7 +249,7 @@ export default {
name: 'Update',
title: this.$t('common.Update'),
can: this.$hasPerm('accounts.change_account') && !this.$store.getters.currentOrgIsRoot,
callback: ({ row }) => {
callback: ({ row, col }) => {
const data = {
...this.asset,
...row.asset
@@ -270,9 +257,10 @@ export default {
vm.account = row
vm.iAsset = data
vm.showAddDialog = false
vm.addTemplate = false
vm.accountCreateUpdateTitle = this.$t('assets.UpdateAccount')
setTimeout(() => {
vm.showAddDialog = true
vm.$eventBus.$emit('showCreateUpdateDrawer', 'update', { url: this.url, row, col })
})
}
}
@@ -317,8 +305,9 @@ export default {
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.addTemplate = false
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddDialog = true
vm.$eventBus.$emit('showCreateUpdateDrawer', 'create', { url: vm.url })
})
}
},
@@ -334,8 +323,9 @@ export default {
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.addTemplate = true
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddTemplateDialog = true
vm.$eventBus.$emit('showCreateUpdateDrawer', 'create', { url: vm.url })
})
}
},

View File

@@ -15,7 +15,7 @@
<script>
import Dialog from '@/components/Dialog/index.vue'
import DataTable from '@/components/DataTable/index.vue'
import DataTable from '@/components/Table/DataTable/index.vue'
export default {
name: 'ResultDialog',

View File

@@ -4,7 +4,7 @@
<script>
import { GenericListTableDialog } from '@/layout/components'
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
import { ShowKeyCopyFormatter } from '@/components/Table/TableFormatters'
export default {
components: {
@@ -29,7 +29,7 @@ export default {
tableConfig: {
id: 'history_date',
url: `/api/v1/accounts/account-secrets/${this.account.id}/histories/`,
columns: ['secret', 'secret_type', 'version', 'history_date'],
columns: ['secret', 'version', 'history_date'],
columnsMeta: {
secret: {
label: this.$t('assets.Password'),

View File

@@ -29,8 +29,8 @@
</template>
<script>
import Dialog from '@/components/Dialog'
import { UpdateToken, UploadKey } from '@/components/FormFields'
import Dialog from '@/components/Dialog/index.vue'
import { UpdateToken, UploadKey } from '@/components/Form/FormFields'
import { encryptPassword } from '@/utils/crypto'
export default {

View File

@@ -1,12 +1,5 @@
<template>
<div>
<div v-if="mfaDialogVisible">
<UserConfirmDialog
:url="url"
@UserConfirmCancel="exit"
@UserConfirmDone="getAuthInfo"
/>
</div>
<Dialog
:destroy-on-close="true"
:show-cancel="false"
@@ -65,10 +58,9 @@
</template>
<script>
import Dialog from '@/components/Dialog'
import PasswordHistoryDialog from './PasswordHistoryDialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
import Dialog from '@/components/Dialog/index.vue'
import PasswordHistoryDialog from './PasswordHistoryDialog.vue'
import { ShowKeyCopyFormatter } from '@/components/Table/TableFormatters'
import { encryptPassword } from '@/utils/crypto'
export default {
@@ -76,7 +68,6 @@ export default {
components: {
Dialog,
PasswordHistoryDialog,
UserConfirmDialog,
ShowKeyCopyFormatter
},
props: {
@@ -128,7 +119,10 @@ export default {
const url = `/api/v1/accounts/account-secrets/${this.account.id}/histories/?limit=1`
this.$axios.get(url, { disableFlashErrorMsg: true }).then(resp => {
this.versions = resp.count
this.showSecretDialog()
})
} else {
this.showSecretDialog()
}
},
methods: {
@@ -146,10 +140,10 @@ export default {
this.$message.success(this.$tc('common.updateSuccessMsg'))
})
},
getAuthInfo() {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
this.secretInfo = resp
this.sshKeyFingerprint = resp?.spec_info?.ssh_key_fingerprint || '-'
showSecretDialog() {
return this.$axios.get(this.url, { disableFlashErrorMsg: true }).then((res) => {
this.secretInfo = res
this.sshKeyFingerprint = res?.spec_info?.ssh_key_fingerprint || '-'
this.showSecret = true
})
},

View File

@@ -1,5 +1,5 @@
import i18n from '@/i18n/i18n'
import { ChoicesFormatter } from '@/components/TableFormatters'
import { ChoicesFormatter } from '@/components/Table/TableFormatters'
export const connectivityMeta = {
label: i18n.t('assets.Connectivity'),

View File

@@ -1,14 +1,14 @@
<template>
<IBox :fa="icon" :type="type" :title="title" v-bind="$attrs">
<IBox :fa="icon" :title="title" :type="type" v-bind="$attrs">
<table style="width: 100%">
<tr>
<td colspan="2">
<AssetSelect ref="assetSelect" :disabled="disabled" :can-select="canSelect" />
<AssetSelect ref="assetSelect" :can-select="canSelect" :disabled="disabled" />
</td>
</tr>
<tr>
<td colspan="2">
<el-button :type="type" size="small" :disabled="disabled" @click="addObjects">{{ $t('common.Add') }}</el-button>
<el-button :disabled="disabled" :type="type" size="small" @click="addObjects">{{ $t('common.Add') }}</el-button>
</td>
</tr>
</table>
@@ -16,8 +16,8 @@
</template>
<script>
import IBox from '@/components/IBox'
import AssetSelect from '@/components/AssetSelect'
import IBox from '@/components/IBox/index.vue'
import AssetSelect from '@/components/Apps/AssetSelect/index.vue'
export default {
name: 'AssetRelationCard',

View File

@@ -24,8 +24,8 @@
</template>
<script>
import AssetTreeTable from '@/components/AssetTreeTable'
import Dialog from '@/components/Dialog'
import AssetTreeTable from '@/components/Apps/AssetTreeTable/index.vue'
import Dialog from '@/components/Dialog/index.vue'
export default {
componentName: 'AssetSelectDialog',
@@ -86,7 +86,7 @@ export default {
{
prop: 'protocols',
formatter: function(row) {
const data = row.protocols.map(p => {
const data = row.protocols?.map(p => {
return <el-tag size='mini'>{p.name}/{p.port} </el-tag>
})
return <span> {data} </span>

View File

@@ -25,7 +25,7 @@
</template>
<script>
import Select2 from '@/components/FormFields/Select2'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import AssetSelectDialog from './dialog.vue'
import { b } from 'css-color-function/lib/adjusters'

View File

@@ -1,10 +1,10 @@
<template>
<TreeTable
ref="TreeList"
component="TabTree"
:table-config="tableConfig"
:active-menu.sync="treeTableConfig.activeMenu"
:table-config="tableConfig"
:tree-tab-config="treeTableConfig"
component="TabTree"
v-bind="$attrs"
v-on="$listeners"
>
@@ -12,13 +12,13 @@
<slot name="table" />
</template>
<div slot="rMenu" slot-scope="{data}">
<slot name="rMenu" :data="data" />
<slot :data="data" name="rMenu" />
</div>
</TreeTable>
</template>
<script>
import TreeTable from '../TreeTable'
import TreeTable from '../../Table/TreeTable/index.vue'
import { setRouterQuery, setUrlParam } from '@/utils/common'
import $ from '@/utils/jquery-vendor'

View File

@@ -2,21 +2,23 @@
<div>
<div>
<el-button
:disabled="isDisabled"
size="mini"
type="primary"
:disabled="isDisabled"
@click="onOpenDialog"
>{{ $tc('common.Setting') }}</el-button>
>
{{ $tc('common.Setting') }}
</el-button>
</div>
<Dialog
v-if="visible"
width="60%"
:visible.sync="visible"
:title="title"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
:destroy-on-close="true"
:title="title"
:visible.sync="visible"
v-bind="$attrs"
width="60%"
v-on="$listeners"
>
<AutoDataForm
@@ -31,9 +33,11 @@
</template>
<script>
import { Dialog, AutoDataForm } from '@/components'
import Dialog from '../../Dialog'
import AutoDataForm from '../../Form/AutoDataForm'
export default {
componentName: 'AutomationParams',
components: {
Dialog,
AutoDataForm
@@ -57,19 +61,26 @@ export default {
type: Array,
default: () => []
},
platforms: {
type: Array,
default: () => []
},
method: {
type: String,
default: ''
},
url: {
type: String,
default: `/api/v1/assets/platform-automation-methods/`
}
},
data() {
const vm = this
return {
remoteMeta: {},
visible: false,
isDisabled: true,
form: this.value,
node_ids: this.nodes,
asset_ids: this.assets,
config: {
url: this.url,
hasSaveContinue: false,
@@ -77,7 +88,8 @@ export default {
method: 'get',
fields: [],
fieldsMeta: {}
}
},
onFieldChangeHandler: _.debounce(vm.handleFieldChange, 1000)
}
},
computed: {
@@ -87,22 +99,27 @@ export default {
},
watch: {
nodes: {
handler(val) {
this.node_ids = val
this.onFieldChangeHandle()
handler() {
this.onFieldChangeHandler()
},
deep: true
},
assets: {
handler(val) {
this.asset_ids = val
this.onFieldChangeHandle()
handler() {
this.onFieldChangeHandler()
},
deep: true
},
platforms: {
handler(newVal) {
this.onFieldChangeHandler()
},
deep: true,
immediate: true
}
},
created() {
this.getUrlMeta()
async mounted() {
await this.getUrlMeta()
},
methods: {
async getUrlMeta() {
@@ -110,35 +127,34 @@ export default {
this.remoteMeta = data.actions[this.config.method.toUpperCase()] || {}
},
async getFilterPlatforms() {
const res = await this.$axios.post(
return await this.$axios.post(
'/api/v1/assets/platforms/filter-nodes-assets/',
{
'node_ids': this.node_ids,
'asset_ids': this.asset_ids
'node_ids': this.nodes,
'asset_ids': this.assets,
'platform_ids': this.platforms.map(i => i.id || i.pk || i)
}
)
return res
},
async onFieldChangeHandle() {
async handleFieldChange() {
const platforms = await this.getFilterPlatforms()
let pushAccountMethods = platforms.map(i => i.automation?.push_account_method)
let pushAccountMethods = platforms.map(i => i.automation[this.method])
pushAccountMethods = _.uniq(pushAccountMethods)
//
const hasCanSettingPushMethods = _.intersection(pushAccountMethods, Object.keys(this.remoteMeta))
this.setFormConfig(hasCanSettingPushMethods)
if (hasCanSettingPushMethods.length > 0) {
this.isDisabled = false
this.$emit('input', this.form)
} else {
this.isDisabled = true
this.$emit('input', {})
}
this.isDisabled = hasCanSettingPushMethods.length <= 0
},
setFormConfig(methods) {
const newForm = {}
const fields = []
const fieldsMeta = {}
this.config.fields = []
// Todo: serializer,
const typeMapper = {
'string': 'input',
'boolean': 'switch'
}
for (const method of methods) {
const filterField = this.remoteMeta[method] || {}
@@ -155,7 +171,7 @@ export default {
for (const [k, v] of Object.entries(filterField.children)) {
const item = {
...v,
type: 'input'
type: typeMapper[v.type] || 'input'
}
delete item.default
fieldsMeta[method].fields.push(k)
@@ -172,8 +188,11 @@ export default {
this.visible = true
},
onSubmit(form) {
this.visible = false
this.form = form
this.$emit('input', form)
setTimeout(() => {
this.visible = false
}, 100)
this.$log.debug('Auto push form:', form)
}
}

View File

@@ -0,0 +1,97 @@
<template>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import ListTable from '@/components/Table/ListTable/index.vue'
export default {
name: 'BlockedIPList',
components: {
ListTable
},
props: {
object: {
type: Object,
required: false,
default: () => ({})
}
},
data() {
const vm = this
return {
tableConfig: {
url: '/api/v1/settings/security/block-ip/',
columns: [
'ip', 'actions'
],
columnsMeta: {
ip: {
label: this.$t('assets.ip')
},
actions: {
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'UnlockIP',
title: this.$t('setting.Unblock'),
can: this.$hasPerm('settings.change_security'),
type: 'primary',
callback: ({ row }) => {
this.$axios.post(
'/api/v1/settings/security/unlock-ip/',
{ ips: [row.ip] }
).then(() => {
vm.$message.success(this.$tc('common.UnlockSuccessMsg'))
vm.$refs.ListTable.reloadTable()
})
}
}
]
}
}
}
},
headerActions: {
hasExport: false,
hasImport: false,
hasCreate: false,
hasSearch: false,
hasRefresh: true,
hasBulkDelete: false,
hasBulkUpdate: false,
hasLeftActions: true,
hasRightActions: true,
extraMoreActions: [
{
name: 'UnlockSelected',
title: this.$t('setting.BulkUnblock'),
type: 'primary',
can: ({ selectedRows }) => {
return selectedRows.length > 0
},
callback: function({ selectedRows }) {
vm.$axios.post(
'/api/v1/settings/security/unlock-ip/',
{
ips: selectedRows.map(v => { return v.ip })
}
).then(res => {
vm.$message.success(vm.$tc('common.UnlockSuccessMsg'))
vm.$refs.ListTable.reloadTable()
})
}
}
]
}
}
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -0,0 +1,75 @@
<template>
<div>
<div>
<el-button
size="mini"
type="primary"
@click="onOpenDialog"
>{{ $tc('common.View') }}</el-button>
</div>
<Dialog
v-if="visible"
:visible.sync="visible"
:title="title"
width="40%"
:show-cancel="false"
:show-confirm="false"
:destroy-on-close="true"
v-bind="$attrs"
v-on="$listeners"
>
<BlockedIPList />
</Dialog>
</div>
</template>
<script>
import { Dialog } from '@/components'
import BlockedIPList from '@/components/Apps/BlockedIPs/BlockedIPList'
export default {
componentName: 'BlockedIPs',
components: {
BlockedIPList,
Dialog
},
props: {
value: {
type: Object,
default: () => ({})
},
title: {
type: String,
default: function() {
return this.$t('setting.BlockedIPS')
}
},
url: {
type: String,
default: `/api/v1/assets/platform-automation-methods/`
}
},
data() {
return {
remoteMeta: {},
visible: false,
form: this.value,
config: {
url: this.url,
hasSaveContinue: false,
hasButtons: true,
fields: [],
fieldsMeta: {}
}
}
},
methods: {
onOpenDialog() {
this.visible = true
}
}
}
</script>
<style scoped>
</style>

View File

@@ -33,7 +33,7 @@
</template>
<script>
import Dialog from '@/components/Dialog'
import Dialog from '@/components/Dialog/index.vue'
import { openTaskPage } from '@/utils/jms'
export default {

View File

@@ -3,8 +3,8 @@
</template>
<script type="text/jsx">
import TreeTable from '../TreeTable'
import { DetailFormatter } from '@/components/TableFormatters'
import TreeTable from '../../Table/TreeTable/index.vue'
import { DetailFormatter } from '@/components/Table/TableFormatters'
export default {
name: 'GrantedAssets',

View File

@@ -7,7 +7,7 @@
</template>
<script>
import ListTable from '@/components/ListTable/index.vue'
import ListTable from '@/components/Table/ListTable/index.vue'
import { toM2MJsonParams } from '@/utils/jms'
export default {

View File

@@ -7,7 +7,7 @@
</template>
<script>
import ListTable from '@/components/ListTable/index.vue'
import ListTable from '@/components/Table/ListTable/index.vue'
import { toM2MJsonParams } from '@/utils/jms'
export default {

View File

@@ -30,8 +30,8 @@
</template>
<script>
import IBox from '@/components/IBox'
import DiffDetail from '@/components/Dialog/DiffDetail'
import IBox from '@/components/IBox/index.vue'
import DiffDetail from '@/components/Dialog/DiffDetail.vue'
import { openTaskPage } from '@/utils/jms'
export default {

View File

@@ -0,0 +1,224 @@
<template>
<Dialog
:close-on-click-modal="false"
:destory-on-close="true"
:show-cancel="false"
:show-confirm="false"
:title="title"
:visible.sync="visible"
class="dialog-content"
v-bind="$attrs"
width="600px"
@confirm="visible = false"
v-on="$listeners"
>
<div v-if="confirmTypeRequired === 'relogin'">
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24">
<el-alert
:title="$tc('auth.ReLoginTitle')"
center
style="margin-bottom: 20px;"
type="error"
/>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="logout">
{{ this.$t('auth.ReLogin') }}
</el-button>
</el-col>
</el-row>
</div>
<div v-else>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24" :span="24" class="add">
<el-select
v-model="subTypeSelected"
style="width: 100%; margin-bottom: 20px;"
@change="handleSubTypeChange"
>
<el-option
v-for="item of subTypeChoices"
:key="item.name"
:disabled="item.disabled"
:label="item.display_name"
:value="item.name"
/>
</el-select>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24" style="display: flex; margin-bottom: 20px;">
<el-input v-model="secretValue" :placeholder="inputPlaceholder" :show-password="showPassword" />
<span v-if="subTypeSelected === 'sms'" style="margin: -1px 0 0 20px;">
<el-button
:disabled="smsBtnDisabled"
size="mini"
style="line-height:20px; float: right;"
type="primary"
@click="sendSMSCode"
>
{{ smsBtnText }}
</el-button>
</span>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 10px auto;">
<el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="handleConfirm">
{{ this.$t('common.Confirm') }}
</el-button>
</el-col>
</el-row>
</div>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
export default {
name: 'UserConfirmDialog',
components: {
Dialog
},
props: {
url: {
type: String,
default: ''
},
handler: {
type: Function,
default: null
}
},
data() {
return {
title: this.$t('common.CurrentUserVerify'),
smsWidth: 0,
subTypeSelected: '',
inputPlaceholder: '',
smsBtnText: this.$t('common.SendVerificationCode'),
smsBtnDisabled: false,
confirmTypeRequired: '',
subTypeChoices: [],
secretValue: '',
visible: false,
callback: null,
cancel: null,
processing: false
}
},
computed: {
showPassword() {
return this.confirmTypeRequired === 'password'
}
},
mounted() {
// const onRecvCallback = _.debounce(this.performConfirm, 500)
this.$eventBus.$on('showConfirmDialog', this.performConfirm)
},
methods: {
handleSubTypeChange(val) {
this.inputPlaceholder = this.subTypeChoices.filter(item => item.name === val)[0]?.placeholder
this.smsWidth = val === 'sms' ? 6 : 0
},
performConfirm({ response, callback, cancel }) {
if (this.processing || this.visible) {
return
}
this.processing = true
this.callback = callback
this.cancel = cancel
this.$log.debug('perform confirm action')
const confirmType = response.data?.code
const confirmUrl = '/api/v1/authentication/confirm/'
this.$axios.get(confirmUrl, { params: { confirm_type: confirmType }}).then((data) => {
this.confirmTypeRequired = data.confirm_type
if (this.confirmTypeRequired === 'relogin') {
this.$axios.post(confirmUrl, { 'confirm_type': 'relogin', 'secret_key': 'x' }).then(() => {
this.callback()
this.visible = false
}).catch(() => {
this.title = this.$t('auth.NeedReLogin')
this.visible = true
})
}
this.subTypeChoices = data.content
const defaultSubType = this.subTypeChoices.filter(item => !item.disabled)[0]
this.subTypeSelected = defaultSubType.name
this.inputPlaceholder = defaultSubType.placeholder
this.visible = true
}).catch((err) => {
const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('common.GetConfirmTypeFailed')
this.$message.error(msg)
this.cancel(err)
}).finally(() => {
this.processing = false
})
},
logout() {
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
},
sendSMSCode() {
this.$axios.post(`/api/v1/authentication/mfa/select/`, { type: 'sms' }).then(res => {
this.$message.success(this.$tc('common.VerificationCodeSent'))
let time = 60
const interval = setInterval(() => {
const originText = this.smsBtnText
this.smsBtnText = this.$t('common.Pending') + `: ${time}`
this.smsBtnDisabled = true
time -= 1
if (time === 0) {
this.smsBtnText = originText
this.smsBtnDisabled = false
clearInterval(interval)
}
}, 1000)
})
},
handleConfirm() {
if (this.confirmTypeRequired === 'relogin') {
return this.logout()
}
if (this.subTypeSelected === 'otp' && this.secretValue.length !== 6) {
return this.$message.error(this.$tc('common.MFAErrorMsg'))
}
const data = {
confirm_type: this.confirmTypeRequired,
mfa_type: this.confirmTypeRequired === 'mfa' ? this.subTypeSelected : '',
secret_key: this.secretValue
}
this.$axios.post(`/api/v1/authentication/confirm/`, data).then(res => {
this.callback()
this.visible = false
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-content >>> .el-dialog__footer {
padding: 0;
}
.dialog-content >>> .el-dialog {
padding: 8px;
.el-dialog__body {
padding-top: 30px;
padding-bottom: 30px;
}
}
.confirm-btn {
width: 100%;
line-height: 20px;
}
</style>

View File

@@ -17,6 +17,11 @@ export default {
default: null
}
},
data() {
return {
formatterData: ''
}
},
computed: {
displayValue() {
if ([null, undefined, ''].includes(this.value)) {
@@ -65,7 +70,17 @@ export default {
},
render(h) {
if (typeof this.formatter === 'function') {
return this.formatter(this.item, this.value)
const data = this.formatter(this.item, this.value)
if (data instanceof Promise) {
data.then(res => {
this.formatterData = res
})
} else {
this.formatterData = data
}
return (
<span>{this.formatterData}</span>
)
}
if (this.value instanceof Array) {
const newArr = this.value || []

View File

@@ -1,9 +1,9 @@
<template>
<DetailCard v-if="!loading && hasObject" :items="items" v-bind="$attrs" />
<DetailCard v-if="!loading && hasObject && items.length > 0" :items="items" v-bind="$attrs" />
</template>
<script>
import DetailCard from './index'
import DetailCard from './index.vue'
import { copy, toSafeLocalDateStr } from '@/utils/common'
export default {

View File

@@ -1,8 +1,8 @@
<template>
<IBox :title="title" :fa="fa">
<IBox :fa="fa" :title="title">
<el-form class="content" label-position="left" label-width="25%">
<el-form-item v-for="item in items" :key="item.key" :label="item.key">
<ItemValue class="item-value" :value="item.value" v-bind="item" />
<ItemValue :value="item.value" class="item-value" v-bind="item" />
</el-form-item>
</el-form>
<slot />
@@ -10,8 +10,8 @@
</template>
<script>
import IBox from '../IBox'
import ItemValue from './ItemValue'
import IBox from '../../IBox/index.vue'
import ItemValue from './ItemValue.vue'
export default {
name: 'DetailCard',

View File

@@ -1,6 +1,6 @@
<template>
<IBox :type="type" :title="title" v-bind="$attrs">
<table style="width: 100%;table-layout:fixed;" class="CardTable">
<IBox :title="title" :type="type" v-bind="$attrs">
<table class="CardTable" style="width: 100%;table-layout:fixed;">
<tr>
<td colspan="2">
<Select2 ref="select2" v-model="select2.value" :disabled="iDisabled" v-bind="select2" />
@@ -9,7 +9,7 @@
<slot />
<tr>
<td colspan="2">
<el-button :type="type" size="small" :loading="submitLoading" :disabled="iDisabled" @click="addObjects">
<el-button :disabled="iDisabled" :loading="submitLoading" :type="type" size="small" @click="addObjects">
{{ $t('common.Add') }}
</el-button>
</td>
@@ -17,12 +17,12 @@
<template v-if="showHasObjects">
<tr v-for="obj of iHasObjects" :key="obj.value" class="item">
<td style="width: 100%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
<el-tooltip style="margin: 4px;" effect="dark" :content="obj.label" placement="left">
<el-tooltip :content="obj.label" effect="dark" placement="left" style="margin: 4px;">
<b>{{ obj.label }}</b>
</el-tooltip>
</td>
<td>
<el-button size="mini" :disabled="iDisabled" type="danger" style="float: right" @click="removeObject(obj)">
<el-button :disabled="iDisabled" size="mini" style="float: right" type="danger" @click="removeObject(obj)">
<i class="fa fa-minus" />
</el-button>
</td>
@@ -30,7 +30,7 @@
</template>
<tr v-if="params.hasMore && showHasMore" class="item">
<td colspan="2">
<el-button :type="type" :disabled="iDisabled" size="small" style="width: 100%" @click="loadMore">
<el-button :disabled="iDisabled" :type="type" size="small" style="width: 100%" @click="loadMore">
<i class="fa fa-arrow-down" />
{{ $t('common.More') }}
</el-button>
@@ -41,10 +41,11 @@
</template>
<script>
import Select2 from '../FormFields/Select2'
import IBox from '../IBox'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import IBox from '../../IBox/index.vue'
import { createSourceIdCache } from '@/api/common'
import { mapGetters } from 'vuex'
export default {
name: 'RelationCard',
components: {

View File

@@ -1,16 +1,19 @@
<template>
<DataForm
v-if="!loading"
:disabled="disabled"
:fields="iFields"
:form="value"
style="margin-left: -26%;margin-right: -6%"
v-bind="kwargs"
@change="updateValue($event)"
@input="updateValue($event)"
v-on="$listeners"
/>
</template>
<script>
import DataForm from '@/components/DataForm'
import DataForm from '@/components/Form/DataForm/index.vue'
export default {
name: 'NestedField',
@@ -37,6 +40,8 @@ export default {
},
data() {
return {
loading: false,
formJson: JSON.stringify(this.value),
kwargs: {
hasReset: false,
hasSaveContinue: false,
@@ -65,7 +70,26 @@ export default {
return fields
}
},
watch: {
value: {
handler(val) {
const valJson = JSON.stringify(val)
// value
if (valJson !== this.formJson) {
this.loading = true
setTimeout(() => {
this.loading = false
}, 10)
}
},
deep: true
}
},
methods: {
updateValue(val) {
this.formJson = JSON.stringify(val)
this.$emit('input', val)
},
objectToString(obj) {
let data = ''
// eslint-disable-next-line prefer-const

View File

@@ -23,9 +23,9 @@
</template>
<script>
import DataForm from '../DataForm'
import FormGroupHeader from '@/components/FormGroupHeader'
import { FormFieldGenerator } from '@/components/AutoDataForm/utils'
import DataForm from '../DataForm/index.vue'
import FormGroupHeader from '@/components/Form/FormGroupHeader/index.vue'
import { FormFieldGenerator } from '@/components/Form/AutoDataForm/utils'
export default {
name: 'AutoDataForm',
@@ -67,6 +67,9 @@ export default {
}
},
computed: {
dataForm() {
return this.$refs.dataForm
},
iForm() {
const iForm = {}
Object.entries(this.form).forEach(([key, value]) => {

View File

@@ -1,13 +1,13 @@
import Vue from 'vue'
import Select2 from '@/components/FormFields/Select2'
import ObjectSelect2 from '@/components/FormFields/NestedObjectSelect2'
import NestedField from '@/components/AutoDataForm/components/NestedField'
import Switcher from '@/components/FormFields/Switcher'
import rules from '@/components/DataForm/rules'
import BasicTree from '@/components/FormFields/BasicTree'
import JsonEditor from '@/components/FormFields/JsonEditor'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import ObjectSelect2 from '@/components/Form/FormFields/NestedObjectSelect2.vue'
import NestedField from '@/components/Form/AutoDataForm/components/NestedField.vue'
import Switcher from '@/components/Form/FormFields/Switcher.vue'
import rules from '@/components/Form/DataForm/rules'
import BasicTree from '@/components/Form/FormFields/BasicTree.vue'
import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue'
import { assignIfNot } from '@/utils/common'
import TagInput from '@/components/FormFields/TagInput.vue'
import TagInput from '@/components/Form/FormFields/TagInput.vue'
export class FormFieldGenerator {
constructor(emit) {

View File

@@ -25,7 +25,9 @@
multiple
style="width:100%"
>
<el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{ item }}</el-option>
<el-option v-for="(item,index) of weekList" :key="index" :value="index === 6 ? 0 : (index + 1)">
{{ item }}
</el-option>
</el-select>
</el-radio>
</el-form-item>

View File

@@ -1,19 +1,22 @@
<template>
<ElFormRender
ref="form"
:class="mobile? 'mobile' : 'desktop'"
:content="fields"
:form="basicForm"
:label-position="labelPosition"
label-width="20%"
v-bind="$attrs"
v-on="$listeners"
>
<!-- slot 透传 -->
<slot v-for="item in fields" :slot="`id:${item.id}`" :name="`id:${item.id}`" />
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
<div>
<ElFormRender
ref="form"
:class="mobile? 'mobile' : 'desktop'"
:content="fields"
:form="basicForm"
:label-position="labelPosition"
class="form-fields"
label-width="22%"
v-bind="$attrs"
v-on="$listeners"
>
<!-- slot 透传 -->
<slot v-for="item in fields" :slot="`id:${item.id}`" :name="`id:${item.id}`" />
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
<el-form-item v-if="hasButtons" class="form-buttons">
</ElFormRender>
<div v-if="hasButtons" class="form-buttons">
<el-button
v-for="button in moreButtons"
:key="button.title"
@@ -38,14 +41,14 @@
v-if="defaultButton"
:disabled="!canSubmit"
:loading="isSubmitting"
size="small"
:size="submitBtnSize"
type="primary"
@click="submitForm('form')"
>
{{ $t('common.Submit') }}
{{ submitBtnText }}
</el-button>
</el-form-item>
</ElFormRender>
</div>
</div>
</template>
<script>
@@ -73,6 +76,16 @@ export default {
type: Boolean,
default: true
},
submitBtnSize: {
type: String,
default: 'small'
},
submitBtnText: {
type: String,
default() {
return this.$t('common.Submit')
}
},
hasSaveContinue: {
type: Boolean,
default: true
@@ -126,8 +139,8 @@ export default {
})
},
//
resetForm(formName) {
this.$refs[formName].resetFields()
resetForm() {
this.$refs['form'].resetFields()
},
handleClick(button) {
const callback = button.callback || function(values, form) {
@@ -138,6 +151,7 @@ export default {
callback(values, form, button)
},
getFormValue() {
return this.$refs.form.getFormValue()
}
}
}
@@ -149,7 +163,7 @@ export default {
}
.el-form ::v-deep .el-form-item__content {
width: 75%;
width: 73%;
}
.mobile.el-form ::v-deep .el-form-item__content {
@@ -187,5 +201,7 @@ export default {
.form-buttons {
margin-top: 20px;
margin-left: 22%;
margin-bottom: 20px;
}
</style>

View File

@@ -53,13 +53,27 @@ export const matchAlphanumericUnderscore = {
trigger: ['blur', 'change']
}
// 不能包含()
export const MatchExcludeParenthesis = {
validator: (rule, value, callback) => {
value = value?.trim()
if (!/^[^()]*$/.test(value)) {
callback(new Error(i18n.t('common.notParenthesis')))
} else {
callback()
}
},
trigger: ['blur', 'change']
}
export default {
IpCheck,
Required,
RequiredChange,
EmailCheck,
specialEmojiCheck,
matchAlphanumericUnderscore
matchAlphanumericUnderscore,
MatchExcludeParenthesis
}
export const JsonRequired = {

View File

@@ -0,0 +1,77 @@
<template>
<div>
<el-radio-group v-model="type" @input="handleTypeChange">
<el-radio v-for="tp of types" :key="tp.name" :label="tp.name">
{{ tp.label }}
</el-radio>
</el-radio-group>
<Select2 v-if="type === 'spec'" v-model="selected" v-bind="select2" @change="onChangeEmit" />
</div>
</template>
<script>
import Select2 from '@/components/Form/FormFields/Select2.vue'
export default {
name: 'AllOrSpec',
components: { Select2 },
props: {
value: {
type: [Array],
default: () => ([])
},
select2: {
type: Object,
default: () => ({})
},
resource: {
type: String,
default: ''
}
},
data() {
return {
type: 'all', // all, selected
types: [
{ name: 'all', label: this.$t('common.All') },
{ name: 'spec', label: this.$t('common.Spec') + this.$t('common.WordSep') + this.resource }
],
selected: []
}
},
computed: {
iValue() {
if (this.type === 'all') {
return ['all']
} else {
return this.selected
}
}
},
mounted() {
if (!this.value || this.value.length === 0) {
return
}
console.log('Value: ', this.value)
if (this.value.indexOf('all') > -1) {
this.type = 'all'
} else {
this.type = 'spec'
this.selected = this.value
}
},
methods: {
onChangeEmit() {
this.$emit('input', this.iValue)
},
handleTypeChange() {
this.$emit('input', this.iValue)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,62 @@
<template>
<div>
<GenericCreateUpdateForm
class="attr-form"
v-bind="formConfig"
@submit="onSubmit"
/>
<DataTable :config="tableConfig" class="attr-list" />
</div>
</template>
<script>
import GenericCreateUpdateForm from '@/layout/components/GenericCreateUpdateForm'
import DataTable from '@/components/Table/DataTable/index.vue'
export default {
name: 'AttrInput',
components: { DataTable, GenericCreateUpdateForm },
props: {
formConfig: {
type: Object,
default: () => ({})
},
tableConfig: {
type: Object,
default: () => ({})
},
beforeSubmit: {
type: Function,
default: (val) => { return true }
}
},
data() {
return {}
},
methods: {
onSubmit(value) {
if (this.beforeSubmit(value)) {
const clonedValue = JSON.parse(JSON.stringify(value))
this.tableConfig.totalData.push(clonedValue)
this.$emit('submit', this.tableConfig.totalData)
}
}
}
}
</script>
<style lang="scss" scoped>
.attr-form {
>>> .el-select {
width: 100%;
}
>>> .el-form-item__content {
width: 100%;
}
>>> .form-buttons {
margin: auto;
}
}
</style>

View File

@@ -85,7 +85,7 @@ export default {
<span>{label} </span>
{helpText
? (<el-tooltip content={helpText} placement='top'>
<i class='fa fa-info-circle'></i>
<i class='fa fa-question-circle-o'></i>
</el-tooltip>) : ''}
</span>)
}

View File

@@ -16,9 +16,8 @@
>
<i :class="item.icon" style="margin-right: 4px;" />{{ item.name }}
</el-button>
<el-autocomplete
v-if="item.type === 'input' && item.el.autoComplete"
v-if="item.type === 'input' &&item.el && item.el.autoComplete"
v-model="item.value"
:placeholder="item.placeholder"
:fetch-suggestions="item.el.query"
@@ -27,7 +26,14 @@
@select="item.callback(item.value)"
@change="item.callback(item.value)"
/>
<el-input
v-else-if="item.type==='input'"
v-model="item.value"
:placeholder="item.placeholder"
class="inline-input"
size="mini"
@change="item.callback(item.value)"
/>
<div v-if="item.type==='select' && item.el && item.el.create" class="select-content">
<span class="filter-label">
{{ item.name }}:

View File

@@ -1,7 +1,7 @@
<template>
<div>
<div v-for="(command, index) in value" :key="index" :prop="'value.' + index + '.value'" class="command-item">
<el-input v-model="value[index]" size="mini">
<div v-for="(command, index) in iValue" :key="index" :prop="'iValue.' + index + '.value'" class="command-item">
<el-input v-model="iValue[index]" size="mini">
<template slot="prepend"> {{ inputTitle + ' ' + (index + 1) }}</template>
</el-input>
<div class="input-button">
@@ -14,7 +14,7 @@
@click="handleDelete(command)"
/>
<el-button
v-if="index === value.length - 1"
v-if="index === iValue.length - 1"
icon="el-icon-plus"
size="mini"
style="flex-shrink: 0;"
@@ -27,6 +27,7 @@
</template>
<script>
export default {
props: {
value: {
@@ -39,20 +40,32 @@ export default {
}
},
data() {
return {}
return {
iValue: ['']
}
},
watch: {
iValue: {
handler(v) {
this.$emit('input', Array.from(v))
}
}
},
created() {
this.iValue = Array.from(this.value)
},
methods: {
handleDelete(command) {
const index = this.value.indexOf(command)
const index = this.iValue.indexOf(command)
if (index !== -1) {
this.value.splice(index, 1)
this.iValue.splice(index, 1)
}
},
handleAdd() {
this.value.push('')
this.iValue.push('')
},
deleteDisabled() {
return this.value.length <= 1
return this.iValue.length <= 1
}
}
}

View File

@@ -18,10 +18,10 @@
</template>
<script>
import DataForm from '@/components/DataForm/index.vue'
import DataForm from '@/components/Form/DataForm/index.vue'
import Dialog from '@/components/Dialog/index.vue'
import ValueField from '@/components/FormFields/JSONManyToManySelect/ValueField.vue'
import { attrMatchOptions, typeMatchMapper } from './const'
import ValueField from '@/components/Form/FormFields/JSONManyToManySelect/ValueField.vue'
import { attrMatchOptions, typeMatchMapper } from '@/components/const'
export default {
name: 'AttrFormDialog',

View File

@@ -13,7 +13,7 @@
<script>
import Dialog from '@/components/Dialog/index.vue'
import ListTable from '@/components/ListTable/index.vue'
import ListTable from '@/components/Table/ListTable/index.vue'
export default {
name: 'AttrMatchResultDialog',

View File

@@ -8,9 +8,9 @@
</template>
<script>
import TagInput from '@/components/FormFields/TagInput.vue'
import Select2 from '@/components/FormFields/Select2.vue'
import Switcher from '@/components/FormFields/Switcher.vue'
import TagInput from '@/components/Form/FormFields/TagInput.vue'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import Switcher from '@/components/Form/FormFields/Switcher.vue'
export default {
name: 'ValueField',
@@ -81,7 +81,6 @@ export default {
changeValueType() {
this.loading = true
this.type = this.getType()
console.log('Type is: ', this.type, this.match)
this.$nextTick(() => {
this.loading = false
})
@@ -89,15 +88,15 @@ export default {
getType() {
const attrType = this.attr.type || 'str'
this.$log.debug('Value field attr type: ', attrType, this.attr, this.match)
if (attrType === 'm2m') {
if (['m2m', 'fk', 'select'].includes(attrType)) {
return 'select'
} else if (attrType === 'bool') {
return 'bool'
} else if (attrType === 'select') {
return 'select'
}
if (['in', 'ip_in'].includes(this.match)) {
return 'array'
} else if (this.match.startsWith('m2m')) {
return 'select'
} else {
return 'string'
}

View File

@@ -3,11 +3,13 @@
<i v-if="value" class="fa fa-check text-primary" />
<i v-else class="fa fa-times text-danger" />
</span>
<span v-else :title="value">{{ value }}</span>
<span v-else :title="value">
{{ value }}
</span>
</template>
<script>
import BaseFormatter from '@/components/TableFormatters/base.vue'
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
import { setUrlParam } from '@/utils/common'
export default {
@@ -32,44 +34,53 @@ export default {
value: ''
}
},
computed: {
},
watch: {
cellValue: {
handler(val) {
handler() {
this.getValue()
},
deep: true
},
formatterArgs: {
handler() {
this.getValue()
},
deep: true
},
row: {
handler() {
this.getValue()
},
immediate: true,
deep: true
}
},
mounted() {
this.getValue()
setTimeout(() => {
this.getValue()
}, 100)
},
methods: {
async getValue() {
this.attr = this.formatterArgs.attrs.find(attr => attr.name === this.row.name)
this.match = this.row.match
const match = this.row.match
this.$log.debug('ValueFormatter: ', this.attr, this.row.name)
if (this.attr.type === 'm2m') {
const url = setUrlParam(this.attr.el.url, 'ids', this.cellValue.join(','))
const data = await this.$axios.get(url)
const data = await this.$axios.get(url) || []
if (data.length > 0) {
const displayField = this.attr.el.displayField || 'name'
this.value = data.map(item => item[displayField]).join(', ')
}
} else if (this.attr.type === 'select') {
this.value = this.attr.el.options
.filter(item => this.cellValue.includes(item.value))
.map(item => item.label).join(',')
} else if (['in', 'ip_in'].includes(this.match)) {
const options = this.attr.el.options || []
const items = options.filter(item => this.cellValue.includes(item.value))
this.value = items.map(item => item.label).join(', ')
} else if (['in', 'ip_in'].includes(match)) {
this.value = this.cellValue.join(', ')
} else {
this.value = this.cellValue
}
this.loading = false
}
}
}
</script>

View File

@@ -38,12 +38,12 @@
<script>
import Select2 from '../Select2.vue'
import DataTable from '@/components/DataTable/index.vue'
import DataTable from '@/components/Table/DataTable/index.vue'
import ValueFormatter from './ValueFormatter.vue'
import AttrFormDialog from './AttrFormDialog.vue'
import AttrMatchResultDialog from './AttrMatchResultDialog.vue'
import { setUrlParam } from '@/utils/common'
import { attrMatchOptions } from './const'
import { attrMatchOptions } from '@/components/const'
import { toM2MJsonParams } from '@/utils/jms'
export default {

View File

@@ -4,6 +4,7 @@
v-model="resultInfo"
:mode="'code'"
:show-btns="false"
:class="{resize: resize === 'vertical'}"
@json-change="onJsonChange"
@json-save="onJsonSave"
@has-error="onError"
@@ -20,6 +21,13 @@ export default {
value: {
type: [String, Object, Array],
default: () => ({})
},
resize: {
type: String,
validator: (value) => {
return ['none', 'vertical'].indexOf(value) !== -1
},
default: 'vertical'
}
},
data() {
@@ -46,15 +54,21 @@ export default {
},
onError: _.debounce(function(value) {
this.$message.error(this.$tc('common.FormatError'))
}, 1100)
}, 1500)
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
@import "~@/styles/variables";
.json-editor {
.resize {
& > > > .jsoneditor {
resize: vertical;
cursor: s-resize;
}
}
& > > > .jsoneditor {
border: 1px solid #e5e6e7;
}

View File

@@ -9,7 +9,7 @@
</template>
<script>
import Select2 from './Select2'
import Select2 from './Select2.vue'
export default {
name: 'NestedObjectSelect2',

View File

@@ -0,0 +1,101 @@
<template>
<div style="display: block">
<el-button size="mini" type="primary" @click="visible=true">
{{ $t('common.Setting') }}
</el-button>
<Dialog
:destroy-on-close="true"
:title="$tc('common.PasswordRule')"
:visible.sync="visible"
width="600px"
@cancel="handleCancel"
@confirm="handleConfirm"
@open="handleOpen"
>
<AutoDataForm ref="dataform" v-bind="form" />
</Dialog>
</div>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
export default {
name: 'PasswordRule',
components: { Dialog, AutoDataForm },
props: {
value: {
type: Object,
default: () => ({
length: 16
})
}
},
data() {
return {
visible: false,
form: {
url: '',
hasButtons: false,
hasReset: false,
hasSaveContinue: false,
form: Object.assign({}, this.value),
fields: [
{
id: 'length',
label: this.$t('common.Length'),
type: 'input-number',
el: {
min: 8,
max: 30
}
},
{
id: 'uppercase',
label: this.$t('common.Uppercase'),
type: 'switch'
},
{
id: 'lowercase',
label: this.$t('common.Lowercase'),
type: 'switch'
},
{
id: 'digit',
label: this.$t('common.Digit'),
type: 'switch'
},
{
id: 'symbol',
label: this.$t('common.SpecialSymbol'),
type: 'switch'
}
]
}
}
},
methods: {
handleConfirm() {
const formValue = this.$refs.dataform.dataForm.getFormValue()
this.form.form = formValue
this.$emit('input', formValue)
setTimeout(() => {
this.visible = false
}, 100)
},
handleCancel() {
this.$refs.dataform.dataForm.resetForm()
setTimeout(() => {
this.visible = false
}, 100)
},
handleOpen() {
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,116 @@
<template>
<Dialog
v-if="$attrs.visible"
:close-on-click-modal="false"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
:title="$tc('assets.PlatformProtocolConfig') + '' + protocol.name"
class="setting-dialog"
v-bind="$attrs"
width="70%"
v-on="$listeners"
>
<el-alert v-if="disabled && platformDetail" style="margin-bottom: 10px" type="success">
{{ $t('assets.InheritPlatformConfig') }}
<el-link :href="platformDetail" class="link-more" target="_blank">
{{ $t('common.View') }}
</el-link>
<i class="fa fa-external-link" />
</el-alert>
<AutoDataForm
:disabled="disabled"
:form="form"
class="data-form"
v-bind="config"
@submit="onSubmit"
/>
</Dialog>
</template>
<script>
import { AutoDataForm, Dialog } from '@/components'
import JsonEditor from '@/components/Form/FormFields/JsonEditor.vue'
export default {
name: 'ProtocolSetting',
components: {
Dialog,
AutoDataForm
},
props: {
protocol: {
type: Object,
default: () => ({})
},
disabled: {
type: Boolean,
default: false
}
},
data() {
const vm = this
const platform = this.$route.query.platform
return {
loading: true,
form: this.protocol,
platformDetail: platform ? '#/console/assets/platforms/' + platform : '',
config: {
hasSaveContinue: false,
hasButtons: !this.disabled,
url: '/api/v1/assets/protocol-settings/?name=' + this.protocol.name,
fields: [
[vm.$t('common.Basic'), [
'primary', 'required', 'default', 'public'
]],
[vm.$t('common.Advanced'), ['setting']]
],
fieldsMeta: {
setting: {
fields: '__all__',
fieldsMeta: {
username_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
},
password_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
},
submit_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
},
script: {
component: JsonEditor,
hidden: (formValue) => formValue['autofill'] !== 'script'
}
}
}
}
}
}
},
methods: {
onSubmit(form) {
this.protocol = Object.assign(this.protocol, form)
this.$emit('update:visible', false)
this.$emit('confirm', this.protocol)
}
}
}
</script>
<style lang="scss" scoped>
.data-form > > > .el-form-item.form-buttons {
padding-top: 10px;
margin-bottom: 0;
}
.setting-dialog > > > .el-dialog__body {
padding-top: 10px;
}
.link-more {
font-size: 10px;
border-bottom: solid 1px;
color: inherit;
}
</style>

View File

@@ -3,9 +3,10 @@
<div v-for="(item, index) in items" :key="item.name" class="protocol-item">
<el-input
v-model="item.port"
:class="readonly ? '' : 'input-with-select'"
:class="isPortReadonly(item) ? '' : 'input-with-select'"
:placeholder="portPlaceholder"
:readonly="readonly"
:readonly="isPortReadonly(item)"
:title="isPortReadonly(item) ? '端口由 URL 指定' : ''"
v-bind="$attrs"
>
<template #prepend>
@@ -62,7 +63,7 @@
<ProtocolSettingDialog
v-if="showDialog"
:disabled="settingReadonly || readonly"
:item="settingItem"
:protocol="currentProtocol"
:visible.sync="showDialog"
@confirm="handleSettingConfirm"
/>
@@ -70,7 +71,7 @@
</template>
<script>
import ProtocolSettingDialog from './ProtocolSettingDialog'
import ProtocolSettingDialog from './ProtocolSettingDialog.vue'
export default {
components: {
@@ -102,13 +103,17 @@ export default {
showSetting: {
type: Function,
default: (item) => true
},
instance: {
type: Object,
default: () => ({})
}
},
data() {
return {
name: '',
items: [],
settingItem: {},
currentProtocol: {},
showDialog: false,
loading: false
}
@@ -138,13 +143,18 @@ export default {
},
watch: {
choices: {
handler(value) {
handler(value, oldValue) {
if (value?.length === oldValue?.length) {
return
}
this.loading = true
setTimeout(() => {
this.loading = false
this.setDefaultItems(value)
}, 100)
}
this.loading = false
},)
},
deep: true,
immediate: true
},
items: {
handler(value) {
@@ -157,6 +167,21 @@ export default {
},
immediate: true,
deep: true
},
instance: {
handler(value) {
const port = this.getPortFromInstance(value)
if (!port) {
return
}
for (const item of this.items) {
if (item['port_from_addr']) {
item.port = port
}
}
},
deep: true,
immediate: true
}
},
mounted() {
@@ -166,21 +191,40 @@ export default {
this.$log.debug('Items: ', this.items)
},
methods: {
getPortFromInstance(instance) {
if (!instance) {
return 0
}
let address = instance.address || ''
if (address.indexOf('://') === -1) {
address = `https://${address}`
}
const parse = require('url-parse')
const path = parse(address)
let port = path.port
if (port < 0 || port > 65535) {
port = 0
}
if (!port) {
port = path.protocol === 'https:' ? 443 : 80
}
return port
},
handleSettingConfirm() {
if (this.settingItem.primary) {
if (this.currentProtocol.primary) {
const others = this.items
.filter(item => item.name !== this.settingItem.name)
.filter(item => item.name !== this.currentProtocol.name)
.map(item => {
item.primary = false
return item
})
this.items = [this.settingItem, ...others]
this.items = [this.currentProtocol, ...others]
}
if (this.settingItem.name === 'winrm') {
if (this.settingItem.setting?.use_ssl) {
this.settingItem.port = 5986
if (this.currentProtocol.name === 'winrm') {
if (this.currentProtocol.setting?.use_ssl) {
this.currentProtocol.port = 5986
} else {
this.settingItem.port = 5985
this.currentProtocol.port = 5985
}
}
},
@@ -217,20 +261,25 @@ export default {
item.name = selected.name
item.port = selected.port
},
isPortFormAddr(item) {
return !!item['port_from_addr']
},
isPortReadonly(item) {
return this.readonly || this.isPortFormAddr(item)
},
setPrimaryIfNeed(items) {
//
if (!this.settingReadonly) {
const primaryProtocols = items.filter(item => item.primary)
if (primaryProtocols.length === 0) {
items[0].primary = true
items[0].default = true
items[0].required = true
items[0].public = true
} else if (primaryProtocols.length > 1) {
primaryProtocols.slice(1, primaryProtocols.length).forEach(item => {
item.primary = false
})
}
if (this.settingReadonly) {
return items
}
const primaryProtocols = items.filter(item => item.primary)
if (primaryProtocols.length === 0) {
items[0].default = true
items[0].public = true
} else if (primaryProtocols.length > 1) {
primaryProtocols.slice(1, primaryProtocols.length).forEach(item => {
item.primary = false
})
}
return items
},
@@ -256,7 +305,7 @@ export default {
items = protocols.filter(item => allProtocolNames.indexOf(item.name) !== -1)
} else {
const defaults = choices.filter(item => (item.required || item.primary || item.default))
if (defaults.length === 0) {
if (defaults.length === 0 && choices.length !== 0) {
defaults.push(choices[0])
}
items = defaults
@@ -271,7 +320,7 @@ export default {
return protocols
},
onSettingClick(item) {
this.settingItem = item
this.currentProtocol = item
this.showDialog = true
}
}

View File

@@ -0,0 +1,5 @@
<template>
<div>
Todo: 抽象 Secret
</div>
</template>

View File

@@ -215,6 +215,13 @@ export default {
handler(newValue, oldValue) {
},
deep: true
},
iOptions(val) {
if (val.length === 0) {
this.remote = false
} else {
this.remote = true
}
}
},
async mounted() {

View File

@@ -10,7 +10,7 @@
@click="handleTagClick(v, k)"
@close="handleTagClose(v)"
>
{{ v }}
{{ isCheckShowPassword ? changeTagShowValue(v) : v }}
</el-tag>
<component
:is="component"
@@ -18,6 +18,7 @@
v-model.trim="filterValue"
:fetch-suggestions="autocomplete"
:placeholder="this.$t('common.EnterToContinue')"
:type="inputType"
class="search-input"
@blur="focus = false"
@change="handleConfirm"
@@ -25,6 +26,13 @@
@select="handleSelect"
@keyup.enter.native="handleConfirm"
/>
<span
v-if="replaceShowPassword && filterTags.length > 0"
class="show-password"
@click="handleShowPassword"
>
<i :class="[isCheckShowPassword ? 'fa-eye-slash' : 'fa-eye']" class="fa" />
</span>
</div>
</template>
@@ -50,6 +58,22 @@ export default {
autocomplete: {
type: Function,
default: null
},
replaceShowPassword: {
type: Boolean,
default: false
},
replaceRule: {
type: String,
default: ''
},
replaceContent: {
type: String,
default: '*'
},
inputType: {
type: String,
default: () => 'text'
}
},
data() {
@@ -57,6 +81,7 @@ export default {
filterTags: this.value,
focus: false,
filterValue: '',
isCheckShowPassword: this.replaceShowPassword,
component: this.autocomplete ? 'el-autocomplete' : 'el-input'
}
},
@@ -76,6 +101,7 @@ export default {
},
handleConfirm() {
if (this.filterValue === '') return
if (!this.filterTags.includes(this.filterValue)) {
this.filterTags.push(this.filterValue)
this.filterValue = ''
@@ -89,6 +115,23 @@ export default {
this.$delete(this.filterTags, k)
this.filterValue = v
this.$refs.SearchInput.focus()
},
matchRule(value) {
const regex = new RegExp(this.replaceRule)
const replacedValue = value.replace(regex, (match, p1, p2, p3) => {
const stars = p2.replace(/./g, this.replaceContent)
return p1 + stars + p3
})
return replacedValue
},
changeTagShowValue(value) {
if (this.replaceShowPassword && this.replaceRule) {
value = this.matchRule(value)
}
return value
},
handleShowPassword() {
this.isCheckShowPassword = !this.isCheckShowPassword
}
}
}
@@ -103,8 +146,7 @@ export default {
display: flex;
flex-wrap: wrap;
align-items: center;
padding-left: 2px;
padding-bottom: 3px;
padding: 1px 2px 1px;
border: 1px solid #dcdee2;
border-radius: 1px;
background-color: #fff;
@@ -115,11 +157,12 @@ export default {
}
&>>> .el-tag {
margin-top: 3px;
margin-top: 1px;
font-family: sans-serif !important;
}
&>>> .el-autocomplete {
height: 26px;
height: 30px;
}
}
@@ -128,7 +171,7 @@ export default {
&>>> .el-input__inner {
max-width: 100%;
border: none;
padding-left: 5px;
padding-left: 10px;
}
}
@@ -138,6 +181,15 @@ export default {
}
.filter-field >>> .el-input__inner {
height: 26px;
height: 29px;
}
.show-password {
display: inherit;
padding-right: 6px;
cursor: pointer;
&:hover {
color: #999999;
}
}
</style>

View File

@@ -0,0 +1,37 @@
<template>
<div class="input-text">
{{ value.toString() || text }}
</div>
</template>
<script>
export default {
props: {
value: {
type: [String, Boolean],
default: () => ''
},
text: {
type: String,
default: () => ''
}
},
data() {
return {}
}
}
</script>
<style lang='scss' scoped>
.input-text {
line-height: 32px;
padding-left: 8px;
height: 32px;
margin-top: 4px;
font-size: 13px;
}
.bolder {
border: solid 1px #dcdfe6;
}
</style>

View File

@@ -23,7 +23,7 @@
</template>
<script>
import Select2 from './Select2'
import Select2 from './Select2.vue'
import { hasUUID } from '@/utils/common'
export default {

View File

@@ -1,12 +1,12 @@
<template>
<div>
<input ref="upLoadFile" type="file" style="display: none" @change="Onchange">
<input ref="upLoadFile" :accept="accept" style="display: none" type="file" @change="Onchange">
<el-button size="mini" @click.native.stop="onUpLoad">
{{ this.$t('common.SelectFile') }}
</el-button>
<span>{{ fileName }}</span>
<div v-if="tip !== ''">{{ tip }}</div>
<input v-model="value" type="text" hidden v-on="$listeners">
<div v-if="tip !== ''" class="help-block">{{ tip }}</div>
<input v-model="value" hidden type="text" v-on="$listeners">
<div>
<img :src="preview" v-bind="$attrs">
</div>
@@ -23,6 +23,10 @@ export default {
tip: {
type: String,
default: () => ''
},
accept: {
type: String,
default: '*'
}
},
data() {

View File

@@ -7,7 +7,7 @@
</template>
<script>
import PasswordInput from './PasswordInput'
import PasswordInput from './PasswordInput.vue'
import { mapGetters } from 'vuex'
import store from '@/store'
import i18n from '@/i18n/i18n'

View File

@@ -13,7 +13,7 @@
<td v-for="t in theadArr" :key="t" :colspan="colspan">{{ t }}</td>
</tr>
</thead>
<tbody class="c-weektime-body">
<tbody class="c-weektime-body" @mouseleave="containerLeave()">
<tr v-for="t in weektimeData" :key="t.row">
<td>{{ t.value }}</td>
<td
@@ -230,6 +230,11 @@ export default {
})
this.setTimeRange()
},
containerLeave() {
this.width = 0
this.height = 0
this.mode = 0
},
setTimeRange() {
this.timeRange = this.weektimeData.map(item => {
return {

View File

@@ -0,0 +1,69 @@
import Link from './Link.vue'
import Select2 from './Select2.vue'
import TagInput from './TagInput.vue'
import Switcher from './Switcher.vue'
import AttrInput from './AttrInput.vue'
import UploadKey from './UploadKey.vue'
import JsonEditor from './JsonEditor.vue'
import PhoneInput from './PhoneInput.vue'
import UploadField from './UploadField.vue'
import UpdateToken from './UpdateToken.vue'
import UserPassword from './UserPassword.vue'
import UploadSecret from './UploadSecret.vue'
import TextReadonly from './TextReadonly.vue'
import DynamicInput from './DynamicInput.vue'
import PasswordInput from './PasswordInput.vue'
import WeekCronSelect from './WeekCronSelect.vue'
import BoolTextReadonly from './BoolTextReadonly.vue'
import NestedObjectSelect2 from './NestedObjectSelect2.vue'
import DatetimeRangePicker from './DatetimeRangePicker.vue'
import JSONManyToManySelect from './JSONManyToManySelect/index.vue'
import PasswordRule from './PasswordRule.vue'
export default {
Link,
Switcher,
Select2,
TagInput,
AttrInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
PasswordRule,
TextReadonly,
WeekCronSelect,
BoolTextReadonly,
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}
export {
Link,
Switcher,
Select2,
TagInput,
AttrInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
PasswordRule,
TextReadonly,
WeekCronSelect,
BoolTextReadonly,
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}

View File

@@ -1,220 +0,0 @@
<template>
<Dialog
:close-on-click-modal="false"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
:title="$tc('assets.PlatformProtocolConfig') + '' + item.name"
class="setting-dialog"
v-bind="$attrs"
width="70%"
v-on="$listeners"
>
<el-alert v-if="disabled && platformDetail" type="success" style="margin-bottom: 10px">
{{ $t('assets.InheritPlatformConfig') }}
<el-link :href="platformDetail" class="link-more" target="_blank">
{{ $t('common.View') }}
</el-link>
<i class="fa fa-external-link" />
</el-alert>
<AutoDataForm
:disabled="disabled"
:form="form"
class="data-form"
v-bind="config"
@submit="onSubmit"
/>
</Dialog>
</template>
<script>
import { AutoDataForm, Dialog } from '@/components'
export default {
name: 'ProtocolSetting',
components: {
Dialog,
AutoDataForm
},
props: {
item: {
type: Object,
default: () => ({})
},
disabled: {
type: Boolean,
default: false
}
},
data() {
const vm = this
const platform = this.$route.query.platform
return {
baseAttrs: ['primary', 'required', 'default', 'public'], // 基础属性, 放到 setting 中处理了,处理完成后,还得返回回去
defaultSetting: {
sftp_enabled: true,
sftp_home: '/tmp',
username_selector: '#username',
password_selector: '#password',
submit_selector: '.btn-submit',
security: 'any',
console: false
},
loading: true,
form: {},
platformDetail: platform ? '#/console/assets/platforms/' + platform : '',
config: {
hasSaveContinue: false,
hasButtons: !this.disabled,
url: '',
fields: [
[this.$t('common.Basic'), [
{
id: 'primary',
label: this.$t('assets.Primary'),
type: 'switch',
helpText: this.$t('assets.PrimaryProtocol'),
on: {
change: ([val], updateForm) => {
const relatedFields = vm.config['fields'][0][1]
.filter(item => this.baseAttrs.includes(item.id))
.filter(item => item.id !== 'primary')
if (val) {
const relatedValue = relatedFields.reduce((acc, cur) => {
acc[cur.id] = true
return acc
}, {})
updateForm(relatedValue)
}
}
}
},
{
id: 'required',
label: this.$t('assets.Required'),
type: 'switch',
helpText: this.$t('assets.RequiredProtocol'),
disabled: false
},
{
id: 'default',
label: this.$t('assets.Default'),
type: 'switch',
helpText: this.$t('assets.DefaultProtocol'),
disabled: false
},
{
id: 'public',
label: this.$t('assets.Public'),
type: 'switch',
helpText: this.$t('assets.PublicProtocol'),
disabled: false
}
]],
[this.$t('assets.LoginConfig'), [
{
id: 'console',
label: 'Console',
type: 'switch',
hidden: () => this.item.name !== 'rdp'
},
{
id: 'security',
label: 'Security',
hidden: () => this.item.name !== 'rdp',
type: 'radio-group',
options: [
{ label: 'Any', value: 'any' },
{ label: 'RDP', value: 'rdp' },
{ label: 'NLA', value: 'nla' },
{ label: 'TLS', value: 'tls' }
]
},
{
id: 'use_ssl',
label: this.$t('assets.UseSSL'),
type: 'switch',
hidden: () => this.item.name !== 'winrm'
},
{
id: 'sftp_enabled',
label: this.$t('common.Enable') + ' SFTP',
type: 'switch',
hidden: () => this.item.name !== 'ssh'
},
{
id: 'sftp_home',
label: 'SFTP home',
type: 'input',
helpText: this.$t('assets.SFTPHelpMessage'),
hidden: (form) => this.item.name !== 'ssh' || !form['sftp_enabled']
},
{
id: 'username_selector',
label: this.$t('assets.UserNameSelector'),
type: 'input',
hidden: (form) => this.item.name !== 'http'
},
{
id: 'password_selector',
label: this.$t('assets.PasswordSelector'),
type: 'input',
hidden: (form) => this.item.name !== 'http'
},
{
id: 'submit_selector',
label: this.$t('assets.SubmitSelector'),
type: 'input',
hidden: (form) => this.item.name !== 'http'
},
{
id: 'auth_username',
label: this.$t('assets.AuthUsername'),
type: 'switch',
hidden: (form) => this.item.name !== 'redis'
}
]]
]
}
}
},
created() {
this.form = this.item.setting
if (!this.form || !this.item) {
return
}
for (const i of this.baseAttrs) {
this.form[i] = !!this.item[i]
}
},
methods: {
onSubmit(form) {
for (const i of this.baseAttrs) {
if (form.hasOwnProperty(i)) {
this.item[i] = form[i]
}
}
this.item.setting = form
this.$emit('update:visible', false)
this.$emit('confirm', this.item)
}
}
}
</script>
<style lang="scss" scoped>
.data-form > > > .el-form-item.form-buttons {
padding-top: 10px;
margin-bottom: 0;
}
.setting-dialog > > > .el-dialog__body {
padding-top: 10px;
}
.link-more {
font-size: 10px;
border-bottom: solid 1px;
color: inherit;
}
</style>

View File

@@ -1,26 +0,0 @@
<template>
<span>
{{ text }}
</span>
</template>
<script>
export default {
name: 'Text',
props: {
text: {
type: String,
default: ''
}
},
methods: {
onClick() {
window.open(this.href)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,60 +0,0 @@
import Link from './Link'
import Text from './Text'
import Select2 from './Select2'
import TagInput from './TagInput'
import Switcher from './Switcher'
import UploadKey from './UploadKey'
import JsonEditor from './JsonEditor'
import PhoneInput from './PhoneInput'
import UploadField from './UploadField'
import UpdateToken from './UpdateToken'
import UserPassword from './UserPassword'
import DynamicInput from './DynamicInput'
import PasswordInput from './PasswordInput'
import UploadSecret from './UploadSecret'
import WeekCronSelect from './WeekCronSelect'
import NestedObjectSelect2 from './NestedObjectSelect2'
import DatetimeRangePicker from './DatetimeRangePicker'
import JSONManyToManySelect from './JSONManyToManySelect/index.vue'
export default {
Text,
Link,
Switcher,
Select2,
TagInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
WeekCronSelect,
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}
export {
Text,
Link,
Switcher,
Select2,
TagInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
WeekCronSelect,
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}

View File

@@ -1,37 +0,0 @@
<template>
<div class="markdown-body">
<VueMarkdown :source="value" />
</div>
</template>
<script>
import VueMarkdown from 'vue-markdown'
import 'github-markdown-css/github-markdown-light.css'
export default {
components: {
VueMarkdown
},
props: {
value: {
type: String,
default: ''
}
},
data() {
return {}
}
}
</script>
<style lang='scss' scoped>
.markdown-body * {
padding: 10px;
background-color: #f3f3f3;
color: #1a1a1a;
font-size: 13px;
//& >>> .table * {
// background-color: #f3f3f3;
//}
}
</style>

View File

@@ -24,9 +24,9 @@
</template>
<script>
import Switcher from '../FormFields/Switcher'
import Select2 from '../FormFields/Select2'
import UpdateSelect from '../FormFields/UpdateSelect'
import Switcher from '@/components/Form/FormFields/Switcher'
import Select2 from '@/components/Form/FormFields/Select2'
import UpdateSelect from '@/components/Form/FormFields/UpdateSelect'
class Action {
constructor() {

View File

@@ -3,8 +3,9 @@
</template>
<script>
import TagSearch from '@/components/TagSearch'
import TagSearch from '@/components/Table/TagSearch/index.vue'
import i18n from '@/i18n/i18n'
export default {
name: 'AutoDataSearch',
components: {

View File

@@ -36,7 +36,7 @@
</template>
<script>
import Dialog from '@/components/Dialog/index'
import Dialog from '@/components/Dialog/index.vue'
export default {
name: 'ColumnSettingPopover',
@@ -75,6 +75,9 @@ export default {
}
})
},
beforeDestroy() {
this.$eventBus.$off('showColumnSettingPopover')
},
methods: {
handleColumnConfirm() {
this.showColumnSettingPopover = false

View File

@@ -20,19 +20,14 @@
</template>
<script type="text/jsx">
import DataTable from '../DataTable'
import DataTable from '@/components/Table/DataTable/index.vue'
import {
ActionsFormatter,
ArrayFormatter,
ChoicesFormatter,
DateFormatter,
DetailFormatter,
DisplayFormatter,
ActionsFormatter, ArrayFormatter, ChoicesFormatter, DateFormatter, DetailFormatter, DisplayFormatter,
ObjectRelatedFormatter
} from '@/components/TableFormatters'
} from '@/components/Table/TableFormatters'
import i18n from '@/i18n/i18n'
import { newURL, replaceAllUUID } from '@/utils/common'
import ColumnSettingPopover from './components/ColumnSettingPopover'
import ColumnSettingPopover from './components/ColumnSettingPopover.vue'
export default {
name: 'AutoDataTable',

Some files were not shown because too many files have changed in this diff Show More