Compare commits

..

1593 Commits

Author SHA1 Message Date
fit2bot
7aa40de518 feat: Update v3.5.4 2023-08-15 11:34:29 +08:00
老广
17fd374e0a Merge pull request #3322 from jumpserver/pr@v3.5@fix_msg_subscribe_for_xss
fix: 修复系统设置 > 消息订阅 > 修改订阅人 因为用户名导致的 xss
2023-08-08 16:17:09 +08:00
ibuler
df5d15c1e5 fix: 修复系统设置 > 消息订阅 > 修改订阅人 因为用户名导致的 xss 2023-08-08 03:08:02 +00:00
“huailei000”
b58c21a79f perf: 命令记录列表增加账号字段 2023-08-03 16:16:38 +08:00
“huailei000”
3d81f92667 perf: 修改github配置 2023-07-21 14:56:38 +08:00
Bryan
a6d642df60 Merge pull request #3283 from jumpserver/dev
v3.5.0
2023-07-20 19:04:29 +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
“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
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
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
ibuler
8449dafd55 perf: 优化 attr form 字段选择 2023-06-15 17:59:23 +08:00
“huailei000”
a787737290 perf: 优化同步设置组织下拉框显示过长问题 2023-06-15 15:10:53 +08:00
Jiangjie.Bai
2e74f1522f Merge pull request #3222 from jumpserver/dev
v3.4.0
2023-06-15 14:51:36 +08:00
老广
fa517c8325 Merge pull request #3220 from jumpserver/pr@dev@perf_attr_change_value
perf: 修改 change value
2023-06-15 14:42:36 +08:00
老广
0748b6ce0c Merge pull request #3221 from jumpserver/pr@dev@perf_org_change_on_create
perf: 修改 更新切换
2023-06-15 14:42:16 +08:00
ibuler
59ee3eff17 perf: 修改 更新切换 2023-06-15 14:31:31 +08:00
ibuler
5cc17de1e0 perf: 修改 change value 2023-06-15 14:28:04 +08:00
Jiangjie.Bai
fe615e0314 Merge pull request #3219 from jumpserver/dev
v3.4.0
2023-06-15 14:17:46 +08:00
feng626
42aacd9df5 Merge pull request #3218 from jumpserver/pr@dev@translate
fix: 修改用户登录和连接方式的详情翻译
2023-06-15 12:45:55 +08:00
feng
bb27171b09 fix: 修改用户登录和连接方式的详情翻译 2023-06-15 12:44:55 +08:00
feng626
ccc163ef07 Merge pull request #3217 from jumpserver/pr@dev@user_change_password
fix: 修改密码时 判断管理员校验规则失败
2023-06-15 12:14:50 +08:00
feng
e63630fce7 fix: 修改密码时 判断管理员校验规则失败 2023-06-15 11:29:03 +08:00
“huailei000”
17748c56c9 perf: 优化自定义资产列表不显示操作问题 2023-06-15 11:03:36 +08:00
老广
d880e5cb8c Merge pull request #3215 from jumpserver/pr@dev@perf_user_json_attr_disabled
perf: 优化 json user field
2023-06-15 10:32:39 +08:00
ibuler
310fe8068a perf: 优化 json user field 2023-06-15 10:31:40 +08:00
Eric
8670c3988d perf: 优化翻译 2023-06-14 21:07:41 +08:00
Bai
b5144625ee perf: 优化 命令过滤 菜单位置 2023-06-14 20:15:13 +08:00
“huailei000”
58b6d75ccf perf: 优化ladp中组织名称过长显示的问题 2023-06-14 20:02:03 +08:00
“huailei000”
c9ec67cc50 perf: 优化平台列表tab页点击导出会导出全部数据问题 2023-06-14 19:02:16 +08:00
“huailei000”
e4d1533091 perf: 优化连接方式详情用户、资产跳转报错问题 2023-06-14 18:31:50 +08:00
老广
97440860d9 Merge pull request #3208 from jumpserver/pr@dev@perf_route_replace
perf: 修改切换组织时的 url 替换
2023-06-14 16:45:08 +08:00
ibuler
3dd31dc76e perf: 替换路由中的 uuid 2023-06-14 16:35:56 +08:00
feng626
1822d72a9b Merge pull request #3209 from jumpserver/pr@dev@perm_asset
perf: 授权切换组织报错
2023-06-14 16:21:35 +08:00
feng
3267839327 perf: 授权切换组织报错 2023-06-14 16:20:47 +08:00
ibuler
17d73f2b3c perf: 修改切换组织时的 url 替换 2023-06-14 16:10:42 +08:00
“huailei000”
ec49241272 perf: 删除资产授权规则详情账号页面的“删除”按钮;删除用户详情页面资产授权规则页的“删除”/“克隆”按钮 2023-06-14 14:37:43 +08:00
feng626
c2e10b8a34 Merge pull request #3205 from jumpserver/pr@dev@website
perf: 资产website script暂时不展示特殊信息
2023-06-14 11:19:59 +08:00
feng
29813e7ce1 perf: 资产website script暂时不展示特殊信息 2023-06-14 11:18:42 +08:00
Aaron3S
919d95b56b fix: 修复playbook文件树无法点击的问题 2023-06-14 11:07:12 +08:00
feng626
5f95fc0422 Merge pull request #3200 from jumpserver/pr@dev@user_perm
fix: 修改node asset 关联的权限位
2023-06-14 10:36:22 +08:00
feng
49a4000086 fix: 修改node asset 关联的权限位 2023-06-14 10:35:14 +08:00
老广
9c7818313e Merge pull request #3199 from jumpserver/pr@dev@perf_select2_componenet
perf: 优化 select2 组件
2023-06-13 19:38:00 +08:00
ibuler
705e236279 merge: with dev 2023-06-13 19:36:59 +08:00
ibuler
d4ecb33c78 perf: 去掉注释内容 2023-06-13 19:34:05 +08:00
ibuler
67e45ad284 perf: 优化修改select2 2023-06-13 19:32:39 +08:00
ibuler
8cb72c3d82 perf: 优化 select2 组件 2023-06-13 19:26:38 +08:00
“huailei000”
b65a007d37 perf: 资产详情添加账号后关闭弹窗 2023-06-13 15:40:33 +08:00
“huailei000”
e487ee24af perf: 资产登录用户匹配结果不显示操作 2023-06-13 14:42:54 +08:00
feng626
bfbc78e342 Merge pull request #3196 from jumpserver/pr@dev@asset_login_acl
fix: 修复创建资产登录规则-选择指定资产-指定账号下拉框显示的是组织下的所有账号问题
2023-06-13 14:36:15 +08:00
feng
54879a8174 fix: 修复创建资产登录规则-选择指定资产-指定账号下拉框显示的是组织下的所有账号问题 2023-06-13 14:34:52 +08:00
老广
36634a2ce5 Merge pull request #3195 from jumpserver/pr@dev@perf_select2_filter
perf: 优化 select 本地搜索
2023-06-13 13:27:41 +08:00
ibuler
07920a4917 perf: 优化 select 本地搜索 2023-06-13 13:24:20 +08:00
老广
25932587a5 Merge pull request #3194 from jumpserver/pr@dev@perf_json_attr_form_dialog
perf: json attr form 更改 name 和 match 方式后,不再清空 value
2023-06-13 12:42:22 +08:00
ibuler
d98534d039 perf: json attr form 更改 name 和 match 方式后,不再清空 value 2023-06-13 12:41:32 +08:00
feng626
6cb5d6ac46 Merge pull request #3193 from jumpserver/pr@dev@connect-method-acls
perf: 连接方式 添加详情页
2023-06-13 11:31:41 +08:00
feng
fab461c10d perf: 连接方式 添加详情页 2023-06-13 11:29:59 +08:00
“huailei000”
644980bc40 perf: 资产登录详情、命令过滤详情里的列表不显示操作功能 2023-06-13 11:19:49 +08:00
老广
a56e3843bf Merge pull request #3191 from jumpserver/pr@dev@perf_action_display
perf: 优化 action 显示
2023-06-13 10:09:29 +08:00
ibuler
5ca188c014 perf: 优化 action 显示 2023-06-13 09:51:46 +08:00
“huailei000”
510cf48def perf: 修改账号推送详情标题不正确问题 2023-06-12 18:29:36 +08:00
feng626
e64fdab7fc Merge pull request #3189 from jumpserver/pr@dev@usergroup
perf: 修改用户组添加全部用户api的权限位
2023-06-12 18:16:26 +08:00
feng
aaec496642 perf: 修改用户组添加全部用户api的权限位 2023-06-12 18:14:49 +08:00
“huailei000”
80c05c9b65 perf: 优化资产列表显示 2023-06-12 18:05:08 +08:00
feng626
c9159838f5 Merge pull request #3187 from jumpserver/pr@dev@accounts
fix: 工单账号组建默认值为空
2023-06-12 17:06:09 +08:00
feng
b8e005f4b1 fix: 工单账号组建默认值为空 2023-06-12 17:03:59 +08:00
feng626
6e73ded101 Merge pull request #3185 from jumpserver/pr@dev@perms_user
perf: 优化授权详情用户组切换组织一些资源不存在抛出html错误
2023-06-12 16:28:45 +08:00
feng
6926556fa3 perf: 优化授权详情用户组切换组织一些资源不存在抛出html错误 2023-06-12 16:24:01 +08:00
老广
24971c1112 Merge pull request #3183 from jumpserver/pr@dev@perf_json_attr_select_match
perf: 优化 Json attr field 选择
2023-06-12 16:14:03 +08:00
“huailei000”
763792f42e perf: 用户登录列表不显示用户字段 2023-06-12 16:12:28 +08:00
ibuler
0ff28d2626 perf: 优化 Json attr field 选择 2023-06-12 16:10:55 +08:00
老广
f607eeda42 Merge pull request #3182 from jumpserver/pr@dev@perf_acl_global_org
perf: 限制 connect method acl 和 user login acl 为 global org
2023-06-12 15:48:10 +08:00
ibuler
c0145f4ec4 perf: 限制 connect method acl 和 user login acl 为 global org 2023-06-12 15:43:54 +08:00
feng626
7c995c005b Merge pull request #3179 from jumpserver/pr@dev@user_add
perf: 用户组添加 user 显示优化
2023-06-09 18:53:42 +08:00
feng
21f4f003bb perf: 用户组添加 user 显示优化 2023-06-09 18:52:44 +08:00
老广
fbbac6cea5 Merge pull request #3178 from jumpserver/pr@dev@perf_account_add_error
perf: 优化 account 添加
2023-06-09 18:43:21 +08:00
ibuler
302400e350 perf: 优化 account 添加 2023-06-09 18:41:52 +08:00
“huailei000”
b2120678dd perf: 优化TagInput组件样式 2023-06-09 18:37:43 +08:00
feng626
03c7755703 Merge pull request #3176 from jumpserver/pr@dev@user_phone
perf: 用户手机添加默认值及账号模版详情切换至显示
2023-06-09 18:32:58 +08:00
feng
21373574de perf: 用户手机添加默认值及账号模版详情切换至显示 2023-06-09 18:31:54 +08:00
“huailei000”
342ee31c72 perf: 优化命令过滤指定账号-选择账号显示不全问题 2023-06-09 18:21:28 +08:00
feng626
7aa8afec44 Merge pull request #3174 from jumpserver/pr@dev@account
perf: 修改创建资产账号的顺序及账号模版批量添加隐藏su_from_username字段
2023-06-09 16:23:30 +08:00
feng
d6b54c9879 perf: 修改创建资产账号的顺序及账号模版批量添加隐藏su_from_username字段 2023-06-09 16:18:52 +08:00
老广
b1952a180f Merge pull request #3173 from jumpserver/pr@dev@perf_asset_json_filter_platform_m2m
perf: 资产根据属性筛选允许多选
2023-06-08 18:40:33 +08:00
ibuler
d3a7fb63b9 perf: 资产根据属性筛选允许多选 2023-06-08 18:34:43 +08:00
jiangweidong
53cfdbd3a1 feat: 支持文件上传下载备份 (#3118)
* feat: 支持文件上传下载备份

* perf: 修改下载sftp文件api接口

* perf: 优化FTP审计中文件下载提示

* perf: 优化文件上传下载审计文件的提示信息
2023-06-08 18:06:37 +08:00
ibuler
41cd77d75e fix: 修复一个正则表达式不被 safari 支持的问题 2023-06-08 15:48:53 +08:00
老广
15ac510c6f Merge pull request #3170 from jumpserver/pr@dev@perf_acls_connect_methods
perf: 用户登录 ACL 挪到控制中
2023-06-08 14:51:26 +08:00
老广
31e005eca7 Merge pull request #3171 from jumpserver/pr@dev@fix_btoa_error
perf: 修复 btoa 的报错,首先 encode 一下
2023-06-08 14:50:54 +08:00
ibuler
842ea3cbf3 perf: 修复 btoa 的报错,首先 encode 一下 2023-06-08 14:50:08 +08:00
ibuler
9f893af74b perf: ACL 中添加一些 help text 2023-06-08 14:37:12 +08:00
ibuler
5274dc4e6b perf: 修改翻译 2023-06-08 13:50:01 +08:00
ibuler
64441e4836 perf: 还是放到权限管理中 2023-06-08 11:28:03 +08:00
fangfang.dong
43997eeac1 feat: 系统设置 - 短信服务 - 多平台配置测试手机号: 增加区号显示与修改功能 2023-06-08 11:03:06 +08:00
ibuler
1b95af54c1 perf: acls 菜单 2023-06-08 10:58:18 +08:00
ibuler
e79f95a822 perf: 修改翻译 2023-06-07 17:55:53 +08:00
ibuler
fb85e168e7 perf: 用户登录 ACL 挪到控制中 2023-06-07 17:41:40 +08:00
feng626
521cafa2af Merge pull request #3168 from jumpserver/pr@dev@fix_ticket
fix: 修复工单选择账号无法按照对应资产节点过滤账号,以及自己申请的工单不能关闭
2023-06-05 15:58:39 +08:00
feng
bb9f905dd4 fix: 修复工单选择账号无法按照对应资产节点过滤账号,以及自己申请的工单不能关闭 2023-06-05 15:57:19 +08:00
nut
3eda4381bb Update Assets.vue 2023-06-02 18:27:23 +08:00
nut
080acf57f7 Update index.vue 2023-06-02 18:27:23 +08:00
nut
9c137e6763 Update ja.json 2023-06-02 18:27:23 +08:00
nut
75f5363602 Update en.json 2023-06-02 18:27:23 +08:00
nut
32f6d5dc4a Update zh.json 2023-06-02 18:27:23 +08:00
fangfangdong
21265aa983 feat: 资产平台详情添加资产列表页(只显示当前组织下的资产) 2023-06-02 18:27:23 +08:00
feng626
e11441e5a7 Merge pull request #3165 from jumpserver/pr@dev@user_list
perf: 用户列表不显示is_superuser
2023-05-31 19:24:44 +08:00
feng
e7624f47bf perf: 用户列表不显示is_superuser 2023-05-31 19:20:13 +08:00
ibuler
7276b19a92 perf: 优化 nest fields 支持是否隐藏 2023-05-31 16:52:25 +08:00
fangfangdong
32fa172197 feat: 系统设置-安全设置 支持配置 作业中心命令黑名单 2023-05-31 14:59:16 +08:00
老广
aa80a07bfc Merge pull request #3161 from jumpserver/pr@dev@perf_platform_automation
perf: 修改 platform automation 的显示
2023-05-30 19:37:41 +08:00
ibuler
fd97a6c4a2 perf: 修改 platform automation 的显示 2023-05-30 19:35:33 +08:00
fangfangdong
9b355a2942 style: 调整国际化文件中时间单位显示方式 2023-05-30 16:59:19 +08:00
ibuler
0431f7108a perf: 优化 perm action 中的 helptext 2023-05-29 19:47:57 +08:00
ibuler
3500ab89f5 perf: 登录资产的 ACL 支持 ip 控制 2023-05-29 19:47:57 +08:00
feng
fcdcf29efa feat: 用户组绑定所有用户 2023-05-29 16:27:00 +08:00
feng
49d74271c8 feat: 用户组一键添加全部用户 2023-05-29 16:27:00 +08:00
Bai
9a7eca3cf8 perf: 优化终端端点 Host 字段默认端点禁止修改 2023-05-26 17:21:19 +08:00
feng
dc686f2af7 fix: 修改k8s修改不了端口问题 2023-05-26 14:56:49 +08:00
feng626
172c6d69a1 Merge pull request #3148 from jumpserver/pr@dev@ldap_import_orgs
perf: ldap 能多组织同步用户
2023-05-25 17:37:18 +08:00
feng
3f2a846184 perf: 账号模版改密的helptext用到修改资产协议上了 2023-05-25 17:05:40 +08:00
ibuler
48ac797b59 perf: LDAP 测试 api 改为异步的 2023-05-25 16:54:54 +08:00
halo
92962bdc5a feat: 支持删除已收集的账号 2023-05-25 14:47:48 +08:00
Bai
ca4889a19a perf: 优化 API 调用最大超时时间为 2 min 2023-05-25 14:47:21 +08:00
ibuler
e4631a5309 perf: 优化 list field 组件为 tag input 2023-05-25 14:45:43 +08:00
jiangweidong
62eced61d2 feat: 支持自定义短信认证 2023-05-25 14:44:00 +08:00
feng626
7a8df3fb7b Merge pull request #3150 from jumpserver/pr@dev@unable_to_delete_all_users
perf: 删除全部用户错误提示
2023-05-25 11:38:07 +08:00
feng
91ef3cfaab perf: 删除全部用户错误提示 2023-05-25 11:22:13 +08:00
吴小白
c92843e973 perf: 更新 nginx 镜像版本 2023-05-25 10:16:48 +08:00
feng
47372df4d2 perf: ldap 能多组织同步用户 2023-05-24 19:10:39 +08:00
老广
143e913554 Merge pull request #3101 from jumpserver/pr@dev@perf_m2m_json_field
feat: ACL 中选择可以根据属性进行选择
2023-05-24 15:21:28 +08:00
ibuler
61b2b0fb23 merge: with dev 2023-05-24 15:18:12 +08:00
ibuler
54ac31920c perf: 修改默认值 2023-05-24 15:15:43 +08:00
ibuler
4eaeff0a18 perf: 去掉 console.log 2023-05-24 14:30:52 +08:00
ibuler
08c16aae72 perf: 拆分为多个文件 2023-05-23 15:28:20 +08:00
feng626
bf5e218edc Merge pull request #3142 from jumpserver/pr@dev@ndoe_tree
perf: 资产树显示节点详情的key
2023-05-22 15:50:09 +08:00
feng
e8dbd99f74 perf: 资产树显示节点详情的key 2023-05-22 15:49:15 +08:00
Bai
9ab2acfa5b fix: 修复系统管理员不能互相更新的问题 2023-05-19 18:08:30 +08:00
jiangweidong
d3cbb48e05 fix: 展示手机号码 2023-05-19 17:02:32 +08:00
jiangweidong
170dde2ba5 fix: 去掉手机区号和手机号之间的空格 2023-05-19 17:02:32 +08:00
Bai
021eb1fd5b perf: 优化资产平台详情显示ID字段;优化组件监控显示Video-Worker名称 2023-05-19 16:01:17 +08:00
ibuler
1b2c85d86d perf: 修改完成 m2m json field 2023-05-18 21:33:58 +08:00
Jiangjie.Bai
09f734e6fc Merge pull request #3135 from jumpserver/dev
v3.3.0
2023-05-18 19:18:11 +08:00
Bai
2434e434b7 perf: 优化组织管理员不能更新系统管理员 2023-05-18 19:04:55 +08:00
ibuler
3a5aa7bf90 perf: 优化 Json field 2023-05-18 17:31:56 +08:00
feng626
dbe4c232c1 Merge pull request #3133 from jumpserver/pr@dev@account
fix: 修改创建资产时创建账号的顺序
2023-05-18 16:30:36 +08:00
feng
3294495577 fix: 修改创建资产时创建账号的顺序 2023-05-18 16:29:30 +08:00
ibuler
05e7e6dd06 perf: 优化组织切换可能引起的路由错误问题 2023-05-17 20:06:13 +08:00
ibuler
936de3c9fb perf: stash json 2023-05-17 18:50:16 +08:00
feng626
51dac8ca30 Merge pull request #3131 from jumpserver/pr@dev@ticket_session
fix: 工单命令复核 session 404
2023-05-17 18:40:07 +08:00
Aaron3S
89b3ea51f5 perf: 优化 ops 用户提示 2023-05-17 18:38:50 +08:00
Aaron3S
bdfc608534 fix: 修复快捷命令选中search节点错误的问题 2023-05-17 18:38:50 +08:00
feng
667514e90b fix: 工单命令复核 session 404 2023-05-17 18:36:33 +08:00
“huailei000”
83a116c094 perf: 优化更新平台时协议如果是http显示为http(s) 2023-05-16 19:55:55 +08:00
“huailei000”
211933349e fix: 修复更新命令存储不显示值 2023-05-16 18:08:02 +08:00
jiangweidong
ec51b243b1 perf: 修改用户来源判断逻辑和函数名对应上 2023-05-16 18:06:09 +08:00
jiangweidong
80eb072c1b perf: 修改变量名 2023-05-16 18:06:09 +08:00
jiangweidong
ce08fd57c6 perf: 优化变量名 2023-05-16 18:06:09 +08:00
jiangweidong
40ccab1a19 perf: 函数功能抽离 2023-05-16 18:06:09 +08:00
jiangweidong
8489d94643 perf: 非本地用户无法解绑飞书、企业微信、钉钉 2023-05-16 18:06:09 +08:00
Bai
72693af5fd perf: 优化忘记密码URL不自动增加 http:// 前缀 2023-05-16 11:27:26 +08:00
Bai
1fdcf9ff75 perf: 优化资产、网关列表页面显示 labels 信息不全的问题 2023-05-15 19:03:56 +08:00
“huailei000”
c4ad25bfe3 perf:账号查看-修改的密码进行加密 2023-05-15 15:51:48 +08:00
Aaron3S
d6a7d93398 fix: 修复ops 快捷命令搜索树不生效的问题 2023-05-15 10:44:58 +08:00
“huailei000”
43b2ad3104 perf: 创建资产增加翻译 2023-05-15 10:42:14 +08:00
“huailei000”
2209eea890 feat: 平台设置中增加公共的属性 2023-05-11 14:49:43 +08:00
Aaron3S
1a56546d2e fix: 添加遗漏翻译 2023-05-10 16:04:31 +08:00
Aaron3S
fa52226958 feat: 作业中心根据当前选择的资产提示用户名 2023-05-10 15:40:36 +08:00
老广
42ee6c0848 Merge pull request #3112 from jumpserver/pr@dev@feat_applet_accounts_reuse
feat: 发布机详情中增加生成账号 api
2023-05-10 15:37:09 +08:00
ibuler
49f63d638c feat: 发布机详情中增加生成账号 api 2023-05-10 15:00:13 +08:00
halo
7e6d78d223 perf: 优化远程应用上传弹窗 2023-05-10 14:22:15 +08:00
“huailei000”
a99a5a6312 perf: 进度条颜色根据系统颜色变化 2023-05-10 14:12:15 +08:00
feng626
e80b162eca Merge pull request #3111 from jumpserver/pr@dev@account_template
feat: 账号模版 切换自
2023-05-09 15:29:15 +08:00
feng
fabf60ac47 feat: 账号模版 切换至 2023-05-09 14:18:49 +08:00
“huailei000”
14b5eb5239 perf: 内置的平台详情协议设置弹窗不显示alert提示 2023-05-08 18:53:13 +08:00
“huailei000”
e365eaef8a feat: 账号列表-查看账号支持类型为password的账号修改密码 2023-05-08 18:46:27 +08:00
“huailei000”
d14cbce2d6 perf: 用户列表、资产列表、资产授权批量更新后自动关闭批量更新窗口;资产授权批量更新后自动刷新列表 2023-05-08 17:03:13 +08:00
feng626
f29f88b78b Merge pull request #3102 from jumpserver/pr@dev@feat_exportdialog_add_tip
feat: 导出弹窗增加导出提示配置;账号导出增加导出提示
2023-05-08 17:01:52 +08:00
“huailei000”
40ccff9685 fix: 修复创建端点规则不显示默认值问题;修复云同步-更新账号不显示IP网段问题 2023-05-08 17:01:07 +08:00
“huailei000”
b85de1de33 fix: 修复更新端点规则ip不显示问题 2023-05-08 14:45:07 +08:00
“huailei000”
640e758016 feat: 导出弹窗增加导出提示配置;账号导出增加导出提示 2023-05-08 14:09:10 +08:00
ibuler
09bd49941f perf: 修改 asset login acl 2023-05-08 10:49:09 +08:00
ibuler
edc74c8dfb perf: 修改翻译 2023-05-08 10:38:03 +08:00
jiangweidong
fcd7d17ef1 perf: 优化变量名 2023-05-08 09:59:20 +08:00
jiangweidong
574b7b54c5 perf: 重复逻辑抽离 2023-05-08 09:59:20 +08:00
jiangweidong
f486da0018 perf: 统一格式 2023-05-08 09:59:20 +08:00
jiangweidong
1598b4e4ad 时间组件快捷支持->半年、1年选项 2023-05-08 09:59:20 +08:00
ibuler
4556d3f4fe perf: 修改 m2m placeholder 2023-05-06 19:51:10 +08:00
ibuler
e521868cd2 Perf: 前端好像差不多了 2023-05-06 19:00:59 +08:00
ibuler
d3d6a0e890 perf: 优化 JSONManyToMany 字段 2023-05-05 19:10:13 +08:00
“huailei000”
fd4223e107 fix: 修复登录限制提交报错问题 2023-05-05 16:04:49 +08:00
“huailei000”
152301b0f3 fix: 修复安全设置-登录限制黑白名单参数不能显示的问题 2023-05-04 10:49:05 +08:00
ibuler
cb7a492b74 fix: 修复更新资产时,其它资产协议丢失的问题 2023-05-04 10:36:44 +08:00
老广
80dd8a23ec Merge pull request #3084 from jumpserver/pr@dev@fix_asset_gatheredinfo_undefined
fix: 修复资产硬件信息显示undefined问题
2023-04-28 11:12:55 +08:00
老广
41729ebe53 Merge pull request #3083 from jumpserver/pr@dev@perf_command_jump
perf: DetailFormatter组件增加配置参数openInNewPage控制是否新页卡打开;命令记录会话点击新页卡打开
2023-04-28 11:12:20 +08:00
“huailei000”
da3e6aff76 perf: DetailFormatter组件增加配置参数createInNewPage控制是否新页卡打开;命令记录会话点击新页卡打开 2023-04-28 11:06:12 +08:00
老广
7ff8114850 Merge pull request #3085 from jumpserver/pr@dev@perf_switch_icon
perf: 修改交换机图标
2023-04-28 10:40:03 +08:00
Bai
43eaaf3eba fix: 修复云账号LAN不能创建的问题 2023-04-27 19:32:58 +08:00
ibuler
26d8154db8 feat: 支持 json m2m field 2023-04-27 16:46:38 +08:00
feng626
673198af07 Merge pull request #3088 from jumpserver/pr@dev@perm_user
perf: 用户工作台 资产可显示标签
2023-04-25 14:47:56 +08:00
feng
b14630c33a perf: 用户工作台 资产可显示标签 2023-04-25 14:46:37 +08:00
feng626
187a0824fc Merge pull request #3087 from jumpserver/pr@dev@perm_user
perf: 用户工作台资产显示更多字段
2023-04-25 14:35:48 +08:00
feng
e180fbd2a5 perf: 用户工作台资产显示更多字段 2023-04-25 14:34:23 +08:00
feng626
90ebb0ff0b Merge pull request #3086 from jumpserver/pr@dev@account_template_change_secret
feat: 修改模版密文后 同步修改账号
2023-04-25 10:28:23 +08:00
feng
c922fa99fd perf: 修改同步密文url 2023-04-25 10:26:27 +08:00
“huailei000”
5e3917d61c perf: 修改更新密文显示字段 2023-04-24 19:13:34 +08:00
feng
57702bcef3 feat: 修改模版密文后 同步修改账号 2023-04-24 15:35:08 +08:00
“huailei000”
a055b4fe45 perf: 修改交换机图标 2023-04-24 15:04:13 +08:00
“huailei000”
7305bf772c fix: 修复资产硬件信息显示undefined问题 2023-04-24 11:28:22 +08:00
ibuler
3a4c579c6c perf: 优化协议的长度 2023-04-21 16:54:00 +08:00
老广
4ce651e319 Revert "perf: 自定义平台协议名称宽度自适应显示" 2023-04-21 16:53:38 +08:00
老广
c3adfe7031 Merge pull request #3076 from jumpserver/pr@dev@perf_platform_select_autowidth
perf: 自定义平台协议名称宽度自适应显示
2023-04-21 16:44:20 +08:00
“huailei000”
b7868e804d perf: 自定义平台协议名称宽度自适应显示 2023-04-21 16:40:51 +08:00
“huailei000”
3ea8239c77 fix: 修复云同步更新实例任务IP网段组不显示问题 2023-04-21 14:29:30 +08:00
老广
ddb7369994 Merge pull request #3071 from jumpserver/pr@dev@fix_custom_platform
perf: 优化平台列表 tab
2023-04-21 10:14:13 +08:00
ibuler
97b0260921 perf: 优化平台列表 tab 2023-04-20 22:51:16 +08:00
ibuler
213f896ab8 perf: 优化账号切换的 disable 属性 2023-04-20 19:47:30 +08:00
ibuler
9ef79e677c perf: 优化账号切换自显示
perf: 切换账号

perf: 修改缩进啊
2023-04-20 19:25:59 +08:00
feng626
8e03194a65 Merge pull request #3065 from jumpserver/pr@dev@active
fix: 账号详情激活
2023-04-20 19:22:29 +08:00
ibuler
4c6f9d6490 perf: 切换账号
perf: 修改缩进啊
2023-04-20 19:22:20 +08:00
feng
95e14227f0 fix: 账号详情激活 2023-04-20 19:19:47 +08:00
Jiangjie.Bai
3117046342 Merge pull request #3061 from jumpserver/dev
v3.2.0
2023-04-20 18:40:08 +08:00
Bai
b68aecb5cc fix: 批量更新资产平台help-text 2023-04-20 18:39:22 +08:00
Bai
1bf5e9c3bc fix: 批量更新资产平台help-text 2023-04-20 18:38:25 +08:00
Jiangjie.Bai
1c9b155d97 Merge pull request #3057 from jumpserver/dev
v3.2.0
2023-04-20 18:22:46 +08:00
Bai
0b52dfd852 fix: 资产/系统平台更新页面去掉重置按钮 2023-04-20 18:22:15 +08:00
“huailei000”
7cc3a7f9a1 perf: 调整用户详情登录规则helptext 2023-04-20 17:46:59 +08:00
“huailei000”
74df2dc164 perf: 文件加密表单显示文字 2023-04-20 17:15:01 +08:00
“huailei000”
b40e6bb412 perf: 网关系统平台不能选择 2023-04-20 15:58:31 +08:00
“huailei000”
10c9a54896 perf: 批量添加账号报错后显示全部报错信息 2023-04-20 15:25:42 +08:00
Aaron3S
1f4d211c32 fix: 修复更新调用创建接口的问题 2023-04-20 14:17:20 +08:00
Aaron3S
b736a3aeb8 fix: 修复 playbook form 回显问题 2023-04-20 14:12:37 +08:00
老广
b3050e62b3 Merge pull request #3048 from jumpserver/pr@dev@fix_assetupdate_form_show
fix: 修复更新资产系统平台显示id问题
2023-04-20 13:32:13 +08:00
老广
675fd1ba9f Merge pull request #3050 from jumpserver/pr@dev@perf_applet_upload
perf: 优化 applet 上传
2023-04-20 13:30:21 +08:00
ibuler
b1579b1fbd perf: 优化 applet 上传 2023-04-20 13:28:07 +08:00
“huailei000”
84d4aebdeb fix: 修复账号详情更新切换自报错问题 2023-04-20 11:32:39 +08:00
“huailei000”
6b1c0590ce fix: 修复更新资产系统平台显示id问题 2023-04-20 11:19:22 +08:00
“huailei000”
b7fd52fa6e perf: 账号改密详情删除节点刷新列表 2023-04-19 14:09:43 +08:00
feng626
904dbd6d5e Merge pull request #3045 from jumpserver/pr@dev@ticket_command
fix: 工单命令复核不显示账号
2023-04-19 13:32:49 +08:00
feng
c6c693d112 fix: 工单命令复核不显示账号 2023-04-19 13:31:23 +08:00
feng626
3f946f9ada Merge pull request #3044 from jumpserver/pr@dev@cmd_group
fix: 命令过滤组 内容默认值修改
2023-04-19 11:41:36 +08:00
feng
35482abf7a fix: 命令过滤组 内容默认值修改 2023-04-19 11:40:54 +08:00
feng626
8b77b3a6df Merge pull request #3043 from jumpserver/pr@dev@web_asset_https
perf: web资产 协议显示https
2023-04-19 11:30:59 +08:00
feng
8240f56ecd perf: web资产 协议显示https 2023-04-19 11:30:02 +08:00
“huailei000”
77dd600393 perf: 平台tab增加icon 2023-04-19 11:12:26 +08:00
“huailei000”
1149195a23 perf: 创建、更新资产新页卡打开 2023-04-19 11:11:06 +08:00
feng626
800162ce27 Merge pull request #3042 from jumpserver/pr@dev@cloud_sync
fix: 云同步 rdp 端口
2023-04-19 11:03:02 +08:00
feng
9b473a8729 fix: 云同步 rdp 端口 2023-04-19 11:02:16 +08:00
jiangweidong
c553a09cb4 perf: 优化站内信查看已读逻辑 2023-04-19 11:01:56 +08:00
“huailei000”
2702257d71 fix: 修复创建资产登录没有默认值,更新资产登录没有数据问题 2023-04-19 10:53:18 +08:00
feng626
d41162a89b Merge pull request #3038 from jumpserver/pr@dev@platform_bulk_del
perf: 平台不能批量删除
2023-04-18 20:46:19 +08:00
feng
60999a7533 perf: 平台不能批量删除 2023-04-18 20:45:34 +08:00
老广
09f20e8149 Merge pull request #3033 from jumpserver/pr@dev@fix_useracl_form_initial
fix: 修复创建用户登录规则时ip不显示默认值问题
2023-04-18 19:15:16 +08:00
老广
bb631556ba Merge pull request #3036 from jumpserver/pr@dev@perf_import_error
perf: 优化错误显示
2023-04-18 19:13:37 +08:00
ibuler
32f708a014 perf: 优化错误显示 2023-04-18 19:08:17 +08:00
feng626
249cc67140 Merge pull request #3035 from jumpserver/pr@dev@ccount_template
perf: 账号模版按钮 优化
2023-04-18 18:14:17 +08:00
feng
301d3a79b7 perf: 账号模版按钮 优化 2023-04-18 18:12:46 +08:00
“huailei000”
d5d86afed7 fix: 修复创建用户登录规则时ip不显示默认值问题 2023-04-18 16:51:26 +08:00
“huailei000”
6e4ea15d82 fix: 修复更新平台设置弹窗不能打开问题 2023-04-18 16:26:03 +08:00
老广
79aa64c999 Merge pull request #3028 from jumpserver/pr@dev@perf_asset_detail_value
perf: 优化创建平台时表单的初始值
2023-04-18 16:03:43 +08:00
feng626
fa405f4cce Merge pull request #3031 from jumpserver/pr@dev@account_create
perf: 账号单独创建 会主动err
2023-04-18 15:01:39 +08:00
feng
3fa2cfd860 perf: 账号单独创建 会主动err 2023-04-18 14:59:49 +08:00
“huailei000”
6dad655704 perf: 优化平台表单字段显示 2023-04-18 14:41:46 +08:00
“huailei000”
2a6406a8fb perf: 优化账号详情字段显示 2023-04-18 14:02:55 +08:00
“huailei000”
eca3685899 perf: 优化创建平台时表单的初始值 2023-04-17 19:20:19 +08:00
feng626
afc4bea076 Merge pull request #3027 from jumpserver/pr@dev@account_exclude
perf: 账号详情去除params
2023-04-17 17:56:35 +08:00
feng
ace2568028 perf: 账号详情去除params 2023-04-17 17:55:45 +08:00
feng626
0382bab537 Merge pull request #3022 from jumpserver/pr@dev@perf_asset_platform
perf: 修改 platform 更新
2023-04-17 17:51:36 +08:00
feng626
5f535d8bae Merge pull request #3025 from jumpserver/pr@dev@cmd_filter_create_update
fix: 命令过滤无默认值
2023-04-17 16:32:42 +08:00
feng
48fe080009 fix: 命令过滤无默认值 2023-04-17 16:31:16 +08:00
feng626
e4cab9c2a4 Merge pull request #3024 from jumpserver/pr@dev@create_account
fix: 修复资产详情创建账号不刷新
2023-04-17 14:20:33 +08:00
feng
61a6b45051 fix: 修复资产详情创建账号不刷新 2023-04-17 14:19:29 +08:00
ibuler
03cda9a47a perf: 修改 platform 更新 2023-04-17 11:21:24 +08:00
halo
f00f679bd2 fix: 时长字段不显示 2023-04-17 11:11:40 +08:00
Jiangjie.Bai
75b1be9864 Merge pull request #3019 from jumpserver/dev
v3.2.0 rc2
2023-04-14 19:01:37 +08:00
“huailei000”
2340efedf5 perf: 调整推送参数helpText 2023-04-14 19:01:01 +08:00
jiangweidong
3d0b722409 feat: 支持部分资源的自定义自动化任务(Ping/VerifyAccount/ChangeSecret) (#3016)
* perf: 自定义指令自动化任务

* feat: 增加自定义改密指令

* perf: 优化

* perf: 优化

* perf: 调换顺序

* perf: 添加国际化
2023-04-14 18:31:35 +08:00
“huailei000”
777d31e562 fix: 修复账号推送参数设置是否可点击逻辑判断;修改表单标题显示;调整自动推送helpText 2023-04-14 18:06:00 +08:00
“huailei000”
47d602302f feat: 账号增加推送设置 2023-04-14 16:23:43 +08:00
Jiangjie.Bai
615c3c1cf4 Merge pull request #3014 from jumpserver/dev
v3.2.0 rc1
2023-04-13 20:02:38 +08:00
feng626
87002430f4 Merge pull request #3013 from jumpserver/pr@dev@fix_form_error
fix:  修复表单报错问题
2023-04-13 19:48:55 +08:00
“huailei000”
1bb0bce869 fix: 修复表单报错问题 2023-04-13 19:36:23 +08:00
Jiangjie.Bai
4d82231af4 Merge pull request #3012 from jumpserver/dev
v3.2.0 rc1
2023-04-13 19:22:38 +08:00
ibuler
9e74a49644 perf: 修改支持 list field form 2023-04-13 19:11:00 +08:00
ibuler
29d40f4d54 perf: 修复平台协议删除问题 2023-04-13 19:10:27 +08:00
fit2bot
dd0314d235 perf: vuex增加获取form的方法;修改账号推送 (#2975)
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: huailei <31801270+huailei000@users.noreply.github.com>
2023-04-13 19:09:13 +08:00
“huailei000”
fd3260faff feat: 平台增加自动化设置组件 2023-04-13 19:01:54 +08:00
feng626
c05f0275de Merge pull request #3009 from jumpserver/pr@dev@account_template
fix: 账号模版创建账号
2023-04-12 17:58:35 +08:00
feng
ed13ab3fdd fix: 账号模版创建账号 2023-04-12 17:58:03 +08:00
老广
5938ddbb35 Merge pull request #3007 from jumpserver/pr@dev@perf_platform_detail
perf: 修改 平台详情
2023-04-11 19:30:30 +08:00
ibuler
99672fc645 perf: 修改 平台详情 2023-04-11 19:13:15 +08:00
老广
3a73cb900d Merge pull request #3005 from jumpserver/pr@dev@fix_applethost_jumpdetail_error
fix: 修复远程应用发布机跳转到详情报错
2023-04-11 17:04:50 +08:00
“huailei000”
87196e0cd1 fix: 修复远程应用发布机跳转到详情报错 2023-04-11 17:03:53 +08:00
feng626
7c171b3a76 Merge pull request #3004 from jumpserver/pr@dev@perf_asset_list
perf: 优化资产列表
2023-04-11 16:21:00 +08:00
feng626
3694a27752 Merge pull request #3003 from jumpserver/pr@dev@asset_update
perf: asset update 500
2023-04-10 18:12:00 +08:00
feng
b5b6b5227d perf: asset update 500 2023-04-10 18:10:03 +08:00
jiangweidong
5ac365a990 fix: 解决更新手机号不同步的问题 2023-04-10 18:00:07 +08:00
jiangweidong
2361b16c30 fix: 优化手机号区号更新为空及展示问题 2023-04-10 17:13:34 +08:00
fit2bot
023fb03490 perf: 优化创建、更新后所有列表默认排序方式 (#2992)
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2023-04-10 17:08:48 +08:00
ibuler
4a0d104a96 perf: 优化资产列表 2023-04-10 17:06:34 +08:00
ibuler
f85351b163 perf: 优化自定义资产显示 2023-04-10 10:58:22 +08:00
ibuler
140ad7cac4 perf: 修改前端页面 2023-04-10 10:58:22 +08:00
ibuler
d0b4b488b1 perf: 优化对自定义资产的支持 2023-04-10 10:58:22 +08:00
ibuler
da69186239 perf: 支持自定义资产 2023-04-10 10:58:22 +08:00
ibuler
2ea6058113 perf: 修改支持自定义资产 2023-04-10 10:58:22 +08:00
jiangweidong
8913a5ea87 perf: 手机区号增加中国台湾地区 2023-04-10 10:27:40 +08:00
jiangweidong
de5ff58d18 feat: 手机号码支持选择区号 2023-04-10 10:27:40 +08:00
feng626
b658e37fcb Merge pull request #2994 from jumpserver/pr@dev@saml2_auth_help_text
perf: 修改saml2 auth help text
2023-04-07 17:45:32 +08:00
feng
99efbd153f perf: 修改saml2 auth help text 2023-04-07 17:44:38 +08:00
feng626
09a0630c6b Merge pull request #2993 from jumpserver/pr@dev@bulk_create_account
perf: 批量添加账号 模版添加 样式修改
2023-04-07 16:16:33 +08:00
feng
cc7dd80a8a perf: 批量添加账号 模版添加 样式修改 2023-04-07 16:15:52 +08:00
老广
a1906fd925 Merge pull request #2973 from jumpserver/pr@dev@feat_windows_winrm
feat: Windows类型资产增加winrm协议
2023-04-07 11:10:07 +08:00
“huailei000”
f48632d7f7 perf: 优化下拉菜单样式 2023-04-07 10:30:33 +08:00
feng626
f3d31a3f0f Merge pull request #2989 from jumpserver/pr@dev@account_push_is_periodic
perf: 账号推送 社区版隐藏定时功能
2023-04-06 10:50:54 +08:00
feng
7aaec2ea43 perf: 账号推送 社区版隐藏定时功能 2023-04-06 10:49:22 +08:00
feng626
40b7dbc211 Merge pull request #2988 from jumpserver/pr@dev@user_secret_key
perf: has_secret_key
2023-04-04 18:03:22 +08:00
feng
1cec999bfd perf: has_secret_key 2023-04-04 17:59:37 +08:00
feng626
b33f598742 Merge pull request #2987 from jumpserver/pr@dev@account_update
perf: 账号创建更新优化
2023-04-04 16:05:10 +08:00
feng
19b2b55051 perf: 账号创建更新优化 2023-04-04 16:03:52 +08:00
fit2bot
b6235ec7dd perf: 优化更多批量操作菜单显示 (#2986)
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: huailei <31801270+huailei000@users.noreply.github.com>
2023-04-04 15:36:41 +08:00
feng626
108a39472a Merge pull request #2985 from jumpserver/pr@dev@bulk_account
perf: 批量创建账号添加模版
2023-04-04 15:33:47 +08:00
feng
63c97e18ad perf: 批量创建账号添加模版 2023-04-04 15:30:40 +08:00
feng626
19f46b098a Merge pull request #2983 from jumpserver/pr@dev@perf_account_error
fix: 修复批量添加账号报错不弹窗
2023-04-04 11:40:48 +08:00
ibuler
03ad5239e9 fix: 修复批量添加账号报错不弹窗 2023-04-04 11:39:03 +08:00
老广
720a076648 Merge pull request #2982 from jumpserver/pr@dev@perf_i18n
perf: 修改翻译
2023-04-04 10:57:25 +08:00
ibuler
80eef76604 fix: 修复添加账号报错 2023-04-04 10:56:09 +08:00
ibuler
feb9c65733 perf: 修改翻译 2023-04-04 10:49:03 +08:00
老广
7597112520 Merge pull request #2972 from jumpserver/pr@dev@perf_account_template
perf: 优化账号批量创建
2023-04-04 09:58:42 +08:00
老广
d54044760d Merge branch 'dev' into pr@dev@perf_account_template 2023-04-04 09:52:51 +08:00
Eric
b369d2d22a perf: 移除 code 字段显示 2023-04-03 18:37:35 +08:00
Eric
2e3db496c0 perf: 会话分享记录新增字段 2023-04-03 18:37:35 +08:00
feng626
97e2f23093 Merge pull request #2980 from jumpserver/pr@dev@session_list
fix: 会话记录翻译问题
2023-04-03 18:12:13 +08:00
feng
42b79c3e30 fix: 会话记录翻译问题 2023-04-03 18:10:55 +08:00
feng626
d2fe84a81e Merge pull request #2979 from jumpserver/pr@dev@perf_asset_helptext
perf: 添加asset helptext
2023-04-03 16:28:44 +08:00
feng
c3bb902e67 perf: 添加asset helptext 2023-04-03 16:27:42 +08:00
ibuler
dde98e470b perf: 修改结果避免返回的错误不对 2023-04-03 15:56:23 +08:00
“huailei000”
822fa9714c perf: 创建、更新资产默认按照更新时间排序 2023-04-03 15:53:27 +08:00
“huailei000”
90659afc36 perf: 优化快捷命令-选择命令列表显示 2023-04-03 15:51:23 +08:00
“huailei000”
7310cbe636 perf: 创建资产时添加账号列表列表增加显示字段 2023-04-03 15:50:43 +08:00
“huailei000”
0857007e15 perf: 命令过滤详情展示更多字段信息 2023-04-03 15:48:34 +08:00
ibuler
41b00cb293 perf: 修改账号创建 2023-04-03 15:02:11 +08:00
ibuler
89466a0995 perf: 优化显示结果 2023-03-31 19:30:35 +08:00
jiangweidong
800315fb7c perf: 工单详情界面不显示添加模版 2023-03-30 16:39:26 +08:00
jiangweidong
8b037e8bac perf: 修改默认值 2023-03-30 16:39:26 +08:00
jiangweidong
085f7e68ef fix: 加个return 2023-03-30 16:39:26 +08:00
jiangweidong
5c075a5a7d perf: 工单界面不显示模版添加 2023-03-30 16:39:26 +08:00
jiangweidong
01bc2b838a fix: 修改逻辑 2023-03-30 11:30:11 +08:00
jiangweidong
0d495e979d fix: 修改改端口逻辑 2023-03-30 10:35:11 +08:00
jiangweidong
6d66419fa6 perf: 优化一下 2023-03-29 17:04:56 +08:00
jiangweidong
96f629a1b7 Merge branch 'dev' of https://github.com/jumpserver/lina into pr@dev@feat_windows_winrm 2023-03-29 15:52:34 +08:00
jiangweidong
35df28ea90 feat: windows类型平台支持winrm协议 2023-03-29 15:52:27 +08:00
“huailei000”
ca98a8ee2e perf: 优化快捷命令-内置变量弹窗内容显示 2023-03-29 15:35:56 +08:00
ibuler
dc09364348 perf: 优化账号批量创建 2023-03-29 15:02:01 +08:00
feng
423601d840 perf: asset address required 2023-03-29 14:15:47 +08:00
feng
09ee34f0d3 perf: 修改lian翻译 2023-03-29 14:05:34 +08:00
“huailei000”
98fef43ece perf: 作业中心-执行历史增加作业名称字段显示 2023-03-29 10:32:21 +08:00
ibuler
41bb35f7c6 perf: 修改账号创建 2023-03-28 15:48:11 +08:00
jiangweidong
827339ad0e fix: 提示文字有误 2023-03-28 10:56:36 +08:00
“huailei000”
9dbdc559cd perf: 资产平台http协议页面显示为http(s) 2023-03-24 18:39:03 +08:00
老广
bce328a440 Merge pull request #2961 from jumpserver/pr@dev@perf_assetbulkupdate_dialog
perf: 优化多次批量更新资产修改项显示不全的问题
2023-03-24 18:11:42 +08:00
老广
84e9cf1ac3 Merge pull request #2959 from jumpserver/pr@dev@perf_passwordhistory_id
perf: 账号密码历史记录列表修改唯一的key字段
2023-03-24 18:09:21 +08:00
老广
5fd5834c8d Merge pull request #2956 from jumpserver/pr@dev@perf_detail_delete_fail_tip
perf:优化RelationCard组件删除之后默认错误处理
2023-03-24 18:08:35 +08:00
老广
73a783bb97 Merge pull request #2964 from jumpserver/pr@dev@device_for_su_from
perf: device 支持账号切换
2023-03-24 18:06:19 +08:00
ibuler
1a5dd023e8 perf: device 支持账号切换 2023-03-24 18:01:59 +08:00
“huailei000”
e4e011e183 fix: 修复资产树连续创建节点后连续修改节点名称,只有最后一个节点名称能修改成功的问题 2023-03-24 16:00:07 +08:00
feng
4b594290e9 feat: 收集账号 可选同步表 2023-03-24 15:26:11 +08:00
“huailei000”
c71a0f2a75 perf: 账号密码历史记录列表修改唯一的key字段 2023-03-23 17:04:56 +08:00
“huailei000”
fd6ab841bf perf: 优化多次批量更新资产修改项显示不全的问题 2023-03-23 16:36:21 +08:00
feng626
2cf27f08b9 Merge pull request #2960 from jumpserver/pr@dev@clear_secret
perf: clear secret
2023-03-23 16:05:27 +08:00
feng
97f531bbec perf: clear secret 2023-03-23 16:01:12 +08:00
feng626
ac7d5e216e Merge pull request #2958 from jumpserver/pr@dev@sync_accounts
feat: 账号收集批量同步账号
2023-03-23 15:24:36 +08:00
feng
ee8b373e77 feat: 账号收集批量同步账号 2023-03-23 15:22:02 +08:00
“huailei000”
ecd1da5fc4 perf: 优化翻译 2023-03-23 11:29:39 +08:00
“huailei000”
cdcf340a75 perf:优化RelationCard组件删除之后默认错误处理 2023-03-23 11:25:58 +08:00
feng626
d8941c14b8 Merge pull request #2955 from jumpserver/pr@dev@remove_secret
feat: account remove secret
2023-03-23 11:21:01 +08:00
feng
bb3ca059b0 feat: account remove secret 2023-03-23 11:18:40 +08:00
老广
d994a01a10 Merge pull request #2954 from jumpserver/pr@dev@perf_platform_create
perf: 优化平台创建
2023-03-22 19:41:55 +08:00
ibuler
bb432dff18 perf: 修改 platform 2023-03-22 19:40:59 +08:00
ibuler
9ce7311f6d perf: 优化平台创建 2023-03-22 19:27:29 +08:00
“huailei000”
a468e04bad perf: 抽离公共复制方法;账号详情增加复制功能 2023-03-22 16:37:46 +08:00
老广
a5dcc8be52 Merge pull request #2950 from jumpserver/pr@dev@perf_platform_protocols
perf: 平台更改协议
2023-03-22 16:26:27 +08:00
ibuler
f905ed0065 perf: 优化代码写法,缩进以及函数 2023-03-22 16:13:42 +08:00
ibuler
0f80375242 perf: 去掉 debug console 2023-03-22 16:07:54 +08:00
feng626
ed8c9df4c3 Merge pull request #2952 from jumpserver/pr@dev@user_asset_detail_add_id
perf: user asset detail add id
2023-03-22 16:02:21 +08:00
feng
7bc9f2f75b perf: user asset detail add id 2023-03-22 16:01:28 +08:00
ibuler
b0c635463a perf: 平台更改协议 2023-03-22 14:22:12 +08:00
老广
5ccf713ef3 Merge pull request #2949 from jumpserver/pr@dev@fix_web_helptext
fix: Web资产提示有误
2023-03-22 14:02:15 +08:00
jiangweidong
16e92e925c fix: Web资产提示有误 2023-03-22 14:01:08 +08:00
feng626
a2ec7d3ccd Merge pull request #2948 from jumpserver/pr@dev@bulk_create_account
perf: 批量创建账号
2023-03-22 11:09:26 +08:00
feng
ae3e072275 perf: 批量创建账号 2023-03-22 11:07:30 +08:00
ibuler
9e195dd1d9 perf: 优化平台协议 2023-03-21 17:54:32 +08:00
老广
8432299660 Merge pull request #2947 from jumpserver/pr@dev@perf_import_reloadtable
perf: 导入数据成功后自动刷新列表
2023-03-21 10:23:27 +08:00
“huailei000”
b9f41570bf perf: 导入数据成功后自动刷新列表 2023-03-21 09:58:12 +08:00
老广
5ead251ea7 Merge pull request #2690 from jumpserver/pr@dev@perf_task_route
perf: 迁移到了系统设置中
2023-03-20 10:37:22 +08:00
ibuler
fc10a77372 perf: 已启动系统任务到系统设置中 2023-03-20 10:35:46 +08:00
ibuler
41ef8c6e97 perf: 持久化存储 pre org,避免别的 tab 切换到系统设置中,当前组织失效 2023-03-17 16:49:10 +08:00
Bai
ef0658de24 fix: 修复报错信息显示, 特殊处理500错误 2023-03-17 16:45:41 +08:00
Bai
fedb068221 fix: 修复 LAN 账号保存 Platform 问题 2023-03-17 15:44:46 +08:00
老广
5a66c39313 Merge pull request #2940 from jumpserver/pr@dev@fix_perms
fix: 修复授权规则创建账号模版弹窗取消按钮不生效问题
2023-03-17 15:29:11 +08:00
Bai
ce6ca288b7 fix: 修复授权规则创建账号模版弹窗取消按钮不生效问题 2023-03-17 14:55:22 +08:00
feng626
65541a7001 Merge pull request #2939 from jumpserver/pr@dev@asset_bulk_update
perf: 资产全局导入提示及批量更新平台
2023-03-16 18:24:54 +08:00
feng
24a5c6be43 perf: 资产全局导入提示及批量更新平台 2023-03-16 18:22:51 +08:00
“huailei000”
c6cf6571b6 perf: ldap导入用户列表-组织下拉框设置最大宽度 2023-03-16 16:44:36 +08:00
Bai
8ea990d070 fix: 修复创建资产添加账号模版报错问题 2023-03-16 16:44:36 +08:00
“huailei000”
f4a32170d5 perf: message 2023-03-16 16:44:36 +08:00
ibuler
073508675e perf: 添加默认的信息 2023-03-16 16:44:36 +08:00
“huailei000”
020c7ec9fa perf: ldap导入用户列表-组织下拉框设置最大宽度 2023-03-16 16:44:15 +08:00
Bai
f12707d958 fix: 修复创建资产添加账号模版报错问题 2023-03-16 12:54:16 +08:00
“huailei000”
82c2e20fce perf: message 2023-03-16 11:22:11 +08:00
老广
11f0ee12cf Merge pull request #2929 from jumpserver/pr@dev@perf_add_default_security
perf: 添加默认的信息
2023-03-16 10:50:12 +08:00
ibuler
ca64c0b219 perf: 添加默认的信息 2023-03-16 10:49:14 +08:00
Jiangjie.Bai
1d6ca0a93a Merge pull request #2924 from jumpserver/dev
v3.1.0 rc4
2023-03-15 19:46:31 +08:00
“huailei000”
e34c6fc843 perf: 导出优化判断 2023-03-15 19:42:47 +08:00
老广
51e139712d Merge pull request #2926 from jumpserver/pr@dev@perf_table_export_mfa
perf: 优化列表导出mfa验证弹窗逻辑
2023-03-15 19:30:34 +08:00
“huailei000”
9daf001312 perf: 优化列表导出mfa验证弹窗逻辑 2023-03-15 11:28:49 +00:00
Eric
27353ee0c2 perf: 监控页 Tinker 组件名称显示 2023-03-15 19:02:17 +08:00
feng626
b6643d89c0 Merge pull request #2923 from jumpserver/pr@dev@endpoint
perf: endpoint rules list
2023-03-15 18:23:50 +08:00
feng
9503586b8a perf: endpoint rules list 2023-03-15 18:20:38 +08:00
老广
317735c69a Merge pull request #2921 from jumpserver/pr@dev@user_password_expire
fix: 用户密码即将到期不提示
2023-03-15 17:37:54 +08:00
老广
5c26000f90 Merge pull request #2920 from jumpserver/pr@dev@perf_platform_add_asset_constrains
perf: 修改账号更改平台的约束
2023-03-15 16:49:43 +08:00
feng
139a47b858 fix: 用户密码即将到期不提示 2023-03-15 16:19:25 +08:00
ibuler
2f2e05101b perf: 修改账号更改平台的约束 2023-03-15 16:15:37 +08:00
Bai
36f7d9711d fix: 修复windows账号详情和更新账号时 su-from 字段的控制 2023-03-15 15:38:12 +08:00
Bai
4e89c8d53f fix: 优化账号模版可以根据 protocols 过滤 secret_type 字段 2023-03-15 14:48:37 +08:00
老广
5902475778 Merge pull request #2911 from jumpserver/pr@dev@fix_createasset_account_editsecret
fix: 修复创建资产-添加账号后编辑账号密文为空的问题
2023-03-14 20:05:47 +08:00
“huailei000”
abdba774cc perf: 全局添加刷新方法;账号详情增加更新操作 2023-03-14 20:04:49 +08:00
ibuler
c1d10322cb perf: 优化导入导出 2023-03-14 20:04:21 +08:00
ibuler
90fdf4982e perf: 优化账号导出 2023-03-14 20:04:21 +08:00
ibuler
f5e5d431c7 perf: 优化系统组织切换的问题 2023-03-14 20:03:58 +08:00
“huailei000”
9d9fb51a7d perf: 优化控制台增长数据显示 2023-03-14 20:03:06 +08:00
“huailei000”
997b5d8d19 fix: 修复创建资产-添加账号后编辑账号密文为空的问题 2023-03-14 15:37:12 +08:00
feng626
ea19dd8e0a Merge pull request #2908 from jumpserver/pr@dev@hardware
fix: 主机硬件信息 多次请求及warning
2023-03-13 23:20:25 +08:00
feng
983663a3fa fix: 主机硬件信息 多次请求及warning 2023-03-13 23:17:47 +08:00
feng626
3809519331 Merge pull request #2906 from jumpserver/pr@dev@ticket_push_account
perf: 工单推荐账号过滤组织
2023-03-13 18:43:55 +08:00
feng
fe7d20778d perf: 工单推荐账号过滤组织 2023-03-13 18:39:59 +08:00
老广
f6bf8b3193 Merge pull request #2902 from jumpserver/pr@dev@feat_component_uploadsecret
feat: 增加上传密钥组件
2023-03-13 18:36:29 +08:00
老广
5d5ee3cdaa Merge pull request #2905 from jumpserver/pr@dev@change_file_name
perf: 修改账号备份
2023-03-13 18:29:17 +08:00
ibuler
ed4da2ab50 perf: 修改账号备份 2023-03-13 18:26:39 +08:00
“huailei000”
9c8ed912bb perf: 账号列表默认按照更新日期排序 2023-03-13 17:28:21 +08:00
feng626
c58551adea Merge pull request #2903 from jumpserver/pr@dev@gateway
fix: 创建网关找不到平台
2023-03-13 16:50:48 +08:00
feng
f44618d915 fix: 创建网关找不到平台 2023-03-13 16:48:44 +08:00
“huailei000”
aeb26c748a feat: 增加上传密钥组件 2023-03-13 16:40:54 +08:00
ibuler
c75f0b1312 perf: 修改 import expore 2023-03-10 19:26:02 +08:00
ibuler
6138fe2e35 perf: 优化导入导出 2023-03-10 19:26:02 +08:00
feng
8d3f99392f perf: 硬件信息浮动延迟 2023-03-10 15:41:13 +08:00
Bai
2fd4792ed4 feat: 支持飞书国际版(lark) 2023-03-10 15:13:42 +08:00
“huailei000”
757a822e34 perf: 增加license显示信息 2023-03-10 11:04:24 +08:00
feng626
03ffe4a911 Merge pull request #2893 from jumpserver/pr@dev@hardware_show
fix: 修复硬件信息undefined
2023-03-09 17:16:43 +08:00
feng
3b83ecd85d fix: 修复硬件信息undefined 2023-03-09 17:15:35 +08:00
老广
80145dc114 Merge pull request #2892 from jumpserver/pr@dev@perf_asset_address_not_rule
perf: 资产-地址前端不做限制
2023-03-09 13:01:40 +08:00
老广
5612f432a5 Merge pull request #2884 from jumpserver/pr@dev@fix_taskperms
fix: 修改任务列表权限控制
2023-03-09 13:01:06 +08:00
“huailei000”
023fd55a70 perf: 资产-地址前端不做限制 2023-03-09 05:00:44 +00:00
老广
897f3881b2 Merge pull request #2889 from jumpserver/pr@dev@perf_asset_ip_rule
perf: 优化创建资产url正则校验
2023-03-09 12:48:31 +08:00
老广
730aa548d4 Merge pull request #2887 from jumpserver/pr@dev@perf_table_drag-border
perf: 优化table列表拖动效果
2023-03-09 12:48:02 +08:00
feng626
f1a3d775cc Merge pull request #2890 from jumpserver/pr@dev@host_hardware_info
perf: host hardware
2023-03-09 11:13:06 +08:00
feng
71d79ec6ef perf: host hardware 2023-03-09 11:12:10 +08:00
“huailei000”
4118a21d1d perf: 优化创建资产url正则校验 2023-03-09 02:20:41 +00:00
feng626
be87eec4e5 Merge pull request #2869 from jumpserver/pr@dev@accounts
perf: 优化 perms 中可以关联账号模版
2023-03-08 18:52:15 +08:00
feng
230433de05 perf: 授权添加账号模版 2023-03-08 18:31:20 +08:00
“huailei000”
e3fdf1cc41 perf: 优化table列表拖动效果 2023-03-08 18:04:18 +08:00
Bai
f1f4ba5dfa fix: 修改任务列表权限控制 2023-03-08 09:15:46 +00:00
“huailei000”
d9d5de5102 perf: 调整其它设置表单显示内容 2023-03-08 16:34:25 +08:00
吴小白
7bf74d8727 Merge pull request #2873 from jumpserver/pr@dev@perf_upload_gitconfig
perf: work flow
2023-03-08 15:49:14 +08:00
Eric
937bdcf5c7 perf: 增加 IGNORE_VERIFY_CERTS 字段 2023-03-08 14:47:29 +08:00
Bai
0a86240f90 fix: 修复组织管理员打开用户列表报错的问题 2023-03-08 14:40:49 +08:00
“huailei000”
ea3c28791d perf: work flow 2023-03-08 13:17:55 +08:00
老广
1ff829182b Merge pull request #2874 from jumpserver/pr@dev@perf_log_diff_performence
perf: 修改活动记录详情中的表现
2023-03-08 10:39:11 +08:00
ibuler
23fea1bf99 perf: 修改活动记录详情中的表现
perf: 优化操作日志 dialog
2023-03-08 10:36:07 +08:00
“huailei000”
496605c539 perf: 优化控制台仪表盘排名列表数据显示 2023-03-07 11:35:08 +08:00
ibuler
051784e52b perf: 优化 perms 中可以关联账号模版 2023-03-07 11:01:04 +08:00
“huailei000”
dcd6fa977d perf: 调整logo对齐 2023-03-06 15:21:43 +08:00
ibuler
411987fb69 perf: 修改授权中账号选择 2023-03-02 19:41:26 +08:00
“huailei000”
ac88b70b1c perf: table列表增加拖动效果 2023-03-02 18:51:46 +08:00
“huailei000”
36e053068e perf: 调整账号详情ssh指纹显示 2023-03-02 16:44:50 +08:00
“huailei000”
7944c4a414 perf: 优化移动端模式下菜单样式 2023-03-02 11:08:00 +08:00
Aaron3S
325c2b45e4 fix: 修改权限依赖 2023-03-01 18:40:17 +08:00
“huailei000”
477fd5164e perf: 优化资产列表控制台报错问题 2023-03-01 16:14:29 +08:00
Bai
acfdb04b09 fix: 修改RDS许可证配置 2023-03-01 15:21:27 +08:00
“huailei000”
50073f0512 perf: 优化通告组件链接样式 2023-03-01 13:55:42 +08:00
“huailei000”
6ab61215b5 perf: 优化选择平台弹窗样式 2023-02-28 19:09:39 +08:00
Aaron3S
b5d4bfd488 feat: 增加按钮提示 2023-02-28 18:46:47 +08:00
feng626
24297dbead Merge pull request #2845 from jumpserver/pr@dev@hardinfo
perf: 主机硬件信息
2023-02-28 18:46:06 +08:00
Aaron3S
ad0c17610e fix: 增加运行用户为空时的提示 2023-02-28 18:30:47 +08:00
feng
a54f6f3a89 perf: 主机硬件信息 2023-02-28 18:30:39 +08:00
老广
3212260d8e Merge pull request #2835 from jumpserver/pr@dev@perf_ztree_overflow
perf: 优化 ztree overflow
2023-02-28 18:19:57 +08:00
Aaron3S
8ec7cd3c3c fix: 修复作业无法执行的问题 2023-02-28 18:09:56 +08:00
“huailei000”
32c09c896c perf: 优化资产树滚动条样式 2023-02-28 18:00:28 +08:00
“huailei000”
71c1d77498 perf: 优化移动端下切换组织组件样式 2023-02-28 17:28:27 +08:00
ibuler
06fc05e6b3 perf: 优化 ztree overflow 2023-02-28 17:12:36 +08:00
老广
6b491ef696 Merge pull request #2831 from jumpserver/pr@dev@fix_version
fix: 修正版本获取不正确
2023-02-28 17:01:41 +08:00
“huailei000”
5e23ae7926 perf: 优化移动端样式 2023-02-28 16:45:58 +08:00
吴小白
f62c6b980e fix: 修正版本获取不正确 2023-02-28 16:36:48 +08:00
老广
d930e09065 Merge pull request #2830 from jumpserver/pr@dev@perf_ztree_height
perf: 优化 tree 高度
2023-02-28 16:30:05 +08:00
ibuler
10a6dae2cf perf: 优化 tree 高度 2023-02-28 08:09:21 +00:00
“huailei000”
c099a16a49 perf: about dialog 2023-02-28 14:00:57 +08:00
feng626
198e6a11d2 Merge pull request #2822 from jumpserver/pr@dev@push_account_community
perf: 推送账号 社区版定时任务关闭
2023-02-28 13:35:30 +08:00
ibuler
8c66e20961 perf: 优化 关于页面 2023-02-28 13:34:51 +08:00
feng
0393128be5 perf: 推送账号 社区版定时任务关闭 2023-02-28 11:41:39 +08:00
Aaron3S
69ff6be5f4 fix: 修复 term 组件上的按钮被覆盖的问题 2023-02-27 18:35:44 +08:00
老广
8685362344 Merge pull request #2815 from jumpserver/pr@dev@fix_platform_create
perf: 修改 assetMeta 调用
2023-02-27 17:56:36 +08:00
ibuler
7ea68e9a09 perf: 修改 assetMeta 调用 2023-02-27 09:46:30 +00:00
ibuler
ebede00841 fix: 修复平台创建 2023-02-27 17:45:39 +08:00
feng
73ce298d6a perf: lina 提示优化 2023-02-27 16:28:23 +08:00
Aaron3S
69cd561dc0 fix: 暂时隐藏参数设置字段 2023-02-27 16:11:28 +08:00
老广
7af1a55e2a Merge pull request #2804 from jumpserver/revert-2798-pr@dev@lina_point_out
Revert "perf: lina 提示优化"
2023-02-27 15:57:06 +08:00
feng626
c1272d9a9f Revert "perf: lina 提示优化" 2023-02-27 15:56:30 +08:00
ibuler
f3e28f7cd4 perf: 平台允许修改 2023-02-27 15:51:32 +08:00
ibuler
412a7ceba1 perf: 添加accounts 搜索建议 2023-02-27 15:20:37 +08:00
feng626
73bf34c422 Merge pull request #2798 from jumpserver/pr@dev@lina_point_out
perf: lina 提示优化
2023-02-27 13:29:11 +08:00
feng
3d2b139214 perf: lina 提示优化 2023-02-27 13:27:41 +08:00
ibuler
658f0ff587 perf: 优化 applet host 请求引起的 eror 2023-02-26 12:38:12 +08:00
“huailei000”
621893fdcc fix: 修复快捷命令操作按钮不能点击问题 2023-02-24 17:53:53 +08:00
feng626
a6e94b4173 Merge pull request #2792 from jumpserver/pr@dev@add_account_asset_required
perf: add account asset required
2023-02-24 16:27:32 +08:00
feng
f9098c3203 perf: add account asset required 2023-02-24 16:22:36 +08:00
“huailei000”
b1c0218ad9 perf: 优化账号列表查看详情MFA弹窗没有关闭问题 2023-02-24 14:47:56 +08:00
“huailei000”
4058843b1a perf: 平台详情增加disabled判断 2023-02-24 11:10:50 +08:00
Jiangjie.Bai
36aea652d6 Merge pull request #2788 from jumpserver/dev
v3.0.0
2023-02-23 20:16:41 +08:00
“huailei000”
7deaf27526 perf: 验证MFA不显示错误提示 2023-02-23 20:06:49 +08:00
老广
fceb5904fe Merge pull request #2786 from jumpserver/pr@dev@perf_account_history1
perf: 修改 history versin
2023-02-23 20:02:29 +08:00
老广
fa86225ae3 Merge branch 'dev' into pr@dev@perf_account_history1 2023-02-23 20:01:11 +08:00
ibuler
7fe43ca0ff perf: 修改 history versin 2023-02-23 19:57:48 +08:00
“huailei000”
6511aca103 perf: 用户详情-授权资产过滤显示字段 2023-02-23 19:35:53 +08:00
feng626
833d530c2f Merge pull request #2784 from jumpserver/pr@dev@i18n
perf: i18n
2023-02-23 19:24:30 +08:00
feng
3acd8d179e perf: i18n 2023-02-23 19:23:44 +08:00
feng626
828bb76057 Merge pull request #2783 from jumpserver/pr@dev@feat_add_view_celerytask_dep
feat: 增加任务执行对日志查看的任务依赖
2023-02-23 19:08:03 +08:00
Aaron3S
d4ab4e3c7b feat: 增加任务执行对日志查看的任务依赖 2023-02-23 19:06:13 +08:00
“huailei000”
0346630f02 perf: 全局组织下资产详情不能模版添加账号 2023-02-23 19:05:55 +08:00
“huailei000”
d74e70893e perf: 优化全局组织下一些权限问题 2023-02-23 18:59:54 +08:00
老广
55c6202c5e Merge pull request #2780 from jumpserver/pr@dev@perf_change_msg
perf: 修改一些提示
2023-02-23 18:49:48 +08:00
ibuler
63cb48ed23 perf: 优化翻译 2023-02-23 18:48:44 +08:00
ibuler
c2d552362a perf: 优化 角色 2023-02-23 18:42:45 +08:00
ibuler
364c8998fa perf: 修改一些提示 2023-02-23 18:36:47 +08:00
“huailei000”
8cb4f9ccda fix: 修复站内信查看会话,会话详情不能下载录像问题 2023-02-23 17:41:16 +08:00
Bai
b46021db49 fix: 修复账号创建更新时 su-from api 的参数 2023-02-23 17:01:36 +08:00
feng626
7552fd7637 Merge pull request #2777 from jumpserver/pr@dev@perf
perf: 账号收集 web资产 字段优化
2023-02-23 16:39:44 +08:00
feng
6eaa21bf66 perf: 账号收集 web资产 字段优化 2023-02-23 16:38:51 +08:00
“huailei000”
a0658d93d8 perf: 优化创建资产时添加相同类型的账号过滤方法 2023-02-23 16:22:37 +08:00
老广
8d87c89da2 Merge pull request #2775 from jumpserver/pr@dev@fix_assetlisttest
fix: 修复资产列表测试按钮添加 auto_info 选项
2023-02-23 16:20:17 +08:00
Bai
6621da8639 fix: 修复资产列表测试按钮添加 auto_info 选项 2023-02-23 16:15:09 +08:00
Aaron3S
6e8c93657e perf: 增加作业中心系统错误显示 2023-02-23 15:32:28 +08:00
Bai
0b5d7c8ca1 fix: 修复 build 时设置版本号 2023-02-23 15:28:37 +08:00
老广
71c86a637c Merge pull request #2771 from jumpserver/pr@dev@perf_ticket2
perf: 优化账号历史数量
2023-02-23 14:12:53 +08:00
ibuler
4dc1102629 perf: 优化账号历史数量 2023-02-23 14:06:51 +08:00
Bai
7fdd463201 fix: 修复请求 profile api 返回 302 的问题 2023-02-23 13:59:29 +08:00
Bai
f3616f06e8 fix: 修复资产账号列表测试权限控制 2023-02-23 11:50:46 +08:00
“huailei000”
c1f0fbbfd9 perf: 优化快捷命令样式 2023-02-23 11:33:26 +08:00
feng626
3597c52af8 Merge pull request #2767 from jumpserver/pr@dev@termian_applet_perm
perf: terminal applet perm
2023-02-23 11:27:11 +08:00
feng
38eb45cc81 perf: terminal applet perm 2023-02-23 11:25:40 +08:00
“huailei000”
94b23241eb perf: 全局组织资产树不显示节点操作 2023-02-23 11:14:07 +08:00
“huailei000”
a851ccdfe7 perf: 优化全局组织下权限 2023-02-23 11:02:36 +08:00
“huailei000”
4b7b3b3507 perf: 全局组织下不能测试 2023-02-23 10:44:37 +08:00
Jiangjie.Bai
1a42ce90ab Merge pull request #2760 from jumpserver/dev
v3.0.0-rc-latest
2023-02-22 22:21:54 +08:00
“huailei000”
70a45bdb03 perf: 优化账号详情查看密码弹窗显示内容 2023-02-22 21:53:50 +08:00
老广
7644313bbf Merge pull request #2762 from jumpserver/pr@dev@perf_change_md_style
perf: 修改 markdown style
2023-02-22 21:31:44 +08:00
ibuler
e067419e00 perf: 修改 markdown style 2023-02-22 21:30:55 +08:00
“huailei000”
cadf057518 fix:修复创建资产报错后账号密码重复加密问题 2023-02-22 21:30:51 +08:00
fit2bot
4d534dabba perf: 优化账号历史 (#2748)
* perf: 优化账号历史

* perf: 修改对其

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-02-22 21:23:23 +08:00
Bai
e60e95c899 fix: 解决 system role detail user list 不显示 orgName 2023-02-22 21:08:41 +08:00
Bai
413e8dcf7f fix: 修复资产授权规则过滤 2023-02-22 21:08:23 +08:00
Bai
a0b6e9c00c fix: 修复云同步实例详情状态显示 2023-02-22 20:40:42 +08:00
Eric_Lee
25e649b4d8 Merge pull request #2755 from jumpserver/pr@dev@fix_cloudip
fix: 修复云同步执行列表 ip 字段显示
2023-02-22 20:12:04 +08:00
Bai
1146d9763a fix: 修复云同步执行列表 ip 字段显示 2023-02-22 20:11:02 +08:00
“huailei000”
afa8cbac88 perf: 优化资产详情账号列表显示字段 2023-02-22 19:45:09 +08:00
“huailei000”
2f97fbe65e perf: 优化列表字段翻译 2023-02-22 19:35:56 +08:00
“huailei000”
002efbc506 perf: 调整角色列表显示 2023-02-22 19:25:30 +08:00
Aaron3S
f67aa65fa2 fix: 增加一些helptext 2023-02-22 19:01:13 +08:00
“huailei000”
983cd266f5 perf: 账号详情增加查看密码 2023-02-22 18:40:07 +08:00
feng626
0fcd2c990b Merge pull request #2750 from jumpserver/pr@dev@fix_ops_delete_file_i18n
fix: 修复翻译错误
2023-02-22 18:19:57 +08:00
Aaron3S
0bb8bb9c01 fix: 修复翻译错误 2023-02-22 18:17:26 +08:00
“huailei000”
c8eead9f82 fix: 修复账号点击查看弹出错误提示 2023-02-22 17:26:30 +08:00
“huailei000”
29012dd05f fix: 修复创建资产时添加相同类型的账号报错问题 2023-02-22 16:49:05 +08:00
feng626
73dd61762f Merge pull request #2746 from jumpserver/pr@dev@push_account_task
perf: push account task
2023-02-22 16:46:58 +08:00
feng
0fedd033d3 perf: push account task 2023-02-22 16:46:09 +08:00
Bai
fc6ce53b8a fix: 修复 celery log 查看页面失败的问题 2023-02-22 16:14:18 +08:00
“huailei000”
02a735c53a perf: 优化导入导出图标 2023-02-22 15:46:07 +08:00
Bai
d6208eabd3 fix: 修复页面url跳转 任务日志页面跳转失败问题 2023-02-22 15:29:14 +08:00
老广
08faad0f41 Merge pull request #2741 from jumpserver/pr@dev@fix_indexurl
fix: 修复重定向 url 包含 /ui/# 前缀
2023-02-22 14:28:42 +08:00
Eric_Lee
a7ac4120f9 Merge pull request #2740 from jumpserver/pr@dev@fix_applethost
fix: 获取 发布机失败的问题
2023-02-22 14:27:17 +08:00
Bai
16236dda09 fix: 修复重定向 url 包含 /ui/# 前缀 2023-02-22 14:25:45 +08:00
Eric
0746879dd5 fix: 获取 发布机失败的问题 2023-02-22 14:23:39 +08:00
Bai
dabd26b604 fix: 修改资产详情页面 2023-02-22 13:56:20 +08:00
feng626
d6f0bcdb16 Merge pull request #2738 from jumpserver/pr@dev@automation_is_active
perf: automation is active
2023-02-22 12:47:39 +08:00
feng
e560455ef8 perf: automation is active 2023-02-22 12:46:53 +08:00
老广
fe5111a105 Merge pull request #2737 from jumpserver/pr@dev@perf_account_history
perf: 优化账号,去掉 version
2023-02-22 11:47:13 +08:00
ibuler
9924e5a0d9 perf: 优化账号,去掉 version 2023-02-22 11:35:55 +08:00
“huailei000”
3131bfa683 perf: 优化列表字段显示 2023-02-22 11:23:55 +08:00
Eric_Lee
5841095e08 Merge pull request #2735 from jumpserver/pr@dev@fix_applethost
fix: 修复发布机详情账号列表显示问题
2023-02-22 11:10:27 +08:00
Eric
8c64b81a12 fix: 修复发布机详情账号列表显示问题 2023-02-22 11:07:20 +08:00
“huailei000”
846c040cd6 perf: 账号改密详情资产和节点列表不显示更多操作 2023-02-22 11:03:31 +08:00
老广
d316d1bf1f Merge pull request #2729 from jumpserver/pr@dev@perf_template_add_account
perf: 修改 account template add error msg
2023-02-22 10:57:21 +08:00
“huailei000”
d0cd7915b7 perf: 资产详情账号列表点击查看列表显示变化问题 2023-02-21 22:55:40 +08:00
feng626
4cac6970f6 Merge pull request #2716 from jumpserver/pr@dev@fix_account_test
fix: 修复资产账号列表的测试可连接性禁用问题
2023-02-21 22:53:37 +08:00
huailei
f1f9a02816 Merge branch 'dev' into pr@dev@fix_account_test 2023-02-21 22:47:21 +08:00
Eric_Lee
34ad979dd0 Merge pull request #2731 from jumpserver/pr@dev@fix_applet_host
fix: 修复发布机账号查看跳转问题
2023-02-21 22:11:51 +08:00
“huailei000”
5e1971bfb8 perf: 修复账号收集点击页面不能跳转问题 2023-02-21 22:08:07 +08:00
Eric
a085b9b10a fix: 修复发布机账号查看跳转问题 2023-02-21 22:02:55 +08:00
ibuler
7c81c913cb perf: 修改 account template add error msg 2023-02-21 21:49:37 +08:00
Aaron3S
a65436c16b fix: ops 页面翻译问题 2023-02-21 21:27:13 +08:00
Aaron3S
40216397a6 fix: 修复所有审计日志日期选择bug 2023-02-21 21:25:30 +08:00
“huailei000”
7608b23131 perf: 修复创建资产账号密码重复加密问题 2023-02-21 20:43:26 +08:00
Eric
940ff7acfa perf: ticket icon 默认跳转到待我审批 2023-02-21 20:11:41 +08:00
“huailei000”
b2fa253fb4 perf:过滤远程应用搜索条件 2023-02-21 19:28:40 +08:00
feng626
1f5670bc39 Merge pull request #2723 from jumpserver/pr@dev@change_secret
perf: change secret is_active
2023-02-21 17:55:18 +08:00
feng
f6125f0e75 perf: change secret is_active 2023-02-21 17:52:45 +08:00
feng
0929d38d3e perf: web account privileged 2023-02-21 15:56:38 +08:00
feng626
11cba07198 Merge pull request #2719 from jumpserver/pr@dev@push_account_update
perf: push account update
2023-02-21 15:09:17 +08:00
feng
8a36398cb7 perf: push account update 2023-02-21 15:08:28 +08:00
老广
703f33629a Merge pull request #2718 from jumpserver/pr@dev@perf_account_detail
perf: 优化账号详情
2023-02-21 14:58:31 +08:00
ibuler
c716b20887 perf: remove detail 2023-02-21 14:56:23 +08:00
ibuler
41b333212d perf: 优化账号详情 2023-02-21 14:37:15 +08:00
Aaron3S
932cd5fb36 fix: 修改 dashboard rand 区域默认展示7天排行 2023-02-21 14:31:25 +08:00
老广
a3b62efa1c Merge pull request #2713 from jumpserver/pr@dev@fix_createupdateerror
fix: 修改创建更新表单报错显示问题
2023-02-21 14:21:56 +08:00
老广
282e7cce8c Merge pull request #2708 from jumpserver/pr@dev@perf_account_takss
perf: 优化 account tasks
2023-02-21 14:20:50 +08:00
ibuler
59fa67a999 merge: with dev 2023-02-21 14:20:22 +08:00
老广
c297c15139 Merge pull request #2710 from jumpserver/pr@fix@clone_ssl_asset_no_ssl_option
fix: SSL资产克隆无SSL等选项
2023-02-21 14:16:38 +08:00
ibuler
c5434df5e4 perf: account 2023-02-21 14:12:11 +08:00
Eric
5e8197cd88 fix: 修复资产账号列表的测试可连接性禁用问题 2023-02-21 14:02:30 +08:00
ibuler
651cb6c806 perf: 修改账号任务 2023-02-21 13:39:07 +08:00
ibuler
1ea005efaf perf: 修改权限位 2023-02-21 13:27:21 +08:00
ibuler
adbaefece9 perf: 优化账号任务 2023-02-21 13:00:19 +08:00
“huailei000”
1e1533a0c9 perf: 账号详情不显示特殊信息 2023-02-21 11:28:45 +08:00
“huailei000”
93431df62b perf: 网络设备、云服务、web不支持批量更新网域 2023-02-21 10:35:17 +08:00
Bai
76fcef69a4 fix: 修改创建更新表单报错显示问题 2023-02-20 20:11:37 +08:00
feng626
c05437f58c Merge pull request #2712 from jumpserver/pr@dev@applet_host_perm
perf: applet host perm
2023-02-20 19:45:29 +08:00
feng
90ac325cbb perf: applet host perm 2023-02-20 19:44:29 +08:00
“huailei000”
26508ae87b perf: 优化列表默认显示的字段 2023-02-20 19:32:36 +08:00
jiangweidong
385764c3be fix: SSL资产克隆无SSL等选项 2023-02-20 18:34:50 +08:00
ibuler
fea6155306 perf: 优化 account tasks 2023-02-20 17:59:57 +08:00
Aaron3S
174e7cb0e3 fix: 增加作业日志过滤列 2023-02-20 17:23:01 +08:00
Bai
413feb6372 fix: 修复资产info信息展示list数据 2023-02-20 17:22:15 +08:00
“huailei000”
494bb8ddcc perf: 优化资产列表字段显示 2023-02-20 17:21:32 +08:00
“huailei000”
71e73e9302 perf: 优化我的列表显示 2023-02-20 16:16:12 +08:00
Aaron3S
7a5bd01ed5 fix: 删除组织管理v2列 2023-02-20 15:28:32 +08:00
Bai
b6d9a20d8f fix: 修改翻译 2023-02-20 15:25:49 +08:00
Aaron3S
7d53d444bd fix: 删除 v2 的概念 2023-02-20 15:07:17 +08:00
Aaron3S
a8a726216e fix: 在全局组织下禁止更新和执行作业 2023-02-20 15:04:15 +08:00
“huailei000”
b6258dd32c fix: 修复删除组织后切换组织下拉列表还会显示问题 2023-02-20 14:48:53 +08:00
Bai
5a0d0f98d3 fix: 修复 rbac 权限位依赖 2023-02-20 12:18:55 +08:00
老广
b2cf5c3442 Merge pull request #2697 from jumpserver/pr@dev@perf_org_to_lang
perf: 组织名称过长显示优化
2023-02-19 16:18:31 +08:00
ibuler
47fe93cd19 perf: 组织名称过长显示优化 2023-02-19 16:05:14 +08:00
老广
f8b9b9e664 Merge pull request #2696 from jumpserver/pr@dev@perf_table_datepicker
perf: 优化 datepicker 时间
2023-02-19 15:25:16 +08:00
ibuler
2045351ebd perf: 优化 datepicker 时间 2023-02-19 14:26:43 +08:00
“huailei000”
265870eff7 perf: 优化工单账号组件 2023-02-17 20:58:55 +08:00
“huailei000”
63e51e0e45 perf: 替换图标 2023-02-17 20:22:03 +08:00
“huailei000”
858333bc57 perf: 优化审计台提示文案 2023-02-17 19:41:20 +08:00
Eric
965c6d4c92 perf: 移除无用的取消按钮 2023-02-17 19:32:39 +08:00
Bai
e82d444cf3 fix: 修复工单详情 account 显示 2023-02-17 18:47:53 +08:00
ibuler
d144cd6809 perf: 迁移到了系统设置中 2023-02-17 18:38:55 +08:00
“huailei000”
49abdf52c2 perf: 优化树组件图标 2023-02-17 18:18:22 +08:00
jiangweidong
e5c9e339e9 fix: 调整格式 2023-02-17 17:22:59 +08:00
jiangweidong
d4debd20c4 fix: 调整格式 2023-02-17 17:22:59 +08:00
jiangweidong
ddd607e1ca fix: 路由还原 2023-02-17 17:22:59 +08:00
jiangweidong
4755bbd549 fix: 终端管理-终端详情中无法显示activity界面 2023-02-17 17:22:59 +08:00
jiangweidong
5566435964 fix: 解决一些资源的Activity日志无法查看问题 2023-02-17 17:22:26 +08:00
“huailei000”
6e29d1a1a7 perf: 更新部分图标 2023-02-17 17:09:21 +08:00
feng626
4f7f8e8315 Merge pull request #2686 from jumpserver/pr@dev@fix_account_backup_execution_button_perm
fix: 修复执行账号备份按钮权限问题
2023-02-17 16:23:02 +08:00
Aaron3S
9b79f46920 fix: 修复执行账号备份按钮权限问题 2023-02-17 16:18:34 +08:00
feng626
722dd4ad66 Merge pull request #2684 from jumpserver/pr@dev@fix_change_secret_execution_button_perm
fix: 修复改密页面执行按钮权限位
2023-02-17 15:32:38 +08:00
Aaron3S
c8f038aad8 fix: 修复改密页面执行按钮权限位 2023-02-17 15:24:48 +08:00
feng626
59336c3418 Merge pull request #2683 from jumpserver/pr@dev@fix_perms_dep
fix: 修复一些权限依赖问题
2023-02-17 15:24:35 +08:00
老广
5d028394d1 Merge pull request #2682 from jumpserver/revert-2680-revert-2678-pr@dev@perf_svg_color
Revert "Revert "perf:修改svg颜色""
2023-02-17 15:03:56 +08:00
Aaron3S
19212545c1 fix: 修复一些权限依赖问题 2023-02-17 15:03:53 +08:00
huailei
199d4abeb7 Revert "Revert "perf:修改svg颜色"" 2023-02-17 15:03:15 +08:00
老广
cdd8bd0477 Merge pull request #2681 from jumpserver/pr@dev@fix_operatelog_no_detail_err
fix: 点击操作日志详情空白的问题
2023-02-17 14:39:14 +08:00
老广
3b87a0f0f7 Merge pull request #2677 from jumpserver/pr@dev@fix_asset_select_tree_api_url
fix: 修复错误的api url 地址
2023-02-17 14:38:40 +08:00
老广
2ffbad8593 Merge pull request #2680 from jumpserver/revert-2678-pr@dev@perf_svg_color
Revert "perf:修改svg颜色"
2023-02-17 14:38:16 +08:00
jiangweidong
d42caccff8 fix: 点击操作日志详情空白的问题 2023-02-17 14:37:59 +08:00
huailei
8f4f34dc9f Revert "perf:修改svg颜色"
This reverts commit db6d36390e.
2023-02-17 14:37:23 +08:00
feng626
c2dfb09ec8 Merge pull request #2679 from jumpserver/pr@dev@tocket
perf: ticket
2023-02-17 14:34:35 +08:00
feng
89f524b186 perf: ticket 2023-02-17 14:34:13 +08:00
“huailei000”
db6d36390e perf:修改svg颜色 2023-02-17 14:16:54 +08:00
Aaron3S
2695aeb5a9 fix: 修复错误的api url 地址 2023-02-17 13:13:42 +08:00
老广
c385fd2f15 Merge pull request #2676 from jumpserver/pr@dev@perf_theme
perf: 修改 theme
2023-02-17 12:39:56 +08:00
ibuler
3d7ca884da perf: 修改 theme 2023-02-17 12:38:29 +08:00
老广
c4b3f3a58a Merge pull request #2674 from jumpserver/pr@dev@perf_theme
perf: 优化 theme
2023-02-17 10:39:15 +08:00
Aaron3S
2e92cc02ea perf: 优化审计台dashboard 2023-02-16 20:15:31 +08:00
ibuler
0a230dcea1 perf: 优化 theme 2023-02-16 20:15:24 +08:00
feng626
5bc0de8cff Merge pull request #2673 from jumpserver/pr@dev@ticket_step
perf: ticket step
2023-02-16 20:05:31 +08:00
feng
f647472325 perf: ticket step 2023-02-16 20:04:35 +08:00
Aaron3S
24682d70ce fix: 修复创建作业资产选择树问题 2023-02-16 19:58:44 +08:00
feng626
91b1ae1766 Merge pull request #2670 from jumpserver/pr@dev@perm
pr@dev@perm
2023-02-16 19:38:44 +08:00
feng
7671c7ec72 pr@dev@perm 2023-02-16 19:37:13 +08:00
老广
4847564447 Merge pull request #2669 from jumpserver/pr@dev@perf_clean_help_text
perf: 优化提示
2023-02-16 18:46:59 +08:00
“huailei000”
ac462e3a8e perf: 调整云同步实例详情删除之后跳转地址 2023-02-16 18:45:59 +08:00
ibuler
8469df52e2 perf: 优化提示 2023-02-16 18:45:56 +08:00
“huailei000”
9650c32faf perf: 修改审计台仪表盘快捷跳转 2023-02-16 18:28:18 +08:00
“huailei000”
129d8badd0 fix: 修复更新命令存储传参 2023-02-16 18:17:34 +08:00
“huailei000”
02b5df25f0 fix: 修复创建、更新录像存储跳转空白问题 2023-02-16 17:34:28 +08:00
jiangweidong
00fb4ffc85 perf: 修改PostgreSQL数据库参数为必填 2023-02-16 17:31:28 +08:00
“huailei000”
44ca4e7620 perf: 资产账号更新时不能修改用户名 2023-02-16 16:24:33 +08:00
老广
39d213d149 Merge pull request #2660 from jumpserver/pr@dev@perf_list_table_popover
perf: 修改 table popover
2023-02-16 16:06:58 +08:00
ibuler
bea73cd9c8 perf: 格式化 2023-02-16 16:06:38 +08:00
ibuler
8fe24a56ef perf: layout page 2023-02-16 15:56:05 +08:00
老广
723088b122 Merge pull request #2658 from jumpserver/pr@dev@fix_storage
fix: 修改提交命令存储表单hosts处理问题
2023-02-16 15:45:39 +08:00
老广
db7d64b9a1 Merge pull request #2661 from jumpserver/pr@dev@fix_endpoint_rule_error
fix: 修复创建端点规则报错问题
2023-02-16 15:44:44 +08:00
“huailei000”
45cfece1c0 fix: 修复创建端点规则报错问题 2023-02-16 15:31:20 +08:00
ibuler
9b5e964c68 perf: 修改 table popover 2023-02-16 15:16:11 +08:00
“huailei000”
1b0c89a704 perf: 调整审计台仪表盘字段 2023-02-16 14:58:35 +08:00
Bai
2b78e0bae5 fix: 修改提交命令存储表单hosts处理问题 2023-02-16 14:56:19 +08:00
“huailei000”
c661177de8 perf: 优化云同步列表显示 2023-02-16 14:50:23 +08:00
老广
02bf964622 Merge pull request #2656 from jumpserver/pr@dev@fix_playbook_upload_failer_error
fix: 修复 playbook 上传失败不显示消息的问题
2023-02-16 14:46:38 +08:00
老广
86baf16f2d Merge pull request #2655 from jumpserver/pr@dev@perf_account
perf: 没有 account secret 则不修改
2023-02-16 14:29:26 +08:00
ibuler
548ce2f981 perf: 没有 account secret 则不修改 2023-02-16 14:18:44 +08:00
Aaron3S
f473d47028 fix: 修复 playbook 上传失败不显示消息的问题 2023-02-16 14:11:46 +08:00
ibuler
6e76bcb0f4 perf: 没有 account secret 则不修改 2023-02-16 13:56:00 +08:00
“huailei000”
51101eba54 perf: 云同步详情列表查询条件不设置到url中 2023-02-16 11:14:21 +08:00
feng626
3dd4ccba17 Merge pull request #2654 from jumpserver/pr@dev@replay_storage
perf: replay storage update
2023-02-16 11:13:27 +08:00
feng
c3be0b01ca perf: replay storage update 2023-02-16 11:12:47 +08:00
“huailei000”
bf9a2179ae fix: 修复创建录像存储报错问题 2023-02-16 10:44:47 +08:00
老广
5e0cfdbfcd Merge pull request #2641 from jumpserver/pr@dev@perf_activities_log
perf: 优化Activity日志[操作日志、登录日志]显示
2023-02-15 20:44:06 +08:00
Bai
bfe9747658 fix: 修改翻译 2023-02-15 20:16:27 +08:00
“huailei000”
39ef4b08f8 fix: 修复创建资产重复加密问题 2023-02-15 20:09:27 +08:00
Aaron3S
f039d13bd2 fix: 修复若干rbac问题, 修复任务名字显示中心不友好问题 2023-02-15 19:20:16 +08:00
“huailei000”
1f95761d38 perf: 列表记录默认显示条数 2023-02-15 18:45:40 +08:00
Bai
c3e865b407 fix: 修改翻译 2023-02-15 16:53:53 +08:00
Bai
d4fe97860a fix: 修改翻译 2023-02-15 16:31:16 +08:00
Bai
041801a319 fix: 修改授权规则列表 accounts popover 显示优化 2023-02-15 16:02:44 +08:00
Bai
1e474b25f3 fix: 删除不用的授权搜索配置 2023-02-15 15:42:14 +08:00
Bai
222e230cc2 fix: 修复批量更新云资产时domain字段禁用 2023-02-15 15:36:04 +08:00
feng626
53f48e7483 Merge pull request #2643 from jumpserver/pr@dev@replay_storage
perf: replay storage
2023-02-15 15:14:02 +08:00
feng
4470dc96b7 perf: replay storage 2023-02-15 15:11:20 +08:00
jiangweidong
e998f92045 perf: 优化Activity日志[操作日志、登录日志]显示 2023-02-15 10:51:06 +08:00
feng626
62b88c2a0b Merge pull request #2640 from jumpserver/pr@dev@ticket
perf: ticket perm
2023-02-14 22:57:12 +08:00
feng
f865af018f perf: ticket perm 2023-02-14 22:56:11 +08:00
Aaron3S
84c5a9a019 feat: 增加作业中心开关 2023-02-14 19:54:46 +08:00
Bai
43fae83603 fix: 修复 rbac 相关权限位问题 2023-02-14 19:54:23 +08:00
“huailei000”
065d6f7ba8 perf: 全局组织下角色详情不能添加成员 2023-02-14 19:49:43 +08:00
Bai
2e6bb9ab66 fix: 修复 rbac 相关权限位问题 2023-02-14 19:04:43 +08:00
“huailei000”
d2226c0b00 perf: 优化工单流程详情显示 2023-02-14 18:59:00 +08:00
“huailei000”
b84bcfcfaa fix:修复账号执行列表跳转详情报错问题 2023-02-14 18:42:17 +08:00
Bai
c1ff1575a4 fix: 修复账号模版密钥查看权限的联动 2023-02-14 18:30:37 +08:00
Bai
a716cb1357 fix: 修复账号、账号密钥查看权限的联动 2023-02-14 18:25:51 +08:00
feng626
a02697d3aa Merge pull request #2631 from jumpserver/pr@dev@re
perf: add re
2023-02-14 18:13:21 +08:00
feng
a50b658f28 perf: add re 2023-02-14 18:12:27 +08:00
“huailei000”
179f74dbd0 fix: 修复创建资产授权时资产、节点没有自动选择问题 2023-02-14 18:07:37 +08:00
Bai
35f1f1f92c fix: 修改用户个人信息页面 connection-token,temp-token 过期权限位 2023-02-14 17:53:07 +08:00
feng626
f81128227c Merge pull request #2628 from jumpserver/pr@dev@button_display
perf: button display
2023-02-14 17:28:42 +08:00
feng
0a7caf71c7 perf: button display 2023-02-14 17:27:35 +08:00
“huailei000”
2d34c6962b perf: 账号密码加密 2023-02-14 17:27:29 +08:00
Bai
8797e8e869 fix: 删除一些不用的方法 2023-02-14 17:17:33 +08:00
Aaron3S
f416fdc875 fix: 修复任务详情白屏的问题 2023-02-14 16:42:11 +08:00
feng626
90e8c21182 Merge pull request #2625 from jumpserver/pr@dev@ldap_org
perf: ldap org
2023-02-14 16:41:31 +08:00
feng
a10e922a7c perf: ldap org 2023-02-14 16:39:55 +08:00
“huailei000”
49b1a3a29b fix: 修复工单流程设置2级审批不能设置问题 2023-02-14 16:11:22 +08:00
老广
f4c16a5377 Merge pull request #2621 from jumpserver/pr@dev@perf_redis_platform
perf: 优化 redis platform,并且增加 Platform protocols
2023-02-14 16:03:36 +08:00
ibuler
675c6586d2 Merge branch 'dev' into pr@dev@perf_redis_platform 2023-02-14 15:53:35 +08:00
ibuler
9570fc1cb6 perf: 优化 sub form disabled 2023-02-14 14:59:25 +08:00
Bai
cce5caec06 fix: 修复创建资产时删除一个账号会全部删除的问题 2023-02-14 14:57:56 +08:00
Bai
64f521ba00 fix: 修复创建资产时删除一个账号会全部删除的问题 2023-02-14 14:57:56 +08:00
ibuler
834739a878 perf: 优化 redis platform,并且增加 Platform protocols 2023-02-14 14:32:26 +08:00
feng626
8b29be3f72 Merge pull request #2620 from jumpserver/pr@dev@account_name_required
perf: account name required
2023-02-14 11:36:56 +08:00
feng
4d4e4299ab perf: account name required 2023-02-14 11:35:00 +08:00
“huailei000”
5d8e623e1e perf: 优化历史会话列表显示 2023-02-14 10:45:52 +08:00
Bai
f8c74c21b9 fix: 修复rbac授权节点同时授权资产、平台查看权限 2023-02-14 10:45:20 +08:00
“huailei000”
1b6a2938f4 fix: 修复资产详情导出账号列表不准确问题 2023-02-13 19:12:48 +08:00
“huailei000”
5bac6e3936 perf: 优化资产树菜单样式 2023-02-13 16:28:41 +08:00
feng626
fd18581841 Merge pull request #2615 from jumpserver/pr@dev@translate
perf: translate
2023-02-13 16:08:10 +08:00
feng
e380a9d0b0 perf: translate 2023-02-13 16:07:08 +08:00
Aaron3S
8e67f5544d fix: 修复 playbook 没有刷新 form 的问题 2023-02-13 15:19:06 +08:00
“huailei000”
b2323784ae perf: 调整我的资产列表显示 2023-02-13 14:50:59 +08:00
Aaron3S
48387ed576 fix: 修复快捷命令账号切换的问题 2023-02-13 14:32:16 +08:00
feng626
d4b101d4b0 Merge pull request #2611 from jumpserver/pr@dev@feishu_bind
perf: wecom feishu dingtalk
2023-02-13 11:43:27 +08:00
feng
063c19996b perf: wecom feishu dingtalk 2023-02-13 11:41:55 +08:00
老广
bf55efeb56 Merge pull request #2547 from jumpserver/pr@dev@perf_activity
perf: 增加Activity日志中此资源的任务执行及详情查看
2023-02-13 11:18:26 +08:00
jiangweidong
b2fe96600f perf: 解决冲突 2023-02-13 11:11:49 +08:00
“huailei000”
13a1356093 perf: 优化模版详情 2023-02-13 10:32:17 +08:00
“huailei000”
51c6f4321c perf: 工单流程设置-审批设置显示默认值 2023-02-10 19:53:03 +08:00
“huailei000”
49c8b24f6c perf: 操作日志弹窗不显示确认、取消 2023-02-10 19:52:40 +08:00
“huailei000”
f86af9c8b8 perf: 优化会话记录详情 2023-02-10 19:39:08 +08:00
Bai
b709333b1b fix: 修复自动详情页面默认去除 write_only 字段 2023-02-10 19:30:14 +08:00
feng626
5cf26dbd86 Merge pull request #2605 from jumpserver/pr@dev@ticket_nodes
perf: ticket node
2023-02-10 19:00:02 +08:00
feng
0ba28e14c8 perf: ticket node 2023-02-10 18:58:50 +08:00
“huailei000”
2457a88778 fix: 修复工单审批时资产显示不正确问题 2023-02-10 18:38:37 +08:00
feng
48aac68248 perf: perms actions 2023-02-10 18:18:48 +08:00
Bai
c39b5a5d79 fix: 修复云同步任务创建 protocols 问题 2023-02-10 18:17:11 +08:00
feng626
de7005a82d Merge pull request #2602 from jumpserver/pr@dev@ticket_type_filter
perf: ticket type filter
2023-02-10 18:02:05 +08:00
feng
70f76fd592 perf: ticket type filter 2023-02-10 18:01:09 +08:00
“huailei000”
7c5b9e128c fix: 修复工单审批提示错误问题 2023-02-10 17:12:09 +08:00
ibuler
de0e824b30 perf: auth backends 2023-02-10 16:47:31 +08:00
ibuler
870c84d318 perf: 修改 backends 2023-02-10 16:47:31 +08:00
Bai
016846b5b4 fix: 修改用户登录复核详情页面字段显示 2023-02-10 16:46:00 +08:00
Bai
4af8304798 fix: 修改rbac权限依赖关系 2023-02-10 16:41:06 +08:00
Bai
1399f1d197 fix: 修复创建云账号时必填字段的校验规则 RequiredChange 2023-02-10 16:40:41 +08:00
feng626
e8487b4786 Merge pull request #2598 from jumpserver/pr@dev@session_is_finished
perf: session is_finished
2023-02-10 16:33:29 +08:00
feng
a70b53b6e6 perf: session is_finished 2023-02-10 16:32:33 +08:00
feng626
00fe260108 Merge pull request #2596 from jumpserver/pr@dev@ticket
perf: 工单受理人 显示问题
2023-02-10 16:17:45 +08:00
feng626
03a88069db Merge branch 'dev' into pr@dev@ticket 2023-02-10 16:17:28 +08:00
feng
6322b27c94 perf: 工单受理人 显示问题 2023-02-10 16:15:54 +08:00
Aaron3S
ab85118e68 fix: 修复一些必填项的问题 2023-02-10 16:15:39 +08:00
Aaron3S
bacac276ff fix : 修复列显示错误的问题 2023-02-10 16:15:39 +08:00
Aaron3S
d0fa87009d fix: 去掉取消按钮 2023-02-10 16:15:39 +08:00
Aaron3S
17d79f4de9 fix: 修复重命名 playbook 文件的 bug 2023-02-10 16:15:39 +08:00
“huailei000”
7e5fcfe8d5 fix: 修复工单什么指定账号不显示输入框 2023-02-10 16:05:18 +08:00
feng626
6a57f5bfdf Merge pull request #2593 from jumpserver/pr@dev@cloud_asset
perf: cloud url 与 协议 同步
2023-02-10 15:47:20 +08:00
feng
0e576754bb perf: cloud url 与 协议 同步 2023-02-10 15:46:17 +08:00
“huailei000”
b54952855b perf: 命令记录详情列表不显示操作 2023-02-10 14:36:34 +08:00
Bai
15e650ef28 fix: 修复没有 push_now 权限的用户可以在创建资产、创建账号中开启推送 2023-02-10 11:12:35 +08:00
“huailei000”
d6de7cce24 perf: 优化控制台仪表盘显示 2023-02-10 10:34:06 +08:00
“huailei000”
8ecd2cfc6a perf: 优化仪表盘资产类型占比 2023-02-09 19:59:18 +08:00
feng626
4409c3e1d3 Merge pull request #2587 from jumpserver/pr@dev@cloud_sync
perf: cloud sync
2023-02-09 19:29:45 +08:00
feng
ac747bcf05 perf: cloud sync 2023-02-09 19:28:55 +08:00
“huailei000”
6def65bb0d perf: 优化关于显示 2023-02-09 18:20:44 +08:00
feng626
92677c4ad2 Merge pull request #2585 from jumpserver/pr@dev@ticket
perf: ticket bug
2023-02-09 18:07:28 +08:00
feng
847d3a331b perf: ticket bug 2023-02-09 18:05:43 +08:00
“huailei000”
51d30f3275 perf: 作业管理创建作业资产是必填项 2023-02-09 17:09:07 +08:00
“huailei000”
0f0d959118 fix: 修复资产时创建账号模版报错问题 2023-02-09 16:49:08 +08:00
“huailei000”
3582ca7c17 perf: 优化资产克隆时模版添加账号 2023-02-09 16:43:51 +08:00
feng626
6fd267a80a Merge pull request #2581 from jumpserver/pr@dev@profile_wecom_id_dingtalk_id_feishu_id
fix: 个人信息 字段重新调整
2023-02-09 15:38:27 +08:00
feng
932a5e2d47 fix: 个人信息 字段重新调整 2023-02-09 15:37:07 +08:00
“huailei000”
1d91d4d065 perf: 优化命令记录风险等级的显示 2023-02-09 14:35:14 +08:00
Bai
fa42ea7cdf fix: 修复翻译问题 2023-02-09 14:32:56 +08:00
“huailei000”
9e9dea6e57 perf: 账号模版查看不显示密码记录 2023-02-09 14:21:12 +08:00
Bai
a18520276a fix: 修复clone资产时 platform 没有获取到的问题 2023-02-09 12:10:18 +08:00
“huailei000”
667f163853 perf: 资产账号更新名称时用户名不自动同步更新 2023-02-09 11:47:03 +08:00
“huailei000”
4c49d0b32d fix: 修复创建资产时添加账号是否立即推送判断条件 2023-02-08 19:59:07 +08:00
Bai
b7cd39d373 fix: 修复账号详情su-from-account url 2023-02-08 19:05:58 +08:00
“huailei000”
4b06a29f10 fix: 修复资产详情创建、更新账号时error提示不准确问题 2023-02-08 18:12:36 +08:00
“huailei000”
ae4962eb45 perf: 优化资产详情创建账号后密文类型不显示问题 2023-02-08 17:26:33 +08:00
“huailei000”
19b7a36aa1 fix: 修复创建平台成功后点击链接跳转报错问题 2023-02-08 16:55:37 +08:00
“huailei000”
1040cca267 perf: 优化资产选择弹窗样式 2023-02-08 16:49:54 +08:00
“huailei000”
58e8145f0e feat: 添加版本信息弹窗展示 2023-02-08 16:27:15 +08:00
Bai
5b3dc2bc48 fix: 修复 connection token 页面信息字段 actions 2023-02-08 15:32:23 +08:00
“huailei000”
8d3a3587d1 perf: 优化ip正则 2023-02-08 14:00:27 +08:00
Bai
b0731d4fbd fix: 修改interface登录标题和logo文案 2023-02-08 13:26:32 +08:00
“huailei000”
4b57c78c8e fix: 修复更新云同步-实例任务参数格式 2023-02-08 11:41:03 +08:00
“huailei000”
241eef173f fix: 创建网域时对选择的资产类型限制 2023-02-08 11:13:25 +08:00
“huailei000”
b0b2954311 fix: 修复云同步创建实例任务没有协议问题 2023-02-07 19:57:08 +08:00
feng626
83c21e2304 Merge pull request #2560 from jumpserver/pr@dev@gather_account
perf: gather account
2023-02-07 19:45:30 +08:00
feng
30369de1f5 perf: gather account 2023-02-07 19:42:31 +08:00
Bai
1f5a8f7694 fix: 修复同步任务实例列表动作字段 2023-02-07 19:40:16 +08:00
Bai
6e060c9038 fix: 修复同步任务历史列表动作字段 2023-02-07 19:31:15 +08:00
“huailei000”
70da1a3a5b fix: 修复账号列表第一次验证mfa后导出弹窗不能关闭问题 2023-02-07 19:30:38 +08:00
Bai
9d7244131f fix: 修复点击账号列表导出两次时,第二次显示导出弹窗的问题(第一次提示需要MFA认证) 2023-02-07 17:58:07 +08:00
“huailei000”
9f0923c955 perf: 资产授权列表显示操作 2023-02-07 16:57:36 +08:00
“huailei000”
c383c2cc54 fix: 修复资产创建时模版添加账号,账号重复问题 2023-02-07 16:42:19 +08:00
“huailei000”
586f8c2c18 fix:修复资产账号无法导入问题 2023-02-07 15:00:17 +08:00
Bai
40554eb93e fix: 修复只授权创建网关权限时,创建网关提示没有权限的问题;add/change_gateway dep view_node view_platform 2023-02-07 14:57:40 +08:00
Bai
963fc97f61 fix: 账号详情增加 激活 按钮 2023-02-07 14:34:08 +08:00
Bai
049bc928ce fix: 修改终端列表批量更新的问题 2023-02-07 14:27:17 +08:00
Aaron3S
288afeeb1f feat: 补充翻译 2023-02-07 11:51:05 +08:00
Aaron3S
6661583a0f 增加任务历史再次执行的功能 2023-02-07 11:51:05 +08:00
“huailei000”
8f5df65f0e perf: 优化tree组件url参数 2023-02-07 11:33:06 +08:00
“huailei000”
5112af8ba1 perf: 批量更新资产添加提示 2023-02-07 11:31:17 +08:00
jiangweidong
0f39a1c1fa perf: 增加登录日志详情 2023-02-07 09:50:02 +08:00
jiangweidong
07f23e4d3b perf: 解决冲突 2023-02-07 09:04:27 +08:00
jiangweidong
6f7e1dbf18 perf: 优化Activity日志 2023-02-07 09:00:17 +08:00
“huailei000”
960f5a6c66 fix: 修复角色详情删除提示不准确问题 2023-02-06 19:42:01 +08:00
“huailei000”
0cf1d64e32 fix: 账号详情操作disabled 2023-02-06 19:09:19 +08:00
“huailei000”
fda8c36867 perf: 账号列表更新类型资产(如Web、网络设备、云服务、数据库)账号密码表单去掉切换至 2023-02-06 19:04:25 +08:00
老广
4bf9d9081e Merge pull request #2542 from jumpserver/pr@dev@perf_icon
perf: 优化 icon
2023-02-06 17:53:12 +08:00
ibuler
54a38cd645 perf: 优化 icon 2023-02-06 17:49:15 +08:00
“huailei000”
66c4d3da91 fix: 修复弹窗显示时导航栏有空白问题 2023-02-06 17:47:43 +08:00
“huailei000”
46e79e5a53 fix: 资产树添加添加、移动资产弹窗关闭后资产树无法刷新问题 2023-02-06 17:42:37 +08:00
老广
9436ee048d Merge pull request #2539 from jumpserver/pr@dev@perf_icon
perf: 优化图标
2023-02-06 17:20:14 +08:00
老广
2da9fcdedd Merge branch 'dev' into pr@dev@perf_icon 2023-02-06 17:19:47 +08:00
ibuler
0b34504abf perf: 优化图标 2023-02-06 17:13:33 +08:00
“huailei000”
610f056dfd perf: ztree config 2023-02-06 17:06:00 +08:00
“huailei000”
49f1ca2329 fix: 修复资产列表-添加资产到节点后资产树无法刷新问题 2023-02-06 16:53:43 +08:00
dependabot[bot]
494138719f build(deps): bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 16:42:21 +08:00
fit2bot
291b15956b perf: 修改 tree menu (#2536)
* perf: 修改 ztree

* perf: 修改 tree menu

---------

Co-authored-by: ibuler <ibuler@qq.com>
2023-02-06 16:41:42 +08:00
ibuler
fa72cd0f7b perf: 修改 tree menu 2023-02-06 16:35:18 +08:00
Bai
5cd45f3493 fix: 修改翻译 LAN 局域网 2023-02-06 16:30:34 +08:00
feng626
3befab9964 Merge pull request #2534 from jumpserver/pr@dev@account_spac_info
perf: account exclude spec info
2023-02-06 16:12:14 +08:00
feng
ff219c0675 perf: account exclude spec info 2023-02-06 16:10:32 +08:00
fit2bot
2f79fa2d50 perf: 优化 i18n-util 工具, apply 后删除 diff 文件; (#2533)
* perf: 添加 npm run diff-i18n | npm run apply-i18n 脚本执行

* perf: 优化 i18n-util 工具, apply 后删除 diff 文件;

---------

Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2023-02-06 16:04:29 +08:00
ibuler
ff182a23e8 perf: 修改 ztree 2023-02-06 15:51:41 +08:00
Bai
71ac63b0c5 perf: 添加 npm run diff-i18n | npm run apply-i18n 脚本执行 2023-02-06 15:50:15 +08:00
“huailei000”
8675da453f perf: 优化table组件默认的翻译 2023-02-06 15:37:51 +08:00
feng626
1c2a8690fc Merge pull request #2529 from jumpserver/pr@dev@yarn_lock
perf: yarn.lock
2023-02-06 15:37:20 +08:00
feng
afe21f9930 perf: yarn.lock 2023-02-06 15:34:52 +08:00
Bai
311b15cd1c perf: 修改翻译信息 2023-02-06 15:19:43 +08:00
Bai
bbe2346bd0 perf: 修改翻译信息 2023-02-06 15:19:43 +08:00
fit2bot
2e7df28b9e perf: 增加i18n翻译 (#2524)
Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2023-02-06 15:11:44 +08:00
feng626
1401875bca Merge pull request #2527 from jumpserver/pr@dev@account_isActive
perf: account is active
2023-02-06 15:09:54 +08:00
Bai
de176466df perf: 修改翻译信息 2023-02-06 15:09:18 +08:00
Bai
6ce2a475a9 perf: 完善 ja.json 翻译文件 2023-02-06 15:09:18 +08:00
Bai
ac998a6082 perf: 完善 en.json 翻译文件 2023-02-06 15:09:18 +08:00
Bai
a6467ee773 perf: 完善 en.json 翻译文件 2023-02-06 15:09:18 +08:00
Bai
77fc2dee89 perf: 完善 en.json 翻译文件 2023-02-06 15:09:18 +08:00
Bai
ef82831e99 perf: 优化 (i18n-util.py) 工具,添加脚本说明信息 2023-02-06 15:09:18 +08:00
Bai
7a4ec597dd perf: 优化 (i18n-util.py) 工具,添加脚本说明信息 2023-02-06 15:09:18 +08:00
Bai
05c2425bc6 feat: 添加 i18n 自动 diff 和 update 工具 (i18n-util.py) 2023-02-06 15:09:18 +08:00
feng
e7619d01a7 perf: account is active 2023-02-06 15:09:11 +08:00
“huailei000”
be6e1a3449 fix: 修复远程应用-账号列表跳转报错问题 2023-02-06 14:39:32 +08:00
feng626
4a003cf617 Merge pull request #2525 from jumpserver/pr@dev@asset_automation_filter
perf: asset automation filter
2023-02-06 13:36:43 +08:00
feng
5bcb6eafb1 perf: asset automation filter 2023-02-06 13:35:05 +08:00
“huailei000”
5c0d0cf598 perf: 优化上传远程应用弹窗清空列表 2023-02-06 11:13:56 +08:00
“huailei000”
46e1fd4d0b perf: 修改工单图标 2023-02-06 10:33:14 +08:00
“huailei000”
295198bad0 fix: 远程应用账号列表资产不能跳转 2023-02-03 19:04:21 +08:00
ibuler
92e5475afb perf: 优化显示 actions 的方法 2023-02-03 18:40:38 +08:00
feng626
026f78f686 Merge pull request #2518 from jumpserver/pr@dev@host_info
perf: 主机硬件信息
2023-02-03 18:23:54 +08:00
feng
42b89944df perf: 主机硬件信息 2023-02-03 18:18:22 +08:00
老广
7a877b0d9b Merge pull request #2516 from jumpserver/pr@dev@perf_protocols_and_conn
pref: 优化一波 lina
2023-02-03 16:12:50 +08:00
ibuler
e5189ed623 merge: with dev 2023-02-03 16:11:34 +08:00
“huailei000”
a4f59d6096 perf: 导入列表每行限制最大高度 2023-02-03 15:32:03 +08:00
ibuler
2470f8cba7 pref: 优化一波 lina 2023-02-03 15:12:56 +08:00
fit2bot
9cb97c68ed perf: 优化账号策略样式 (#2505)
Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
2023-02-03 15:08:54 +08:00
Bai
7f8dd45c21 fix: 修复资产详情-账号列表-模版账号列表跳转问题 2023-02-03 15:07:33 +08:00
“huailei000”
39fa5bb997 fix: 修复批量更新资产网域报错问题 2023-02-03 14:56:59 +08:00
“huailei000”
0d69a3ee9a perf: 资产详情授权用户-查看授权列表筛选条件添加不保存到url中 2023-02-03 14:35:52 +08:00
ibuler
f9ea0cd1a1 perf: 优化任务菜单 2023-02-03 13:28:45 +08:00
“huailei000”
ad51b03296 fix: 修复权限树不显示问题 2023-02-03 11:37:46 +08:00
“huailei000”
cb6139c736 fix: 修复角色详情授权用户不能删除问题 2023-02-03 11:10:40 +08:00
“huailei000”
4bae678f69 perf: 数据库类型切换账号disabled为false 2023-02-03 10:38:50 +08:00
“huailei000”
e8ae9e2fe5 perf: 网络设备详情添加资产不显示切换自 2023-02-03 10:18:33 +08:00
feng626
d3f4c62550 Merge pull request #2507 from jumpserver/pr@dev@risk_level
perf: command log risk_level
2023-02-02 23:03:52 +08:00
feng
06e7e4482c perf: command log risk_level 2023-02-02 23:02:39 +08:00
Aaron3S
3099889cff perf: 添加选择账号input类型的label 2023-02-02 20:13:07 +08:00
Aaron3S
e842246202 perf: 优化账号策略样式 2023-02-02 19:58:28 +08:00
“huailei000”
406d159852 fix: 修复资产详情添加账号时先更新账号后无法继续添加新账号问题 2023-02-02 19:53:06 +08:00
feng626
e3ad602add Merge pull request #2502 from jumpserver/pr@dev@task_perm
perf: task perm
2023-02-02 19:50:51 +08:00
feng
8019d4457b perf: task perm 2023-02-02 19:49:53 +08:00
Bai
7e4d2ac1d0 fix: 修复资产详情-账号列表-模版账号列表跳转问题 2023-02-02 18:56:10 +08:00
Bai
1401b59b13 fix: 修复系统设置认证设置中 attr_map 字段保存问题 2023-02-02 18:06:03 +08:00
Bai
efdfd0af67 fix: 修复系统设置认证设置中 attr_map 字段保存问题 2023-02-02 18:06:03 +08:00
feng626
3e1af7ef57 Merge pull request #2499 from jumpserver/pr@dev@not_show_builtin_tree
perf: 授权不展示类型树
2023-02-02 17:44:40 +08:00
feng
f6724b2d8c perf: 授权不展示类型树 2023-02-02 17:40:03 +08:00
“huailei000”
ea611a518d fix: 修复批量更新资产标签可以自定义输入 2023-02-02 17:14:01 +08:00
老广
6b550a2cfa Merge pull request #2497 from jumpserver/pr@dev@perf_table_select
pref: 优化表单选择,搜索后,已选择的会清空
2023-02-02 16:40:01 +08:00
ibuler
fe7997b7b1 pref: 去掉 Debug msg 2023-02-02 16:23:43 +08:00
ibuler
3ea28ee963 pref: 优化表单选择,搜索后,已选择的会清空 2023-02-02 16:22:38 +08:00
“huailei000”
f18a7fe6fa perf: 资产选择组件去掉操作 2023-02-02 16:08:12 +08:00
“huailei000”
cece17cbe6 fix:修复资产授权不能导入问题 2023-02-02 15:54:25 +08:00
老广
d808aca25e Merge pull request #2494 from jumpserver/pr@dev@perf_perms_accounts
pref: 优化 perms 账号输入,增加 help text 等
2023-02-02 15:43:29 +08:00
ibuler
eb90e036ca pref: 优化 perms 账号输入,增加 help text 等 2023-02-02 15:41:33 +08:00
Eric
559fc8b837 perf: 新增发布机的部署设置 2023-02-02 15:37:38 +08:00
“huailei000”
059aa62ed8 perf: 创建账号时创建模版不显示保存并继续按钮 2023-02-02 15:36:19 +08:00
Aaron3S
6e6dfc6912 fix: 修复发布日期不显示的问题 2023-02-02 15:32:08 +08:00
Aaron3S
6200512cae perf: 优化冲突的变量名 2023-02-02 15:32:08 +08:00
Aaron3S
171ee84c1b perf: 优化playbook 翻译文本 2023-02-02 15:32:08 +08:00
“huailei000”
5a27662f47 fix: 资产授权批量更新添加账号字段 2023-02-02 15:23:41 +08:00
Bai
a569ffa003 fix: 所有资产列表页面不支持文件导入, 解决导入其他类型的资产时对象不存在的问题(因为后端没有保存到 Database,Host 表中) 2023-02-02 15:20:55 +08:00
“huailei000”
1ea52433d5 fix: 修复资产授权添加用户、资产操作不能点击问题 2023-02-02 15:02:32 +08:00
“huailei000”
a9f65ddc81 perf: 添加翻译 2023-02-02 11:21:55 +08:00
“huailei000”
222c76bdae fix: 修复创建资产时有报错信息页面没有提示问题 2023-02-02 10:52:32 +08:00
“huailei000”
7d46392174 fix: 修复资产详情查看账号密码报错问题 2023-02-02 10:40:07 +08:00
老广
13089e80f8 Merge pull request #2482 from jumpserver/pr@dev@perf_account_create_error
perf: 修改 acounts 创建提示
2023-02-01 19:40:16 +08:00
ibuler
a484fc4e2a perf:修改冲突 2023-02-01 19:37:19 +08:00
“huailei000”
8f9c186343 perf: 资产详情-账号列表导入增加创建 2023-02-01 19:16:23 +08:00
ibuler
c9065c88f3 perf: 修改 acounts 创建提示 2023-02-01 18:55:08 +08:00
“huailei000”
52e34c5e75 perf: 远程应用详情显示兼容 2023-02-01 18:50:43 +08:00
“huailei000”
a4acc55994 perf: 优化资产详情里账号弹窗标题 2023-02-01 17:21:42 +08:00
Bai
2c2fac2ac1 fix: 主机详情显示资产硬件信息 2023-02-01 17:05:59 +08:00
老广
2ded71fa90 Merge pull request #2475 from jumpserver/pr@dev@perf_delete_playbook_detail_field
perf: 隐藏保留字段
2023-02-01 16:58:25 +08:00
“huailei000”
9a5700b48b fix: 修复应用开发机详情点击更新跳转不准确问题 2023-02-01 16:56:30 +08:00
老广
0bc3a9f0e7 Merge pull request #2477 from jumpserver/pr@dev@perf_user_create
perf: 优化 site msg
2023-02-01 16:51:00 +08:00
ibuler
2ff292b55f perf: 修改 site msg icon 颜色 2023-02-01 16:49:29 +08:00
ibuler
1f8ef33c5c perf: 优化 site msg 2023-02-01 16:36:35 +08:00
“huailei000”
b37ef2d144 perf: 平台类型为网络设备时切换账号不可点击 2023-02-01 16:34:11 +08:00
Aaron3S
b045fb1c8a perf: 隐藏保留字段 2023-02-01 16:23:18 +08:00
Bai
9b3c75f0a6 fix: 修改认证设置中 json 字段的校验问题 2023-02-01 16:21:24 +08:00
Aaron3S
3e171e20c3 fix: 修改 terminal 颜色,修复文字被背景色覆盖的问题
feat: 增加检测命令长度

Nan

feat: 增加playbook ide

playbook ide

fix: 修复创建 playbook 后页面不刷新
2023-02-01 16:01:01 +08:00
feng626
a6200e07f3 Merge pull request #2473 from jumpserver/pr@dev@user_group
perf: user group
2023-02-01 15:28:07 +08:00
feng
a4ec078c17 perf: user group 2023-02-01 15:26:25 +08:00
“huailei000”
ab5f6abd9e perf: 仪表盘切换日期按钮添加阴影效果 2023-02-01 14:48:41 +08:00
ibuler
b3d41b5fc2 perf: 优化用户创建 2023-02-01 14:30:21 +08:00
“huailei000”
ad870fe837 perf: 克隆资产时克隆账号,template为false 2023-02-01 14:30:09 +08:00
“huailei000”
88c4d9e56f perf:创建资产-添加模版账号调整参数 2023-02-01 13:02:21 +08:00
老广
b4414bcaf2 Merge pull request #2469 from jumpserver/pr@dev@perf_audit
perf: 优化 operate log
2023-02-01 12:13:59 +08:00
ibuler
3212d90436 perf: 优化 operate log 2023-02-01 12:12:26 +08:00
“huailei000”
117b237bda fix: 修复资产无法批量从节点移除 2023-02-01 11:44:48 +08:00
Bai
0616b0bc7c perf: 修改导入文件敏感字段进行加密 2023-02-01 11:18:26 +08:00
“huailei000”
4e04675dfe fix: 修复新建用户第一次登录切换路由跳转地址不正确问题 2023-01-31 19:57:37 +08:00
老广
6a5cf5f35d Merge pull request #2461 from jumpserver/pr@dev@perf_assets_select_dialog
perf: 优化 asset detail spec info 和 统一 asset select dialog
2023-01-31 19:41:16 +08:00
ibuler
d0f9b272f1 merge: with dev 2023-01-31 19:40:38 +08:00
ibuler
2e7ffb217e perf: 修改一些翻译 2023-01-31 19:38:27 +08:00
Jiangjie.Bai
31a401b55d Merge pull request #2463 from jumpserver/dev
v3.0.0-rc4
2023-01-31 18:55:34 +08:00
jiangweidong
c16be0a85c fix: 使用type值 2023-01-31 18:30:33 +08:00
jiangweidong
15cf13d4de fix: 使用type 2023-01-31 18:30:33 +08:00
jiangweidong
6257b7fdc1 fix: mongodb无指定数据库时,一些自动化任务会失败 2023-01-31 18:30:33 +08:00
jiangweidong
3b17b44de5 fix: 使用type 2023-01-31 18:30:01 +08:00
jiangweidong
7a724e76b7 fix: 自定义平台(Redis/MongoDB)无ssl选项 2023-01-31 18:30:01 +08:00
“huailei000”
8b3399351c perf: 数据库类型的资产,添加账号时不显示切换自 2023-01-31 18:29:01 +08:00
ibuler
3d9b034ab8 perf: 优化 asset detail spec info 和 统一 asset select dialog 2023-01-31 17:41:33 +08:00
“huailei000”
bd1fb83325 perf: 资产列表批量激活、禁用后刷新列表 2023-01-31 17:32:46 +08:00
“huailei000”
b20386cd18 perf: 菜单临时密码添加图标 2023-01-31 17:03:17 +08:00
Aaron3S
c4512dc3a9 fix: 隐藏 task 列表中行内的 action 按钮 2023-01-31 16:50:03 +08:00
“huailei000”
7064a48744 perf: 优化快捷命令页-上传下载图标位置 2023-01-31 15:55:50 +08:00
“huailei000”
4e1ade34b8 perf: 优化资产详情-账号列表布局 2023-01-31 15:40:10 +08:00
“huailei000”
4a014a338d perf: 仪表盘标题组件不显示提示 2023-01-31 15:39:45 +08:00
Bai
523c31d3ad perf: 修改终端列表不能根据负载状态进行排序 2023-01-31 15:05:03 +08:00
“huailei000”
7a627a5bfc perf: 调整工单详情审批人容器高度 2023-01-31 14:32:38 +08:00
feng626
9864d43e95 Merge pull request #2452 from jumpserver/pr@dev@role_update
fix: role update
2023-01-31 13:23:07 +08:00
feng
cf2a16a746 fix: role update 2023-01-31 13:21:39 +08:00
Bai
25df2096fd perf: 优化用户列表导入时密码字段进行加密回显 2023-01-31 11:32:56 +08:00
“huailei000”
47f5cd892a fix: 修复站内信弹窗样式 2023-01-31 11:01:24 +08:00
“huailei000”
2aa3451c24 perf: 命令记录列表不显示操作 2023-01-30 19:50:46 +08:00
“huailei000”
f3f679831b perf: 命令记录列表显示折叠功能 2023-01-30 19:44:44 +08:00
“huailei000”
4bf00fac7c perf: 优化添加账号提示文案 2023-01-30 19:10:11 +08:00
“huailei000”
e867277a7f perf: 创建资产类型为web时,资产详情添加账号过滤掉切换字、特权账号等字段 2023-01-30 19:01:44 +08:00
Bai
c9a3fe625c perf: 优化资产授权详情授权账号更新卡片 2023-01-30 19:01:17 +08:00
“huailei000”
7e3db76c9f perf: 创建资产模版添加账号带id 2023-01-30 18:59:34 +08:00
Bai
5fef193029 perf: 优化资产授权详情授权账号更新卡片 2023-01-30 18:52:25 +08:00
Bai
2289b43516 fix: 修改资产树节点 url / 问题 2023-01-30 18:26:19 +08:00
“huailei000”
affca62d1a perf: 调整列表操作里按钮高度 2023-01-30 17:33:55 +08:00
Bai
3041dee3ce fix: 修改用户列表角色字段不显示的问题 2023-01-30 17:17:15 +08:00
老广
ecde3f6375 Merge pull request #2435 from jumpserver/pr@dev@fix_create_job_select_assets
fix: 修复创建作业选择树权限不对的问题
2023-01-30 17:15:18 +08:00
老广
b2823f6978 Merge pull request #2436 from jumpserver/pr@dev@perf_theme_color
pref: 修改 theme color
2023-01-30 16:41:00 +08:00
Bai
06b0b748a7 perf: 修改创建平台时 ansible_config 字段传递 dict 对象 2023-01-30 16:26:33 +08:00
ibuler
6313184711 pref: 修改 theme color 2023-01-30 15:58:50 +08:00
Aaron3S
a04c613905 fix: 修复创建作业选择树权限不对的问题 2023-01-30 15:54:28 +08:00
“huailei000”
26d106ca9e perf: 优化账号收集详情翻译问题 2023-01-30 15:29:59 +08:00
“huailei000”
6ce6fd6c21 feat: 资产详情-账号列表添加账号模版 2023-01-30 15:16:31 +08:00
老广
5c68d786ce Merge pull request #2432 from jumpserver/pr@dev@perf_run_job
perf: 修改作业执行为弹窗
2023-01-30 15:09:22 +08:00
Aaron3S
ac5ec22d5e perf: 修改作业执行为弹窗 2023-01-30 15:04:26 +08:00
老广
bb431bf58b Merge pull request #2430 from jumpserver/pr@dev@perf_add_yarn_lock_css
perf: 添加 lock
2023-01-30 14:24:29 +08:00
ibuler
bb7030d6e7 perf: 添加 lock 2023-01-30 14:23:43 +08:00
老广
08e5996705 Merge pull request #2425 from jumpserver/pr@dev@pref_applet_list_detail
perf: 优化 applet list 和 detail
2023-01-30 14:17:47 +08:00
ibuler
01e4edc7d8 merge: 解决冲突 2023-01-30 14:17:09 +08:00
feng626
524e3499a1 Merge pull request #2429 from jumpserver/pr@dev@user_profile
perf: user profile
2023-01-30 13:41:25 +08:00
feng
1b417549d6 perf: user profile 2023-01-30 13:39:30 +08:00
ibuler
443617e66e perf: 优化 applet list 和 detail 2023-01-30 12:31:21 +08:00
feng626
df5f1097e6 Merge pull request #2428 from jumpserver/pr@dev@login_password
fix: 重制密码 disabled
2023-01-30 11:39:02 +08:00
feng
5a8e4027c6 fix: 重制密码 disabled 2023-01-30 11:37:57 +08:00
“huailei000”
77d1acd691 fix: 修复克隆自定义平台后创建资产-添加账号密文类型为空问题 2023-01-30 11:25:29 +08:00
v-hleihuai
615df0e77a feat: markdown 2023-01-30 10:13:08 +08:00
ibuler
4496f58d84 perf: 优化 applet list 和 detail 2023-01-29 19:47:07 +08:00
feng626
90d5022933 Merge pull request #2424 from jumpserver/pr@dev@ticket_user
perf: 工作台 工单列表url
2023-01-29 19:05:47 +08:00
feng
c3a298739b perf: 工作台 工单列表url 2023-01-29 19:04:36 +08:00
老广
2775d32ca0 Merge pull request #2414 from jumpserver/pr@dev@perf_remoteapp_view
perf: 优化远程应用界面
2023-01-29 18:29:18 +08:00
ibuler
2aa712f72b merge: with dev 2023-01-29 18:27:02 +08:00
老广
48e64534b4 Merge pull request #2422 from jumpserver/pr@dev@change_some_name
perf: 修改 activity
2023-01-29 18:18:17 +08:00
ibuler
504d0050c8 perf: 修改 taginput placeholder 2023-01-29 18:16:45 +08:00
ibuler
d840d2d38d perf: 修改 activity 2023-01-29 17:57:58 +08:00
“huailei000”
891309ee9f perf: 优化折叠后菜单显示的高度 2023-01-29 16:45:38 +08:00
“huailei000”
e307ec2744 perf: 资产授权-AccountFormatter组件增加helpText参数 2023-01-29 16:14:05 +08:00
ibuler
1aa325b429 perf: 修改组件 Asset Tree Table 名称 2023-01-29 16:07:32 +08:00
jiangweidong
5bf3f726e8 feat: 解决冲突 2023-01-29 15:26:46 +08:00
“huailei000”
906ef63a50 perf: 优化远程应用列表协议展示 2023-01-29 15:08:16 +08:00
feng626
dbc5656555 Merge pull request #2418 from jumpserver/pr@dev@ansible_enabled_disables
perf: ansible enabled disabled
2023-01-29 13:30:37 +08:00
feng
91a2cc075a perf: ansible enabledt disabled 2023-01-29 13:29:49 +08:00
“huailei000”
098eabf308 fix: 上传远程应用弹窗清空上次上传内容 2023-01-28 15:08:28 +08:00
“huailei000”
5de8c055c1 perf: 发布机详情去掉网域 2023-01-28 14:04:43 +08:00
“huailei000”
3acb1b9a10 fix: 修复远程应用-应用发布机详情页按钮没有权限问题 2023-01-28 11:15:26 +08:00
jiangweidong
929a394bee perf: 去掉打印 2023-01-20 18:03:43 +08:00
jiangweidong
e835e0a671 Merge branch 'dev' of https://github.com/jumpserver/lina into pr@dev@perf_remoteapp_view 2023-01-20 17:53:14 +08:00
jiangweidong
2b1c44b6f5 perf: 优化远程应用界面 2023-01-20 17:53:06 +08:00
jiangweidong
fbc94ac4f2 perf: 修改远程应用的列表界面 2023-01-19 18:00:19 +08:00
“huailei000”
14a76db7d8 fix: 修复创建改密会自动填写上次的账号问题 2023-01-19 10:18:19 +08:00
“huailei000”
f2cec72378 perf: ip字段增加正则过滤 2023-01-18 15:47:07 +08:00
“huailei000”
2fe14c7257 fix: 修复网域-网关更新后页面undefined问题 2023-01-18 15:10:46 +08:00
“huailei000”
5cebef0f59 fix: 修复平台详情-自动化提示没有权限问题 2023-01-18 11:04:00 +08:00
“huailei000”
49eeb7e8a2 perf: 优化创建用户form的字段label显示 2023-01-17 17:13:50 +08:00
“huailei000”
bba4750ec3 fix: 修复修改资产协议端口不生效问题 2023-01-17 15:00:34 +08:00
jiangweidong
8049e0d965 fix: 去掉title 2023-01-17 13:44:33 +08:00
jiangweidong
45ff13c7ce perf: 优化操作日志详情界面 2023-01-17 13:44:33 +08:00
“huailei000”
449d4ae18e fix: 修复工单动作组件不回显问题 2023-01-17 12:29:31 +08:00
“huailei000”
db457d169c perf: 添加动作组件 2023-01-17 12:29:31 +08:00
“huailei000”
17efdb8096 fix: 修复平台更新字段格式 2023-01-17 10:50:31 +08:00
feng626
f13031d120 Merge pull request #2404 from jumpserver/pr@dev@ticket_asset
perf: ticket asset
2023-01-16 20:40:20 +08:00
feng
d751a23df1 perf: ticket asset 2023-01-16 20:37:01 +08:00
“huailei000”
b8b22a6f8e perf: 使用xss 2023-01-16 19:15:16 +08:00
fit2bot
b891be3607 v3.0.0-rc1 (#2400)
* feat: 资产选择优化

* perf: 修改用户列表显示字段

* perf: 修改 改密 收集账号名字

* perf: 添加AssetTreeTable组件;资产列表、资产选择、资产账号、资产授权使用AssetTreeTable组件

* perf: 修改资产列表 tab

* perf: 修改路径

* perf: 修改 tree

* perf: 修改 tab icon

* fix: 修复资产列表点击创建按钮页面空白问题

* feat: 支持超时时间设置

* perf: 改密去除tab

* perf: table column添加属性showFullContent: 折行显示全部内容

* perf: 添加 account push

* perf: 修改 asset select padding

* perf: 账号收集

* feat: terminal 页面增加padding

* perf: account list source

* perf: AssetTreeTable配置默认不显示右键菜单

* perf: 修改账号

* fix: 修复用户登录规则动作是审批时没有显示审批人选项

* refactor: 修改列表显示字段1 (#2309)

* refactor: 修改列表显示字段(用户组列表)

* refactor: 修改列表显示字段(角色列表)

* perf: 修改列表显示字段(资产列表); 修改DataTable showOverflowTooltip 参数默认为 true;  优化 ArrayFormatter 组件, 支持传递 delimiter 参数;

* perf: 修改列表显示字段(主机列表、网络设备、数据库、云服务、Web)

* perf: 修改列表字段显示(云同步,同步实例任务列表,云账号列表)

* perf: 修改列表字段显示(网域列表,网关列表)

* perf: 修改列表字段显示(平台列表)

* perf: 修改列表字段显示(标签列表)

* perf: 修改 SyncInstanceTask 组件; 删除 GatheredUserList.vue 页面;

Co-authored-by: Bai <baijiangjie@gmail.com>

* feat: 修复一些页面上的问题

* fix: 修复资产详情协议修改端口不生效问题

* perf: 用户组详情不显示授权的资产

* fix: 修复账号收集详情key相同控制台报错问题

* fix: 修复显示密码组件样式布局问题

* feat: 增加 terminal 滚动控制和清屏按钮

* feat: 增加 terminal 滚动控制和清屏按钮

* perf: 调整terminal 按钮样式

* feat: 优化detail 字段

* perf: 资产批量更新去掉特权用户

* feat: 修改按钮样式

* fix: 修复节点选择错误的问题

* perf: 修改账号推送

* perf: 优化列表显示字段2 (#2322)

* perf: 优化表格字段允许显示 ID 列

* perf: 修改列表字段显示(账号列表)

* perf: 修改列表字段显示(账号模版)

* perf: 修改列表字段显示(收集账号)

* perf: 修改列表字段显示(账号改密)

* perf: 修改列表字段显示(账号备份)

* perf: 修改列表字段显示(授权列表)

* perf: 修改列表字段显示(授权详情页面-用户/用户组,资产/节点,授权账号)

* perf: 修改权限位

* perf: 修改账号地址

* feat: 防止xss攻击;可以自定义配置xss

* perf: 修改账号

* perf: 修改列表字段显示(资产登录ACL, 命令过滤ACL)

* perf: 优化xss过滤规则判断

* fix: 远程应用修改操作选项

* perf: 修改对应权限位 各种

* perf: 修改账号

* perf: 优化TreeTable组件布局

* perf: 远程应用不进入详情页

* perf: 修改列表字段显示(命令过滤, 命令组)

* perf: 修改列表字段显示(用户详情, 授权的资产, 资产授权规则, 用户登录规则)

* perf: 修改列表字段显示(任务列表,任务执行历史列表)

* perf: 上传远程应用接口报错时给出提示

* perf: 修改 applet host

* perf: 修改 accounts 添加

* feat: ops增加rbac

* perf: 修改 assets 结构

* perf: 修改列表字段显示(会话列表, 在线会话, 历史会话)

* perf: 修改列表字段显示(命令列表)

* perf: 修改列表字段显示(文件传输)

* perf: 修改列表字段显示(登录日志,操作日志,改密日志,作业日志)

* perf: 优化PageHeading组件标题对齐

* perf: 修改列表字段显示(工作台,概览,我的资产,作业中心,作业管理,模版管理,执行历史)

* perf: 修改翻译

* perf: 修改 tag search

* fix: 修复账号改密更新、克隆页面空白问题

* perf: 修改列表字段显示(系统设置,终端列表,命令存储,录像存储,终端端点,终端规则)

* perf: 修改列表字段显示(工单管理,我的申请,待我审批,流程设置)

* perf: 修改列表字段显示(个人信息,API Key,连接令牌)

* perf: 修改列表字段显示(远程应用,应用发布机)

* perf: 修改 tableConfig 字段 excludes -> columnsExclude, extraColumns -> columnsExtra

* perf: 修改 ConnectionToken 组件

* perf: 修改 AutoDataTable 组件

* perf: 修改 AssetAclCreateUpdate 组件 reviewers 字段

* feat: 修改字段

* perf: 优化table组件表头高度对齐

* fix: 修复资产列表-所有列表不能导入问题

* perf: 我的资产收藏资产添加提示

* feat: 修改列顺序

* perf: automation

* merge: v3

* perf: 修改账号自创建

* perf: 快捷命令select组件筛选功能

* perf: select参数兼容

* feat: 修改选择用户样式

* perf: 修改账号自动化路由

* perf: 修改 form json editor

* perf: account gather 翻译

* fix: 修复平台列表上传功能

* feat: 支持账号、资产在详情页查看活动(Activities)时间线

* fix: 修复 powershell 不能选择问题

* fix: 修复 powershell 不能选择问题

* perf: 优化云资产同步

* perf: account 翻译

* fix: 修复账号列表导出报错问题

* fix: 修复账号列表测试功能权限位

* fix: 修复角色列表权限位不准确问题

* feat: 增加快捷命令页面刷新后续接功能

* fix: 应用发布机的测试

* fix: 修复账号列表不能批量删除问题

* perf: 修改 form tree

* perf: account 翻译

* fix: 修复资产树组件搜索后关闭搜索框无法显示搜索框问题

* perf: 移除发布机和应用的导入导出

* perf: 树组件关闭按钮增加刷新树功能

* fix: 修复资产树显示当前节点资产报错问题

* perf: 优化资产树组件关闭按钮执行事件顺序

* perf: upload applet and reload table list

* perf: 优化显示发布机的远程应用

* perf: 修改 settings 组织

* perf: 系统设置-远程应用详情资产不能跳转

* perf: 修改 applet status

* perf: 修改 applet status

* perf: account

* perf: account backup

* perf: verify code ttl

* perf: 修改菜单

* perf: 修改网关创建

* perf: asset ping api

* perf: 再次优化 menu

* perf: 优化菜单

* perf: menu 去掉一下 css

* perf: 资产创建、更新标签支持自定义输入创建

* perf: 修改 gateway

* perf: account change secret

* fix: 修复资产详情标签不显示问题

* perf: 修改 accounts 路由

* perf: gateway test perm

* fix: 修复账号备份-创建、更新、删除跳转到空白页面问题

* fix: 修复账号收集创建、删除后跳转到空白页面问题

* perf: 修改 choices formattor

* fix: 修改资产详情页面字段 spec_info

* fix: 修复资产详情-授权用户-查看授权字段显示不全问题

* fix: 修复工作台列表字段显示

* perf: gateways

* feat: ops 修改一些交互细节

* feat: 删除模版执行的功能

* perf: 修改 endpoint 端口监听

* perf: gateway ui

* perf: 优化字段显示

* feat: 支持资源用户在详情页查看活动(Activities)时间线

* perf: 细化权限

* fix: 修改审计日志列

* Merge remote-tracking branch 'origin/v3' into v3

# Conflicts:
#	src/views/assets/Domain/DomainDetail/GatewayList.vue

* perf: 控制台仪表盘资产类型占比取消hover效果

* perf: gateway

* fix: 修改工单详情 type.value 参数

* perf: gateway dialog

* perf: 优化ProtoSelector组件逻辑

* fix: 修改 terminal 颜色,修复文字被背景色覆盖的问题

* feat: 增加检测命令长度

* fix: 修复账号收集-执行列表详情报错问题

* fix: 修复资产列表-数据库克隆没有协议问题

* perf: push_account_enabled

* fix: 修复资产授权详情用户、资产不能删除问题

* feat: Redis/MongoDB 支持SSL

* perf: push account

* fix: 修复命令过滤-命令组克隆页面跳转不准确问题

* fix: 修改授权规则列表过滤字段 asset_name,node_name;

* fix: 修复测试连接报错问题

* perf: account platform

* perf: 调整平台详情展示字段

* perf: account push

* fix: 修复detail 详情页面 404

* pref: 修改 assets 布局

* pref: 去掉页面滚动

* pref: 暂时修改 choice left align

* perf: account template access_key

* perf: 优化activity记录都保存至operatelog中

* perf: 优化页面布局

* perf: asset add account template

* fix: 修复table搜索项重复问题

* perf: 账号收集详情

* pref: table -

* perf: 创建资产-模版添加列表增加刷新按钮

* fix: 修复任务列表操作内容显示

* perf: 先去掉自动创建

* perf: change secret

* perf: 优化账号列表资产树数量按照账号进行计算

* perf: account change secret

* pref: 修改 select hover 效果

* pref: 去掉视图 icon

* perf: executed amount

* pref: 修改 set pre org,避免回到 system

* perf: 创建资产-创建账号模版弹窗显示

* perf: account task 修改

* perf: account trigger

* perf: user reset password

* fix: 修复平台克隆失败问题

* fix: 修复资产授权批量更新报错问题

* perf: 优化账号列表资产树数量按照账号进行计算增加默认值 asset

* fix: 修复用户详情-资产授权规则跳转页面报错问题

* perf: 资产树-类型树关闭搜索功能

* fix: 修复执行窗口有空白问题

* fix: 修复账号改密详情权限不准确问题

* fix: 文件传输列表不显示操作

Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>
Co-authored-by: jiangweidong <weidong.jiang@fit2cloud.com>
Co-authored-by: Eric <xplzv@126.com>
Co-authored-by: huailei <31801270+huailei000@users.noreply.github.com>
2023-01-16 18:57:40 +08:00
老广
a4840aa2a6 Merge pull request #2201 from jumpserver/pr@dev@fix_yui_cve
fix: jsencrypt包含YUI引发的漏洞问题
2022-12-23 19:29:18 +08:00
halo
b1c2645ab0 fix: 解决v-html的xss注入问题 2022-12-13 14:39:21 +08:00
halo
3d90ee0b41 fix: 解决v-html的xss注入问题 2022-12-13 14:39:21 +08:00
“huailei000”
3da57560e7 perf: 调整布局 2022-12-06 18:11:24 +08:00
Jiangjie.Bai
d4dbd8a535 Merge pull request #2251 from jumpserver/pr@dev@dev_merged_v3
merge: with v3
2022-12-06 17:07:32 +08:00
fit2bot
791f173cea merge: with v3 (#2250)
* perf: 增加celery输出

* fix: 修复网域列表资产选中后更新时不显示选中问题

* fix: 选择资产时会根据接口返回状态设置disabled

* feat: 资产选择form 匹配正确的字段

* feat: 资产选择form 匹配正确的字段

* perf: 优化仪表盘环形图数据显示

* feat: 修改资产选择组件支持我的资产选择

* fix: 改密计划选择资产组件添加disabled状态

* fix: 修复资产账号点击资产树接口500问题

* fix: 更新网域选择资产组件添加disabled状态

* perf: 优化显示

* perf: 修改 Domain 列表页面

* perf: 修改网域列表网关字段跳转

* perf: 修改 GatewayList 页面

* perf: 选择资产组件弹窗显示资产详情

* perf: 修改资产详情账号列表页面

* perf: 修改资产账号详情

* fix: 修复改密详情页面报错误提示问题

* fix: 修复资产树点击资产接口报错问题

Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: Bai <baijiangjie@gmail.com>
2022-12-06 17:04:53 +08:00
Bai
7b5ab3defe merge: with v3 2022-12-06 16:53:43 +08:00
Bai
a272fbb542 perf: 资产账号详情添加 su_from 选择 2022-12-06 16:44:21 +08:00
Bai
d754acf77d perf: 修改 yarn.lock 文件 2022-12-06 13:16:21 +08:00
老广
454ef107ae Merge pull request #2247 from jumpserver/pr@dev@v3_to_dev
merge: with v3
2022-12-06 11:37:41 +08:00
ibuler
68b1234e81 merge: with v3 2022-12-06 11:31:38 +08:00
“huailei000”
6349ae2c17 fix: 修复资产树点击资产接口报错问题 2022-12-06 11:16:18 +08:00
“huailei000”
ca9c467644 fix: 修复改密详情页面报错误提示问题 2022-12-06 10:44:39 +08:00
Bai
b2e87d7457 perf: 修改资产账号详情 2022-12-05 19:42:46 +08:00
Bai
ba6750d7d6 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-05 19:31:21 +08:00
Bai
d6518019dd perf: 修改资产详情账号列表页面 2022-12-05 19:31:00 +08:00
“huailei000”
fa77a95d93 perf: 选择资产组件弹窗显示资产详情 2022-12-05 19:25:13 +08:00
Bai
d66c6b59a2 perf: 修改 GatewayList 页面 2022-12-05 19:11:49 +08:00
Bai
9e3fbbad10 perf: 修改网域列表网关字段跳转 2022-12-05 18:51:46 +08:00
Bai
9623264e56 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-05 17:45:01 +08:00
Bai
bef1e8f49a perf: 修改 Domain 列表页面 2022-12-05 17:44:52 +08:00
Aaron3S
47ef7120f7 perf: 优化显示 2022-12-05 17:36:51 +08:00
“huailei000”
7f0924fb52 fix: 更新网域选择资产组件添加disabled状态 2022-12-05 17:24:30 +08:00
“huailei000”
7312a899e1 fix: 修复资产账号点击资产树接口500问题 2022-12-05 16:52:21 +08:00
“huailei000”
94955cb0d8 fix: 改密计划选择资产组件添加disabled状态 2022-12-05 16:30:09 +08:00
Aaron3S
2ec9c02d0c feat: 修改资产选择组件支持我的资产选择 2022-12-05 15:59:25 +08:00
“huailei000”
208c7c0aa8 perf: 优化仪表盘环形图数据显示 2022-12-05 15:39:35 +08:00
Aaron3S
5e321e9a27 feat: 资产选择form 匹配正确的字段 2022-12-05 15:28:36 +08:00
Aaron3S
1dfe004370 feat: 资产选择form 匹配正确的字段 2022-12-05 15:11:28 +08:00
“huailei000”
5aec4f3f44 fix: 选择资产时会根据接口返回状态设置disabled 2022-12-05 14:15:46 +08:00
“huailei000”
b12aaf003e fix: 修复网域列表资产选中后更新时不显示选中问题 2022-12-05 11:12:34 +08:00
Aaron3S
1c80faede4 perf: 增加celery输出 2022-12-05 10:54:59 +08:00
Bai
4c8819c039 perf: 提取 CommandACL 和 LoginAssetACL 对于 User Asset Account 公共数据和处理逻辑 2022-12-04 21:50:44 +08:00
Bai
d3c297d24f feat: 添加 CommandFilterAclDetail, CommandGroupDetail 页面 2022-12-04 20:01:35 +08:00
Bai
18150eb8ab perf: 修改命令组的创建更新问题 2022-12-04 18:48:15 +08:00
Bai
1c00db1978 feat: 权限管理中增加命令过滤菜单; 路由中添加CommandFilterACL,CommandGroup; 添加CommandFilterAclList,Create,Update;添加CommandGroupList,Create,Update; 2022-12-04 18:30:37 +08:00
ibuler
0ea46e9ee2 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-02 20:29:06 +08:00
ibuler
70e9b26c4d pref: asset accounts 添加 name 2022-12-02 20:19:47 +08:00
“huailei000”
6af2ee0555 fix: 修复作业管理创建作业参数组件输入样式问题 2022-12-02 19:06:59 +08:00
“huailei000”
b68a3b27fa perf: 审计台仪表盘筛选日期储存到localStorage中 2022-12-02 18:51:23 +08:00
“huailei000”
3ee819dd4c fix: 调整作业管理-创建作业时参数组件样式 2022-12-02 17:44:43 +08:00
feng626
de29a07c35 Merge pull request #2233 from jumpserver/pr@v3@gateways
perf: 网关优化
2022-12-02 17:27:21 +08:00
feng
59bbd4d743 perf: 网关优化 2022-12-02 17:20:58 +08:00
“huailei000”
790a3573e9 perf: 调整柱状图组件参数,调整不同主题下柱体颜色;审计台仪 表盘增加翻译 2022-12-02 16:58:48 +08:00
ibuler
023f4fde09 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-02 16:39:04 +08:00
ibuler
e29a4db922 perf: 修改 ztree 2022-12-02 16:38:52 +08:00
Aaron3S
df06fbe85e perf: 持续优化job 页面 2022-12-02 12:23:05 +08:00
feng626
7a315a056a Merge pull request #2230 from jumpserver/pr@v3@gateway
perf: gateway
2022-12-02 11:26:34 +08:00
feng
e51d13a47b perf: gateway 2022-12-02 11:19:21 +08:00
“huailei000”
917c22a9eb fix: 修复账号模版删除后列表不自动刷新问题 2022-12-02 11:13:18 +08:00
“huailei000”
650b5ded35 fix: 修复收集用户-删除任务后,浏览器后退会进入到详情在此执行删除接口404问题 2022-12-02 10:54:06 +08:00
Bai
92c53cbfc1 fix: 删除 <用户详情-授权账号> 页面, 删除UserGrantedAccounts 组件 2022-12-01 20:46:02 +08:00
Bai
2ce02c54b6 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-01 20:42:48 +08:00
Bai
2ed6ddb92a fix: 修改用户授权相关的API,使用 self 2022-12-01 20:42:13 +08:00
“huailei000”
efdbc001ff perf: 调整审计台仪表盘显示内容 2022-12-01 19:05:50 +08:00
Bai
bbc43b7ec6 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-12-01 12:10:00 +08:00
Bai
41d07fd670 perf: 修改<工作台-我的资产>页面;修改<控制台-用户详情>页面;修改<GrantedSystemUsersShowFormatter>为<GrantedAccountShowFormatter>组件; 2022-12-01 12:09:43 +08:00
“huailei000”
66a33d0c44 perf: 拆分控制台仪表盘、审计台仪表盘 2022-12-01 10:54:25 +08:00
Bai
179c420e9d perf: 优化 Login Asset ACL 详情页面 2022-11-30 22:09:12 +08:00
“huailei000”
bd4811c485 perf: 优化移动端下菜单显示效果 2022-11-30 20:51:38 +08:00
feng
7ea639c078 perf: update account template 2022-11-30 20:43:05 +08:00
吴小白
105230eeb0 perf: 添加代码构建测试 actions 2022-11-30 17:07:53 +08:00
Bai
93ec844121 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-30 16:19:03 +08:00
Bai
fd84c73d6b perf: 修改 acl assets name,address 2022-11-30 16:18:40 +08:00
Aaron3S
1af963337b feat: 修改部分交互 2022-11-30 16:03:57 +08:00
ibuler
c99505f39f perf: merge with remove 2022-11-30 15:27:48 +08:00
ibuler
d886a5e607 perf: 优化菜单左侧视图对接 2022-11-30 15:25:08 +08:00
Bai
cc21e63b5b Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-30 15:10:08 +08:00
Bai
d18cd3d254 perf: 移动 Acl 到 perms 2022-11-30 15:09:31 +08:00
“huailei000”
b01133020d feat: 设置默认展开的子菜单 2022-11-30 14:51:15 +08:00
老广
cc9b4ea2bd Merge pull request #2221 from jumpserver/revert-2220-pr@v3@feaat_router_submenu_open
Revert "feat: 仪表盘、工作台默认展开子菜单"
2022-11-30 14:29:17 +08:00
huailei
006477172b Revert "feat: 仪表盘、工作台默认展开子菜单"
This reverts commit 3b2f4cddea.
2022-11-30 14:28:23 +08:00
“huailei000”
3b2f4cddea feat: 仪表盘、工作台默认展开子菜单 2022-11-30 13:30:57 +08:00
“huailei000”
01fb9f5411 perf: 仪表盘增加翻译;混合生成仪表盘颜色 2022-11-30 12:15:27 +08:00
“huailei000”
4281e02f95 perf: 调整切换二级菜单触发方式为hover显示 2022-11-29 23:10:30 +08:00
“huailei000”
fc0ee3d4f8 perf: 调整仪表盘显示内容 2022-11-29 23:04:52 +08:00
feng626
f79121724d Merge pull request #2215 from jumpserver/pr@v3@gateway
perf: geteway
2022-11-29 20:07:45 +08:00
feng
f50191d538 perf: geteway 2022-11-29 20:04:41 +08:00
Aaron3S
5b1bc4478c perf: 重新设计菜单和交互流程 2022-11-29 19:43:26 +08:00
feng
bb910aa447 perf: del domain node 2022-11-29 19:16:54 +08:00
feng626
f13afff928 Merge pull request #2214 from jumpserver/pr@v3@domian_add_node
perf: domian add node
2022-11-29 17:08:14 +08:00
feng
a003e20e51 perf: domian add node 2022-11-29 17:03:25 +08:00
ibuler
33d5d725d3 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-29 15:48:42 +08:00
ibuler
8fb0485887 perf: 还原 nav 20 2022-11-29 15:48:28 +08:00
“huailei000”
4850dce79b perf: 替换头像;修改导航栏气泡样式 2022-11-29 12:34:33 +08:00
ibuler
2097e8a361 perf: 颜色再深点 2022-11-29 12:06:06 +08:00
“huailei000”
ad27c4b9fe fix: 设置导航栏背景颜色 2022-11-29 11:58:12 +08:00
“huailei000”
2230177680 perf: 根据系统颜色混合导航栏颜色 2022-11-29 11:43:13 +08:00
ibuler
1279015c28 pref: 修改主题颜色 2022-11-29 11:21:11 +08:00
ibuler
23c66964cd pref: 修改主题 2022-11-29 11:12:34 +08:00
“huailei000”
a180265585 fix: 修复修改主题报错问题 2022-11-29 10:35:00 +08:00
“huailei000”
4af602b706 perf: 修改菜单主题颜色配置 2022-11-28 18:55:23 +08:00
feng626
d445019131 Merge pull request #2207 from jumpserver/pr@v3@pr@v3@history_account_secret_perm
perf: history account secret
2022-11-28 18:44:26 +08:00
feng
f97105ede0 perf: history account secret 2022-11-28 18:41:23 +08:00
feng626
76a63f2be5 Merge pull request #2206 from jumpserver/perf_dashboard
Perf dashboard
2022-11-28 17:14:29 +08:00
“huailei000”
b5d30129f2 Merge branch 'v3' into perf_dashboard 2022-11-28 17:12:24 +08:00
“huailei000”
26c021fc77 perf: 调试接口 2022-11-28 17:11:18 +08:00
ibuler
672db6380d pref: 修改 dev 模式下的连接 web terminal url 2022-11-28 14:54:56 +08:00
吴小白
feb428356c perf: 优化构建 2022-11-28 09:50:43 +08:00
吴小白
212c4e5bd7 perf: 去掉不使用的变量 2022-11-28 09:50:43 +08:00
吴小白
1029d0cfa1 perf: 优化构建 2022-11-27 21:03:56 +08:00
Aaron3S
e55272180d feat: 实时命令页面 2022-11-26 02:51:02 +08:00
ibuler
332112e4dd Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-25 21:19:35 +08:00
ibuler
5f65099af5 pref: 修改主题 2022-11-25 21:19:19 +08:00
“huailei000”
ebe85219eb perf: 调整仪表盘显示内容 2022-11-25 18:15:42 +08:00
Chenyang Shen
a8a1c99312 Merge pull request #2202 from jumpserver/revert-2199-pr@v3@feat_org_select_width
Revert "feat: 切换组织选择器宽度自适应"
2022-11-25 16:42:11 +08:00
huailei
adec7f4020 Revert "feat: 切换组织选择器宽度自适应"
This reverts commit 3fa33e482a.
2022-11-25 16:40:22 +08:00
ibuler
02e744d833 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-25 11:18:10 +08:00
ibuler
e70b5cb2c4 perf: 修改一些图标 2022-11-25 11:17:48 +08:00
feng
30213bc4c0 Merge remote-tracking branch 'origin/v3' into v3 2022-11-25 10:10:05 +08:00
feng
acc919b0e7 perf: gateway 2022-11-24 21:15:18 +08:00
halo
8e21eb0a97 fix: jsencrypt包含YUI引发的漏洞问题 2022-11-24 18:29:39 +08:00
“huailei000”
3fa33e482a feat: 切换组织选择器宽度自适应 2022-11-24 12:37:43 +08:00
jiangweidong
d88ff02fa8 fix: 解决命令过滤获取不到一些应用的系统用户问题 2022-11-24 09:37:30 +08:00
Aaron3S
d46e49df2a perf: 优化job 页面 2022-11-24 00:54:18 +08:00
ibuler
608b8b727f Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-23 16:54:34 +08:00
ibuler
fd3191ad09 perf: 修改 logo 2022-11-23 16:53:54 +08:00
“huailei000”
0b270fe3bb perf: 替换概览图标 2022-11-23 16:28:10 +08:00
“huailei000”
9ad0ee6c24 fix: 调整header组件图标对其方式 2022-11-23 15:56:21 +08:00
“huailei000”
c05a01e46f perf: 调整页面布局为上下布局;不显示footer组件 2022-11-23 14:45:09 +08:00
ibuler
4f68d57666 pref: 修改左侧菜单样式 2022-11-22 19:38:43 +08:00
jiangweidong
fd05028cff fix: 隐藏clickhouse改密入口 2022-11-22 18:39:00 +08:00
“huailei000”
a28dd9cf6f perf: 调整菜单样式 2022-11-22 18:13:35 +08:00
ibuler
7e7bcae8e7 perf: 修改 header 高度 2022-11-22 13:13:54 +08:00
老广
218ef50ff7 Merge pull request #2189 from jumpserver/feat_add_theme
Feat add theme
2022-11-22 12:37:15 +08:00
“huailei000”
18a9d99f08 feat: 修改系统图标 2022-11-22 12:16:27 +08:00
feng
53a763f3c1 perf: accout backup types 2022-11-21 15:55:16 +08:00
feng
cfd1b1e550 perf: change secret timedelta 2022-11-21 15:17:32 +08:00
feng
f8b6df9487 perf: change secre atutomation 2022-11-21 11:47:00 +08:00
“huailei000”
6d8b45817e feat: 修复head图标 2022-11-18 19:32:30 +08:00
Aaron3S
fc9b44db21 feat: 支持作业定时执行 2022-11-18 19:01:32 +08:00
“huailei000”
100405e080 feat: 修改主题样式 2022-11-18 12:21:35 +08:00
Aaron3S
4b84a77a5a feat: Job 支持运行参数 2022-11-17 20:11:15 +08:00
“huailei000”
119b494cc6 feat: 修改header组件样式 2022-11-17 19:37:04 +08:00
feng
95945a3b20 perf: ticket 2022-11-17 19:21:46 +08:00
Jiangjie.Bai
582a84178d Merge pull request #2187 from jumpserver/dev
v2.28.0
2022-11-17 17:44:19 +08:00
feng626
1b613a82f9 Merge pull request #2186 from jumpserver/pr@v3@ticket_optimization
perf: ticket optimization
2022-11-17 17:34:45 +08:00
feng
c691a93ee5 perf: ticket optimization 2022-11-17 17:27:52 +08:00
“huailei000”
73de782756 fix: 修复绑定企业微信弹窗时input样式遮挡问题 2022-11-17 16:55:11 +08:00
Jiangjie.Bai
9b9f7c936c Merge pull request #2184 from jumpserver/dev
v2.28.0-rc5
2022-11-17 14:18:15 +08:00
jiangweidong
55100e64a1 perf: 翻译用户的[邮件]改为[邮箱] 2022-11-17 14:16:00 +08:00
jiangweidong
6d74959b64 perf: 翻译用户的[邮件]改为[邮箱] 2022-11-17 14:16:00 +08:00
Aaron3S
16e7e548b3 feat: 创建作业支持参数 2022-11-16 21:11:14 +08:00
Jiangjie.Bai
2a6100957f Merge pull request #2182 from jumpserver/dev
v2.28.0-rc4
2022-11-16 21:08:55 +08:00
feng
3704e4d478 perf: ticket 2022-11-16 21:05:45 +08:00
feng
c16ff3e894 perf: ticket list 2022-11-16 17:19:08 +08:00
feng
47006a2a88 perf: user confirm dialog css 2022-11-16 15:56:05 +08:00
feng626
952a968d3c Merge pull request #2181 from jumpserver/pr@v3@ticket
perf: ticket
2022-11-16 15:51:56 +08:00
feng
d7f3274b59 perf: ticket 2022-11-16 15:50:46 +08:00
Aaron3S
cfedd153c8 perf: 任务列表优化 2022-11-16 14:25:11 +08:00
feng
b21d1533de perf: update yarn.lock 2022-11-15 18:16:06 +08:00
feng626
6a3f6f8914 Merge pull request #2180 from jumpserver/pr@dev@ticket_expire_time
pef: ticket expire time
2022-11-15 17:34:08 +08:00
“huailei000”
704ae0b294 fix: 修复改密计划详情中列表和资产树添加资产到节点时table会获取url中参数问题 2022-11-15 17:11:40 +08:00
feng
9bf4597d8d pef: ticket expire time 2022-11-15 16:54:45 +08:00
Eric
5f7237309c perf: add host depolyment view 2022-11-15 16:03:20 +08:00
吴小白
e30b15ceec perf: 添加 yarn build 2022-11-15 15:32:37 +08:00
吴小白
2d62fc5429 perf: 优化 Dockerfile 2022-11-15 15:07:20 +08:00
“huailei000”
cd710f37a5 perf: update yarn.lock 2022-11-15 10:36:18 +08:00
ibuler
b55d2208ae pref: 修改 ticket detail 2022-11-15 10:33:02 +08:00
ibuler
ec8a3cee21 pref: 修改 ticket detail 2022-11-14 20:25:06 +08:00
ibuler
1c30a646dc pref: 修改工单详情 2022-11-14 20:13:26 +08:00
ibuler
24357c486a Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-14 19:19:08 +08:00
ibuler
f6d00a5030 pref: 修改 ticket actions 2022-11-14 19:18:57 +08:00
Eric
b52cd1200a perf: publish applets 2022-11-14 19:05:32 +08:00
“huailei000”
1819dfb311 fix: 修复资产克隆失败问题 2022-11-14 15:39:13 +08:00
feng
eeb1aed26a perf: change secret router 2022-11-14 13:51:53 +08:00
feng
b63d6cd748 perf: yarn lock 2022-11-14 10:50:13 +08:00
Jiangjie.Bai
16606d6a27 Merge pull request #2176 from jumpserver/dev
v2.28.0-rc2
2022-11-14 10:01:05 +08:00
jiangweidong
bb1d19610e perf: 优化操作日志界面显示随主题变化 2022-11-14 09:47:12 +08:00
ibuler
da808ca007 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-11 19:41:23 +08:00
ibuler
aa351f0c2d pref: 修改 asset table 2022-11-11 19:40:21 +08:00
老广
ca871b16c4 Revert "perf: 优化刷新页面方法,避免刷新时页面出现空白"
This reverts commit a514e88b78.
2022-11-11 19:39:14 +08:00
Aaron3S
9636cbace0 feat: ops页面 2022-11-11 19:27:07 +08:00
feng626
188ff04ec7 Merge pull request #2172 from jumpserver/pr@v3@change_secret
perf: change secret
2022-11-11 19:12:02 +08:00
feng
057bb73405 perf: change secret 2022-11-11 19:06:27 +08:00
“huailei000”
5d2e826bae fix: 修复创建平台时,切换方式默认值显示不准确问题 2022-11-11 18:22:57 +08:00
ibuler
166adbb7ba Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-11 18:04:46 +08:00
ibuler
8213aa8a68 pref: 修改 perms actions组件 2022-11-11 17:28:52 +08:00
feng
fc08f54394 perf: change secret 2022-11-11 16:39:11 +08:00
“huailei000”
9ec45a889f fix: 改密计划创建表单增加用户名字段;抽离TagInput公共组件 2022-11-11 16:32:04 +08:00
ibuler
ae6c7d33a8 pref: 修改 asset permission 2022-11-11 15:02:17 +08:00
“huailei000”
21b61f22f7 更新改密计划表单字段;暴露form获取meta方法 2022-11-11 14:47:49 +08:00
“huailei000”
9516fb4963 perf: update yarn.lock 2022-11-10 18:37:35 +08:00
Jiangjie.Bai
0a612f50e6 Merge pull request #2164 from jumpserver/dev
v2.28.0-rc1
2022-11-10 17:45:47 +08:00
“huailei000”
d566adb644 fix: 修复账号信息更新消息订阅从新进入页面状态没有改变问题 2022-11-10 17:43:28 +08:00
jiangweidong
242f958428 feat: 云资产同步支持选择IP类型 2022-11-10 17:42:14 +08:00
ibuler
a5a3a47a69 pref: 修改授权详情 2022-11-09 20:58:26 +08:00
ibuler
8b38d45883 pref: 修改 item value 2022-11-09 19:01:21 +08:00
ibuler
5d8a9251e5 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-09 17:02:09 +08:00
“huailei000”
84fb2da1d2 perf: 优化资产授权-账号表单组件 2022-11-09 17:01:34 +08:00
ibuler
46d61151f2 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-09 17:00:41 +08:00
ibuler
bd84b44175 pref: 修改我的资产 2022-11-09 17:00:29 +08:00
feng626
253673fc9a Merge pull request #2157 from jumpserver/pr@v3@gather_account
perf: gather account page
2022-11-09 16:02:01 +08:00
feng
7f6f9ec285 perf: gather account page 2022-11-09 15:57:58 +08:00
ibuler
88d108f85c pref: 优化授权列表 2022-11-09 11:43:23 +08:00
ibuler
a9925bcf28 pref: 修改 perms account 2022-11-08 21:00:03 +08:00
ibuler
f601a45700 pref: 修改 perms account 2022-11-08 20:58:01 +08:00
ibuler
283d321307 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-08 20:52:26 +08:00
ibuler
ef27cd7862 pref: 修改授权表单 2022-11-08 20:51:57 +08:00
“huailei000”
4c1be1aa68 feat: 资产列表增加测试;账号详测试可连接性 2022-11-08 20:26:54 +08:00
老广
eb550aeec3 Merge pull request #2155 from jumpserver/pr@v3@perf_account
pref: 继续优化 accounts view
2022-11-08 19:10:44 +08:00
ibuler
14c4d4fe00 pref: 继续优化 accounts view 2022-11-08 19:06:38 +08:00
“huailei000”
eec62c12ff fix: 修复平台详情-更新平台信息设置为false后不能点击问题 2022-11-08 18:53:21 +08:00
ibuler
b84e191d31 pref: 修改一些 css 2022-11-08 17:28:41 +08:00
ibuler
ac7994b631 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-08 17:14:42 +08:00
ibuler
ab345ee4ef pref: 修改账号详情 2022-11-08 17:14:02 +08:00
“huailei000”
beced802f0 fix: eslint 2022-11-08 17:03:55 +08:00
ibuler
b4331b7758 perf: 修改支持 date filter 2022-11-08 16:47:04 +08:00
ibuler
ae112ab7d9 pref: 优化 css 2022-11-08 15:39:12 +08:00
“huailei000”
f97d46814d perf: update yarn.lock 2022-11-08 15:28:11 +08:00
ibuler
84985b85e0 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-08 14:43:29 +08:00
ibuler
78d4867f25 pref: 更新 table pager 2022-11-08 14:41:40 +08:00
“huailei000”
dbf44cdfd8 fix: 修复平台详情中更新协议,协议不能添加问题 2022-11-08 14:22:39 +08:00
ibuler
73d03fecaf Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-08 11:33:06 +08:00
ibuler
392ab31b1f perf: 优化 choices table formattor 2022-11-08 11:32:48 +08:00
“huailei000”
f05c773bc7 perf: 优化表单复杂组件错误提示 2022-11-08 11:03:53 +08:00
ibuler
3b8ae66db5 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-07 20:13:28 +08:00
ibuler
03ee1b0513 pref: 修改一些布局颜色 2022-11-07 20:13:07 +08:00
Jiangjie.Bai
5cc501f5af perf: 优化优先使用系统设置中的 rdp_resolution 配置 2022-11-07 18:47:29 +08:00
“huailei000”
f013194265 feat: 平台详情添加自动化页面 2022-11-07 17:01:04 +08:00
“huailei000”
9322c4e7ae fix: 修复更新平台时有多个协议只显示一个协议问题 2022-11-07 10:15:14 +08:00
“huailei000”
aafc6af69c perf: 优化选择协议组件;增加翻译 2022-11-04 16:04:37 +08:00
ibuler
fbcb522f6c pref: 优化 action fa 2022-11-04 15:51:04 +08:00
jiangweidong
31fd0ecde0 feat: 显示部分资源的批量删除操作按钮 2022-11-04 14:34:14 +08:00
jiangweidong
9d6ac3907a feat: 重构操作日志 (#2088)
* feat: 操作日志重构-支持查看变更资源信息

* feat: 修改界面

* feat: 优化操作日志详情界面

* feat: 修改显示样式
2022-11-04 14:33:02 +08:00
jiangweidong
784bd16e87 feat: 支持纳管 clickhouse[Web Terminal] (#2112) 2022-11-04 14:31:54 +08:00
jiangweidong
4a11ea2c57 feat: 云同步支持金山云 (#2125) 2022-11-04 14:31:20 +08:00
ibuler
4f628e9b33 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-04 11:40:28 +08:00
ibuler
3366540521 pref: 修改组件的状态 2022-11-04 11:39:59 +08:00
Jiangjie.Bai
262f77da9c Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-03 16:23:15 +08:00
Jiangjie.Bai
cde1c8bf79 feat: 用户详情中添加授权给用户所有账号列表 2022-11-03 16:22:54 +08:00
feng626
c39f0a0aba Merge pull request #2142 from jumpserver/pr@v3@perf_backup_update_typeurl
perf: 更新账号备份类型接口
2022-11-03 16:21:37 +08:00
“huailei000”
476cfb1f9c perf: AutoDataTable组件columns参数为空时默认显示所有 2022-11-03 16:21:13 +08:00
“huailei000”
e6915c669b perf: 更新账号备份类型接口 2022-11-03 16:20:10 +08:00
“huailei000”
b2987e1d4f perf: 调整资产账号-查看密码展示字段 2022-11-03 15:23:39 +08:00
ibuler
5eb6a4307d Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-02 17:23:45 +08:00
ibuler
a26b42fef8 preff: 修改 applets hosts 详情 2022-11-02 17:23:25 +08:00
feng626
24c8661453 Merge pull request #2139 from jumpserver/pr@v3@feat_add_account_detail
merge v3
2022-11-02 15:47:29 +08:00
“huailei000”
4f2a8149fe merge v3 2022-11-02 15:44:03 +08:00
“huailei000”
aba8a3cc55 feat: 增加资产账号详情 2022-11-02 15:34:34 +08:00
ibuler
7f6edc2749 pref: 修改表哥的 style 2022-11-02 15:26:20 +08:00
ibuler
7f28629748 pref: 修改 switch icon 2022-11-02 14:47:52 +08:00
ibuler
2ac9b885c9 pref: 修改 remote applet 2022-11-02 14:13:13 +08:00
ibuler
6d756eab5d Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-01 20:37:58 +08:00
ibuler
8649bb86e9 pref: 修改 accounts 2022-11-01 20:37:40 +08:00
“huailei000”
7b0e41d478 fix: 修复资产账号不能更新问题 2022-11-01 20:23:30 +08:00
Jiangjie.Bai
3127afbbc2 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-01 19:53:09 +08:00
Jiangjie.Bai
0d993c0b90 feat: 资产授权规则详情页面添加授权账号tab页,显示所有授权的账号列表 2022-11-01 19:52:58 +08:00
“huailei000”
424f688406 perf: 优化账号创建更新组件 2022-11-01 18:47:00 +08:00
ibuler
f2f0661ed3 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-11-01 17:19:59 +08:00
ibuler
14fd1a06fd pref: 修改 remote app deployments 2022-11-01 17:19:40 +08:00
Jiangjie.Bai
4a2ffc754f fix: 修复创建第三方用户时 need_update_password 默认为 true 的问题 2022-11-01 16:38:06 +08:00
“huailei000”
4c94694e78 perf: 调整账号历史密码展示字段 2022-11-01 14:15:38 +08:00
ibuler
f1b5a26f2d merge: with remote 2022-11-01 11:50:21 +08:00
ibuler
357daf2756 pref: 修改 applet host 2022-11-01 11:48:23 +08:00
“huailei000”
97f708b9ef fix: 修改快速更新参数 2022-10-31 20:04:07 +08:00
“huailei000”
91f6fe3965 perf: component UpdateToken 2022-10-31 19:58:29 +08:00
“huailei000”
85abb5937c perf: 优化账号模版创建、更新显示字段 2022-10-31 19:29:42 +08:00
feng
c03b08e8f2 perf: history secret 2022-10-31 17:37:21 +08:00
“huailei000”
f5cc891cc4 fix: 修改历史密码接口 2022-10-31 17:29:21 +08:00
“huailei000”
89de63edcd perf: 优化创建资产时模版导入账号 2022-10-31 17:07:52 +08:00
“huailei000”
8551426619 feat: 增加账号模版模块 2022-10-28 19:12:52 +08:00
Aaron3S
d8deab799e feat: 拆分ops 和task 菜单 2022-10-28 19:01:53 +08:00
“huailei000”
f4b09a76b8 fix: 修复创建资产时添加账号控制台报错问题 2022-10-28 15:38:13 +08:00
ibuler
32ec05e04c Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-10-27 20:00:04 +08:00
ibuler
ca6e20573f pref: 添加 applet host detail 2022-10-27 19:59:45 +08:00
Aaron3S
ae7e8df986 Merge remote-tracking branch 'origin/v3' into v3 2022-10-27 19:30:59 +08:00
Aaron3S
dc90a13671 feat: 任务列表 2022-10-27 19:30:15 +08:00
ibuler
f294cb4e9a Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-10-27 19:06:04 +08:00
ibuler
ba5a19582e pref: 修改 Applet Host 创建 2022-10-27 19:05:43 +08:00
“huailei000”
da4cc3de20 perf: 优化ZTree组件选择完左侧资产后进入资产详情在返回列表页面还保持之前选择的状态 2022-10-27 15:12:33 +08:00
ibuler
7b6ccf3f30 pref: 修改 dialog 布局 2022-10-26 16:04:38 +08:00
“huailei000”
13122b07d4 fix: 修复资产账号创建、更新报错问题 2022-10-25 16:43:57 +08:00
feng626
4effc3c3b4 Merge pull request #2121 from jumpserver/pr@v3@feat_account_password_history
feat: 资产账号增加查看历史密码
2022-10-25 14:00:13 +08:00
“huailei000”
fcc74f0ca3 merge v3 2022-10-25 13:55:24 +08:00
“huailei000”
8950d57ff8 feat: 资产账号增加查看历史密码 2022-10-24 14:57:45 +08:00
吴小白
d31929eb33 perf: 优化构建 2022-10-24 09:51:15 +08:00
ibuler
6398c54b49 perf: 拆分到不同组件 2022-10-20 18:03:31 +08:00
ibuler
0da88c6a61 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-10-20 15:43:23 +08:00
ibuler
e62bffd20a pref: 修改查看 account 2022-10-20 15:40:05 +08:00
“huailei000”
537cb70a89 fix: 创建资产时如果选择了节点显示默认节点 2022-10-20 14:49:19 +08:00
ibuler
173bbe52bd Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-10-20 14:48:37 +08:00
ibuler
b924fdc308 pref: 修改账号更新 2022-10-20 14:23:46 +08:00
“huailei000”
84a04ecfca fix: 修复资产账号创建账号失败问题 2022-10-20 11:13:45 +08:00
ibuler
3935643e35 pref: 修改资产创建 2022-10-19 18:21:04 +08:00
ibuler
91df9c8f1e pref: 修改 accounts 2022-10-19 11:40:33 +08:00
ibuler
e8db62f900 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-10-19 10:09:09 +08:00
Jiangjie.Bai
fe36fa9390 Merge pull request #2117 from jumpserver/dev
v2.27.0-rc4
2022-10-18 21:02:10 +08:00
“huailei000”
a97de8afb4 perf: 重置element-ui的message组件,防止重复点击重复弹出提示 2022-10-18 20:59:39 +08:00
“huailei000”
239d06bbcc fix: 资产账号创建、更新报错问题 2022-10-18 15:13:11 +08:00
Jiangjie.Bai
ba109900ec Merge pull request #2113 from jumpserver/dev
v2.27.0-rc3
2022-10-18 11:20:57 +08:00
“huailei000”
f8649457d6 perf: 优化页面布局 2022-10-18 10:34:18 +08:00
“huailei000”
8863693541 fix: 修复平台列表修复克隆名称带空格不能创建问题 2022-10-18 10:29:15 +08:00
ibuler
47a423284b perf: 修改平台 2022-10-17 17:21:59 +08:00
“huailei000”
c2cbd3f5b0 fix: 修复切换组织下拉框icon图标颜色不明显 2022-10-17 16:32:07 +08:00
“huailei000”
0b84b96afb fix: 修复终端设置-创建录像存储设置默认存储字段不生效问题 2022-10-17 14:50:43 +08:00
“huailei000”
2669c8fff0 feat: 调整资产详情账号列表显示字段 2022-10-14 18:00:00 +08:00
Jiangjie.Bai
ec7768267f Merge pull request #2105 from jumpserver/dev
v2.27.0-rc2
2022-10-14 11:01:32 +08:00
吴小白
4aefb6779f fix: 修正错误的构建参数 2022-10-14 10:52:14 +08:00
吴小白
06fd007c62 Revert "revert: 还原 dockerfile"
This reverts commit 6f4e029537.
2022-10-14 10:52:14 +08:00
ibuler
6f4e029537 revert: 还原 dockerfile 2022-10-14 10:29:27 +08:00
Jiangjie.Bai
cc58b374ab Merge pull request #2101 from jumpserver/dev
v2.27.0-rc1
2022-10-13 17:44:53 +08:00
“huailei000”
07f35dbbb2 fix: jQuery undefined 2022-10-13 17:41:08 +08:00
“huailei000”
ebaf97a495 perf: update account list 2022-10-13 16:06:03 +08:00
Jiangjie.Bai
04ffbb8fd6 Merge pull request #2097 from jumpserver/dev
v2.27.0-rc1
2022-10-13 15:14:40 +08:00
“huailei000”
12a501d559 perf: update jquery 2022-10-13 11:20:29 +08:00
feng626
7dcd4490ba Merge pull request #2093 from jumpserver/pr@dev@task_log
fix: 修复任务列表无法查看日志信息bug
2022-10-13 10:54:48 +08:00
feng626
dd1ac7c7f8 fix: 修复任务列表无法查看日志信息bug 2022-10-13 10:50:53 +08:00
“huailei000”
471910e0b8 pref: 作业中心任务详情添加查看输出快捷键 2022-10-12 19:13:08 +08:00
“huailei000”
4afb282ca2 fix: 修复创建资产时平台不准确问题 2022-10-12 16:26:46 +08:00
“huailei000”
a514e88b78 perf: 优化刷新页面方法,避免刷新时页面出现空白 2022-10-11 16:21:02 +08:00
“huailei000”
25f4f15e76 fix: 修复平台详情跳转到更新页面路由不准确问题 2022-10-10 18:22:42 +08:00
“huailei000”
60286f69ad fix: 添加默认菜单激活状态的文字颜色 2022-10-10 18:00:04 +08:00
“huailei000”
addd22ec6c fix: 修复平台详情操作权限不准确问题 2022-10-10 11:34:56 +08:00
Jiangjie.Bai
b79fefdee8 feat: 命令过滤器支持关联节点; 2022-10-09 19:02:17 +08:00
“huailei000”
0bab09e48e fix: 修复从平台列表页进入其他页面返回后列表数据显示不正确问题 2022-10-09 17:46:30 +08:00
Jiangjie.Bai
d2b3025709 perf: 优化用户创建默认勾选登录后需要修改密码 2022-10-09 16:57:02 +08:00
“huailei000”
cf234ca067 fix: 修复公共弹窗组件嵌套时遮罩层遮挡问题 2022-10-09 15:46:46 +08:00
“huailei000”
a908cc61c9 perf: update platform detail 2022-10-09 11:30:46 +08:00
吴小白
386e2417e3 Merge pull request #2075 from YonezawaYukar/dev
fix: 修正 Dockerfile
2022-10-08 09:38:21 +08:00
米泽由香里
fd57b37cea Update Dockerfile
修改一处错误
RUN重复两次 导致无法正常build
2022-10-04 03:28:10 +08:00
“huailei000”
b19c79f48c feat: 平台详情增加快速更新模块 2022-09-30 14:20:46 +08:00
吴小白
a6222f87d2 fix: 编译时修改版本 2022-09-30 10:08:14 +08:00
吴小白
5cd4e5b40b perf: 使用 yarn 构建 2022-09-30 10:08:14 +08:00
吴小白
eb3d9089e0 perf: 构建时使用缓存 2022-09-30 10:08:14 +08:00
Jiangjie.Bai
14f0fe1160 feat: 授权规则创建 2022-09-29 20:40:41 +08:00
feng626
21c8fd6e98 perf: 资产详情bug 2022-09-29 16:33:27 +08:00
“huailei000”
803ff92976 fix: 修复资产详情里账号创建不成功问题;资产里不显示系统用户 2022-09-29 11:05:34 +08:00
“huailei000”
5d74a975df fix: 修复资产详情字段展示;创建、更新资产页面报错问题 2022-09-27 14:49:55 +08:00
ibuler
25802db0d8 perf: 修改 platform 支持设置 ansible 2022-09-26 18:04:03 +08:00
ibuler
537a3d3ce8 pref: 修改平台创建 2022-09-26 17:23:04 +08:00
jiangweidong
56c22cffe6 perf: 优化短信配置错误提示不友好问题 2022-09-26 14:53:03 +08:00
“huailei000”
fe1e26957a fix: 修复全局组织下更新、删除:用户、端点、端点规则、组织权限 2022-09-26 14:52:16 +08:00
“huailei000”
bc366947f0 fix: 实例同步列表不显示多选框;设置云同步详情页面的菜单高亮显示;云同步进入详情不主动激活detail页卡 2022-09-26 14:51:06 +08:00
“huailei000”
86150cc571 fix: 修复账号信息内容更新不及时问题 2022-09-26 14:49:56 +08:00
ibuler
a0e124717b Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-09-23 19:00:00 +08:00
ibuler
320ba89aea perf: 修改资产中的账号创建 2022-09-23 18:59:42 +08:00
Jiangjie.Bai
f11fc947af feat: 修改 Endpoint 的创建页面; 修改 Oracle 数据库创建不包含版本号字段 2022-09-22 19:24:15 +08:00
feng626
8514444508 perf: ticket 2022-09-22 14:59:48 +08:00
ibuler
b194c0100f perf: change cateogory data strucature 2022-09-21 20:13:13 +08:00
ibuler
d7dedf15f1 perf: 修改平台选择 2022-09-21 19:59:18 +08:00
ibuler
c491fb6c40 perf: 优化平台 2022-09-21 18:48:52 +08:00
ibuler
0e3af4df5d perf: 修改资产创建 2022-09-21 11:17:35 +08:00
ibuler
32188dcef4 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-09-20 21:19:45 +08:00
ibuler
0a199a2588 perf: 优化平台 2022-09-20 21:19:29 +08:00
feng626
8f1893f665 Merge pull request #2067 from jumpserver/feat_component_cascader
perf: 修改账号备份表单字段配置
2022-09-20 19:36:10 +08:00
“huailei000”
4f765fe527 perf: 修改账号备份表单字段配置 2022-09-20 19:33:51 +08:00
ibuler
7eeb917e16 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-09-20 17:36:27 +08:00
ibuler
93d8d0f5bf perf: 优化平台 2022-09-20 17:32:58 +08:00
feng626
6db7cb4a6e perf 账号列表展示 2022-09-19 20:57:31 +08:00
feng626
602ea51bbf perf: account filter 2022-09-19 19:48:55 +08:00
feng626
ec3eab6e72 perf: 账号管理相关权限 2022-09-19 11:36:21 +08:00
ibuler
a8bb7811ed perf: 修改平台类别 2022-09-15 21:20:44 +08:00
Jiangjie.Bai
49880f6739 Merge pull request #2059 from jumpserver/dev
v2.26.0
2022-09-15 17:49:44 +08:00
“huailei000”
82faf0f99e perf: 资产详情-授权用户没有数据时显示暂无数据 2022-09-15 17:48:41 +08:00
ibuler
9ef9e656e2 perf: 修改资产创建 2022-09-15 17:29:29 +08:00
fit2bot
c4bc4a1d9b perf: 封装资产创建基本组件 (#2053)
Co-authored-by: “huailei000” <2280131253@qq.com>
Co-authored-by: 老广 <ibuler@qq.com>
2022-09-15 17:27:12 +08:00
ibuler
f50445032f perf: 修改 platform 的创建 2022-09-15 16:46:04 +08:00
Jiangjie.Bai
e6f98d58c4 Merge pull request #2057 from jumpserver/dev
v2.26.0-rc4
2022-09-15 16:18:03 +08:00
“huailei000”
3536a94976 fix: 修复全局组织下命令过滤不能创建 2022-09-15 15:59:53 +08:00
“huailei000”
45276010e0 fix: 创建数据库端口设置为必填项 2022-09-15 15:34:00 +08:00
“huailei000”
2e47f42366 fix: 修复批量命令列表可点击链接颜色 2022-09-15 15:33:41 +08:00
“huailei000”
dd6e9a1512 fix: 修复批量命令列表可点击链接颜色 2022-09-15 15:33:41 +08:00
ibuler
af00517102 merge: with remote 2022-09-13 19:47:55 +08:00
“huailei000”
9a3c251867 perf: 资产创建封装公共的初始化函数 2022-09-13 19:43:07 +08:00
ibuler
daa662ac27 perf: 修改 accounts 创建 2022-09-13 19:42:51 +08:00
Jiangjie.Bai
fd1f16d43c Merge pull request #2050 from jumpserver/dev
v2.26.0-rc2
2022-09-13 17:41:39 +08:00
feng626
24931a9f5a perf: 工单新增相关过滤 2022-09-13 15:33:22 +08:00
ibuler
f51924bf1d perf: 优化密码加密,如果没有key就不加密了 2022-09-13 15:32:53 +08:00
“huailei000”
f82257edb8 fix: 修复创建、更新用户后点击邀请用户接口404问题 2022-09-13 15:31:53 +08:00
jiangweidong
286e9894c0 perf: 屏蔽--secure参数,目前redis-cli版本为6.0,暂时用不到 2022-09-13 11:50:06 +08:00
ibuler
0157c42c52 perf: 平台影响资产创建 2022-09-08 21:19:18 +08:00
ibuler
ccfb7356eb perf: 修改平台和资产 2022-09-08 20:29:56 +08:00
ibuler
7fa7096d91 perf: 优化协议选择 2022-09-08 16:03:52 +08:00
Jiangjie.Bai
968b2415b1 Merge pull request #2043 from jumpserver/dev
v2.26.0-rc1
2022-09-08 15:46:44 +08:00
“huailei000”
e0f6fb305d perf: cas用户属性映射不能为空,至少设置username 2022-09-08 15:46:08 +08:00
jiangweidong
e0fd33f376 fix: 修复数据库创建页面有多个mongdob的问题 (#2041) 2022-09-08 15:16:54 +08:00
ibuler
c5972f1b59 perf: 解决 form group 不隐藏的问题 2022-09-08 15:11:18 +08:00
ibuler
c2d97b58ee perf: 修改 protocols 2022-09-07 18:22:25 +08:00
ibuler
c97b3ffbdf perf: 修改 protocol selector 2022-09-07 17:19:40 +08:00
jiangweidong
7ad86062b4 perf: 支持连接开启ssl且自签证书的Redis/MongoDB (#2039)
* perf: 支持连接开启ssl且自签证书的Redis/MongoDB

* 修改字段文案

* 修改字段名称

* 修改变量名
2022-09-07 16:09:07 +08:00
“huailei000”
3ec02a299c fix: 修复所有资产创建显示问题 2022-09-07 15:03:38 +08:00
“huailei000”
1fce7561db fix: 修复用户首次登录页面翻译 2022-09-06 19:38:49 +08:00
“huailei000”
3b17235b6e fix: 批量更新不请求接口 2022-09-06 19:06:14 +08:00
jiangweidong
52c9b9503b feat: 支持MFA可配置华为云平台短信对接 2022-09-06 17:33:42 +08:00
Jiangjie.Bai
48a2b20320 Merge pull request #2025 from jumpserver/pr@dev@feat_cloud_support_ctyun_private
feat: 云同步支持同步天翼私有云平台资产
2022-09-06 17:31:01 +08:00
Jiangjie.Bai
e6cc8cd2e8 Merge branch 'dev' into pr@dev@feat_cloud_support_ctyun_private 2022-09-06 17:30:47 +08:00
jiangweidong
3a183ddf53 feat: 支持OAuth2协议自定义注销功能 2022-09-06 17:27:11 +08:00
jiangweidong
7eb77487d1 feat: feat: 支持连接开启了ssl的Redis数据库 2022-09-06 16:55:37 +08:00
“huailei000”
2cffb5c952 fix: 修复克隆路由问题;批量更新显示问题 2022-09-06 16:47:58 +08:00
jiangweidong
a5da581317 feat: 云同步支持资产同步腾讯云(轻量应用服务器) 2022-09-06 16:19:58 +08:00
“huailei000”
03ca2d614f fix: 修复资产详情更新路由跳转地址 2022-09-06 14:14:18 +08:00
“huailei000”
17bf2b0611 fix: 修复资产列表baseList传参 2022-09-06 10:47:25 +08:00
ibuler
8c178d92de Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-09-05 20:57:15 +08:00
ibuler
c0a3251f44 perf: 配合后端升级 object related field 2022-09-05 20:17:51 +08:00
“huailei000”
bfdc6b4504 fix: 修复资产列表table组件点击资产树列表不刷新问题 2022-09-05 17:05:47 +08:00
“huailei000”
6bda9a372e fix: moment.js 插件升级修复官方漏洞 2022-09-05 13:55:52 +08:00
jiangweidong
a8de087137 feat: 云同步支持同步天翼私有云平台资产 2022-09-02 17:37:27 +08:00
ibuler
bfdf09908e perf: 修改 host 2022-09-01 20:59:46 +08:00
ibuler
80afe04aa9 perf: 修改平台创建 2022-09-01 17:42:30 +08:00
ibuler
a9e38b2be6 perf: 修改 v3 2022-09-01 15:06:39 +08:00
ibuler
22738982cb Merge remote-tracking branch 'origin/v3' into v3 2022-08-31 16:16:19 +08:00
“huailei000”
757c6ef44c fix: 修复切换tab路由参数不能添加问题;修复创建云平台页面空白问题; 2022-08-31 16:04:37 +08:00
ibuler
bf6025c971 Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-08-31 10:33:04 +08:00
“huailei000”
4252fb6533 feat: 平台选择添加最近选择的平台;云同步只在主机中保留;平台选择某种类型时不带类别; 2022-08-31 10:32:37 +08:00
ibuler
e451930e7b perf: 添加支持新的 choice 2022-08-31 10:00:12 +08:00
ibuler
09d6f7b82b Merge remote-tracking branch 'origin/v3' into v3 2022-08-30 17:25:48 +08:00
feng626
0f9bcda6ca 账号备份类型 2022-08-30 15:31:09 +08:00
ibuler
cd367fb0d5 perf: 修改 platform ops 2022-08-30 14:54:12 +08:00
ibuler
cd7010dccb Merge branch 'v3' of github.com:jumpserver/lina into v3 2022-08-29 18:30:54 +08:00
ibuler
3136319352 perf: 修改平台 2022-08-29 18:30:47 +08:00
“huailei000”
eb00b5f1ca feat: 创建资产相关页面;配置路由; 2022-08-29 18:20:28 +08:00
ibuler
b4377e0746 perf: 修改 platform ops 2022-08-29 15:59:28 +08:00
“huailei000”
5f1d67ee21 feat: 创建表单分类选择 2022-08-29 10:42:51 +08:00
ibuler
e932cb2456 perf: 修改 hostname 为 name 2022-08-24 19:32:20 +08:00
ibuler
85abefff74 perf: 去掉 applications perm 2022-08-24 16:17:36 +08:00
jiangweidong
34d9790a04 feat: MongoDB支持连接SSL类型 2022-08-24 15:00:56 +08:00
“huailei000”
5bfe2497fd fix: 修复新建用户个人信息确认后跳转路由还会返回个人信息确认页问题 2022-08-24 14:48:08 +08:00
jiangweidong
e16a775037 feat: 改密计划支持MongoDB改密 2022-08-24 14:47:46 +08:00
ibuler
ee4a9a967b perf: 去掉 applications 2022-08-23 20:01:51 +08:00
ibuler
a3d3dcc44c perf: 修改资产 2022-08-23 13:43:13 +08:00
ibuler
75fbfab95d perf: 修改 asset 2022-08-19 19:42:14 +08:00
ibuler
d48a61c597 perf: 修改 platform list 和 asset list 2022-08-19 19:38:24 +08:00
“huailei000”
42fab92237 fix: 调整按钮大小 2022-08-19 16:24:29 +08:00
Jiangjie.Bai
e2eac83615 fix: 修复上传json文件上传问题 2022-08-19 13:36:22 +08:00
“huailei000”
04465a1da3 fix: 修复LDAP用户导入失败弹出提示 2022-08-19 11:05:31 +08:00
“huailei000”
2adb1ee980 fix: 升级lodash 2022-08-19 11:04:43 +08:00
ibuler
01919a496e perf: 修改平台和资产 2022-08-18 17:59:18 +08:00
ibuler
1bfe5eed15 perf: 修改账号创建 2022-08-15 18:32:13 +08:00
ibuler
d311884ec0 perf: 修改 添加 account 2022-08-11 16:26:16 +08:00
ibuler
1291b693f0 perf: 修改 protocol 2022-08-10 19:26:28 +08:00
ibuler
df15fd497d pref: 修改 nestfield 2022-08-09 16:53:17 +08:00
ibuler
23ec8e4687 perf: 修改 select2 2022-08-09 13:28:36 +08:00
ibuler
2f7e3bbc85 perf: 修改 host 2022-08-09 10:43:01 +08:00
ibuler
690757b225 perf: 修改展现方式 2022-08-08 15:32:21 +08:00
ibuler
d3e3561407 v3 init 2022-08-03 16:31:36 +08:00
ibuler
2e7c48a999 perf: 修改 account 2022-07-28 18:50:05 +08:00
ibuler
76d9a69220 perf: 修改 rdp 2022-07-19 18:58:44 +08:00
ibuler
6388eed6e3 perf: 修改系统用户列表 2022-07-19 18:03:16 +08:00
ibuler
90d737773d perf: 优化修改添加账号 2022-07-17 13:56:43 +08:00
ibuler
4f23c40598 perf: 重构账号 2022-07-15 18:57:38 +08:00
ibuler
7bb16515b1 stash it 2022-06-16 11:35:23 +08:00
ibuler
36bb2cf62f perf: 修改 base model 2022-05-05 16:17:35 +08:00
ibuler
d7f7650e3a stash: 平台先这样,等待怀磊搞 2022-05-05 10:58:49 +08:00
ibuler
348847e196 perf: 修改 platform 2022-05-05 09:54:38 +08:00
ibuler
95b2650a8a stash it 2022-05-04 09:57:58 +08:00
ibuler
14935cb2f7 perf: 修改平台 2022-05-02 21:29:58 +08:00
ibuler
f059640602 perf: 优化选择 2022-05-01 12:20:44 +08:00
ibuler
22fe547215 perf: 优化 protocols 2022-05-01 10:42:53 +08:00
ibuler
2612134273 perf: 设置 platform 2022-04-30 23:19:16 +08:00
ibuler
9630d8200c stash 2022-04-29 18:29:50 +08:00
ibuler
0a5bfa5a55 perf: 添加平台选择 2022-04-28 18:54:48 +08:00
ibuler
29e51e92a4 stash 2022-04-28 15:52:10 +08:00
ibuler
bd935e9dc2 stash it 2022-04-26 22:22:18 +08:00
ibuler
2edee985fa perf: 添加主机和网络设备 2022-04-25 16:48:19 +08:00
ibuler
7afa58319f perf: .. 2022-04-21 15:24:43 +08:00
ibuler
7d3d4ab73c perf: 修改 .. 2022-04-19 15:31:45 +08:00
760 changed files with 38027 additions and 22198 deletions

View File

@@ -4,11 +4,17 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{js,jsx,ts,tsx,vue}]
indent_size = 2
[*.py]
indent_size = 4
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

32
.github/workflows/jms-build-test.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: "Run Build Test"
on:
push:
branches:
- pr@*
- repr@*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v3
with:
context: .
push: false
tags: jumpserver/lina:test
file: Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max
- uses: LouisBrunner/checks-action@v1.5.0
if: always()
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: Check Build
conclusion: ${{ job.status }}

View File

@@ -31,6 +31,9 @@ jobs:
config-name: release-config.yml
version: ${{ steps.get_version.outputs.TAG }}
tag: ${{ steps.get_version.outputs.TAG }}
- uses: actions/setup-node@v2
with:
node-version: '14.16'
build-and-release:
needs: create-realese
@@ -39,7 +42,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Build it and upload
uses: jumpserver/action-build-upload-assets@node10
uses: jumpserver/action-build-upload-assets@node14.16
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@ tests/**/coverage/
*.njsproj
*.sln
.env.development
.python-version

View File

@@ -1,23 +1,24 @@
FROM node:10 as stage-build
FROM node:14.16 as stage-build
ARG TARGETARCH
ARG NPM_REGISTRY="https://registry.npmmirror.com"
ENV NPM_REGISTY=$NPM_REGISTRY
ARG SASS_BINARY_SITE="https://npmmirror.com/mirrors/node-sass"
ENV SASS_BINARY_SITE=$SASS_BINARY_SITE
WORKDIR /data
RUN npm config set sass_binary_site=${SASS_BINARY_SITE}
RUN npm config set registry ${NPM_REGISTRY}
RUN yarn config set registry ${NPM_REGISTRY}
COPY package.json yarn.lock /data/
RUN yarn install
RUN npm rebuild node-sass
RUN set -ex \
&& npm config set registry ${NPM_REGISTRY} \
&& yarn config set registry ${NPM_REGISTRY}
ADD package.json yarn.lock /data
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn,sharing=locked,id=lina \
yarn install
ARG VERSION
ENV VERSION=$VERSION
ADD . /data
RUN cd utils && bash -xieu build.sh build
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn,sharing=locked,id=lina \
sed -i "s@version-dev@${VERSION}@g" src/layout/components/NavHeader/About.vue \
&& yarn build
FROM nginx:alpine
COPY --from=stage-build /data/release/lina /opt/lina
FROM nginx:1.24
COPY --from=stage-build /data/lina /opt/lina
COPY nginx.conf /etc/nginx/conf.d/default.conf

1
GITSHA Normal file
View File

@@ -0,0 +1 @@
17fd374e0adc7a7a9992dfe4f86fa4125974ec85

View File

@@ -7,17 +7,21 @@
"scripts": {
"dev": "vue-cli-service serve",
"serve": "vue-cli-service serve",
"build": "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",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icas/svgo.yml",
"vue-i18n-extract": "vue-i18n-extract",
"vue-i18n-report": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json'",
"vue-i18n-report-json": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -o /tmp/abc.json",
"vue-i18n-report-add-miss": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -a"
"vue-i18n-report-add-miss": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -a",
"diff-i18n": "python ./src/i18n/langs/i18n-util.py diff en ja",
"apply-i18n": "python ./src/i18n/langs/i18n-util.py apply en ja"
},
"dependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
@@ -32,7 +36,7 @@
"element-ui": "2.13.2",
"eslint-plugin-html": "^6.0.0",
"install": "^0.13.0",
"jquery": "^3.5.0",
"jquery": "^3.6.1",
"js-cookie": "2.2.0",
"jsencrypt": "^3.2.1",
"krry-transfer": "^1.7.3",
@@ -50,24 +54,26 @@
"lodash.set": "^4.3.2",
"lodash.topairs": "^4.3.0",
"lodash.values": "^4.3.0",
"moment": "^2.29.1",
"moment-parseformat": "^3.0.0",
"moment": "^2.29.4",
"moment-parseformat": "^4.0.0",
"normalize.css": "7.0.0",
"npm": "^7.8.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"vue": "2.6.10",
"vue-codemirror-lite": "^1.0.4",
"vue-codemirror": "4.0.6",
"vue-cookie": "^1.1.4",
"vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.15.5",
"vue-json-editor": "^1.4.3",
"vue-markdown": "^2.2.4",
"vue-moment": "^4.1.0",
"vue-password-strength-meter": "^1.7.2",
"vue-router": "3.0.6",
"vue-select": "^3.9.5",
"vuejs-logger": "^1.5.4",
"vuex": "3.1.0",
"xss": "^1.0.14",
"xterm": "^4.5.0",
"xterm-addon-fit": "^0.3.0",
"zxcvbn": "^4.4.2"
@@ -91,6 +97,7 @@
"eslint": "^5.15.3",
"eslint-plugin-vue": "5.2.2",
"eslint-plugin-vue-i18n": "^0.3.0",
"github-markdown-css": "^5.1.0",
"html-webpack-plugin": "3.2.0",
"husky": "^4.2.3",
"less-loader": "^5.0.0",

View File

@@ -17,9 +17,15 @@
</noscript>
<script>
window.onload = function() {
const baseUrl = "/ui/"
if (location.pathname === '/' && baseUrl !== '/') {
location.pathname = baseUrl
if (location.pathname === '/') {
location.pathname = '/ui/'
}
const pathname = window.location.pathname
if (pathname.startsWith('/core')) {
return
}
if(pathname.indexOf('/ui') === -1) {
window.location.href = window.location.origin + '/ui/#' + pathname
}
}
</script>

View File

@@ -194,17 +194,16 @@ td .el-button.el-button--mini {
line-height: 34px;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
color: #606266;
background-color: #ddd;
font-weight: 400;
}
.el-select-dropdown__item.hover {
.option-group .el-select-dropdown__item.hover, .option-group .el-select-dropdown__item.selected {
background-color: primary;
color: white;
}
.option-group:has(.hover) .el-select-dropdown__item.selected {
background-color: light-2;
}
.el-select-dropdown__item.is-disabled:hover{
color:#c0c4cc;
}
@@ -215,7 +214,7 @@ td .el-button.el-button--mini {
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover {
color: white;
background-color: primary;
background-color: light-4;
}
.el-tag.el-tag--info {
@@ -247,6 +246,15 @@ td .el-button.el-button--mini {
border-top-color: #676a6c;
}
.text-link {
color: info!important;
}
.text-link:hover {
color: info!important;
filter: opacity(65%)!important;
}
.text-danger {
color: danger;
}
@@ -322,13 +330,12 @@ td .el-button.el-button--mini {
}
.el-table .cell,
.el-table--border td:first-child .cell,
.el-table--border th:first-child .cell {
.el-table td:first-child .cell,
.el-table th:first-child .cell {
padding-left: 10px;
padding-right: 14px;
}
.el-tag--default.el-tag--dark {
background-color: #d1dade;
color: #5e5e5e;
@@ -444,11 +451,56 @@ td .el-button.el-button--mini {
.el-select-dropdown__item.selected {
font-weight: 400;
color: #606266;
background-color: #ddd;
color: white;
background-color: primary;
}
.el-input-group__prepend div.el-select .el-input__inner,
.el-input-group__prepend div.el-select .el-input__inner:hover {
color: #303133;
}
.el-input-group__append, .el-input-group__prepend {
color: primary
}
.el-input.is-disabled .el-input__inner {
color: $--color-text-primary;
cursor: not-allowed;
}
.el-step__description.is-finish {
color: #676a6c;
}
.el-alert {
border: solid 1px #e7eaec;
}
.el-alert.el-alert--success.is-light {
border-color: var(--color-success-light);
}
.el-alert.el-alert--primary.is-light {
border-color: var(--color-primary-light);
}
.el-alert.el-alert--info.is-light {
border-color: var(--color-info-light);
}
.el-alert.el-alert--warning.is-light {
border-color: var(--color-warning-light);
}
.el-alert.el-alert--error.is-light {
border-color: var(--color-danger-light);
}
#nprogress .bar {
background: light-5!important;
}
#nprogress .peg {
box-shadow: 0 0 10px light-5, 0 0 5px light-5!important;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,19 @@
<template>
<div id="app">
<router-view />
<router-view v-if="isRouterAlive" />
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'App'
name: 'App',
computed: {
...mapState({
isRouterAlive: state => state.common.isRouterAlive
})
}
}
</script>

View File

@@ -40,3 +40,10 @@ export function getCommandFilterList(data) {
})
}
export function getCategoryTypes() {
return request({
url: '/api/v1/assets/categories/',
method: 'get'
})
}

View File

@@ -1,6 +1,13 @@
import request from '@/utils/request'
export function createSourceIdCache(ids) {
ids = ids.map(item => {
if (typeof item === 'object' && item.id) {
return item.id
} else {
return item
}
})
return request({
url: '/api/v1/common/resources/cache/',
method: 'post',

View File

@@ -1,12 +1,5 @@
import request from '@/utils/request'
export function getTaskDetail(id) {
return request({
url: `/api/v1/ops/tasks/${id}/`,
method: 'get'
})
}
export function getAdhocDetail(id) {
return request({
url: `/api/v1/ops/adhoc/${id}/`,
@@ -20,3 +13,34 @@ export function getHistoryExecutionDetail(id) {
method: 'get'
})
}
export function getTaskDetail(id) {
return request({
url: `/api/v1/ops/job-execution/task-detail/${id}/`,
method: 'get'
})
}
export function getJob(id) {
return request({
url: `/api/v1/ops/jobs/${id}/`,
method: 'get'
})
}
export function uploadPlaybook(form) {
return request({
url: '/api/v1/ops/playbooks/',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' },
data: form
})
}
export function renameFile(playbookId, node) {
return request({
url: `/api/v1/ops/playbook/${playbookId}/file/`,
method: 'patch',
data: node
})
}

View File

@@ -1,43 +0,0 @@
import request from '@/utils/request'
export function getAssetPermissionDetail(id) {
return request({
url: `/api/v1/perms/asset-permissions/${id}/`,
method: 'get'
})
}
export function getRemoteAppPermissionDetail(id) {
return request({
url: `/api/v1/perms/remote-app-permissions/${id}/`,
method: 'get'
})
}
export function getDatabaseAppPermissionDetail(id) {
return request({
url: `/api/v1/perms/database-app-permissions/${id}/`,
method: 'get'
})
}
export function getUserAssetGrantedSystemUsers(userId, assetId) {
return request({
url: `/api/v1/perms/users/${userId}/assets/${assetId}/system-users/?cache_policy=1`,
method: 'get'
})
}
export function getMyAssetGrantedSystemUsers(userId, assetId) {
return request({
url: `/api/v1/perms/users/assets/${assetId}/system-users/?cache_policy=1`,
method: 'get'
})
}
export function getUserGroupAssetGrantedSystemUsers(gId, assetId) {
return request({
url: `/api/v1/perms/user-groups/${gId}/assets/${assetId}/system-users/?cache_policy=1`,
method: 'get'
})
}

View File

@@ -25,12 +25,28 @@ export function importLicense(formData) {
data: formData
})
}
export function testLdapSetting(data) {
return request({
disableFlashErrorMsg: true,
url: '/api/v1/settings/ldap/testing/config/',
method: 'post',
data: data
export function testLdapSetting(data, refresh = true) {
let url = '/api/v1/settings/ldap/testing/config/'
if (refresh) {
url = url + '?refresh=1'
}
return new Promise((resolve, reject) => {
request({
disableFlashErrorMsg: true,
url: url,
method: 'post',
data: data
}).then(res => {
if (res.status !== 'running') {
resolve(res)
} else {
setTimeout(() => {
resolve(testLdapSetting(data, false))
}, 1000)
}
}).catch(error => {
reject(error)
})
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

BIN
src/assets/img/avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,321 @@
<template>
<AutoDataForm
v-if="!loading"
ref="AutoDataForm"
v-bind="$data"
@submit="confirm"
/>
</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 { encryptPassword } from '@/utils/crypto'
import { Required, RequiredChange } from '@/components/DataForm/rules'
import AutomationParamsForm from '@/views/assets/Platform/AutomationParamsSetting.vue'
export default {
name: 'AccountCreateForm',
components: {
AutoDataForm
},
props: {
asset: {
type: Object,
default: null
},
platform: {
type: Object,
default: null
},
account: {
type: Object,
default: () => ({})
},
// 默认组件密码加密
encryptPassword: {
type: Boolean,
default: true
},
addTemplate: {
type: Boolean,
default: false
}
},
data() {
return {
loading: true,
usernameChanged: false,
defaultPrivilegedAccounts: ['root', 'administrator'],
iPlatform: {
automation: {},
su_enabled: false,
protocols: [
{
name: 'ssh',
secret_types: ['password', 'ssh_key', 'token', 'access_key', 'api_key']
}
]
},
url: '/api/v1/accounts/accounts/',
form: Object.assign({ 'on_invalid': 'error' }, this.account || {}),
encryptedFields: ['secret'],
fields: [
[this.$t('assets.Asset'), ['assets']],
[this.$t('accounts.AccountTemplate'), ['template']],
[this.$t('common.Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username']],
[this.$t('assets.Secret'), [
'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key'
]],
[this.$t('common.Other'), ['push_now', 'params', 'on_invalid', 'is_active', 'comment']]
],
fieldsMeta: {
assets: {
rules: [Required],
component: AssetSelect,
label: this.$t('assets.Asset'),
el: {
multiple: false
},
hidden: () => {
return this.platform || this.asset
}
},
template: {
component: Select2,
rules: [Required],
el: {
multiple: false,
ajax: {
url: '/api/v1/accounts/account-templates/',
transformOption: (item) => {
return { label: item.name, value: item.id }
}
}
},
hidden: () => {
return this.platform || this.asset || !this.addTemplate
}
},
on_invalid: {
rules: [Required],
label: this.$t('accounts.AccountPolicy'),
helpText: this.$t('accounts.BulkCreateStrategy'),
hidden: () => {
return this.platform || this.asset
}
},
name: {
rules: [RequiredChange],
on: {
input: ([value], updateForm) => {
if (!this.usernameChanged) {
if (!this.account?.name) {
updateForm({ username: value })
}
const maybePrivileged = this.defaultPrivilegedAccounts.includes(value)
if (maybePrivileged) {
updateForm({ privileged: true })
}
}
}
},
hidden: () => {
return this.addTemplate
}
},
username: {
el: {
disabled: !!this.account?.name
},
on: {
input: ([value], updateForm) => {
this.usernameChanged = true
},
change: ([value], updateForm) => {
const maybePrivileged = this.defaultPrivilegedAccounts.includes(value)
if (maybePrivileged) {
updateForm({ privileged: true })
}
}
},
hidden: () => {
return this.addTemplate
}
},
privileged: {
hidden: () => {
return this.addTemplate
}
},
su_from: {
component: Select2,
hidden: (formValue) => {
return !this.asset?.id || !this.iPlatform.su_enabled
},
el: {
multiple: false,
clearable: true,
ajax: {
url: `/api/v1/accounts/accounts/su-from-accounts/?account=${this.account?.id || ''}&asset=${this.asset?.id || ''}`,
transformOption: (item) => {
return { label: `${item.name}(${item.username})`, value: item.id }
}
}
}
},
su_from_username: {
label: this.$t('assets.UserSwitchFrom'),
hidden: (formValue) => {
return this.platform || this.asset || this.addTemplate
}
},
password: {
label: this.$t('assets.Password'),
component: UpdateToken,
hidden: (formValue) => formValue.secret_type !== 'password' || this.addTemplate
},
ssh_key: {
label: this.$t('assets.PrivateKey'),
component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || this.addTemplate
},
passphrase: {
label: this.$t('assets.Passphrase'),
component: UpdateToken,
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || this.addTemplate
},
token: {
label: this.$t('assets.Token'),
component: UploadSecret,
hidden: (formValue) => formValue.secret_type !== 'token' || this.addTemplate
},
access_key: {
id: 'access_key',
label: this.$t('assets.AccessKey'),
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: [],
hidden: () => {
return this.addTemplate
}
},
push_now: {
helpText: this.$t('accounts.AccountPush.WindowsPushHelpText'),
hidden: () => {
const automation = this.iPlatform.automation || {}
return !automation.push_account_enabled ||
!automation.ansible_enabled ||
!this.$hasPerm('accounts.push_account') ||
this.addTemplate
}
},
params: {
label: this.$t('assets.PushParams'),
component: AutomationParamsForm,
el: {
method: this.asset?.auto_config?.push_account_method
},
hidden: (formValue) => {
const automation = this.iPlatform.automation || {}
return !formValue.push_now ||
!automation.push_account_enabled ||
!automation.ansible_enabled ||
!this.$hasPerm('accounts.push_account') ||
this.addTemplate
}
},
comment: {
hidden: () => {
return this.addTemplate
}
}
},
hasSaveContinue: false
}
},
async mounted() {
try {
await this.getPlatform()
this.setSecretTypeOptions()
} finally {
this.loading = false
}
},
methods: {
async getPlatform() {
if (this.platform) {
this.iPlatform = this.platform
}
if (!this.asset || !this.asset.platform) {
return
}
const platformId = this.asset.platform.id
this.iPlatform = await this.$axios.get(`/api/v1/assets/platforms/${platformId}/`)
},
setSecretTypeOptions() {
const choices = [
{
label: this.$t('assets.Password'),
value: 'password'
},
{
label: this.$t('assets.SSHKey'),
value: 'ssh_key'
},
{
label: this.$t('assets.Token'),
value: 'token'
},
{
label: this.$t('assets.AccessKey'),
value: 'access_key'
},
{
label: this.$t('assets.ApiKey'),
value: 'api_key'
}
]
const secretTypes = []
this.iPlatform.protocols?.forEach(p => {
secretTypes.push(...p['secret_types'])
})
if (!this.form?.secret_type) {
this.form.secret_type = secretTypes[0]
}
this.fieldsMeta.secret_type.options = choices.filter(item => {
return secretTypes.indexOf(item.value) > -1
})
},
confirm(form) {
const secretType = form.secret_type || 'password'
form.secret = form[secretType]
form.secret = this.encryptPassword ? encryptPassword(form.secret) : form.secret
if (!form.secret) {
delete form['secret']
}
if (this.account?.name) {
this.$emit('edit', form)
} else {
this.$emit('add', form)
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,156 +0,0 @@
<template>
<div>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" :help-message="title" />
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
</div>
</template>
<script>
import { ActionsFormatter, DetailFormatter, DisplayFormatter } from '@/components/TableFormatters'
import ShowSecretInfo from '../AccountListTable/ShowSecretInfo'
import { GenericListPage } from '@/layout/components'
export default {
name: 'AccountHistoryTable',
components: {
GenericListPage,
ShowSecretInfo
},
props: {
url: {
type: String,
required: true
},
exportUrl: {
type: String,
default() {
return this.url.replace('/assets/accounts-history/', '/assets/account-history-secrets/')
}
},
hasLeftActions: {
type: Boolean,
default: false
},
otherActions: {
type: Array,
default: null
},
hasClone: {
type: Boolean,
default: false
}
},
data() {
const vm = this
return {
showViewSecretDialog: false,
account: {},
tableConfig: {
url: this.url,
permissions: {
app: 'assets',
resource: 'authbook'
},
columns: [
'hostname', 'ip', 'username', 'version',
'systemuser', 'date_created', 'date_updated', 'actions'
],
columnsShow: {
min: ['username', 'actions'],
default: ['hostname', 'ip', 'username', 'version', 'actions']
},
columnsMeta: {
hostname: {
prop: 'hostname',
label: this.$t('assets.Hostname'),
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
can: this.$hasPerm('assets.view_asset'),
getRoute({ row }) {
return {
name: 'AssetDetail',
params: { id: row.asset }
}
}
}
},
ip: {
width: '120px'
},
username: {
showOverflowTooltip: true
},
systemuser: {
formatter: DisplayFormatter
},
version: {
width: '70px'
},
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'),
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
can: this.$hasPerm('assets.view_assethistoryaccountsecret'),
type: 'primary',
callback: ({ row }) => {
vm.account = row
vm.showViewSecretDialog = true
}
}
]
}
}
}
},
headerActions: {
hasLeftActions: this.hasLeftActions,
hasMoreActions: false,
hasCreate: false,
hasImport: false,
hasExport: this.$hasPerm('assets.view_assethistoryaccountsecret'),
exportOptions: {
url: this.exportUrl,
mfaVerifyRequired: true
},
searchConfig: {
exclude: ['systemuser', 'asset']
},
hasSearch: true
}
}
},
computed: {
title() {
return this.$t('accounts.AccountHistableHelpMessage')
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
this.$set(this.headerActions.exportOptions, 'url', iNew.replace('/accounts-history/', '/account-history-secrets/'))
}
},
mounted() {
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
},
methods: {
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -0,0 +1,178 @@
<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"
>
<AccountCreateUpdateForm
v-if="!loading"
ref="form"
:account="account"
:add-template="addTemplate"
:asset="asset"
@add="addAccount"
@edit="editAccount"
/>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
import AccountCreateUpdateForm from '@/components/AccountCreateUpdateForm'
export default {
name: 'CreateAccountDialog',
components: {
Dialog,
AccountCreateUpdateForm
},
props: {
visible: {
type: Boolean,
default: false
},
addTemplate: {
type: Boolean,
default: false
},
asset: {
type: Object,
default: null
},
account: {
type: Object,
default: () => ({})
},
title: {
type: String,
default: function() {
return this.$t('assets.AddAccount')
}
}
},
data() {
return {
loading: false,
platform: {}
}
},
computed: {
protocols() {
return this.asset ? this.asset.protocol : []
},
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
methods: {
addAccount(form) {
const formValue = Object.assign({}, form)
let data, url, iVisible
if (this.asset) {
data = {
asset: this.asset.id,
...formValue
}
iVisible = false
url = `/api/v1/accounts/accounts/`
} else {
iVisible = true
data = formValue
url = `/api/v1/accounts/accounts/bulk/`
if (data.assets.length === 0) {
this.$message.error(this.$tc('assets.PleaseSelectAsset'))
return
}
}
this.$axios.post(url, data, {
disableFlashErrorMsg: iVisible
}).then((data) => {
this.handleResult(data, null)
this.iVisible = iVisible
if (!iVisible) {
this.$emit('add', true)
}
}).catch(error => {
this.iVisible = true
this.handleResult(null, error)
})
},
editAccount(form) {
const data = { ...form }
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, data).then(() => {
this.iVisible = false
this.$emit('add', true)
this.$message.success(this.$tc('common.updateSuccessMsg'))
}).catch(error => this.setFieldError(error))
},
handleResult(resp, error) {
let bulkCreate = !this.asset
if (error && !Array.isArray(error?.response?.data)) {
bulkCreate = false
}
if (resp && !Array.isArray(resp)) {
bulkCreate = false
}
if (!bulkCreate) {
if (!error) {
this.$message.success(this.$tc('common.createSuccessMsg'))
} else {
this.setFieldError(error)
}
} else {
let result
if (error) {
result = error.response.data
} else {
result = resp
}
this.$emit('bulk-create-done', result)
}
},
setFieldError(error) {
const response = error.response
const data = response.data
const refsAutoDataForm = this.$refs.form.$refs.AutoDataForm
if (response.status === 400) {
for (const key of Object.keys(data)) {
let err = ''
let current = key
let errorTips = data[current]
if (errorTips instanceof Array) {
errorTips = _.filter(errorTips, (item) => Object.keys(item).length > 0)
for (const i of errorTips) {
if (i instanceof Object) {
err += i?.port?.join(',')
} else {
err += errorTips
}
}
} else {
err = errorTips
}
if (current === 'secret') {
current = refsAutoDataForm.form.secret_type?.value || key
}
refsAutoDataForm.setFieldError(current, err)
}
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,438 @@
<template>
<div>
<ListTable ref="ListTable" :header-actions="headerActions" :table-config="tableConfig" />
<ViewSecret
v-if="showViewSecretDialog"
:account="account"
:url="secretUrl"
:visible.sync="showViewSecretDialog"
/>
<UpdateSecretInfo
v-if="showUpdateSecretDialog"
:account="account"
:visible.sync="showUpdateSecretDialog"
@updateAuthDone="onUpdateAuthDone"
/>
<AccountCreateUpdate
v-if="showAddDialog"
:account="account"
: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"
:title="accountCreateUpdateTitle"
:visible.sync="showAddTemplateDialog"
@add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)"
/>
<ResultDialog
v-if="showResultDialog"
:result="createAccountResults"
:visible.sync="showResultDialog"
/>
</div>
</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 { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms'
import ResultDialog from './BulkCreateResultDialog.vue'
export default {
name: 'AccountListTable',
components: {
ResultDialog,
ListTable,
UpdateSecretInfo,
ViewSecret,
AccountCreateUpdate
},
props: {
url: {
type: String,
required: true
},
exportUrl: {
type: String,
default() {
return this.url.replace('/accounts/accounts/', '/accounts/account-secrets/')
}
},
hasLeftActions: {
type: Boolean,
default: false
},
otherActions: {
type: Array,
default: null
},
hasClone: {
type: Boolean,
default: false
},
asset: {
type: Object,
default: null
},
columns: {
type: Array,
default: () => []
},
hasExport: {
type: Boolean,
default: true
},
hasImport: {
type: Boolean,
default: true
},
hasDeleteAction: {
type: Boolean,
default: true
},
columnsMeta: {
type: Object,
default: () => {
}
},
columnsDefault: {
type: Array,
default: () => ([
'name', 'username', 'asset', 'privileged',
'secret_type', 'date_updated'
])
},
headerExtraActions: {
type: Array,
default: () => []
}
},
data() {
const vm = this
return {
showViewSecretDialog: false,
showUpdateSecretDialog: false,
showResultDialog: false,
showAddDialog: false,
showAddTemplateDialog: false,
createAccountResults: [],
accountCreateUpdateTitle: this.$t('assets.AddAccount'),
iAsset: this.asset,
account: {},
secretUrl: '',
tableConfig: {
url: this.url,
permissions: {
app: 'assets',
resource: 'account'
},
extraQuery: {
order: '-date_updated'
},
columnsExclude: ['spec_info'],
columns: [
'name', 'username', 'asset', 'privileged',
'secret_type', 'source', 'actions'
],
columnsShow: {
min: ['name', 'username', 'actions'],
default: this.columnsDefault
},
columnsMeta: {
name: {
formatter: function(row) {
const to = {
name: 'AssetAccountDetail',
params: { id: row.id }
}
if (vm.$hasPerm('accounts.view_account')) {
return <router-link to={to}>{row.name}</router-link>
} else {
return <span>{row.name}</span>
}
}
},
asset: {
label: this.$t('assets.Asset'),
formatter: function(row) {
const to = {
name: 'AssetDetail',
params: { id: row.asset.id }
}
if (vm.$hasPerm('assets.view_asset')) {
return <router-link to={to}>{row.asset.name}</router-link>
} else {
return <span>{row.asset.name}</span>
}
}
},
secret_type: {
width: '100px',
formatter: function(row) {
return row.secret_type.label
}
},
source: {
formatter: function(row) {
return row.source.label
}
},
has_secret: {
width: '100px',
formatterArgs: {
showFalse: false
}
},
privileged: {
label: this.$t('assets.Privileged'),
width: '120px',
formatterArgs: {
showText: false,
showFalse: false
}
},
connectivity: connectivityMeta,
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'),
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
can: this.$hasPerm('accounts.view_accountsecret'),
type: 'primary',
callback: ({ row }) => {
// debugger
vm.secretUrl = `/api/v1/accounts/account-secrets/${row.id}/`
vm.account = row
vm.showViewSecretDialog = false
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
name: 'ClearSecret',
title: this.$t('common.ClearSecret'),
can: this.$hasPerm('accounts.change_account'),
type: 'primary',
callback: ({ row }) => {
this.$axios.patch(
`/api/v1/accounts/accounts/clear-secret/`,
{ account_ids: [row.id] }
).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg'))
})
}
},
{
name: 'Test',
title: this.$t('common.Test'),
can: ({ row }) =>
!this.$store.getters.currentOrgIsRoot &&
this.$hasPerm('accounts.change_account') &&
row.asset['auto_config'].ansible_enabled &&
row.asset['auto_config'].ping_enabled,
callback: ({ row }) => {
this.$axios.post(
`/api/v1/accounts/accounts/tasks/`,
{ action: 'verify', accounts: [row.id] }
).then(res => {
openTaskPage(res['task'])
})
}
},
{
name: 'Update',
title: this.$t('common.Update'),
can: this.$hasPerm('accounts.change_account') && !this.$store.getters.currentOrgIsRoot,
callback: ({ row }) => {
const data = {
...this.asset,
...row.asset
}
vm.account = row
vm.iAsset = data
vm.showAddDialog = false
vm.accountCreateUpdateTitle = this.$t('assets.UpdateAccount')
setTimeout(() => {
vm.showAddDialog = true
})
}
}
]
}
},
...this.columnsMeta
}
},
headerActions: {
hasLeftActions: this.hasLeftActions,
hasMoreActions: true,
hasCreate: false,
hasImport: this.hasImport,
hasExport: this.hasExport && this.$hasPerm('accounts.view_accountsecret'),
handleImportClick: ({ selectedRows }) => {
this.$eventBus.$emit('showImportDialog', {
selectedRows,
url: '/api/v1/accounts/accounts/',
name: this?.name
})
},
exportOptions: {
url: this.exportUrl,
mfaVerifyRequired: true,
tips: this.$t('accounts.AccountExportTips')
},
importOptions: {
canImportCreate: this.$hasPerm('accounts.add_account'),
canImportUpdate: this.$hasPerm('accounts.change_account')
},
extraActions: [
{
name: 'add',
title: this.$t('common.Add'),
type: 'primary',
can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
},
callback: async() => {
await this.getAssetDetail()
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddDialog = true
})
}
},
{
name: 'add-template',
title: this.$t('common.TemplateAdd'),
has: !(this.platform || this.asset),
can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
},
callback: async() => {
await this.getAssetDetail()
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.accountCreateUpdateTitle = this.$t('assets.AddAccount')
vm.showAddTemplateDialog = true
})
}
},
...this.headerExtraActions
],
extraMoreActions: [
{
name: 'ClearSecrets',
title: this.$t('common.ClearSecret'),
type: 'primary',
fa: 'clean',
can: ({ selectedRows }) => {
return selectedRows.length > 0 && vm.$hasPerm('accounts.change_account')
},
callback: function({ selectedRows }) {
const ids = selectedRows.map(v => { return v.id })
this.$axios.patch(
'/api/v1/accounts/accounts/clear-secret/',
{ account_ids: ids }).then(() => {
this.$message.success(this.$tc('common.ClearSuccessMsg'))
}).catch(err => {
this.$message.error(this.$tc('common.bulkClearErrorMsg' + ' ' + err))
})
}.bind(this)
}
],
canBulkDelete: vm.$hasPerm('accounts.delete_account'),
searchConfig: {
getUrlQuery: false,
exclude: ['asset']
},
hasSearch: true
}
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
this.$set(this.headerActions.exportOptions, 'url', iNew.replace(/(.*)accounts/, '$1account-secrets'))
}
},
mounted() {
if (this.columns.length > 0) {
this.tableConfig.columns = this.columns
}
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
if (this.hasDeleteAction) {
this.tableConfig.columnsMeta.actions.formatterArgs.extraActions.push(
{
name: 'Delete',
title: this.$t('common.Delete'),
can: this.$hasPerm('accounts.delete_account'),
type: 'primary',
callback: ({ row }) => {
this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => {
this.$message.success(this.$tc('common.deleteSuccessMsg'))
this.$refs.ListTable.reloadTable()
})
}
}
)
}
},
methods: {
onUpdateAuthDone(account) {
Object.assign(this.account, account)
},
addAccountSuccess() {
this.$refs.ListTable.reloadTable()
},
async getAssetDetail() {
const { query: { asset }} = this.$route
if (asset) {
this.iAsset = await this.$axios.get(`/api/v1/assets/assets/${asset}/`)
}
},
refresh() {
this.$refs.ListTable.reloadTable()
},
showBulkCreateResult(results) {
this.showResultDialog = false
this.createAccountResults = results
setTimeout(() => {
this.showResultDialog = true
}, 100)
}
}
}
</script>
<style lang='scss' scoped>
.cell a {
color: var(--color-info);
}
</style>

View File

@@ -0,0 +1,120 @@
<template>
<Dialog
:show-cancel="false"
:title="title"
v-bind="$attrs"
@confirm="closeDialog"
v-on="$listeners"
>
<el-alert style="margin-bottom: 10px" type="success">
<span v-for="item of summary" :key="item.key"><b>{{ item.label }}</b>: {{ item.value }} </span>
</el-alert>
<DataTable :config="config" />
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import DataTable from '@/components/DataTable/index.vue'
export default {
name: 'ResultDialog',
components: {
DataTable,
Dialog
},
props: {
result: {
type: Array,
default: () => []
}
},
data() {
const errorProp = this.$t('common.Error')
const stateMap = {
'created': this.$tc('common.Created'),
'updated': this.$tc('common.Updated'),
'skipped': this.$tc('common.Skipped')
}
const stateClsMap = {
'created': 'color-primary',
'updated': 'color-success',
'skipped': 'color-default'
}
return {
title: this.$t('accounts.AddAccountResult'),
config: {
columns: [
{
prop: 'asset',
label: this.$t('assets.Asset')
},
{
prop: 'state',
label: this.$t('common.Status'),
width: '200px',
formatter: (row) => {
if (row.error) {
return <span class='color-error'>{ errorProp }: { row.error }</span>
} else if (row.state) {
const colorCls = stateClsMap[row.state]
const state = stateMap[row.state]
return <span class={ colorCls }>{ state }</span>
}
}
}
],
totalData: this.result
}
}
},
computed: {
summary() {
const labels = {
total: this.$tc('common.Total'),
created: this.$tc('common.Created'),
updated: this.$tc('common.Updated'),
skipped: this.$tc('common.Skipped'),
error: this.$tc('common.Error')
}
const grouped = _.groupBy(this.result, 'state')
const groupedLength = _.mapValues(grouped, 'length')
groupedLength['total'] = this.result.length
return _.map(groupedLength, (value, key) => {
return {
label: labels[key],
value: value,
key: key
}
})
}
},
methods: {
closeDialog() {
this.$emit('update:visible', false)
}
}
}
</script>
<style scoped>
.color-error {
color: var(--color-danger);
}
.color-primary {
color: var(--color-primary);
}
.color-success {
color: var(--color-success);
}
.color-default {
}
::v-deep .el-data-table .el-table .el-table__row > td > div > span {
white-space: inherit;
}
</style>

View File

@@ -0,0 +1,78 @@
<template>
<GenericListTableDialog :visible.sync="iVisible" v-bind="config" />
</template>
<script>
import { GenericListTableDialog } from '@/layout/components'
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
export default {
components: {
GenericListTableDialog
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
config: {
title: this.$t('accounts.HistoryPassword'),
visible: false,
width: '60%',
tableConfig: {
id: 'history_date',
url: `/api/v1/accounts/account-secrets/${this.account.id}/histories/`,
columns: ['secret', 'secret_type', 'version', 'history_date'],
columnsMeta: {
secret: {
label: this.$t('assets.Password'),
formatter: ShowKeyCopyFormatter,
formatterArgs: {
hasDownload: false,
name: this.account.name
}
},
history_date: {
label: this.$t('accounts.HistoryDate')
},
secret_type: {
width: '200px'
},
version: {
width: '100px'
},
actions: {
has: false
}
}
},
headerActions: {
hasLeftActions: false,
hasSearch: false
}
}
}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,83 +0,0 @@
<template>
<div>
<UserConfirmDialog
:url="url"
@UserConfirmDone="getAuthInfo"
@UserConfirmCancel="exit"
/>
<Dialog
:title="dialogTitle"
:show-confirm="false"
:show-cancel="false"
:destroy-on-close="true"
:width="'50'"
:visible.sync="showAuthInfo"
v-bind="$attrs"
v-on="$listeners"
>
<div>
<el-form label-position="right" label-width="80px" :model="authInfo">
<el-form-item :label="this.$t('assets.Hostname')">
<el-input v-model="account.hostname" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Username')">
<el-input v-model="account['username']" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Password')">
<el-input v-model="authInfo.password" type="password" show-password />
</el-form-item>
<el-form-item :label="this.$t('users.SSHKey')">
<el-input v-model="authInfo['private_key']" class="item-textarea" type="textarea" show-password />
</el-form-item>
</el-form>
</div>
</Dialog>
</div>
</template>
<script>
import Dialog from '@/components/Dialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
UserConfirmDialog
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
dialogTitle: this.$t('common.ViewSecret'),
authInfo: {},
showAuthInfo: false,
url: `/api/v1/assets/account-secrets/${this.account.id}/`
}
},
methods: {
getAuthInfo() {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
this.authInfo = resp
this.showAuthInfo = true
})
},
exit() {
this.$emit('update:visible', false)
}
}
}
</script>
<style scoped>
.item-textarea >>> .el-textarea__inner {
height: 110px;
}
</style>

View File

@@ -1,27 +1,27 @@
<template>
<Dialog
width="50"
:title="this.$t('assets.UpdateAssetUserToken')"
:visible.sync="visible"
:destroy-on-close="true"
@confirm="handleConfirm()"
:title="$tc('assets.UpdateAssetUserToken')"
:visible.sync="visible"
width="50"
@cancel="handleCancel()"
@confirm="handleConfirm()"
v-on="$listeners"
>
<el-form label-position="right" label-width="90px">
<el-form-item :label="this.$t('assets.Hostname')">
<el-input v-model="account.hostname" readonly />
<el-form-item :label="$tc('assets.Name')">
<el-input v-model="account['asset_name']" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Username')">
<el-form-item :label="$tc('assets.Username')">
<el-input v-model="account['username']" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Password')">
<el-form-item :label="$tc('assets.Password')">
<UpdateToken v-model="authInfo.password" />
</el-form-item>
<el-form-item :label="this.$t('assets.SSHSecretKey')">
<el-form-item :label="$tc('assets.SSHSecretKey')">
<UploadKey @input="getFile" />
</el-form-item>
<el-form-item :label="this.$t('assets.Passphrase')">
<el-form-item :label="$tc('assets.Passphrase')">
<UpdateToken v-model="authInfo.passphrase" />
</el-form-item>
</el-form>
@@ -32,6 +32,7 @@
import Dialog from '@/components/Dialog'
import { UpdateToken, UploadKey } from '@/components/FormFields'
import { encryptPassword } from '@/utils/crypto'
export default {
name: 'UpdateSecretInfo',
components: {
@@ -51,7 +52,7 @@ export default {
},
data() {
return {
authInfo: {
secretInfo: {
password: '',
private_key: '',
passphrase: ''
@@ -61,15 +62,15 @@ export default {
methods: {
handleConfirm() {
const data = {}
if (this.authInfo.password !== '') {
data.password = encryptPassword(this.authInfo.password)
if (this.secretInfo.password !== '') {
data.password = encryptPassword(this.secretInfo.password)
}
if (this.authInfo.private_key !== '') {
data.private_key = encryptPassword(this.authInfo.private_key)
if (this.authInfo.passphrase) data.passphrase = this.authInfo.passphrase
if (this.secretInfo.private_key !== '') {
data.private_key = encryptPassword(this.secretInfo.private_key)
if (this.secretInfo.passphrase) data.passphrase = this.secretInfo.passphrase
}
this.$axios.patch(
`/api/v1/assets/accounts/${this.account.id}/`,
`/api/v1/accounts/accounts/${this.account.id}/`,
data,
{ disableFlashErrorMsg: true }
).then(res => {
@@ -87,7 +88,7 @@ export default {
this.$emit('update:visible', false)
},
getFile(file) {
this.authInfo.private_key = file
this.secretInfo.private_key = file
}
}
}

View File

@@ -0,0 +1,215 @@
<template>
<div>
<div v-if="mfaDialogVisible">
<UserConfirmDialog
:url="url"
@UserConfirmCancel="exit"
@UserConfirmDone="getAuthInfo"
/>
</div>
<Dialog
:destroy-on-close="true"
:show-cancel="false"
:title="title"
:visible.sync="showSecret"
:width="'50'"
v-bind="$attrs"
@confirm="accountConfirmHandle"
v-on="$listeners"
>
<el-form :model="secretInfo" class="password-form" label-position="right" label-width="100px">
<el-form-item :label="$tc('assets.Name')">
<span>{{ account['name'] }}</span>
</el-form-item>
<el-form-item :label="$tc('assets.Username')">
<span>{{ account['username'] }}</span>
</el-form-item>
<el-form-item :label="secretTypeLabel">
<ShowKeyCopyFormatter
:cell-value="secretInfo.secret"
:col="{ formatterArgs: {
name: account['name'],
secretType: secretType || ''
}}"
@input="onShowKeyCopyFormatterChange"
/>
</el-form-item>
<el-form-item v-if="secretType === 'ssh_key'" :label="$tc('assets.sshKeyFingerprint')">
<span>{{ sshKeyFingerprint }}</span>
</el-form-item>
<el-form-item :label="$tc('common.DateCreated')">
<span>{{ account['date_created'] | date }}</span>
</el-form-item>
<el-form-item :label="$tc('common.DateUpdated')">
<span>{{ account['date_updated'] | date }}</span>
</el-form-item>
<el-form-item v-if="showPasswordRecord" v-perms="'accounts.view_accountsecret'" :label="$tc('accounts.PasswordRecord')">
<el-link
:underline="false"
type="success"
@click="showHistoryDialog"
>
<span style="padding-right: 30px">
{{ versions }}
</span>
</el-link>
</el-form-item>
</el-form>
</Dialog>
<PasswordHistoryDialog
v-if="showPasswordHistoryDialog"
:account="account"
:visible.sync="showPasswordHistoryDialog"
/>
</div>
</template>
<script>
import Dialog from '@/components/Dialog'
import PasswordHistoryDialog from './PasswordHistoryDialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
import { ShowKeyCopyFormatter } from '@/components/TableFormatters'
import { encryptPassword } from '@/utils/crypto'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
PasswordHistoryDialog,
UserConfirmDialog,
ShowKeyCopyFormatter
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
},
url: {
type: String,
default: ''
},
title: {
type: String,
default: function() {
return this.$tc('assets.AccountDetail')
}
},
showPasswordRecord: {
type: Boolean,
default: true
}
},
data() {
return {
modifiedSecret: '',
secretInfo: {},
versions: '-',
showSecret: false,
mfaDialogVisible: true,
sshKeyFingerprint: '-',
historyCount: 0,
showPasswordHistoryDialog: false
}
},
computed: {
secretTypeLabel() {
return this.account['secret_type'].label || 'Password'
},
secretType() {
return this.account['secret_type'].value
}
},
mounted() {
if (this.showPasswordRecord) {
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
})
}
},
methods: {
accountConfirmHandle() {
this.modifiedSecret && this.onChangeSecretSubmit()
this.showSecret = false
this.mfaDialogVisible = false
},
onChangeSecretSubmit() {
const params = {
name: this.secretInfo.name,
secret: encryptPassword(this.modifiedSecret)
}
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, params).then(() => {
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 || '-'
this.showSecret = true
})
},
exit() {
this.$emit('update:visible', false)
},
showHistoryDialog() {
this.showPasswordHistoryDialog = true
},
onShowKeyCopyFormatterChange(value) {
if (value === this.secretInfo.secret) return
this.modifiedSecret = value
}
}
}
</script>
<style lang="scss" scoped>
.item-textarea >>> .el-textarea__inner {
height: 110px;
}
.el-form-item {
border-bottom: 1px solid #EBEEF5;
padding: 5px 0;
margin-bottom: 0;
&:last-child {
border-bottom: none;
}
>>> .el-form-item__label {
padding-right: 20px;
line-height: 30px;
}
>>> .el-form-item__content {
line-height: 30px;
pre {
margin: 0;
}
}
}
ul {
margin: 0;
}
li {
display: block;
font-size: 13px;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.title {
color: #303133;
font-weight: 500;
}
}
</style>

View File

@@ -1,36 +1,26 @@
import { toSafeLocalDateStr } from '@/utils/common'
import ChoicesFormatter from '@/components/TableFormatters/ChoicesFormatter'
import i18n from '@/i18n/i18n'
import { ChoicesFormatter } from '@/components/TableFormatters'
export const connectivityMeta = {
label: i18n.t('assets.Reachable'),
label: i18n.t('assets.Connectivity'),
formatter: ChoicesFormatter,
formatterArgs: {
iconChoices: {
ok: 'fa-check',
failed: 'fa-times',
unknown: 'fa-circle-o'
faChoices: {
'-': '',
ok: 'fa-check-circle',
err: 'fa-times-circle'
},
classChoices: {
ok: 'text-primary',
failed: 'text-danger',
unknown: 'text-warning'
err: 'text-danger'
},
hasTips: true,
getTips: ({ row, cellValue }) => {
const mapper = {
'ok': i18n.t('assets.Reachable'),
'failed': i18n.t('assets.Unreachable'),
'unknown': i18n.t('assets.Unknown')
getText({ cellValue }) {
if (cellValue?.value === '-' || cellValue?.value === 'unknown') {
return '-'
} else {
return cellValue?.label
}
let tips = mapper[cellValue]
if (row['date_verified']) {
const datetime = toSafeLocalDateStr(row['date_verified'])
tips += '<br> ' + datetime
}
return tips
}
},
width: '90px',
align: 'center'
width: '100px'
}

View File

@@ -1,213 +0,0 @@
<template>
<div>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
<UpdateSecretInfo v-if="showUpdateSecretDialog" :visible.sync="showUpdateSecretDialog" :account="account" @updateAuthDone="onUpdateAuthDone" />
</div>
</template>
<script>
import ListTable from '@/components/ListTable/index'
import { ActionsFormatter, DetailFormatter, DisplayFormatter } from '@/components/TableFormatters'
import ShowSecretInfo from './ShowSecretInfo'
import UpdateSecretInfo from './UpdateSecretInfo'
import { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms'
// import i18n from '@/i18n/i18n'
export default {
name: 'AccountListTable',
components: {
ListTable,
UpdateSecretInfo,
ShowSecretInfo
},
props: {
url: {
type: String,
required: true
},
exportUrl: {
type: String,
default() {
return this.url.replace('/assets/accounts/', '/assets/account-secrets/')
}
},
hasLeftActions: {
type: Boolean,
default: false
},
otherActions: {
type: Array,
default: null
},
hasClone: {
type: Boolean,
default: false
}
},
data() {
const vm = this
return {
showViewSecretDialog: false,
showUpdateSecretDialog: false,
account: {},
tableConfig: {
url: this.url,
permissions: {
app: 'assets',
resource: 'authbook'
},
columns: [
'hostname', 'ip', 'username', 'version', 'connectivity',
'systemuser', 'date_created', 'date_updated', 'actions'
],
columnsShow: {
min: ['username', 'actions'],
default: ['hostname', 'ip', 'username', 'version', 'actions']
},
columnsMeta: {
hostname: {
prop: 'hostname',
label: this.$t('assets.Hostname'),
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
can: this.$hasPerm('assets.view_asset'),
getRoute({ row }) {
return {
name: 'AssetDetail',
params: { id: row.asset }
}
}
}
},
ip: {
width: '120px'
},
username: {
showOverflowTooltip: true
},
systemuser: {
formatter: DisplayFormatter
},
version: {
width: '70px'
},
connectivity: connectivityMeta,
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'),
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
can: this.$hasPerm('assets.view_assetaccountsecret'),
type: 'primary',
callback: ({ row }) => {
vm.account = row
vm.showViewSecretDialog = false
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
name: 'Delete',
title: this.$t('common.Delete'),
can: this.$hasPerm('assets.delete_authbook'),
type: 'primary',
callback: ({ row }) => {
this.$axios.delete(`/api/v1/assets/accounts/${row.id}/`).then(() => {
this.$message.success(this.$tc('common.deleteSuccessMsg'))
this.$refs.ListTable.reloadTable()
})
}
},
{
name: 'Test',
title: this.$t('common.Test'),
can: this.$hasPerm('assets.test_authbook'),
callback: ({ row }) => {
this.$axios.post(
`/api/v1/assets/accounts/${row.id}/verify/`,
{ action: 'test' }
).then(res => {
openTaskPage(res['task'])
})
}
},
{
name: 'Update',
title: this.$t('common.Update'),
can: this.$hasPerm('assets.change_assetaccountsecret') && !this.$store.getters.currentOrgIsRoot,
callback: ({ row }) => {
vm.account = row
vm.showUpdateSecretDialog = false
setTimeout(() => {
vm.showUpdateSecretDialog = true
})
}
}
// {
// name: 'History',
// title: i18n.t('common.History'),
// can: this.$hasPerm('assets.view_assethistoryaccount') && !this.$store.getters.currentOrgIsRoot,
// callback: ({ row }) => {
// this.$router.push({
// name: 'AssetAccountHistoryList',
// query: { id: row.id }
// })
// }
// }
]
}
}
}
},
headerActions: {
hasLeftActions: this.hasLeftActions,
hasMoreActions: true,
hasCreate: false,
hasImport: false,
hasExport: this.$hasPerm('assets.view_assetaccountsecret'),
exportOptions: {
url: this.exportUrl,
mfaVerifyRequired: true
},
searchConfig: {
exclude: ['systemuser', 'asset']
},
hasSearch: true
}
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
this.$set(this.headerActions.exportOptions, 'url', iNew.replace('/accounts/', '/account-secrets/'))
}
},
mounted() {
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
},
methods: {
onUpdateAuthDone(account) {
Object.assign(this.account, account)
}
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -18,16 +18,16 @@ export default {
type: Array,
default: () => []
},
moreActionBtn: {
type: Object,
default: () => ({})
},
moreActionsTitle: {
type: String,
default() {
return this.$t('common.MoreActions')
}
},
moreActionsType: {
type: String,
default: 'default'
},
moreActionsPlacement: {
type: String,
default: 'bottom'
@@ -43,14 +43,21 @@ export default {
return actions
},
iMoreAction() {
return {
const defaultBtn = {
name: 'moreActions',
title: this.iMoreActionsTitle,
title: this.$t('common.MoreActions'),
type: 'primary',
plain: true
}
const btn = {
...defaultBtn,
...this.moreActionBtn,
dropdown: this.moreActions || []
}
},
iMoreActionsTitle() {
return this.moreActionsTitle || this.$t('common.MoreActions')
if (this.moreActionsTitle) {
btn.title = this.moreActionsTitle
}
return btn
}
}
}

View File

@@ -9,10 +9,10 @@
>
<span class="announcement-main">{{ announcement.content }}</span>
<span v-if="announcement.link">
<el-link :href="announcement.link" target="_blank" class="link-more">
<el-link :href="announcement.link" target="_blank" type="info" class="link-more">
{{ $t('common.ViewMore') }}
</el-link>
<i class="fa fa-external-link" />
<i class="fa fa-external-link icon" />
</span>
</el-alert>
</template>
@@ -67,5 +67,7 @@ export default {
margin-left: 10px;
border-bottom: solid 1px;
}
.icon {
vertical-align: text-bottom;
}
</style>

View File

@@ -1,78 +0,0 @@
<template>
<div>
<UserConfirmDialog
:url="url"
@UserConfirmDone="getAuthInfo"
@UserConfirmCancel="exit"
/>
<Dialog
:title="dialogTitle"
:show-confirm="false"
:show-cancel="false"
:destroy-on-close="true"
:width="'50'"
:visible.sync="showAuthInfo"
v-bind="$attrs"
v-on="$listeners"
>
<div>
<el-form label-position="right" label-width="80px" :model="authInfo">
<el-form-item :label="this.$t('applications.appName')">
<el-input v-model="account['app_display']" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Username')">
<el-input v-model="account['username']" readonly />
</el-form-item>
<el-form-item :label="this.$t('assets.Password')">
<el-input v-model="authInfo.password" type="password" show-password />
</el-form-item>
</el-form>
</div>
</Dialog>
</div>
</template>
<script>
import Dialog from '@/components/Dialog'
import UserConfirmDialog from '@/components/UserConfirmDialog'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
UserConfirmDialog
},
props: {
account: {
type: Object,
default: () => ({})
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
dialogTitle: this.$t('common.ViewSecret'),
authInfo: {},
showAuthInfo: false,
url: `/api/v1/applications/account-secrets/${this.account.id}/`
}
},
methods: {
getAuthInfo() {
this.$axios.get(this.url, { disableFlashErrorMsg: true }).then(resp => {
this.authInfo = resp
this.showAuthInfo = true
})
},
exit() {
this.$emit('update:visible', false)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,31 +0,0 @@
import { ChoicesFormatter } from '@/components/TableFormatters'
import { toSafeLocalDateStr } from '@/utils/common'
import i18n from '@/i18n/i18n'
export const connectivityMeta = {
label: i18n.t('assets.Reachable'),
formatter: ChoicesFormatter,
formatterArgs: {
iconChoices: {
ok: 'fa-check text-primary',
failed: 'fa-times text-danger',
unknown: 'fa-circle text-warning'
},
hasTips: true,
getTips: ({ row, cellValue }) => {
const mapper = {
'ok': i18n.t('assets.Reachable'),
'failed': i18n.t('assets.Unreachable'),
'unknown': i18n.t('assets.Unknown')
}
let tips = mapper[cellValue]
if (row['date_verified']) {
const datetime = toSafeLocalDateStr(row['date_verified'])
tips += '<br> ' + datetime
}
return tips
}
},
width: '90px',
align: 'center'
}

View File

@@ -1,173 +0,0 @@
<template>
<div>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
<ShowSecretInfo v-if="showViewSecretDialog" :visible.sync="showViewSecretDialog" :account="account" />
</div>
</template>
<script>
import ListTable from '@/components/ListTable/index'
import { ActionsFormatter, DetailFormatter } from '@/components/TableFormatters'
import ShowSecretInfo from './ShowSecretInfo'
export default {
name: 'Detail',
components: {
ListTable,
ShowSecretInfo
},
props: {
url: {
type: String,
required: true
},
exportUrl: {
type: String,
default() {
return this.url.replace('/applications/accounts/', '/applications/account-secrets/')
}
},
hasLeftActions: {
type: Boolean,
default: false
},
otherActions: {
type: Array,
default: null
},
hasClone: {
type: Boolean,
default: false
},
systemUserDisabled: {
type: Boolean,
default: true
}
},
data() {
return {
showViewSecretDialog: false,
showUpdateSecretDialog: false,
account: {},
tableConfig: {
url: this.url,
columns: [
'app_display', 'username', 'category_display',
'type_display', 'systemuser', 'actions'
],
columnsMeta: {
app_display: {
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
getRoute({ row }) {
switch (row['category']) {
case 'remote_app':
return {
name: 'RemoteAppDetail',
params: { id: row.app }
}
case 'db':
return {
name: 'DatabaseAppDetail',
params: { id: row.app }
}
default:
return {
name: 'KubernetesAppDetail',
params: { id: row.app }
}
}
}
}
},
username: {
showOverflowTooltip: true
},
systemuser: {
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
can: this.systemUserDisabled && this.$hasPerm('assets.view_systemuser'),
getTitle({ row }) {
return row.systemuser_display
},
getRoute({ row }) {
return {
name: 'SystemUserDetail',
params: { id: row.systemuser }
}
}
}
},
actions: {
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
moreActionsTitle: this.$t('common.More'),
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
type: 'primary',
can: this.$hasPerm('applications.view_applicationaccountsecret'),
callback: function({ row }) {
this.account = row
this.showViewSecretDialog = true
}.bind(this)
},
{
name: 'Update',
title: this.$t('common.Update'),
can: !this.$store.getters.currentOrgIsRoot,
callback: function({ row }) {
this.$message.success(this.$tc('applications.updateAccountMsg'))
}.bind(this)
}
]
}
}
}
},
headerActions: {
hasLeftActions: this.hasLeftActions,
hasMoreActions: false,
hasImport: false,
hasExport: this.$hasPerm('applications.view_applicationaccountsecret'),
exportOptions: {
url: this.exportUrl,
mfaVerifyRequired: true
},
searchConfig: {
exclude: ['systemuser', 'app']
},
hasSearch: true
}
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
}
},
mounted() {
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
},
methods: {
onUpdateAuthDone(account) {
Object.assign(this.account, account)
}
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -0,0 +1,192 @@
<template>
<Dialog
:title="$tc('assets.Assets')"
custom-class="asset-select-dialog"
top="1vh"
v-bind="$attrs"
width="80vw"
@cancel="handleCancel"
@close="handleClose"
@confirm="handleConfirm"
v-on="$listeners"
>
<AssetTreeTable
ref="ListPage"
:header-actions="headerActions"
:node-url="baseNodeUrl"
:table-config="tableConfig"
:tree-url="`${baseNodeUrl}children/tree/`"
:url="baseUrl"
class="tree-table"
v-bind="$attrs"
/>
</Dialog>
</template>
<script>
import AssetTreeTable from '@/components/AssetTreeTable'
import Dialog from '@/components/Dialog'
export default {
componentName: 'AssetSelectDialog',
components: { AssetTreeTable, Dialog },
props: {
baseUrl: {
type: String,
default: '/api/v1/assets/assets/'
},
baseNodeUrl: {
type: String,
default: '/api/v1/assets/nodes/'
},
value: {
type: Array,
default: () => []
},
canSelect: {
type: Function,
default(row, index) {
return true
}
},
disabled: {
type: [Boolean, Function],
default: false
}
},
data() {
const vm = this
return {
dialogVisible: false,
rowSelected: _.cloneDeep(this.value) || [],
rowsAdd: [],
tableConfig: {
url: this.baseUrl,
hasTree: true,
canSelect: this.canSelect,
columns: [
{
prop: 'name',
label: this.$t('assets.Name'),
sortable: true
},
{
prop: 'address',
label: this.$t('assets.ipDomain'),
sortable: 'custom'
},
{
prop: 'platform',
label: this.$t('assets.Platform'),
sortable: true,
formatter: function(row) {
return row.platform.name
}
},
{
prop: 'protocols',
formatter: function(row) {
const data = row.protocols.map(p => {
return <el-tag size='mini'>{p.name}/{p.port} </el-tag>
})
return <span> {data} </span>
},
label: this.$t('assets.Protocols')
},
{
prop: 'actions',
has: false
}
],
listeners: {
'toggle-row-selection': (isSelected, row) => {
if (isSelected) {
vm.addRowToSelect(row)
} else {
vm.removeRowFromSelect(row)
}
}
},
theRowDefaultIsSelected: (row) => {
return this.value.indexOf(row.id) > -1
}
},
headerActions: {
hasLeftActions: false,
hasRightActions: false,
searchConfig: {
getUrlQuery: false
}
}
}
},
methods: {
handleClose() {
this.$eventBus.$emit('treeComponentKey')
},
handleConfirm() {
this.$emit('confirm', this.rowSelected, this.rowsAdd)
if (this.rowSelected.length > 0) {
this.handleClose()
}
},
handleCancel() {
this.$emit('cancel')
this.handleClose()
},
addRowToSelect(row) {
const selectValueIndex = this.rowSelected.indexOf(row.id)
if (selectValueIndex === -1) {
this.rowSelected.push(row.id)
this.rowsAdd.push(row)
}
},
removeRowFromSelect(row) {
const selectValueIndex = this.rowSelected.indexOf(row.id)
if (selectValueIndex > -1) {
this.rowSelected.splice(selectValueIndex, 1)
}
}
}
}
</script>
<style lang="scss" scoped>
.page ::v-deep .page-heading {
display: none;
}
.el-dialog__wrapper ::v-deep .el-dialog__body {
padding: 0 0 0 3px;
.tree-table {
.search {
}
.left {
padding: 5px;
}
.right {
height: calc(100vh - 200px);
overflow: auto;
}
.mini {
padding-top: 8px;
}
.transition-box {
padding: 10px 5px;
}
}
}
.page ::v-deep .treebox .ztree {
}
.asset-select-dialog ::v-deep .el-icon-circle-check {
display: none;
}
</style>

View File

@@ -1,151 +1,96 @@
<template>
<div class="asset-select-dialog">
<div class="asset-select-formatter">
<Select2
ref="select2"
v-model="select2Config.value"
v-bind="select2Config"
@input="onInputChange"
v-on="$listeners"
@focus.stop="handleFocus"
/>
<AssetSelectDialog
v-if="dialogVisible"
ref="dialog"
:base-node-url="baseNodeUrl"
:base-url="baseUrl"
:tree-url-query="treeUrlQuery"
:value="value"
:visible.sync="dialogVisible"
v-bind="$attrs"
@cancel="handleCancel"
@confirm="handleConfirm"
v-on="$listeners"
/>
<Dialog
v-if="dialogVisible"
:title="this.$t('assets.Assets')"
:visible.sync="dialogVisible"
custom-class="asset-select-dialog"
width="80vw"
top="1vh"
@confirm="handleConfirm"
@cancel="handleCancel"
>
<TreeTable
ref="ListPage"
:tree-setting="treeSetting"
:table-config="tableConfig"
:header-actions="headerActions"
/>
</Dialog>
</div>
</template>
<script>
import TreeTable from '@/components/TreeTable'
import { DetailFormatter } from '@/components/TableFormatters'
import Select2 from '@/components/FormFields/Select2'
import Dialog from '@/components/Dialog'
import AssetSelectDialog from './dialog.vue'
import { b } from 'css-color-function/lib/adjusters'
export default {
componentName: 'AssetSelect',
components: { TreeTable, Select2, Dialog },
components: { AssetSelectDialog, Select2 },
props: {
baseUrl: {
type: String,
default: '/api/v1/assets/assets/'
},
baseNodeUrl: {
type: String,
default: '/api/v1/assets/nodes/'
},
treeUrlQuery: {
type: Object,
default: () => {}
},
value: {
type: Array,
default: () => []
},
canSelect: {
type: Function,
default(row, index) {
return true
}
},
disabled: {
type: [Boolean, Function],
default: false
}
},
data() {
const select2Config = {
value: this.value,
multiple: true,
clearable: true,
ajax: {
url: '/api/v1/assets/assets/?fields_size=mini',
transformOption: (item) => {
return { label: item.hostname + '(' + item.ip + ')', value: item.id }
}
const iValue = []
for (const item of this.value) {
if (typeof item === 'object') {
iValue.push(item.id)
} else {
iValue.push(item)
}
}
const vm = this
return {
dialogVisible: false,
initialValue: _.cloneDeep(this.value),
rowSelected: [],
initSelection: null,
treeSetting: {
showMenu: false,
showRefresh: true,
showAssets: false,
showSearch: true,
customTreeHeader: true,
url: '/api/v1/assets/assets/?fields_size=mini',
nodeUrl: '/api/v1/assets/nodes/',
// ?assets=0不显示资产. =1显示资产
treeUrl: '/api/v1/assets/nodes/children/tree/?assets=0'
},
select2Config: select2Config,
dialogSelect2Config: select2Config,
tableConfig: {
url: '/api/v1/assets/assets/?fields_size=mini',
hasTree: true,
canSelect: this.canSelect,
columns: [
{
prop: 'hostname',
label: this.$t('assets.Hostname'),
sortable: true,
showOverflowTooltip: true,
formatter: DetailFormatter,
formatterArgs: {
route: 'AssetDetail'
}
},
{
prop: 'ip',
label: this.$t('assets.ipDomain'),
sortable: 'custom'
},
{
prop: 'platform',
label: this.$t('assets.Platform'),
sortable: true
},
{
prop: 'protocols',
formatter: function(row) {
return <span> {row.protocols.toString()} </span>
},
label: this.$t('assets.Protocols')
initialValue: _.cloneDeep(iValue),
select2Config: {
value: iValue,
multiple: true,
clearable: true,
ajax: {
url: this.baseUrl,
transformOption: (item) => {
return { label: item.name + '(' + item.address + ')', value: item.id }
}
],
listeners: {
'toggle-row-selection': (isSelected, row) => {
if (isSelected) {
vm.addRowToSelect(row)
} else {
vm.removeRowFromSelect(row)
}
}
},
theRowDefaultIsSelected: (row) => {
return this.value.indexOf(row.id) > -1
}
},
headerActions: {
hasLeftActions: false,
hasRightActions: false
}
}
},
methods: {
b,
handleFocus() {
this.$refs.select2.selectRef.blur()
this.dialogVisible = true
},
handleConfirm() {
handleConfirm(valueSelected, rowsAdd) {
if (valueSelected === undefined) {
return
}
this.$refs.select2.iValue = valueSelected
this.addRowsToSelect(rowsAdd)
this.onInputChange(valueSelected)
this.dialogVisible = false
},
handleCancel() {
this.$refs.select2.iValue = this.initialValue
this.dialogVisible = false
},
onInputChange(val) {
@@ -156,53 +101,54 @@ export default {
// 如果select2的options中没有那么可能无法显示正常的值
if (selectOptionsHas === undefined) {
const option = {
label: `${row.hostname}(${row.ip})`,
label: `${row.name}(${row.address})`,
value: row.id
}
options.push(option)
}
},
addRowToSelect(row) {
addRowsToSelect(rows) {
const outSelectOptions = this.$refs.select2.options
this.addToSelect(outSelectOptions, row)
const selectValue = this.$refs.select2.iValue
const selectValueIndex = selectValue.indexOf(row.id)
if (selectValueIndex === -1) {
selectValue.push(row.id)
}
this.onInputChange(selectValue)
},
removeRowFromSelect(row) {
const selectValue = this.$refs.select2.iValue
const selectValueIndex = selectValue.indexOf(row.id)
if (selectValueIndex > -1) {
selectValue.splice(selectValueIndex, 1)
for (const row of rows) {
this.addToSelect(outSelectOptions, row)
}
}
}
}
</script>
<style lang='scss' scoped>
.el-select{
width: 100%;
}
.page ::v-deep .page-heading{
display: none;
}
.el-dialog__wrapper ::v-deep .el-dialog__body{
padding: 5px 10px;
}
.page ::v-deep .treebox {
height: inherit !important;
}
.asset-select-dialog >>> .transition-box:first-child {
background-color: #f3f3f3 ;
}
<style lang="scss" scoped>
.el-select {
width: 100%;
}
.el-dialog__wrapper ::v-deep .el-dialog__body .wrapper-content {
padding: 10px;
}
.page ::v-deep .page-heading {
display: none;
}
.el-dialog__wrapper ::v-deep .el-dialog__body {
padding: 0 0 0 3px;
.tree-table {
.left {
padding: 5px;
.ztree {
height: calc(100vh - 250px) !important;
}
}
.mini {
padding-top: 8px;
}
.transition-box {
padding: 10px 5px;
}
}
}
.page ::v-deep .treebox {
height: inherit !important;
}
</style>

View File

@@ -0,0 +1,175 @@
<template>
<TreeTable
ref="TreeList"
component="TabTree"
:table-config="tableConfig"
:active-menu.sync="treeTableConfig.activeMenu"
:tree-tab-config="treeTableConfig"
v-bind="$attrs"
v-on="$listeners"
>
<template #table>
<slot name="table" />
</template>
<div slot="rMenu" slot-scope="{data}">
<slot name="rMenu" :data="data" />
</div>
</TreeTable>
</template>
<script>
import TreeTable from '../TreeTable'
import { setRouterQuery, setUrlParam } from '@/utils/common'
import $ from '@/utils/jquery-vendor'
export default {
components: {
TreeTable
},
props: {
url: {
type: String,
default: '/api/v1/assets/assets/'
},
nodeUrl: {
type: String,
default: '/api/v1/assets/nodes/'
},
treeUrl: {
type: String,
default: '/api/v1/assets/nodes/children/tree/'
},
treeUrlQuery: {
type: Object,
default: () => ({})
},
treeSetting: {
type: Object,
default: () => ({})
},
tableConfig: {
type: Object,
default: () => ({})
},
showAssets: {
type: Boolean,
default: false
}
},
data() {
const showAssets = this.treeSetting?.showAssets || this.showAssets
const treeUrlQuery = this.setTreeUrlQuery()
const assetTreeUrl = `${this.treeUrl}?assets=${showAssets ? '1' : '0'}&${treeUrlQuery}`
return {
treeTabConfig: {
activeMenu: 'CustomTree',
submenu: [
{
title: this.$t('assets.AssetTree'),
name: 'CustomTree',
treeSetting: {
showAssets,
showMenu: false,
showRefresh: true,
showCreate: true,
showUpdate: true,
showDelete: true,
hasRightMenu: true,
showSearch: true,
url: this.url,
nodeUrl: this.nodeUrl,
treeUrl: assetTreeUrl,
callback: {
onSelected: (event, treeNode) => this.getAssetsUrl(treeNode)
},
...this.treeSetting
}
},
{
title: this.$t('assets.BuiltinTree'),
name: 'BuiltinTree',
treeSetting: {
showRefresh: true,
showAssets: false,
showSearch: false,
customTreeHeaderName: this.$t('assets.BuiltinTree'),
url: '/api/v1/assets/nodes/category/tree/',
nodeUrl: this.treeSetting?.nodeUrl || this.nodeUrl,
treeUrl: `/api/v1/assets/nodes/category/tree/?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,
callback: {
onSelected: (event, treeNode) => this.getAssetsUrl(treeNode)
}
}
}
]
}
}
},
computed: {
treeTableConfig() {
if (this.treeSetting.notShowBuiltinTree) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.treeTabConfig.submenu.splice(1, 1)
}
return this.treeTabConfig
}
},
mounted() {
this.decorateRMenu()
const treeSetting = this.treeTabConfig.submenu[0].treeSetting
treeSetting.hasRightMenu = !this.currentOrgIsRoot
treeSetting.showCreate = this.$hasPerm('assets.add_node')
treeSetting.showUpdate = this.$hasPerm('assets.change_node')
treeSetting.showDelete = this.$hasPerm('assets.delete_node')
},
methods: {
setTreeUrlQuery() {
let str = ''
for (const key in this.treeUrlQuery) {
str += `${key}=${this.treeUrlQuery[key]}&`
}
str = str.substr(0, str.length - 1)
return str
},
decorateRMenu() {
const show_current_asset = this.$cookie.get('show_current_asset') || '0'
if (show_current_asset === '1') {
$('#m_show_asset_all_children_node').css('color', '#606266')
$('#m_show_asset_only_current_node').css('color', 'green')
} else {
$('#m_show_asset_all_children_node').css('color', 'green')
$('#m_show_asset_only_current_node').css('color', '#606266')
}
},
getAssetsUrl(treeNode) {
let url = this.treeSetting?.url || this.url
if (treeNode.meta.type === 'node') {
const nodeId = treeNode.meta.data.id
url = setUrlParam(url, 'node_id', nodeId)
url = setUrlParam(url, 'asset_id', '')
} else if (treeNode.meta.type === 'asset') {
const assetId = treeNode.meta.data?.id || treeNode.id
url = setUrlParam(url, 'node_id', '')
url = setUrlParam(url, 'asset_id', assetId)
} else if (treeNode.meta.type === 'category') {
url = setUrlParam(url, 'category', treeNode.meta.category)
} else if (treeNode.meta.type === 'type') {
url = setUrlParam(url, 'category', treeNode.meta.category)
url = setUrlParam(url, 'type', treeNode.meta._type)
} else if (treeNode.meta.type === 'platform') {
url = setUrlParam(url, 'platform', treeNode.id)
}
const query = this.setTreeUrlQuery()
url = query ? `${url}&${query}` : url
this.$set(this.tableConfig, 'url', url)
setRouterQuery(this, url)
}
}
}
</script>
<style lang='scss' scoped>
</style>

View File

@@ -1,9 +1,13 @@
<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>
@@ -28,10 +32,16 @@ export default {
errors: {
type: [Object, String],
default: ''
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
formJson: JSON.stringify(this.value),
kwargs: {
hasReset: false,
hasSaveContinue: false,
@@ -60,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

@@ -1,13 +1,24 @@
<template>
<DataForm ref="dataForm" v-loading="loading" :fields="totalFields" :form="iForm" v-bind="$attrs" v-on="$listeners">
<FormGroupHeader
<DataForm
v-if="!loading"
ref="dataForm"
:fields="totalFields"
:form="iForm"
v-bind="$attrs"
v-on="$listeners"
>
<span
v-for="(group, i) in groups"
:slot="'id:'+group.name"
:key="'group-'+group.name"
:group="group"
:index="i"
:line="i !== 0"
/>
:slot="'id:'+group.name"
>
<FormGroupHeader
v-if="!groupHidden(group, i)"
:group="group"
:index="i"
:line="i !== 0 && !groupHidden(groups[i - 1], i - 1)"
/>
</span>
</DataForm>
</template>
@@ -15,6 +26,7 @@
import DataForm from '../DataForm'
import FormGroupHeader from '@/components/FormGroupHeader'
import { FormFieldGenerator } from '@/components/AutoDataForm/utils'
export default {
name: 'AutoDataForm',
components: {
@@ -51,32 +63,52 @@ export default {
totalFields: [],
loading: true,
groups: [],
iForm: this.form,
errors: {}
}
},
computed: {
iForm() {
const iForm = {}
Object.entries(this.form).forEach(([key, value]) => {
// 初始值是 choice 对象
if (value && typeof value === 'object' && value.label && value.value !== undefined) {
iForm[key] = value.value
} else if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' &&
value[0].label && value[0].value !== undefined) {
iForm[key] = value.map(item => item.value)
} else {
iForm[key] = value
}
})
return iForm
}
},
mounted() {
this.optionUrlMetaAndGenerateColumns()
},
methods: {
optionUrlMetaAndGenerateColumns() {
this.$store.dispatch('common/getUrlMeta', { url: this.url }).then(data => {
this.remoteMeta = data.actions[this.method.toUpperCase()] || {}
this.generateColumns()
this.cleanFormValue()
}).catch(err => {
this.$log.error(err)
}).finally(() => {
this.loading = false
})
async optionUrlMetaAndGenerateColumns() {
let data = { actions: {}}
if (this.url) {
data = await this.$store.dispatch('common/getUrlMeta', { url: this.url })
}
this.remoteMeta = data.actions[this.method.toUpperCase()] || {}
this.$emit('afterRemoteMeta', this.remoteMeta)
this.generateColumns()
this.$emit('afterGenerateColumns', this.totalFields)
this.cleanFormValue()
this.loading = false
},
generateColumns() {
const generator = new FormFieldGenerator()
const generator = new FormFieldGenerator(this.$emit)
this.totalFields = generator.generateFields(this.fields, this.fieldsMeta, this.remoteMeta)
this.groups = generator.groups
this.$log.debug('Total fields: ', this.totalFields)
},
_cleanFormValue(form, remoteMeta) {
if (!form) {
form = {}
}
for (const [k, v] of Object.entries(remoteMeta)) {
let valueSet = form[k]
if (v.type === 'nested object' && v.children) {
@@ -114,6 +146,18 @@ export default {
} else {
field.attrs.error = error
}
},
groupHidden(group, i) {
for (const field of group.fields) {
let hidden = field.hidden
if (typeof hidden === 'function') {
hidden = hidden(this.iForm)
}
if (!hidden) {
return false
}
}
return true
}
}
}

View File

@@ -1,26 +1,37 @@
import Vue from 'vue'
import Select2 from '@/components/FormFields/Select2'
import ObjectSelect2 from '@/components/FormFields/NestedObjectSelect2'
import NestedField from '@/components/AutoDataForm/components/NestedField'
import Swicher from '@/components/FormFields/Swicher'
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 { assignIfNot } from '@/utils/common'
import TagInput from '@/components/FormFields/TagInput.vue'
export class FormFieldGenerator {
constructor() {
constructor(emit) {
this.$emite = emit
this.groups = []
}
generateFieldByType(type, field, fieldMeta, fieldRemoteMeta) {
switch (type) {
case 'labeled_choice':
case 'choice':
type = 'radio-group'
if (!fieldRemoteMeta.read_only) {
field.options = fieldRemoteMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
// Value 处理事在 AutoDataForm 中处理的
if (!fieldRemoteMeta['read_only']) {
field.options = fieldRemoteMeta.choices
}
type = 'radio-group'
break
case 'multiple choice':
field.el.choices = fieldRemoteMeta['choices']
field.options = fieldRemoteMeta.choices
type = 'checkbox-group'
break
case 'tree':
field.el.tree = fieldRemoteMeta.tree
field.component = BasicTree
break
case 'datetime':
type = 'date-picker'
@@ -28,12 +39,19 @@ export class FormFieldGenerator {
type: 'datetime'
}
break
case 'json':
type = 'json-editor'
field.component = JsonEditor
break
case 'field':
type = ''
field.component = Select2
if (fieldRemoteMeta.required) {
field.el.clearable = false
}
if (fieldRemoteMeta.child && fieldRemoteMeta.child.type === 'nested object') {
field.component = ObjectSelect2
}
break
case 'string':
type = 'input'
@@ -47,40 +65,54 @@ export class FormFieldGenerator {
break
case 'boolean':
type = ''
field.component = Swicher
field.component = Switcher
break
case 'list':
type = 'input'
field.component = TagInput
break
case 'object_related_field':
field.component = ObjectSelect2
break
case 'm2m_related_field':
field.component = ObjectSelect2
break
case 'nested object':
type = 'nestedField'
field.component = NestedField
field.label = ''
field.labelWidth = 0
field.el = { ...field.el, ...fieldMeta }
field.el.fields = this.generateNestFields(field, fieldMeta, fieldRemoteMeta)
field.el.errors = {}
Vue.$log.debug('All fields in generate: ', field.el.allFields)
field.hidden = () => {
const hidden = fieldMeta['hiddenFields'] || (() => field.el.fields.length === 0)
return hidden(fieldMeta, fieldRemoteMeta, field.el.fields)
}
break
default:
type = 'input'
break
}
// 上面重写了 type
if (type === 'radio-group') {
if (!fieldRemoteMeta.read_only) {
const options = fieldRemoteMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
if (options.length > 4) {
type = 'select'
field.el.filterable = true
}
if (field.options.length > 4) {
type = 'select'
field.el.filterable = true
}
}
field.type = type
return field
}
generateNestFields(field, fieldMeta, fieldRemoteMeta) {
const fields = []
const nestedFields = fieldMeta.fields || []
let nestedFields = fieldMeta.fields || []
const nestedFieldsMeta = fieldMeta.fieldsMeta || {}
const nestedFieldsRemoteMeta = fieldRemoteMeta.children || {}
if (nestedFields === '__all__') {
nestedFields = Object.keys(nestedFieldsRemoteMeta)
}
for (const name of nestedFields) {
const f = this.generateField(name, nestedFieldsMeta, nestedFieldsRemoteMeta)
fields.push(f)
@@ -88,6 +120,7 @@ export class FormFieldGenerator {
Vue.$log.debug('NestFields: ', fields)
return fields
}
generateFieldByName(name, field) {
switch (name) {
case 'email':
@@ -102,6 +135,7 @@ export class FormFieldGenerator {
}
return field
}
generateFieldByOther(field, fieldMeta, fieldRemoteMeta) {
const filedRules = field.rules || []
if (fieldRemoteMeta.required) {
@@ -111,15 +145,20 @@ export class FormFieldGenerator {
filedRules.push(rules.RequiredChange)
}
}
// 一些 field 有 choices 但不是 choiceField
if (fieldRemoteMeta.choices && field.type.indexOf('choice') === -1) {
field.el.choices = fieldRemoteMeta.choices
}
field.rules = filedRules
return field
}
generateField(name, fieldsMeta, remoteFieldsMeta) {
let field = { id: name, prop: name, el: {}, attrs: {}, rules: [] }
const remoteFieldMeta = remoteFieldsMeta[name] || {}
const fieldMeta = fieldsMeta[name] || {}
field.label = remoteFieldMeta.label
field.helpText = remoteFieldMeta.help_text
field.helpText = remoteFieldMeta['help_text']
field = this.generateFieldByType(remoteFieldMeta.type, field, fieldMeta, remoteFieldMeta)
field = this.generateFieldByName(name, field)
field = this.generateFieldByOther(field, fieldMeta, remoteFieldMeta)
@@ -132,18 +171,25 @@ export class FormFieldGenerator {
// Vue.$log.debug('Generate field: ', name, field)
return field
}
generateFieldGroup(field, fieldsMeta, remoteFieldsMeta) {
const [groupTitle, fields] = field
this.groups.push({
const _fields = this.generateFields(fields, fieldsMeta, remoteFieldsMeta)
const group = {
id: groupTitle,
title: groupTitle,
name: fields[0],
fields: fields
})
return this.generateFields(fields, fieldsMeta, remoteFieldsMeta)
fields: _fields,
name: _fields[0]?.id
}
this.groups.push(group)
return _fields
}
generateFields(_fields, fieldsMeta, remoteFieldsMeta) {
let fields = []
if (_fields === '__all__') {
_fields = Object.keys(remoteFieldsMeta)
}
for (let field of _fields) {
if (field instanceof Array) {
const items = this.generateFieldGroup(field, fieldsMeta, remoteFieldsMeta)

View File

@@ -33,7 +33,8 @@ export default {
},
computed: {
iOption() {
return this.options.concat(this.internalOptions)
const options = this.options.concat(this.internalOptions)
return _.uniqWith(options, _.isEqual)
}
},
watch: {
@@ -67,16 +68,16 @@ export default {
type: field.type,
value: name
}
if (field.type === 'choice' && field.choices) {
if (['choice', 'labeled_choice'].indexOf(field.type) > -1 && field.choices) {
option.children = field.choices.map(item => {
if (typeof (item.value) === 'boolean') {
if (item.value) {
return { label: item.display_name, value: 'True' }
return { label: item.label, value: 'True' }
} else {
return { label: item.display_name, value: 'False' }
return { label: item.label, value: 'False' }
}
}
return { label: item.display_name, value: item.value }
return { label: item.label, value: item.value }
})
}
if (field.type === 'boolean') {

View File

@@ -1,12 +1,13 @@
<template>
<Dialog
v-if="showColumnSettingPopover"
:title="$t('common.CustomCol')"
:visible.sync="showColumnSettingPopover"
:cancel-title="$tc('common.RestoreDefault')"
:destroy-on-close="true"
:show-cancel="false"
width="35%"
:title="$tc('common.CustomCol')"
:visible.sync="showColumnSettingPopover"
top="10%"
width="50%"
@cancel="restoreDefault()"
@confirm="handleColumnConfirm()"
>
<el-alert type="success">
@@ -23,24 +24,20 @@
style="margin-top:5px;"
>
<el-checkbox
:disabled="item.prop==='actions' || minColumns.indexOf(item.prop)!==-1"
:label="item.prop"
:disabled="
item.prop==='id' ||
item.prop==='actions' ||
minColumns.indexOf(item.prop)!==-1
"
>
{{ item.label }}
</el-checkbox>
</el-col>
</el-row>
</el-checkbox-group>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index'
export default {
name: 'ColumnSettingPopover',
components: {
@@ -82,6 +79,10 @@ export default {
handleColumnConfirm() {
this.showColumnSettingPopover = false
this.$emit('columnsUpdate', { columns: this.iCurrentColumns, url: this.url })
},
restoreDefault() {
this.showColumnSettingPopover = false
this.$emit('columnsUpdate', { columns: null, url: this.url })
}
}
}

View File

@@ -11,8 +11,8 @@
/>
<ColumnSettingPopover
:current-columns="popoverColumns.currentCols"
:total-columns-list="popoverColumns.totalColumnsList"
:min-columns="popoverColumns.minCols"
:total-columns-list="popoverColumns.totalColumnsList"
:url="config.url"
@columnsUpdate="handlePopoverColumnsChange"
/>
@@ -22,15 +22,18 @@
<script type="text/jsx">
import DataTable from '../DataTable'
import {
ActionsFormatter,
ArrayFormatter,
ChoicesFormatter,
DateFormatter,
DetailFormatter,
DisplayFormatter,
ActionsFormatter,
ChoicesFormatter
ObjectRelatedFormatter
} from '@/components/TableFormatters'
import i18n from '@/i18n/i18n'
import { newURL, replaceAllUUID } from '@/utils/common'
import ColumnSettingPopover from './components/ColumnSettingPopover'
import { newURL } from '@/utils/common'
export default {
name: 'AutoDataTable',
components: {
@@ -63,13 +66,12 @@ export default {
}
}
},
computed: {
},
computed: {},
watch: {
config: {
handler(iNew) {
handler: function(iNew, iOld) {
this.optionUrlMetaAndGenCols()
this.$log.debug('AutoDataTable Config change found')
this.$log.debug('AutoDataTable Config change found: ')
},
deep: true
}
@@ -79,8 +81,12 @@ export default {
},
methods: {
async optionUrlMetaAndGenCols() {
if (this.config.url === '') { return }
const url = (this.config.url.indexOf('?') === -1) ? `${this.config.url}?draw=1&display=1` : `${this.config.url}&draw=1&display=1`
if (this.config.url === '') {
return
}
const url = (this.config.url.indexOf('?') === -1)
? `${this.config.url}?draw=1&display=1`
: `${this.config.url}&draw=1&display=1`
this.$store.dispatch('common/getUrlMeta', { url: url }).then(data => {
const method = this.method.toUpperCase()
this.meta = data.actions && data.actions[method] ? data.actions[method] : {}
@@ -117,7 +123,22 @@ export default {
case 'is_valid':
col.label = i18n.t('common.Validity')
col.formatter = ChoicesFormatter
col.align = 'center'
col.formatterArgs = {
textChoices: {
true: i18n.t('common.Yes'),
false: i18n.t('common.No')
}
}
col.width = '80px'
break
case 'is_active':
col.formatter = ChoicesFormatter
col.formatterArgs = {
textChoices: {
true: i18n.t('common.Active'),
false: i18n.t('common.Inactive')
}
}
col.width = '80px'
break
case 'datetime':
@@ -129,21 +150,41 @@ export default {
}
return col
},
generateColumnByType(type, col) {
generateColumnByType(type, col, meta) {
switch (type) {
case 'choice':
col.sortable = 'custom'
col.formatter = DisplayFormatter
break
case 'labeled_choice':
col.sortable = 'custom'
col.formatter = ChoicesFormatter
break
case 'boolean':
col.formatter = ChoicesFormatter
col.align = 'center'
col.width = '80px'
break
case 'datetime':
col.formatter = DateFormatter
col.width = '160px'
break
case 'object_related_field':
col.formatter = ObjectRelatedFormatter
break
case 'm2m_related_field':
col.formatter = ObjectRelatedFormatter
break
case 'list':
col.formatter = ArrayFormatter
break
case 'json':
case 'field':
if (meta.child && meta.child.type === 'nested object') {
col.formatter = ObjectRelatedFormatter
}
break
}
// this.$log.debug('Field: ', type, col.prop, col)
return col
},
addHelpTipsIfNeed(col) {
@@ -155,9 +196,9 @@ export default {
return (
<span>{column.label}
<el-tooltip placement='bottom' effect='light' popperClass='help-tips'>
<div slot='content' domPropsInnerHTML={helpTips} />
<div slot='content' domPropsInnerHTML={helpTips}/>
<el-button style='padding: 0'>
<i class='fa fa-info-circle' />
<i class='fa fa-info-circle'/>
</el-button>
</el-tooltip>
</span>
@@ -183,12 +224,12 @@ export default {
col.filters = column.choices.map(item => {
if (typeof (item.value) === 'boolean') {
if (item.value) {
return { text: item['display_name'], value: 'True' }
return { text: item['label'], value: 'True' }
} else {
return { text: item['display_name'], value: 'False' }
return { text: item['label'], value: 'False' }
}
}
return { text: item['display_name'], value: item.value }
return { text: item['label'], value: item.value }
})
col.sortable = false
col['column-key'] = col.prop
@@ -196,22 +237,65 @@ export default {
}
return col
},
addOrderingIfNeed(col) {
if (col.prop) {
const column = this.meta[col.prop] || {}
if (column.order) {
col.sortable = 'custom'
col['column-key'] = col.prop
}
}
return col
},
setDefaultFormatterIfNeed(col) {
if (!col.formatter) {
col.formatter = (row, column, cellValue) => {
let value = cellValue
let padding = '0'
const excludes = [undefined, null, '']
if (excludes.indexOf(value) !== -1) {
padding = '6px'
value = '-'
}
return <span style={{ marginLeft: padding }}>{value}</span>
}
}
return col
},
generateColumn(name) {
const colMeta = this.meta[name] || {}
const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {}
let col = { prop: name, label: colMeta.label }
let col = { prop: name, label: colMeta.label, showOverflowTooltip: true }
col = this.generateColumnByName(name, col)
col = this.generateColumnByType(colMeta.type, col)
col = this.generateColumnByType(colMeta.type, col, colMeta)
col = this.setDefaultFormatterIfNeed(col)
col = Object.assign(col, customMeta)
col = this.addHelpTipsIfNeed(col)
col = this.addFilterIfNeed(col)
col = this.addOrderingIfNeed(col)
return col
},
generateTotalColumns() {
const config = _.cloneDeep(this.config)
let columns = []
for (let col of config.columns) {
const allColumnNames = Object.entries(this.meta)
.filter(([name, meta]) => !meta['write_only'])
.map(([name, meta]) => name)
.concat(config.columnsExtra || [])
let configColumns = config.columns || allColumnNames
const columnsExclude = config.columnsExclude || []
configColumns = configColumns.filter(item => !columnsExclude.includes(item))
// 解决后端 API 返回字段中包含 actions 的问题;
const hasColumnActions = configColumns.findIndex(item => item?.prop === 'actions') !== -1
if (!hasColumnActions) {
configColumns = [...configColumns.filter(i => i !== 'actions'), 'actions']
}
for (let col of configColumns) {
if (typeof col === 'object') {
columns.push(col)
} else if (typeof col === 'string') {
@@ -219,7 +303,11 @@ export default {
columns.push(col)
}
}
columns = columns.filter(item => {
if (item?.showFullContent) {
item.className = 'show-full-content'
}
let has = item.has
if (has === undefined) {
has = true
@@ -246,13 +334,14 @@ export default {
// 最小列
const minColumnsNames = _.get(this.iConfig, 'columnsShow.min', ['actions', 'id'])
.filter(n => defaultColumnsNames.indexOf(n) > -1)
.filter(n => totalColumnsNames.includes(n))
// 应该显示的列
const _tableConfig = localStorage.getItem('tableConfig')
? JSON.parse(localStorage.getItem('tableConfig'))
: {}
const tableName = this.config.name || this.$route.name + '_' + newURL(this.iConfig.url).pathname
let tableName = this.config.name || this.$route.name + '_' + newURL(this.iConfig.url).pathname
tableName = replaceAllUUID(tableName)
const configShowColumnsNames = _.get(_tableConfig[tableName], 'showColumns', null)
let showColumnsNames = configShowColumnsNames || defaultColumnsNames
if (showColumnsNames.length === 0) {
@@ -293,11 +382,17 @@ export default {
},
handlePopoverColumnsChange({ columns, url }) {
this.$log.debug('Columns change: ', columns)
if (columns === null) {
columns = this.cleanedColumnsShow.default
}
this.popoverColumns.currentCols = columns
const _tableConfig = localStorage.getItem('tableConfig')
? JSON.parse(localStorage.getItem('tableConfig'))
: {}
const tableName = this.config.name || this.$route.name + '_' + newURL(url).pathname
let tableName = this.config.name || this.$route.name + '_' + newURL(url).pathname
// 替换url中的uuid避免同一个类型接口生成多个keylocalStorage中的数据无法共用
tableName = replaceAllUUID(tableName)
_tableConfig[tableName] = {
'showColumns': columns
}

View File

@@ -2,13 +2,13 @@
<DataZTree ref="dataztree" :setting="treeSetting" class="data-z-tree" v-on="$listeners">
<slot v-if="treeSetting.hasRightMenu" slot="rMenu">
<li v-if="treeSetting.showCreate" id="m_create" class="rmenu" tabindex="-1" @click="createTreeNode">
<i class="fa fa-plus-square-o" /> {{ this.$t('tree.CreateNode') }}
<i class="fa fa-plus-square-o" /> {{ this.$t('tree.CreateNode') }}
</li>
<li v-if="treeSetting.showUpdate" id="m_edit" class="rmenu" tabindex="-1" @click="editTreeNode">
<i class="fa fa-pencil-square-o" /> {{ this.$t('tree.RenameNode') }}
<i class="fa fa-pencil-square-o" /> {{ this.$t('tree.RenameNode') }}
</li>
<li v-if="treeSetting.showDelete" id="m_del" class="rmenu" tabindex="-1" @click="removeTreeNode">
<i class="fa fa-minus-square" /> {{ this.$t('tree.DeleteNode') }}
<i class="fa fa-minus-square" /> {{ this.$t('tree.DeleteNode') }}
</li>
<slot name="rMenu" />
</slot>
@@ -39,12 +39,12 @@ export default {
showDelete: true,
showUpdate: true,
showSearch: false,
// 自定义header
customTreeHeader: false,
customTreeHeaderName: this.$t('assets.AssetTree'),
async: {
enable: true,
url: (process.env.VUE_APP_ENV === 'production') ? (`${this.setting.treeUrl}`) : (`${process.env.VUE_APP_BASE_API}${this.setting.treeUrl}`),
url: (process.env.VUE_APP_ENV === 'production')
? (`${this.setting.treeUrl}`)
: (`${process.env.VUE_APP_BASE_API}${this.setting.treeUrl}`),
autoParam: ['id=key', 'name=n', 'level=lv'],
type: 'get',
headers: {
@@ -128,9 +128,9 @@ export default {
query['asset'] = ''
url = `${this.setting.url}${combinator}node_id=${objectId}&show_current_asset=${show_current_asset}`
} else if (treeNode.meta.type === 'asset') {
query['asset'] = treeNode.meta.data.id
query['asset'] = treeNode.meta.data?.id || treeNode.id
query['node'] = ''
url = `${this.setting.url}${combinator}asset_id=${objectId}&show_current_asset=${show_current_asset}`
url = `${this.setting.url}${combinator}asset_id=${query.asset}&show_current_asset=${show_current_asset}`
}
this.$router.push({ query })
this.$emit('urlChange', url)
@@ -144,22 +144,20 @@ export default {
this.$axios.delete(
`${this.treeSetting.nodeUrl}${currentNode.meta.data.id}/`
).then(() => {
this.$message.success(this.$t('common.deleteSuccessMsg'))
this.$message.success(this.$tc('common.deleteSuccessMsg'))
this.zTree.removeNode(currentNode)
this.refreshTree()
}).catch(() => {
// this.$message.error(this.$t('common.deleteErrorMsg') + ' ' + error)
// this.$message.error(this.$tc('common.deleteErrorMsg') + ' ' + error)
})
},
onRename: function(event, treeId, treeNode, isCancel) {
const url = `${this.treeSetting.nodeUrl}${this.currentNodeId}/`
const currentNodeId = this.currentNodeId || treeNode.meta.data?.id || ''
const url = `${this.treeSetting.nodeUrl}${currentNodeId}/`
if (isCancel) {
return
}
this.$axios.patch(
url,
{ 'value': treeNode.name }
).then(res => {
this.$axios.patch(url, { 'value': treeNode.name }).then(res => {
let assetsAmount = treeNode.meta.data['assetsAmount']
if (!assetsAmount) {
assetsAmount = 0
@@ -167,8 +165,10 @@ export default {
treeNode.name = treeNode.name + ' (' + assetsAmount + ')'
treeNode.meta.data = res
this.zTree.updateNode(treeNode)
this.$message.success(this.$t('common.updateSuccessMsg'))
}).finally(() => { this.refreshTree() })
this.$message.success(this.$tc('common.updateSuccessMsg'))
}).finally(() => {
this.refreshTree()
})
},
onBodyMouseDown: function(event) {
const rMenuID = this.$refs.dataztree.$refs.ztree.iRMenuID
@@ -208,6 +208,9 @@ export default {
this.showRMenu('root', event.clientX, event.clientY)
} else if (treeNode && !treeNode.noR) {
this.zTree.selectNode(treeNode)
if (treeNode.meta?.data?.id) {
this.currentNodeId = treeNode.meta.data.id
}
this.showRMenu('node', event.clientX, event.clientY)
}
},
@@ -234,9 +237,9 @@ export default {
nodes: treeNodesIds
}
).then((res) => {
this.$message.success(this.$t('common.updateSuccessMsg'))
this.$message.success(this.$tc('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
this.$message.error(this.$tc('common.updateErrorMsg' + ' ' + error))
}).finally()
},
createTreeNode: function() {
@@ -264,9 +267,9 @@ export default {
const node = this.zTree.getNodeByParam('id', newNode.id, parentNode)
this.currentNodeId = node.meta.data.id || newNode.id
this.zTree.editName(node)
this.$message.success(this.$t('common.createSuccessMsg'))
this.$message.success(this.$tc('common.createSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.createErrorMsg') + ' ' + error)
this.$message.error(this.$tc('common.createErrorMsg') + ' ' + error)
})
},
refresh: function() {
@@ -285,30 +288,32 @@ export default {
</script>
<style scoped>
.rmenu {
font-size: 12px;
padding: 0 16px;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
height: 24px;
line-height: 24px;
box-sizing: border-box;
cursor: pointer;
}
.rmenu {
font-size: 12px;
padding: 0 16px;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
height: 24px;
line-height: 24px;
box-sizing: border-box;
cursor: pointer;
}
.rmenu > a:hover, .dropdown-menu > a:focus {
color: #262626;
text-decoration: none;
background-color: #f5f5f5;
}
.rmenu:hover{
background-color: #f5f7fa;
}
.rmenu > a:hover, .dropdown-menu > a:focus {
color: #262626;
text-decoration: none;
background-color: #f5f5f5;
}
.data-z-tree >>> .fa {
width: 10px;
}
.rmenu:hover {
background-color: #f5f7fa;
}
.data-z-tree >>> .fa {
width: 10px;
margin-right: 3px;
}
</style>

View File

@@ -0,0 +1,188 @@
<template>
<div>
<div>
<el-button
size="mini"
type="primary"
:disabled="isDisabled"
@click="onOpenDialog"
>{{ $tc('common.Setting') }}</el-button>
</div>
<Dialog
v-if="visible"
width="60%"
:visible.sync="visible"
:title="title"
:show-cancel="false"
:show-confirm="false"
:destroy-on-close="true"
v-bind="$attrs"
v-on="$listeners"
>
<AutoDataForm
ref="autoDataForm"
:form="form"
class="data-form"
v-bind="config"
@submit="onSubmit"
/>
</Dialog>
</div>
</template>
<script>
import { Dialog, AutoDataForm } from '@/components'
export default {
componentName: 'AutomationParams',
components: {
Dialog,
AutoDataForm
},
props: {
value: {
type: Object,
default: () => ({})
},
title: {
type: String,
default: function() {
return this.$t('assets.PushParams')
}
},
assets: {
type: Array,
default: () => []
},
nodes: {
type: Array,
default: () => []
},
method: {
type: String,
default: ''
},
url: {
type: String,
default: `/api/v1/assets/platform-automation-methods/`
}
},
data() {
return {
remoteMeta: {},
visible: false,
isDisabled: true,
form: this.value,
node_ids: this.nodes,
asset_ids: this.assets,
config: {
url: this.url,
hasSaveContinue: false,
hasButtons: true,
method: 'get',
fields: [],
fieldsMeta: {}
}
}
},
computed: {
refForm() {
return this.$refs.autoDataForm
}
},
watch: {
nodes: {
handler(val) {
this.node_ids = val
this.onFieldChangeHandle()
},
deep: true
},
assets: {
handler(val) {
this.asset_ids = val
this.onFieldChangeHandle()
},
deep: true
}
},
created() {
this.getUrlMeta()
},
methods: {
async getUrlMeta() {
const data = await this.$store.dispatch('common/getUrlMeta', { url: this.url })
this.remoteMeta = data.actions[this.config.method.toUpperCase()] || {}
},
async getFilterPlatforms() {
return await this.$axios.post(
'/api/v1/assets/platforms/filter-nodes-assets/',
{
'node_ids': this.node_ids,
'asset_ids': this.asset_ids
}
)
},
async onFieldChangeHandle() {
const platforms = await this.getFilterPlatforms()
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', {})
}
},
setFormConfig(methods) {
const newForm = {}
const fields = []
const fieldsMeta = {}
this.config.fields = []
for (const method of methods) {
const filterField = this.remoteMeta[method] || {}
// 修改资产、节点时不点击设置按钮也需要获取form表单值暴露出去
if (this.form.hasOwnProperty(method)) {
newForm[method] = this.form[method]
}
fields.push([filterField.label, [method]])
fieldsMeta[method] = {
fields: [],
fieldsMeta: {}
}
if (Object.keys(filterField?.children || {}).length > 0) {
for (const [k, v] of Object.entries(filterField.children)) {
const item = {
...v,
type: 'input'
}
delete item.default
fieldsMeta[method].fields.push(k)
fieldsMeta[method].fieldsMeta[k] = item
}
}
}
this.form = newForm
this.config.fields = fields
this.config.fieldsMeta = fieldsMeta
},
onOpenDialog() {
this.visible = true
},
onSubmit(form) {
this.visible = false
this.$emit('input', form)
this.$log.debug('Auto push form:', form)
}
}
}
</script>
<style scoped>
</style>

View File

@@ -2,7 +2,7 @@
<template>
<div>
<el-tabs type="border-card">
<el-tab-pane v-if="shouldHide('min')" :label="this.$t('common.CronTab.min')">
<el-tab-pane v-if="shouldHide('min')" :label="$tc('common.CronTab.min')">
<CrontabMin
ref="cronmin"
:check="checkNumber"
@@ -11,7 +11,7 @@
/>
</el-tab-pane>
<el-tab-pane v-if="shouldHide('hour')" :label="this.$t('common.CronTab.hour')">
<el-tab-pane v-if="shouldHide('hour')" :label="$tc('common.CronTab.hour')">
<CrontabHour
ref="cronhour"
:check="checkNumber"
@@ -20,7 +20,7 @@
/>
</el-tab-pane>
<el-tab-pane v-if="shouldHide('day')" :label="this.$t('common.CronTab.day')">
<el-tab-pane v-if="shouldHide('day')" :label="$tc('common.CronTab.day')">
<CrontabDay
ref="cronday"
:check="checkNumber"
@@ -29,7 +29,7 @@
/>
</el-tab-pane>
<el-tab-pane v-if="shouldHide('month')" :label="this.$t('common.CronTab.month')">
<el-tab-pane v-if="shouldHide('month')" :label="$tc('common.CronTab.month')">
<CrontabMonth
ref="cronmonth"
:check="checkNumber"
@@ -38,7 +38,7 @@
/>
</el-tab-pane>
<el-tab-pane v-if="shouldHide('week')" :label="this.$t('common.CronTab.week')">
<el-tab-pane v-if="shouldHide('week')" :label="$tc('common.CronTab.week')">
<CrontabWeek
ref="cronweek"
:check="checkNumber"
@@ -390,6 +390,7 @@ export default {
text-align: center;
margin-top: 20px;
}
.popup-main {
position: relative;
margin: 10px auto 0;
@@ -398,12 +399,14 @@ export default {
font-size: 12px;
overflow: hidden;
}
.popup-title {
overflow: hidden;
line-height: 34px;
padding-top: 6px;
background: #f2f2f2;
}
.popup-result {
position: relative;
box-sizing: border-box;
@@ -413,6 +416,7 @@ export default {
border: 1px solid #dcdfe6;
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%);
}
.popup-result .title {
position: absolute;
top: -17px;
@@ -424,11 +428,13 @@ export default {
line-height: 30px;
background: #fff;
}
.popup-result table {
text-align: center;
width: 100%;
margin: 0 auto;
}
.popup-result table span {
display: block;
width: 100%;
@@ -439,12 +445,14 @@ export default {
overflow: hidden;
border: 1px solid #e8e8e8;
}
.popup-result-scroll {
font-size: 12px;
line-height: 24px;
height: 10em;
overflow-y: auto;
}
.el-form-item--mini.el-form-item,
.el-form-item--small.el-form-item {
margin-bottom: 10px;

View File

@@ -25,7 +25,13 @@
<el-form-item>
<el-radio v-model="radioValue" :label="7">
{{ this.$t('common.CronTab.appoint') }}
<el-select v-model="checkboxList" clearable :placeholder="this.$t('common.CronTab.manyChoose')" multiple style="width:100%">
<el-select
v-model="checkboxList"
clearable
:placeholder="$tc('common.CronTab.manyChoose')"
multiple
style="width:100%"
>
<el-option v-for="item in 31" :key="item" :value="item">{{ item }}</el-option>
</el-select>
</el-radio>
@@ -45,7 +51,8 @@ export default {
},
check: {
type: Function,
default: () => {}
default: () => {
}
}
},
data() {
@@ -184,6 +191,6 @@ export default {
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
margin-bottom: 10px;
}
</style>

View File

@@ -25,7 +25,13 @@
<el-form-item>
<el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }}
<el-select v-model="checkboxList" clearable :placeholder="this.$t('common.CronTab.manyChoose')" multiple style="width:100%">
<el-select
v-model="checkboxList"
clearable
:placeholder="$tc('common.CronTab.manyChoose')"
multiple
style="width:100%"
>
<el-option v-for="item in 24" :key="item" :value="item-1">{{ item-1 }}</el-option>
</el-select>
</el-radio>
@@ -45,7 +51,8 @@ export default {
},
check: {
type: Function,
default: () => {}
default: () => {
}
}
},
data() {
@@ -153,6 +160,6 @@ export default {
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px
}
margin-bottom: 10px
}
</style>

View File

@@ -25,7 +25,14 @@
<el-form-item>
<el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }}
<el-select v-model="checkboxList" clearable :placeholder="this.$t('common.CronTab.manyChoose')" multiple style="width:100%" size="small">
<el-select
v-model="checkboxList"
clearable
:placeholder="$tc('common.CronTab.manyChoose')"
multiple
style="width:100%"
size="small"
>
<el-option v-for="item in 60" :key="item" :value="item-1">{{ item-1 }}</el-option>
</el-select>
</el-radio>
@@ -46,7 +53,8 @@ export default {
},
check: {
type: Function,
default: () => {}
default: () => {
}
}
},
data() {
@@ -151,6 +159,6 @@ export default {
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
margin-bottom: 10px;
}
</style>

View File

@@ -25,7 +25,13 @@
<el-form-item>
<el-radio v-model="radioValue" :label="4">
{{ this.$t('common.CronTab.appoint') }}
<el-select v-model="checkboxList" clearable :placeholder="this.$t('common.CronTab.manyChoose')" multiple style="width:100%">
<el-select
v-model="checkboxList"
clearable
:placeholder="$tc('common.CronTab.manyChoose')"
multiple
style="width:100%"
>
<el-option v-for="item in 12" :key="item" :value="item">{{ item }}</el-option>
</el-select>
</el-radio>
@@ -45,7 +51,8 @@ export default {
},
check: {
type: Function,
default: () => {}
default: () => {
}
}
},
data() {
@@ -158,6 +165,6 @@ export default {
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
margin-bottom: 10px;
}
</style>

View File

@@ -13,7 +13,7 @@
<script>
import parser from 'cron-parser'
import moment from 'moment'
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'CrontabResult',
props: {
@@ -46,10 +46,10 @@ export default {
const rule = 0 + ' ' + this.$options.propsData.ex
try {
this.resultList = []
var interval = parser.parseExpression(rule)
const interval = parser.parseExpression(rule)
for (let index = 0; index < 5; index++) {
const cur = interval.next().toString()
this.resultList.push(moment(cur).format('YYYY-MM-DD HH:mm:ss'))
this.resultList.push(toSafeLocalDateStr(cur))
}
} catch (error) {
this.isShow = false

View File

@@ -18,7 +18,13 @@
<el-form-item>
<el-radio v-model="radioValue" :label="6">
{{ this.$t('common.CronTab.appoint') }}
<el-select v-model="checkboxList" clearable :placeholder="this.$t('common.CronTab.manyChoose')" multiple style="width:100%">
<el-select
v-model="checkboxList"
clearable
:placeholder="$tc('common.CronTab.manyChoose')"
multiple
style="width:100%"
>
<el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{ item }}</el-option>
</el-select>
</el-radio>
@@ -39,7 +45,8 @@ export default {
},
check: {
type: Function,
default: () => {}
default: () => {
}
}
},
data() {
@@ -173,6 +180,6 @@ export default {
<style scoped>
.el-form-item--small.el-form-item {
margin-bottom: 10px;
}
margin-bottom: 10px;
}
</style>

View File

@@ -3,7 +3,7 @@
<div class="box">
<el-input v-model="input" clearable @focus="showDialog" @clear="onClear" />
</div>
<el-dialog :title="this.$t('common.CronTab.newCron')" :visible.sync="showCron" top="8vh" width="580px" append-to-body>
<el-dialog :title="$tc('common.CronTab.newCron')" :visible.sync="showCron" top="8vh" width="580px" append-to-body>
<Crontab
:expression="expression"
@hide="showCron = false"
@@ -15,6 +15,7 @@
<script>
import Crontab from './Crontab.vue'
export default {
components: { Crontab },
props: {
@@ -51,5 +52,5 @@ export default {
<style scoped>
.el-dialog__body {
padding: 12px 16px;
}
}
</style>

View File

@@ -10,7 +10,7 @@
placement="bottom-start"
@command="handleDropdownCallback"
>
<el-button :size="size" v-bind="cleanButtonAction(action)">
<el-button class="more-action" :size="size" v-bind="cleanButtonAction(action)">
{{ action.title }}<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh">
@@ -28,6 +28,10 @@
:command="[option, action]"
v-bind="option"
>
<span v-if="option.fa">
<i v-if="option.fa.startsWith('fa-')" :class="'fa ' + option.fa" />
<svg-icon v-else :icon-class="option.fa" style="font-size: 14px; margin-right: 2px; margin-left: -2px;" />
</span>
{{ option.title }}
</el-dropdown-item>
</template>
@@ -44,7 +48,11 @@
>
<el-tooltip :disabled="!action.tip" :content="action.tip" placement="top">
<span>
<i v-if="action.fa" :class="'fa ' + action.fa" />{{ action.title }}
<span v-if="action.fa" style="vertical-align: initial;">
<i v-if="action.fa.startsWith('fa-')" :class="'fa ' + action.fa" />
<svg-icon v-else :icon-class="action.fa" style="font-size: 14px;" />
</span>
{{ action.title }}
</span>
</el-tooltip>
</el-button>
@@ -153,7 +161,7 @@ export default {
}
</script>
<style scoped>
<style lang="scss" scoped>
.layout {
display: flex;
justify-content: center;
@@ -181,4 +189,22 @@ export default {
.el-button-ungroup .action-item:first-child {
margin-left: 0;
}
::v-deep .more-batch-processing {
&.el-dropdown-menu__item--divided {
margin-top: 0;
border-top: none;
color: #909399;
cursor: auto;
font-size: 12px;
line-height: 30px;
border-bottom: 1px solid #E4E7ED;
&:before {
height: 0;
}
}
&.el-dropdown-menu__item:not(.is-disabled):hover {
color: #909399;
background-color: #FFFFFF;
}
}
</style>

View File

@@ -43,16 +43,25 @@
<template v-for="opt in options">
<el-option
v-if="data.type === 'select'"
:key="opt.value"
v-bind="opt"
/>
<!-- TODO: 支持 el-checkbox-button 变体 -->
<el-checkbox
v-else-if="data.type === 'checkbox-group'"
:key="opt.label"
v-bind="opt"
/>
<el-checkbox-button
v-else-if="data.type === 'checkbox-group' && data.style === 'button'"
:key="opt.value"
v-bind="opt"
:label="'value' in opt ? opt.value : opt.label"
>
{{ opt.value }}
{{ opt.label }}
</el-checkbox-button>
<el-checkbox
v-else-if="data.type === 'checkbox-group' && data.style !== 'button'"
:key="opt.value"
v-bind="opt"
:label="'value' in opt ? opt.value : opt.label"
>
{{ opt.label }}
</el-checkbox>
<!-- WARNING: radio label 属性来表示 value 的含义 -->
<!-- FYI: radio value 属性可以在没有 radio-group 时用来关联到同一个 v-model -->
@@ -229,7 +238,9 @@ export default {
.then(resp => {
if (isOptionsCase) {
let formRenderer = this.$parent
while (formRenderer.$options._componentTag !== 'el-form-renderer') { formRenderer = formRenderer.$parent }
while (formRenderer.$options._componentTag !== 'el-form-renderer') {
formRenderer = formRenderer.$parent
}
formRenderer.setOptions(this.prop, resp)
} else {
this.propsInner = { [prop]: resp }

View File

@@ -14,10 +14,36 @@
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
<el-form-item v-if="hasButtons" class="form-buttons">
<el-button v-for="button in moreButtons" :key="button.title" size="small" v-bind="button" :loading="button.loading" @click="handleClick(button)">{{ button.title }}</el-button>
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">{{ $t('common.Reset') }}</el-button>
<el-button v-if="defaultButton && hasSaveContinue" size="small" @click="submitForm('form', true)">{{ $t('common.SaveAndAddAnother') }}</el-button>
<el-button v-if="defaultButton" size="small" :loading="isSubmitting" type="primary" @click="submitForm('form')">{{ $t('common.Submit') }}</el-button>
<el-button
v-for="button in moreButtons"
:key="button.title"
:loading="button.loading"
size="small"
v-bind="button"
@click="handleClick(button)"
>
{{ button.title }}
</el-button>
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">
{{ $t('common.Reset') }}
</el-button>
<el-button
v-if="defaultButton && hasSaveContinue"
size="small"
@click="submitForm('form', true)"
>
{{ $t('common.SaveAndAddAnother') }}
</el-button>
<el-button
v-if="defaultButton"
:disabled="!canSubmit"
:loading="isSubmitting"
size="small"
type="primary"
@click="submitForm('form')"
>
{{ $t('common.Submit') }}
</el-button>
</el-form-item>
</ElFormRender>
</template>
@@ -25,6 +51,7 @@
<script>
import ElFormRender from './components/el-form-renderer'
import { scrollToError } from '@/utils'
export default {
components: {
ElFormRender
@@ -42,6 +69,10 @@ export default {
type: Boolean,
default: true
},
canSubmit: {
type: Boolean,
default: true
},
hasSaveContinue: {
type: Boolean,
default: true
@@ -70,6 +101,9 @@ export default {
}
},
computed: {
elForm() {
return this.$refs.form
},
mobile() {
return this.$store.state.app.device === 'mobile'
},
@@ -102,6 +136,8 @@ export default {
const form = this.$refs['form']
const values = form.getFormValue()
callback(values, form, button)
},
getFormValue() {
}
}
}
@@ -125,7 +161,7 @@ export default {
}
.el-form ::v-deep .el-form-item__error {
position: inherit;
position: inherit;
}
.el-form ::v-deep .form-group-header {
@@ -144,10 +180,12 @@ export default {
font-size: 12px;
line-height: 18px;
}
.el-form ::v-deep .help-block a {
color: var(--color-primary);
}
.form-buttons {
padding-top: 10px;
margin-top: 20px;
}
</style>

View File

@@ -14,9 +14,23 @@ export const EmailCheck = {
trigger: ['blur', 'change']
}
export const IpCheck = {
required: true,
validator: (rule, value, callback) => {
value = value?.trim()
const urlRegExp = /^[\w://.?=&#-]+$/
if (urlRegExp.test(value)) {
callback()
} else {
callback(new Error(i18n.t('common.FormatError')))
}
},
trigger: ['blur', 'change']
}
export const specialEmojiCheck = {
validator: (rule, value, callback) => {
value = value.trim()
value = value?.trim()
if (/[\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/.test(value)) {
callback(new Error(i18n.t('common.NotSpecialEmoji')))
} else {
@@ -26,11 +40,26 @@ export const specialEmojiCheck = {
trigger: ['blur', 'change']
}
// 只能输入字母、数字、下划线
export const matchAlphanumericUnderscore = {
validator: (rule, value, callback) => {
value = value?.trim()
if (!/^[a-zA-Z0-9_]+$/.test(value)) {
callback(new Error(i18n.t('common.notAlphanumericUnderscore')))
} else {
callback()
}
},
trigger: ['blur', 'change']
}
export default {
IpCheck,
Required,
RequiredChange,
EmailCheck,
specialEmojiCheck
specialEmojiCheck,
matchAlphanumericUnderscore
}
export const JsonRequired = {
@@ -38,7 +67,24 @@ export const JsonRequired = {
trigger: 'change',
validator: (rule, value, callback) => {
try {
JSON.parse(value)
typeof value === 'string' ? JSON.parse(value) : value
callback()
} catch (e) {
callback(new Error(i18n.t('common.InvalidJson')))
}
}
}
export const JsonRequiredUserNameMapped = {
required: true,
trigger: 'change',
validator: (rule, value, callback) => {
try {
const v = typeof value === 'string' ? JSON.parse(value) : value
const hasUserName = _.map(v, (value) => value)
if (!hasUserName.includes('username')) {
callback(new Error(i18n.t('common.requiredHasUserNameMapped')))
}
callback()
} catch (e) {
callback(new Error(i18n.t('common.InvalidJson')))

View File

@@ -8,12 +8,12 @@
<el-table
ref="table"
v-loading="loading"
v-bind="tableAttrs"
:data="data"
:row-class-name="rowClassName"
v-bind="tableAttrs"
@select="selectStrategy.onSelect"
v-on="$listeners"
@selection-change="selectStrategy.onSelectionChange"
@select="selectStrategy.onSelect"
@select-all="selectStrategy.onSelectAll($event, canSelect)"
@sort-change="onSortChange"
>
@@ -91,28 +91,28 @@
<!--非树-->
<template v-else>
<el-data-table-column v-if="hasSelection" type="selection" :align="selectionAlign" :selectable="canSelect" />
<el-data-table-column v-if="hasSelection" :align="selectionAlign" :selectable="canSelect" type="selection" />
<el-data-table-column
v-for="col in columns"
:key="col.prop"
:formatter="typeof col.formatter === 'function' ? col.formatter : null"
:filters="col.filters || null"
:filter-multiple="false"
:filter-method="typeof col.filterMethod === 'function' ? col.filterMethod : null"
:filter-multiple="false"
:filters="col.filters || null"
:formatter="typeof col.formatter === 'function' ? col.formatter : null"
v-bind="{align: columnsAlign, ...col}"
>
<template v-if="col.formatter && typeof col.formatter !== 'function'" v-slot:default="{row, column, index}">
<div
:is="col.formatter"
:key="row.id"
:table-data="data"
:row="row"
:cell-value="row[col.prop]"
:col="col"
:column="column"
:index="index"
:url="url"
:reload="getList"
:col="col"
:cell-value="row[col.prop]"
:row="row"
:table-data="data"
:url="url"
/>
</template>
</el-data-table-column>
@@ -122,13 +122,12 @@
<el-pagination
v-if="hasPagination"
:current-page="page"
:page-sizes="paginationSizes"
:page-size="size"
:total="total"
:background="paginationBackground"
style="text-align: right; padding: 10px 0;"
:current-page="page"
:layout="paginationLayout"
:page-size="size"
:page-sizes="paginationSizes"
:total="total"
v-bind="extraPaginationAttrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@@ -136,18 +135,18 @@
<the-dialog
ref="dialog"
:new-title="dialogNewTitle"
:button-size="buttonSize"
:dialog-attrs="dialogAttrs"
:edit-title="dialogEditTitle"
:view-title="dialogViewTitle"
:form="form"
:form-attrs="formAttrs"
:dialog-attrs="dialogAttrs"
:button-size="buttonSize"
:new-title="dialogNewTitle"
:view-title="dialogViewTitle"
@confirm="onConfirm"
>
<template v-slot="scope">
<!-- @slot 表单作用域插槽当编辑查看时传入row新增时row=null -->
<slot name="form" :row="scope.row" />
<slot :row="scope.row" name="form" />
</template>
</the-dialog>
</template>
@@ -167,6 +166,7 @@ import getLocatedSlotKeys from './utils/extract-keys'
import transformSearchImmediatelyItem from './utils/search-immediately-item'
import isFalsey from './utils/is-falsey'
import merge from 'deepmerge'
const defaultFirstPage = 1
const noPaginationDataPath = 'payload'
@@ -268,7 +268,8 @@ export default {
*/
beforeSearch: {
type: Function,
default() {}
default() {
}
},
/**
* 单选, 适用场景: 不可以批量删除
@@ -360,28 +361,36 @@ export default {
*/
newText: {
type: String,
default: '新增'
default: function() {
return this.$t('ops.Add')
}
},
/**
* 修改按钮文案
*/
editText: {
type: String,
default: '修改'
default: function() {
return this.$t('ops.Modify')
}
},
/**
* 查看按钮文案
*/
viewText: {
type: String,
default: '查看'
default: function() {
return this.$t('ops.View')
}
},
/**
* 删除按钮文案
*/
deleteText: {
type: String,
default: '删除'
default: function() {
return this.$t('ops.Delete')
}
},
/**
* 删除提示语。接受要删除的数据(单个对象或数组);返回字符串
@@ -391,7 +400,7 @@ export default {
deleteMessage: {
type: Function,
default() {
return `确认${this.deleteText}吗?`
return this.$t('ops.Confirm') + this.deleteText + '?'
}
},
/**
@@ -450,7 +459,7 @@ export default {
onSuccess: {
type: Function,
default() {
return this.$message.success('操作成功')
return this.$message.success(this.$t('ops.SuccessfulOperation'))
}
},
/**
@@ -707,7 +716,8 @@ export default {
},
extraPaginationAttrs: {
type: Object,
default: () => {}
default: () => {
}
},
hasSelection: {
type: Boolean,
@@ -1037,6 +1047,7 @@ export default {
} else {
this.innerQuery = merge(this.innerQuery, attrs)
}
this.selected.splice(0, this.selected.length)
return this.getList()
},
searchDate(attrs) {
@@ -1156,7 +1167,7 @@ export default {
* @param {object|object[]} - 要删除的数据对象或数组
*/
onDefaultDelete(data) {
this.$confirm(this.deleteMessage(data), '提示', {
this.$confirm(this.deleteMessage(data), this.$t('common.Info'), {
type: 'warning',
confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => {
@@ -1199,7 +1210,9 @@ export default {
remain === 0 &&
this.page === lastPage &&
this.page > defaultFirstPage
) { this.page-- }
) {
this.page--
}
},
// 树形table相关

View File

@@ -1,16 +1,22 @@
.el-data-table ::v-deep .el-pagination{
text-align: center !important;
}
.el-data-table ::v-deep .el-table td{
padding: 4px 0;
}
.el-data-table ::v-deep .el-table th{
padding: 4px 0;
}
.el-data-table ::v-deep .el-form-item{
margin-bottom:10px !important ;
margin-top:10px;
}
.el-data-table ::v-deep .el-pagination{
padding:15px 0 !important ;
.el-data-table ::v-deep .el-table td {
padding: 4px 0;
}
.el-data-table ::v-deep .el-table th {
padding: 4px 0;
}
.el-data-table ::v-deep .el-form-item {
margin-bottom: 10px !important;
margin-top: 10px;
}
.el-data-table ::v-deep .el-pagination {
text-align: right;
padding: 15px 25px 20px 15px;
.el-pagination__total {
float: left;
}
}

View File

@@ -1,11 +1,11 @@
<template>
<ElDatableTable
ref="table"
class="el-table"
class="el-data-table"
v-bind="tableConfig"
@sizeChange="handleSizeChange"
@update="onUpdate"
v-on="iListeners"
@sizeChange="handleSizeChange"
/>
</template>
@@ -21,7 +21,8 @@ export default {
props: {
config: {
type: Object,
default: () => {}
default: () => {
}
}
},
data() {
@@ -49,7 +50,11 @@ export default {
stripe: false, // 斑马纹表格
border: true, // 表格边框
fit: true, // 宽度自适应,
tooltipEffect: 'dark'
tooltipEffect: 'dark',
rowClassName: ({ row }) => {
const selected = this.dataTable.selected.find(item => item.id === row.id)
return selected ? 'selected-row' : ''
}
},
extraButtons: userTableActions.extraButtons,
onEdit: (row) => {
@@ -65,6 +70,7 @@ export default {
},
pageCount: 5,
paginationLayout: 'total, sizes, prev, pager, next',
paginationSize: JSON.parse(localStorage.getItem('paginationSize')) || 15,
paginationSizes: [15, 30, 50, 100],
paginationBackground: true,
transformQuery: query => {
@@ -86,40 +92,36 @@ export default {
}
return query
},
theRowDefaultIsSelected: (row) => { return false }
theRowDefaultIsSelected: (row) => {
return false
}
}
}
},
computed: {
iListeners() {
const defaultListeners = {}
return Object.assign(defaultListeners, this.$listeners, this.tableConfig?.listeners)
},
dataTable() {
return this.$refs.table
},
tableConfig() {
const tableDefaultConfig = this.defaultConfig
tableDefaultConfig.paginationSize = _.get(this.globalTableConfig, 'paginationSize', 15)
let tableAttrs = tableDefaultConfig.tableAttrs
if (this.config.tableAttrs) {
tableAttrs = Object.assign(tableAttrs, this.config.tableAttrs)
}
const config = Object.assign(tableDefaultConfig, this.config)
config.tableAttrs = tableAttrs
this.$log.debug('elTableConfig', config)
return config
},
iListeners() {
return Object.assign({}, this.$listeners, this.tableConfig.listeners)
},
dataTable() {
return this.$refs.table
},
...mapGetters({
'globalTableConfig': 'tableConfig'
})
},
watch: {
config: {
handler() {
// this.getList()
},
deep: true
}
},
watch: {},
methods: {
getList() {
this.$refs.table.clearSelection()
@@ -153,6 +155,7 @@ export default {
}
},
handleSizeChange(val) {
localStorage.setItem('paginationSize', val)
this.$store.commit('table/SET_TABLE_CONFIG',
{
key: 'paginationSize',
@@ -164,37 +167,5 @@ export default {
}
</script>
<style lang="less" scoped>
.el-table ::v-deep .el-table__row > td {
line-height: 1.5;
padding: 8px 0;
}
.el-table ::v-deep .el-table__row > td> div > span {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.el-table ::v-deep .el-table__header > thead > tr >th {
padding: 8px 0;
background-color: #F5F5F6;
font-size: 13px;
line-height: 1.5;
}
.table{
margin-top: 15px;
}
//分页
.el-pagination ::v-deep .el-pagination__total{
float: left;
}
.el-pagination ::v-deep .el-pagination__sizes{
float: left;
}
//修改颜色
// .el-button--text{
// color: #409EFF;
// }
<style lang="scss" scoped>
</style>

View File

@@ -1,47 +1,31 @@
<template>
<div>
<div
v-if="treeSetting.customTreeHeader"
class="tree-header treebox"
>
<div class="content">
<span class="title">
{{ treeSetting.customTreeHeaderName }}
</span>
<span class="tree-banner-icon-zone">
<a id="searchIcon" class="tree-search special">
<i
class="fa fa-search tree-banner-icon"
@click.stop="treeSearch"
<div class="treebox">
<div>
<el-input
v-if="treeSetting.showSearch && showTreeSearch"
v-model="treeSearchValue"
:placeholder="$tc('common.Search')"
class="fixed-tree-search"
prefix-icon="fa fa-search"
size="mini"
@input="treeSearchHandle"
>
<span slot="suffix">
<!-- <i class="fa fa-search" style="font-size: 14px; color: #676A6C;" /> -->
<svg-icon
:icon-class="'close'"
class="icon"
style="font-size: 14px;"
@click="onClose"
/>
<input
id="searchInput"
v-model="treeSearchValue"
type="text"
autocomplete="off"
class="tree-input"
>
</a>
<i
class="fa fa-refresh tree-banner-icon"
style="margin-right: 2px;"
@click.stop="refresh"
/>
</span>
</span>
</el-input>
</div>
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<ul v-show="!loading" :id="iZTreeID" class="ztree" />
<div v-if="treeSetting.treeUrl===''" class="tree-empty">
{{ this.$t('common.tree.Empty') }}
</div>
</div>
<div v-else class="treebox">
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<ul v-show="!loading" :id="iZTreeID" class="ztree" />
<ul v-show="!loading" :id="iZTreeID" :key="iZTreeID" class="ztree" />
<div v-if="treeSetting.treeUrl===''" class="tree-empty">
{{ this.$t('common.tree.Empty') }}
<a id="tree-refresh"><i class="fa fa-refresh" /></a>
@@ -62,16 +46,17 @@ import $ from '@/utils/jquery-vendor.js'
import '@ztree/ztree_v3/js/jquery.ztree.all.min.js'
import '@ztree/ztree_v3/js/jquery.ztree.exhide.min.js'
import '@/styles/ztree.css'
import '@/styles/ztree_icon.css'
import axiosRetry from 'axios-retry'
const defaultObject = {
type: Object,
default: () => {}
default: () => {
}
}
export default {
name: 'ZTree',
components: {
},
components: {},
props: {
setting: defaultObject
},
@@ -83,6 +68,7 @@ export default {
rMenu: '',
init: false,
loading: false,
showTreeSearch: JSON.parse(localStorage.getItem('showTreeSearch')) || false,
treeSearchValue: ''
}
},
@@ -93,88 +79,99 @@ export default {
},
mounted() {
window.refresh = this.refresh
window.treeSearch = this.treeSearch
window.onSearch = this.onSearch
this.initTree()
},
beforeDestroy() {
$.fn.zTree.destroy(this.iZTreeID)
},
methods: {
initTree: function() {
async initTree(refresh = false) {
const vm = this
let treeUrl
if (this.init) {
this.loading = true
}
if (this.init && this.treeSetting.treeUrl.indexOf('/perms/') !== -1 && this.treeSetting.treeUrl.indexOf('rebuild_tree') === -1) {
treeUrl = (this.treeSetting.treeUrl.indexOf('?') === -1) ? `${this.treeSetting.treeUrl}?rebuild_tree=1` : `${this.treeSetting.treeUrl}&rebuild_tree=1`
this.loading = true
if (refresh && this.treeSetting.treeUrl.indexOf('/perms/') !== -1 &&
this.treeSetting.treeUrl.indexOf('rebuild_tree') === -1
) {
treeUrl = (this.treeSetting.treeUrl.indexOf('?') === -1)
? `${this.treeSetting.treeUrl}?rebuild_tree=1`
: `${this.treeSetting.treeUrl}&rebuild_tree=1`
} else {
treeUrl = this.treeSetting.treeUrl
}
this.$axios.get(treeUrl, {
if (refresh) {
$.fn.zTree.destroy(this.iZTreeID)
}
let res = await this.$axios.get(treeUrl, {
'axios-retry': {
retries: 20,
retryCondition: e => {
return axiosRetry.isNetworkOrIdempotentRequestError(e) || e.response.status === 409
},
shouldResetTimeout: true,
retryDelay: () => { return 5000 }
retryDelay: () => {
return 5000
}
}
}).then(res => {
if (!res) res = []
if (res.length === 0) {
res.push({
name: this.$t('common.tree.Empty')
})
}
this.treeSetting.treeUrl = treeUrl
if (this.init) {
vm.zTree.destroy()
}
this.zTree = $.fn.zTree.init($(`#${this.iZTreeID}`), this.treeSetting, res)
if (!this.treeSetting.customTreeHeader) {
this.rootNodeAddDom(this.zTree)
}
// 手动上报事件, Tree加载完成
this.$emit('TreeInitFinish', this.zTree)
if (this.treeSetting.showMenu) {
this.rMenu = $(`#${this.iRMenuID}`)
}
if (this.treeSetting.otherMenu) {
$('.menu-actions').append(this.otherMenu)
}
}).finally(_ => {
vm.loading = false
vm.init = true
})
vm.loading = false
if (!res) res = []
if (res?.length === 0) {
res?.push({
name: this.$t('common.tree.Empty')
})
}
this.treeSetting.treeUrl = treeUrl
vm.zTree = $.fn.zTree.init($(`#${this.iZTreeID}`), this.treeSetting, res)
const rootNode = this.zTree.getNodes()[0]
this.rootNodeAddDom(rootNode)
// 手动上报事件, Tree加载完成
this.$emit('TreeInitFinish', this.zTree)
if (this.treeSetting.showMenu) {
this.rMenu = $(`#${this.iRMenuID}`)
}
if (this.treeSetting?.otherMenu) {
$('.menu-actions').append(this.otherMenu)
}
},
rootNodeAddDom(ztree) {
onSearch() {
this.showTreeSearch = !this.showTreeSearch
localStorage.setItem('showTreeSearch', JSON.stringify(this.showTreeSearch))
},
onClose() {
this.refresh()
this.onSearch()
},
rootNodeAddDom(rootNode) {
const { showSearch, showRefresh } = this.treeSetting
const searchIcon = `<a class="tree-search" id="searchIcon">
<i class='fa fa-search tree-banner-icon' onclick="treeSearch()" /></i>
<input type="text" autocomplete="off" id="searchInput" class="tree-input" />
</a>`
const refreshIcon = "<a id='tree-refresh' onclick='refresh()'><i class='fa fa-refresh'></i></a>"
const searchIcon = `
<a class="tree-action-btn" id="search-btn" onclick="onSearch()">
<i class="fa fa-search tree-banner-icon"></i>
</a>`
const refreshIcon = `
<a id="tree-refresh" class="tree-action-btn" onclick="refresh()">
<i class="fa fa-refresh"></i>
</a>`
const treeActions = `${showSearch ? searchIcon : ''}${showRefresh ? refreshIcon : ''}`
const icons = `<span class="">${treeActions}</span>`
const rootNode = ztree.getNodes()[0]
const icons = `
<span style="float: right; margin-right: 10px">
${treeActions}
</span>`
if (rootNode) {
const $rootNodeRef = $('#' + rootNode.tId + '_a')
$rootNodeRef.after(icons)
}
},
refresh() {
async refresh() {
this.treeSearchValue = ''
const result = this.treeSetting?.callback?.refresh()
if (result && result.then) {
result.finally(() => {
this.initTree()
})
} else {
this.initTree()
if (this.treeSetting?.callback?.refresh) {
await this.treeSetting.callback.refresh()
}
this.zTree.destroy()
setTimeout(() => this.initTree(true), 200)
},
treeSearch() {
const searchIcon = document.getElementById(`searchIcon`)
@@ -190,16 +187,15 @@ export default {
searchIcon.classList.toggle('active')
}
}
searchInput.oninput = _.debounce((e) => {
e.stopPropagation()
const value = e.target.value || ''
if (this.treeSetting.async.enable) {
this.filterAssetsServer(value)
} else {
this.filterTree(value)
}
}, 600)
searchInput.oninput = e => this.treeSearchHandle((e.target.value || ''))
},
treeSearchHandle: _.debounce(function(value) {
if (this.treeSetting.async.enable) {
this.filterAssetsServer(value)
} else {
this.filterTree(value)
}
}, 600),
getCheckedNodes: function() {
return this.zTree.getCheckedNodes(true)
},
@@ -310,7 +306,7 @@ export default {
this.zTree.hideNodes(treeNodes)
}
let treeUrl = this.treeSetting.treeUrl
let treeUrl = this.treeSetting.searchUrl ? this.treeSetting.searchUrl : this.treeSetting.treeUrl
const filterField = treeUrl.includes('?') ? `&search=${keyword}` : `?search=${keyword}`
if (treeUrl.indexOf('assets/nodes/children/tree') > -1) {
treeUrl = treeUrl + '&all=all'
@@ -323,8 +319,10 @@ export default {
const newNode = { id: 'search', name: name, isParent: true, open: true, zAsync: true }
searchNode = this.zTree.addNodes(null, newNode)[0]
searchNode.zAsync = true
this.rootNodeAddDom(searchNode)
const nodesGroupByOrg = this.groupBy(nodes, (node) => {
return node.meta.data.org_name
return node.meta?.data?.org_name
})
for (const item of nodesGroupByOrg) {
@@ -332,180 +330,267 @@ export default {
}
searchNode.open = true
})
return
}
}
}
</script>
<style lang='scss' scoped>
div.rMenu {
position: absolute;
visibility: hidden;
text-align: left;
top: 0;
left: 0;
z-index: 999;
float: left;
padding: 0 0;
margin: 2px 0 0;
list-style: none;
background-clip: padding-box;
}
.dataTables_wrapper .dataTables_processing {
opacity: .9;
border: none;
}
div.rMenu li{
margin: 6px 0;
cursor: pointer;
list-style: none outside none;
}
.dropdown-menu {
border: medium none;
min-width: 160px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
display: block;
float: left;
font-size: 12px;
left: 0;
list-style: none outside none;
padding: 0;
position: absolute;
text-shadow: none;
top: 100%;
z-index: 1000;
}
.ztree ::v-deep .fa {
font: normal normal normal 14px/1 FontAwesome !important;
}
.dropdown a:hover {
background-color: #f1f1f1
}
.dropdown-menu > li > a {
border-radius: 3px;
color: inherit;
line-height: 25px;
margin: 4px;
text-align: left;
font-weight: normal;
display: block;
padding: 3px 20px;
clear: both;
white-space: nowrap;
}
.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus {
color: #262626;
text-decoration: none;
background-color: #f5f5f5;
}
.treebox {
height: 80vh;
<style lang="scss" scoped>
::-webkit-scrollbar-corner {
background: transparent;
}
::-webkit-scrollbar-track:horizontal {
background: #FFFFFF;
border-radius: 10px;
}
div.rMenu {
position: absolute;
visibility: hidden;
text-align: left;
top: 0;
left: 0;
z-index: 999;
float: left;
padding: 0 0;
margin: 2px 0 0;
list-style: none;
background-clip: padding-box;
}
.dataTables_wrapper .dataTables_processing {
opacity: .9;
border: none;
}
div.rMenu li {
margin: 6px 0;
cursor: pointer;
list-style: none outside none;
}
.dropdown-menu {
border: medium none;
min-width: 160px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
display: block;
float: left;
font-size: 12px;
left: 0;
list-style: none outside none;
padding: 0;
position: absolute;
text-shadow: none;
top: 100%;
z-index: 1000;
}
.ztree ::v-deep .fa {
font: normal normal normal 14px/1 FontAwesome !important;
}
.dropdown a:hover {
background-color: #f1f1f1
}
.dropdown-menu > li > a {
border-radius: 3px;
color: inherit;
line-height: 25px;
margin: 4px;
text-align: left;
font-weight: normal;
display: block;
padding: 3px 20px;
clear: both;
white-space: nowrap;
}
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {
color: #262626;
text-decoration: none;
background-color: #f5f5f5;
}
.treebox {
background-color: transparent;
> > > .ztree {
overflow: auto;
background-color: transparent;
height: calc(100vh - 237px);
li {
background-color: transparent !important;
.button {
background-color: rgba(0, 0, 0, 0);
}
ul {
background-color: transparent !important;
}
}
}
::v-deep #tree-refresh {
margin-left: 3px;
}
::v-deep #tree-refresh {
margin-left: 3px;
}
::v-deep .tree-banner-icon-zone {
position: absolute;
right: 7px;
height: 30px;
overflow: hidden;
.fa {
color: #838385 !important;;
&:hover {
color: #606266 !important;;
}
}
::v-deep .tree-banner-icon-zone {
position: absolute;
right: 7px;
}
::v-deep .tree-search {
position: relative;
top: -2px;
width: 20px;
height: 20px;
display: inline-block;
border-radius: 12px;
vertical-align: sub;
transition: .25s;
overflow: hidden;
.fa {
width: 13px !important;
}
.fa-search {
padding-top: 1px;
}
}
::v-deep .tree-search .tree-banner-icon {
position: absolute;
top: 4px;
left: 6px;
border-radius: 12px;
overflow: hidden;
background-color: transparent !important;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
::v-deep .tree-search.active {
width: 160px;
background-color: #ffffff !important;
}
::v-deep .tree-search.active:hover {
border-radius: 12px;
}
::v-deep .tree-search input {
position: relative;
left: 20px;
width: 133px;
height: 100%;
background-color: #ffffff !important;
color: #606266;
display: flex;
justify-content: center;
align-items: center;
border: none;
outline: none;
}
.tree-header {
position: relative;
.title {
font-weight: 500;
}
.content {
height: 30px;
line-height: 30px;
border-bottom: 1px solid #e0e0e0;
border-radius: 3px;
padding: 0 5px;
box-sizing: border-box;
overflow: hidden;
.fa {
color: #838385!important;;
&:hover {
color: #606266!important;;
}
}
}
::v-deep .tree-search {
position: relative;
top: -2px;
width: 20px;
height: 20px;
display: inline-block;
border-radius: 12px;
vertical-align: sub;
transition: .25s;
overflow: hidden;
.fa {
width: 13px!important;
}
.fa-search {
padding-top: 1px;
}
}
::v-deep .tree-search .tree-banner-icon {
position: absolute;
top: 1px;
left: 6px;
width: 6px;
height: 6px;
border-radius: 12px;
padding: 10px 6px;
overflow: hidden;
background-color: transparent!important;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background-color: #D7D8DC;
.rotate {
transition: all .1 .8s;
transform: rotate(-90deg);
}
.fa-caret-down {
font-size: 16px;
}
.special {
top: 1px !important;
}
}
}
.tree-empty {
margin-left: 4px;
}
.fixed-tree-search {
margin-bottom: 10px;
& > > > .el-input__inner {
border-radius: 4px;
background: #fafafa;
padding-right: 32px;
}
::v-deep .tree-search.active {
width: 160px;
background-color: #ffffff!important;
& > > > .el-input__suffix {
padding-right: 8px;
}
::v-deep .tree-search.active:hover {
border-radius: 12px;
& > > > .el-input__prefix {
padding-left: 6px;
}
::v-deep .tree-search input {
position: relative;
left: 20px;
width: 133px;
height: 100%;
background-color: #ffffff!important;
& > > > .el-input__suffix-inner {
line-height: 30px;
}
}
.icon-refresh {
border-radius: 4px;
padding: 0 1px;
z-index: 1;
&:hover {
cursor: pointer;
color: #606266;
display: flex;
justify-content: center;
align-items: center;
border: none;
outline: none;
}
.tree-header {
position: relative;
.title {
font-weight: 500;
}
.content {
height: 30px;
line-height: 30px;
border-bottom: 1px solid #e0e0e0;
border-radius: 3px;
padding: 0 5px;
box-sizing: border-box;
overflow: hidden;
cursor: pointer;
background-color: #D7D8DC;
.rotate {
transition: all .1.8s;
transform: rotate(-90deg);
}
.fa-caret-down {
font-size: 16px;
}
.special {
top: 1px!important;
}
}
}
.tree-empty {
margin-left: 4px;
border-color: #d2d2d2;
background-color: #e6e6e6;
}
}
.icon {
cursor: pointer;
}
.tree-action-btn {
padding: 0 2px;
color: red;
}
</style>

View File

@@ -1,4 +1,6 @@
<script type="text/jsx">
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'ItemValue',
props: {
@@ -15,27 +17,60 @@ export default {
default: null
}
},
computed: {
displayValue() {
if ([null, undefined, ''].includes(this.value)) {
return '-'
}
if (typeof this.value === 'boolean') {
return this.toChoicesDisplay(this.value)
} else if (typeof this.value === 'object') {
return this.value
} else if (this.value instanceof Array) {
return this.value.map(item => {
if (typeof item === 'object') {
return item.label || item.title
} else {
return item
}
}).join(', ')
} else if (this.isDatetime(this.value)) {
return toSafeLocalDateStr(this.value)
} else {
return this.value
}
}
},
methods: {
toChoicesDisplay(value) {
if (!value) {
return this.$t('common.No')
}
return this.$t('common.Yes')
},
isDatetime(value) {
if (typeof value !== 'string') {
return false
}
if (value.split(' ').length !== 3) {
return false
}
if (value.split(' ')[1].split(':').length !== 3) {
return false
}
if (isNaN(value) && !isNaN(Date.parse(value))) {
return true
}
}
},
render(h) {
if (typeof this.formatter === 'function') {
return this.formatter(this.item, this.value)
}
if (typeof this.value === 'boolean') {
return (
<span class='item-value'>{this.toChoicesDisplay(this.value)}</span>
)
}
if (this.value instanceof Array) {
const newArr = this.value || []
return (
<span class='item-value'>
<span>
{
newArr.map((item, index) => <div key={index}>{item.key}{item.value} </div>)
}
@@ -43,15 +78,14 @@ export default {
)
}
return (
<span class='item-value'>{this.value}</span>
<span>{this.displayValue}</span>
)
}
}
</script>
<style scoped>
.item-value {
word-break: break-word;
a {
color: var(--color-success);
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<DetailCard v-if="!loading && hasObject && items.length > 0" :items="items" v-bind="$attrs" />
</template>
<script>
import DetailCard from './index'
import { copy, toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'AutoDetailCard',
components: { DetailCard },
props: {
object: {
type: Object,
default: () => ({})
},
url: {
type: String,
required: true
},
fields: {
type: Array,
default: null
},
excludes: {
type: Array,
default: null
},
showUndefine: {
type: Boolean,
default: true
},
formatters: {
type: Object,
default: () => ({})
},
nested: {
type: String,
default: null
}
},
data() {
return {
items: [],
loading: true
}
},
computed: {
iObject() {
if (this.nested) {
return this.object[this.nested] || {}
} else {
return this.object
}
},
hasObject() {
return Object.keys(this.iObject).length > 0
}
},
async mounted() {
await this.optionAndGenFields()
this.loading = false
},
methods: {
defaultFormatter(fields) {
const formatter = {}
for (const name of fields) {
formatter[name] = function(item, val) {
if (val === '-') {
return <span>{'-'}</span>
}
return (<span style={{ cursor: 'pointer' }} onClick={() => copy(val)}>
{val}
</span>)
}
}
return formatter
},
async optionAndGenFields() {
const data = await this.$store.dispatch('common/getUrlMeta', { url: this.url })
let remoteMeta = data.actions['GET'] || {}
if (this.nested) {
remoteMeta = remoteMeta[this.nested]?.children || {}
}
let fields = this.fields
fields = fields || Object.keys(remoteMeta)
const defaultExcludes = ['org_id']
const excludes = (this.excludes || []).concat(defaultExcludes)
fields = fields.filter(item => !excludes.includes(item))
const defaultFormatter = this.defaultFormatter(fields)
for (const name of fields) {
if (typeof name === 'object') {
this.items.push(name)
continue
}
const fieldMeta = remoteMeta[name]
if (!fieldMeta) {
continue
}
if (fieldMeta['write_only']) {
continue
}
let value = this.iObject[name]
const label = fieldMeta.label
if (Array.isArray(value)) {
if (typeof value[0] === 'object') {
value.forEach(item => {
const fieldName = `${name}.${item.name}`
if (excludes.includes(fieldName)) {
return
}
this.items.push({
key: item.label,
value: item.value
})
})
} else if (typeof value[0] === 'string') {
value.forEach((item, index) => {
let data = {}
if (index === 0) {
data = {
key: label,
value: value[index]
}
} else {
data = {
value: value[index]
}
}
this.items.push(data)
})
}
continue
}
if (value === null || value === '') {
value = '-'
} else if (fieldMeta.type === 'datetime') {
value = toSafeLocalDateStr(value)
} else if (fieldMeta.type === 'labeled_choice') {
value = value?.['label']
} else if (fieldMeta.type === 'related_field' || fieldMeta.type === 'nested object') {
value = value?.['name']
} else if (fieldMeta.type === 'm2m_related_field') {
value = value?.map(item => item['name']).join(', ')
} else if (fieldMeta.type === 'boolean') {
value = value ? this.$t('common.Yes') : this.$t('common.No')
}
if (value === undefined) {
if (this.showUndefine) {
value = '-'
} else {
continue
}
}
const item = {
key: label,
value: value,
formatter: this.formatters[name] || defaultFormatter[name]
}
this.items.push(item)
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,22 +1,11 @@
<template>
<IBox :title="title" fa="fa-info-circle">
<div class="content">
<el-row v-if="this.$route.params.id" :gutter="10" class="item">
<el-col :span="6"><div :style="{ 'text-align': align }" class="item-label"><label>ID: </label></div></el-col>
<el-col :span="18"><div class="item-text">{{ this.$route.params.id }}</div></el-col>
</el-row>
<el-row v-for="item in items" :key="'card-' + item.key" :gutter="10" class="item">
<el-col :span="6">
<div :style="{ 'text-align': align }" class="item-label"><label>{{ item.key }}: </label></div>
</el-col>
<el-col :span="18">
<div class="item-text">
<ItemValue :value="item.value" v-bind="item" />
</div>
</el-col>
</el-row>
<slot />
</div>
<IBox :title="title" :fa="fa">
<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" />
</el-form-item>
</el-form>
<slot />
</IBox>
</template>
@@ -34,6 +23,10 @@ export default {
return this.$t('common.BasicInfo')
}
},
fa: {
type: String,
default: 'fa-info-circle'
},
items: {
type: Array,
default: () => []
@@ -46,7 +39,42 @@ export default {
}
</script>
<style scoped>
<style lang="scss" scoped>
.el-card__body {
padding: 20px 40px;
}
.el-form-item {
border-bottom: 1px dashed #EBEEF5;
padding: 1px 0;
margin-bottom: 0;
&:last-child {
border-bottom: none;
}
&:hover {
}
>>> .el-form-item__label {
padding-right: 8%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
>>> .el-form-item__content {
font-size: 13px;
}
>>> .el-tag--mini {
margin-right: 3px;
}
}
.item-value span {
word-break: break-word;
}
.content {
font-size: 13px;
line-height: 2.5;

View File

@@ -0,0 +1,105 @@
<template>
<Dialog
v-if="detailVisible"
:show-cancel="false"
:show-confirm="false"
:title="title"
:visible.sync="detailVisible"
>
<div>
<div v-if="isEmpty()" style="text-align: center">
{{ this.$tc('common.NoContent') }}
</div>
<div v-else>
<el-table
:data="diff"
class="diffTable"
>
<el-table-column
:label="$tc('audits.ChangeField')"
:prop="fieldName"
show-overflow-tooltip
width="100"
/>
<el-table-column
:label="$tc('audits.BeforeChange')"
:prop="leftKeyName"
show-overflow-tooltip
/>
<el-table-column
:label="$tc('audits.AfterChange')"
:prop="rightKeyName"
show-overflow-tooltip
/>
</el-table>
</div>
</div>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index'
export default {
name: 'DiffDetail',
components: {
Dialog
},
props: {
title: {
type: String,
default: () => ''
},
fieldName: {
type: String,
default: () => 'field'
},
leftKeyName: {
type: String,
default: () => 'before'
},
rightKeyName: {
type: String,
default: () => 'after'
}
},
data() {
return {
diff: [],
detailVisible: false
}
},
methods: {
isEmpty() {
const content = this.diff
return !content || JSON.stringify(content) === '{}'
},
show(data) {
this.diff = data
this.detailVisible = true
}
}
}
</script>
<style lang='scss' scoped>
.el-tag {
width: 100%;
white-space: normal;
height: auto;
}
.el-table::before {
background-color: inherit;
}
.diffTable {
width: 100%;
max-height: 80vh;
& >>> td {
padding: 5px 0 !important;
}
}
</style>

View File

@@ -1,19 +1,21 @@
<template>
<el-dialog
:append-to-body="true"
:modal-append-to-body="true"
:title="title"
:top="top"
:width="iWidth"
class="dialog"
v-bind="$attrs"
:append-to-body="false"
:modal-append-to-body="false"
v-on="$listeners"
>
<slot />
<div slot="footer" class="dialog-footer">
<slot name="footer">
<el-button v-if="showCancel" size="small" @click="onCancel">{{ cancelTitle }}</el-button>
<el-button v-if="showConfirm" type="primary" size="small" :loading="loadingStatus" @click="onConfirm">{{ confirmTitle }}</el-button>
<el-button v-if="showCancel && showButtons" @click="onCancel">{{ cancelTitle }}</el-button>
<el-button v-if="showConfirm && showButtons" :loading="loadingStatus" type="primary" @click="onConfirm">
{{ confirmTitle }}
</el-button>
</slot>
</div>
</el-dialog>
@@ -27,16 +29,6 @@ export default {
type: String,
default: 'Title'
},
showCancel: {
type: Boolean,
default: true
},
cancelTitle: {
type: String,
default() {
return this.$t('common.Cancel')
}
},
top: {
type: String,
default: '3vh'
@@ -49,20 +41,37 @@ export default {
type: Boolean,
default: true
},
loadingStatus: {
type: Boolean,
default: false
},
confirmTitle: {
type: String,
default() {
return this.$t('common.Confirm')
}
},
showCancel: {
type: Boolean,
default: true
},
cancelTitle: {
type: String,
default() {
return this.$t('common.Cancel')
}
},
showButtons: {
type: Boolean,
default: true
},
loadingStatus: {
type: Boolean,
default: false
},
maxWidth: {
type: String,
default: '1200px'
}
},
data() {
return {
}
return {}
},
computed: {
iWidth() {
@@ -81,12 +90,38 @@ export default {
</script>
<style lang="scss" scoped>
.dialog >>> .el-dialog__header {
/*padding-top: 10px;*/
.dialog >>> .el-dialog {
border-radius: 0.3em;
max-width: 1500px;
.el-icon-circle-check {
display: none;
}
&__header {
box-sizing: border-box;
padding: 15px 22px;
border-bottom: 1px solid #dee2e6;
font-weight: 400;
}
&__body {
padding: 20px 30px;
&:has(.el-table) {
background: #f3f3f4;
}
}
&__footer {
border-top: 1px solid #dee2e6;
padding: 16px;
justify-content: flex-end;
}
}
.dialog-footer {
padding-right: 20px;
.dialog-footer >>> button.el-button {
font-size: 13px;
padding: 10px 20px;
}
</style>

View File

@@ -0,0 +1,109 @@
<template>
<el-tree
:data="iTree"
:default-checked-keys="iValue"
:default-expand-all="true"
:default-expanded-keys="iValue"
:props="defaultProps"
:render-content="renderContent"
class="el-tree-custom"
node-key="value"
show-checkbox
@check="handleCheckChange"
/>
</template>
<script>
export default {
props: {
value: {
type: Array,
default: () => []
},
tree: {
type: Array,
default: () => []
},
readonly: {
type: Boolean,
default: false
}
},
data() {
return {
defaultProps: {
children: 'children',
label: 'label'
}
}
},
computed: {
iValue() {
return this.value.map(item => {
if (item.value) {
return item.value
}
return item
})
},
iTree() {
if (!this.readonly) {
return this.tree
} else {
return this.setTreeReadonly(this.tree)
}
}
},
methods: {
handleCheckChange(node, { checkedNodes }) {
const checkedKeys = checkedNodes
.filter(item => !item.children)
.map(node => node.value)
this.$emit('input', checkedKeys)
},
setTreeReadonly(tree) {
return tree.map(item => {
item.disabled = true
if (item.children) {
item.children = this.setTreeReadonly(item.children)
}
return item
})
},
renderContent(h, { node, data, store }) {
let label = node.label
let helpText = ''
const regex = /(.*?)\s*\((.*?)\)/
const match = label.match(regex)
if (match) {
label = match[1]
helpText = match[2]
}
return (
<span >
<span>{label} </span>
{helpText
? (<el-tooltip content={helpText} placement='top'>
<i class='fa fa-info-circle'></i>
</el-tooltip>) : ''}
</span>)
}
}
}
</script>
<style lang="scss" scoped>
.el-tree-custom >>> {
.help-tips {
margin-left: 10px;
font-size: 12px;
color: #999;
}
.el-tree-node__content:hover {
background-color: inherit;
}
}
</style>

View File

@@ -0,0 +1,283 @@
<template>
<div class="code-editor" style="font-size: 12px">
<div class="toolbar">
<div
v-for="(item,index) in toolbar.left"
:key="index"
style="display: inline-block; margin: 0 2px"
>
<el-tooltip :content="item.tip" :disabled="!item.tip" placement="top">
<el-button
v-if="item.type ==='button'"
:disabled="item.disabled"
:type="item.el&&item.el.type"
size="mini"
@click="item.callback()"
>
<i :class="item.icon" style="margin-right: 4px;" />{{ item.name }}
</el-button>
<el-autocomplete
v-if="item.type === 'input' && item.el.autoComplete"
v-model="item.value"
:placeholder="item.placeholder"
:fetch-suggestions="item.el.query"
class="inline-input"
size="mini"
@select="item.callback(item.value)"
@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 }}:
</span>
<el-select
v-if="item.type==='select' && item.el && item.el.create"
:key="index"
v-model="item.value"
:allow-create="item.el.create || false"
:filterable="item.el.create || false"
:multiple="item.el.multiple"
:placeholder="item.name"
class="autoWidth-select"
default-first-option
size="mini"
@change="item.callback(item.value)"
>
<template slot="prefix">
{{ item.label + ':' + item.value }}
</template>
<el-option
v-for="(option,id) in item.options"
:key="id"
:label="option.label"
:title="option.value"
:value="option.value"
/>
</el-select>
</div>
<el-dropdown
v-if="item.type==='select' && (!item.el || !item.el.create) "
trigger="click"
@command="(command) => {
item.value= command
item.callback(command)
}"
>
<el-button size="mini" type="default">
<b>{{ item.name }}:</b> {{ getLabel(item.value, item.options) }} <i
class="el-icon-arrow-down el-icon--right"
/>
</el-button>
<el-dropdown-menu v-slot="dropdown">
<el-dropdown-item v-for="(option,i) in item.options" :key="i" :command="option.value">
{{ option.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-switch
v-if="item.type === 'switch'"
v-model="item.value"
:active-text="item.name"
:disabled="item.disabled"
@change="item.callback( item.value)"
/>
</el-tooltip>
</div>
<div class="right-side" style="float: right">
<div
v-for="(item,index) in toolbar.right"
:key="index"
style="display: inline-block"
>
<el-tooltip :content="item.tip">
<el-button
v-if="item.type ==='button'"
:disabled="item.disabled"
size="mini"
style="background-color: transparent"
type="default"
@click="item.callback()"
>
<i v-if="item.icon.startsWith('fa')" :class="'fa ' + item.icon" />
<svg-icon v-else :icon-class="item.icon" style="font-size: 14px;" />
</el-button>
</el-tooltip>
</div>
</div>
</div>
<codemirror ref="myCm" v-model="iValue" :options="iOptions" class="editor" />
</div>
</template>
<script>
import { codemirror } from 'vue-codemirror'
import 'codemirror/mode/shell/shell'
import 'codemirror/mode/powershell/powershell'
import 'codemirror/mode/python/python'
import 'codemirror/mode/yaml/yaml'
import 'codemirror/mode/ruby/ruby' // theme css
import 'codemirror/theme/base16-light.css'
import 'codemirror/theme/idea.css'
import 'codemirror/theme/mbo.css'
import 'codemirror/theme/duotone-light.css'
import 'codemirror/lib/codemirror.css'
export default {
components: {
codemirror
},
props: {
toolbar: {
type: [Array, Object],
default: () => []
},
value: {
type: [String, Object],
default: () => ''
},
options: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {}
},
computed: {
iValue: {
get() {
return this.value
},
set(val) {
this.$emit('update:value', val)
this.$emit('change', val)
}
},
iOptions() {
const defaultOptions = {
tabSize: 4,
mode: 'shell',
lineNumbers: true,
theme: 'idea',
placeholder: 'Code goes here...',
autofocus: true
}
return Object.assign(defaultOptions, this.options)
}
},
methods: {
getLabel(value, items) {
for (const item of items) {
if (item.value === value) {
return item.label
}
}
}
}
}
</script>
<style lang="scss" scoped>
.editor {
border: solid 1px #f3f3f3;
}
.toolbar {
height: 100%;
width: 100%;
line-height: 29px;
vertical-align: bottom;
display: inline-block;
padding: 3px 3px 3px 0;
margin-bottom: 5px;
}
> > > .CodeMirror pre.CodeMirror-line,
> > > .CodeMirror-linenumber.CodeMirror-gutter-elt {
line-height: 18px !important;
}
.runas-input {
height: 28px;
> > > {
.el-select {
width: 100px;
}
}
}
.right-side {
.el-button {
border: none;
padding: 2px;
font-size: 14px;
width: 26px;
height: 26px;
color: #888;
background-color: transparent;
margin-left: 2px;
}
}
.autoWidth-select {
min-width: 100px;
}
.autoWidth-select > > > .el-input__prefix {
position: relative;
left: 0px;
box-sizing: border-box;
height: 28px;
line-height: 28px;
visibility: hidden;
}
.autoWidth-select > > > input {
position: absolute;
padding-left: 0px;
border: none;
color: #606266;
background-color: #e6e6e6;
font-size: 12px;
font-weight: 470;
line-height: 27px;
}
> > > .el-select {
top: -1px;
.el-input .el-select__caret {
color: #7a7c7f;
}
}
> > > .el-button.el-button--default {
background-color: #e6e6e6;
}
.filter-label {
font-size: 12px;
font-weight: 700;
}
.select-content {
display: inline-block;
position: relative;
top: 1px;
height: 28px;
line-height: 28px;
padding-left: 15px;
font-size: 0;
border: 1px solid #DCDFE6;
border-radius: 4px;
background-color: #e6e6e6;
}
</style>

View File

@@ -2,9 +2,9 @@
<el-date-picker
v-model="value"
type="datetimerange"
:range-separator="this.$t('common.To')"
:start-placeholder="this.$t('common.DateStart')"
:end-placeholder="this.$t('common.DateEnd')"
:range-separator="$tc('common.To')"
:start-placeholder="$tc('common.DateStart')"
:end-placeholder="$tc('common.DateEnd')"
size="small"
:clearable="false"
class="datepicker"
@@ -41,37 +41,23 @@ export default {
shortcuts: [
{
text: this.$t('common.DateLast24Hours'),
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24)
picker.$emit('pick', [start, end])
}
onClick: (picker) => this.onShortcutClick(picker, 1)
},
{
text: this.$t('common.DateLastWeek'),
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
onClick: (picker) => this.onShortcutClick(picker, 7)
}, {
text: this.$t('common.DateLastMonth'),
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
onClick: (picker) => this.onShortcutClick(picker, 30)
}, {
text: this.$t('common.DateLast3Months'),
onClick(picker) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
onClick: (picker) => this.onShortcutClick(picker, 90)
}, {
text: this.$t('common.DateLastHarfYear'),
onClick: (picker) => this.onShortcutClick(picker, 183)
}, {
text: this.$t('common.DateLastYear'),
onClick: (picker) => this.onShortcutClick(picker, 365)
}
]
}
@@ -86,28 +72,38 @@ export default {
this.$log.debug('Date change: ', val)
this.$emit('dateChange', val)
}
},
onShortcutClick(picker, day) {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
picker.$emit('pick', [start, end])
}
}
}
</script>
<style lang='scss' scoped>
.datepicker{
.datepicker {
width: 233px;
&>>> .el-range__icon {
& >>> .el-range__icon {
margin-top: 2px;
margin-right: 3px;
}
&>>> .el-range-input {
& >>> .el-range-input {
width: 49%;
}
}
.el-input__inner{
.el-input__inner {
border: 1px solid #dcdee2;
border-radius: 3px;
height: 32x;
height: 32px;
}
.el-date-editor ::v-deep .el-range-separator{
.el-date-editor ::v-deep .el-range-separator {
line-height: 28px;
}
</style>

View File

@@ -0,0 +1,83 @@
<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">
<template slot="prepend"> {{ inputTitle + ' ' + (index + 1) }}</template>
</el-input>
<div class="input-button">
<el-button
:disabled="deleteDisabled()"
icon="el-icon-minus"
size="mini"
style="flex-shrink: 0;"
type="danger"
@click="handleDelete(command)"
/>
<el-button
v-if="index === value.length - 1"
icon="el-icon-plus"
size="mini"
style="flex-shrink: 0;"
type="primary"
@click="handleAdd()"
/>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: Array,
default: () => ['']
},
inputTitle: {
type: String,
default: () => ''
}
},
data() {
return {}
},
methods: {
handleDelete(command) {
const index = this.value.indexOf(command)
if (index !== -1) {
this.value.splice(index, 1)
}
},
handleAdd() {
this.value.push('')
},
deleteDisabled() {
return this.value.length <= 1
}
}
}
</script>
<style lang="scss" scoped>
.el-input {
width: 85%;
}
.command-item {
display: flex;
margin: 5px 0;
}
.input-button {
margin-top: 2px;
display: flex;
margin-left: 20px
}
.input-button ::v-deep .el-button.el-button--mini {
height: 25px;
padding: 5px;
}
.el-input-group__append .el-button {
font-size: 14px;
color: #1a1a1a;
padding: 9px 20px;
}
</style>

View File

@@ -0,0 +1,161 @@
<template>
<Dialog
:destroy-on-close="true"
:show-buttons="false"
:title="$tc('common.SelectAttrs')"
v-bind="$attrs"
v-on="$listeners"
>
<div v-if="!loading">
<DataForm
:form="form"
class="attr-form"
v-bind="formConfig"
@submit="onAttrDialogConfirm"
/>
</div>
</Dialog>
</template>
<script>
import DataForm from '@/components/DataForm/index.vue'
import Dialog from '@/components/Dialog/index.vue'
import ValueField from '@/components/FormFields/JSONManyToManySelect/ValueField.vue'
import { attrMatchOptions, typeMatchMapper } from './const'
export default {
name: 'AttrFormDialog',
components: { Dialog, DataForm },
props: {
attrs: {
type: Array,
default: () => ([])
},
attrsAdded: {
type: Array,
default: () => ([])
},
form: {
type: Object,
default: () => ({})
}
},
data() {
const vm = this
return {
loading: true,
currentValue: '',
formConfig: {
// 为了方便更新,避免去取 fields 的索引
hasSaveContinue: false,
fields: [
{
id: 'name',
label: this.$t('common.AttrName'),
type: 'select',
options: this.attrs.map(attr => {
let disabled = this.attrsAdded.includes(attr.name) && this.form.name !== attr.name
if (attr.disabled) {
disabled = true
}
return { label: attr.label, value: attr.name, disabled: disabled }
}),
on: {
change: ([val], updateForm) => {
// 变化会影响 match 的选项
const attr = this.attrs.find(attr => attr.name === val)
if (!attr) return
const matchOption = vm.updateMatchOptions(attr)
setTimeout(() => {
updateForm({ match: matchOption.value })
}, 10)
}
}
},
{
id: 'match',
label: this.$t('common.Match'),
type: 'select',
options: attrMatchOptions,
on: {
change: ([value], updateForm) => {
// 变化会影响 value 的选项
setTimeout(() => {
this.formConfig.fields[2].el.match = value
}, 10)
}
}
},
{
id: 'value',
label: this.$t('common.AttrValue'),
component: ValueField,
el: {
match: attrMatchOptions[0].value,
attr: this.attrs[0]
},
on: {
input: ([value], updateForm) => {
vm.currentValue = value
}
}
}
]
}
}
},
mounted() {
if (this.form.index === undefined || this.form.index === -1) {
Object.assign(this.form, this.getDefaultAttrForm())
}
this.updateMatchOptions()
this.$log.debug('Attr Form config: ', this.formConfig)
this.loading = false
},
methods: {
getDefaultAttrForm() {
const attrKeys = this.attrs.map(attr => attr.name)
const diff = attrKeys.filter(attr => !this.attrsAdded.includes(attr))
let name = this.attrs[0].name
if (diff.length > 0) {
name = diff[0]
}
return {
name: name,
match: 'exact',
value: '',
rel: 'and'
}
},
onAttrDialogConfirm(form) {
this.$emit('confirm', form)
},
updateMatchOptions(attr) {
if (!attr) {
attr = this.attrs.find(attr => attr.name === this.form.name)
}
if (!attr) return
const attrType = attr.type || 'str'
const matchSupports = typeMatchMapper[attrType]
attrMatchOptions.forEach((option) => {
option.hidden = !matchSupports.includes(option.value)
})
this.formConfig.fields[2].el.attr = attr
const supports = attrMatchOptions.filter(option => !option.hidden)
const matchOption = supports.find(item => item.value === this.form.match) || supports[0]
this.formConfig.fields[2].el.match = matchOption.value
return matchOption
}
}
}
</script>
<style lang="scss" scoped>
.attr-form {
>>> .el-select {
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,77 @@
<template>
<Dialog
:destroy-on-close="true"
:show-buttons="false"
:title="$tc('common.MatchResult')"
:v-bind="$attrs"
:v-on="$listeners"
:visible.sync="iVisible"
>
<ListTable v-bind="attrMatchTableConfig" />
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import ListTable from '@/components/ListTable/index.vue'
export default {
name: 'AttrMatchResultDialog',
components: { ListTable, Dialog },
props: {
url: {
type: String,
default: ''
},
attrs: {
type: Array,
default: () => ([])
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
attrMatchTableConfig: {
headerActions: {
hasCreate: false,
hasImport: false,
hasExport: false,
hasMoreActions: false
},
tableConfig: {
url: this.url,
columns: this.attrs.filter(item => item.inTable).map(item => {
return {
prop: item.name,
label: item.label,
formatter: item.formatter
}
}),
columnsMeta: {
actions: {
has: false
}
}
}
}
}
},
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div v-if="!loading">
<TagInput v-if="type === 'array'" :value="iValue" @input="handleInput" />
<Select2 v-else-if="type === 'select'" :value="iValue" v-bind="attr.el" @change="handleInput" @input="handleInput" />
<Switcher v-else-if="type === 'bool'" :value="iValue" @change="handleInput" @input="handleInput" />
<el-input v-else :value="iValue" @input="handleInput" />
</div>
</template>
<script>
import TagInput from '@/components/FormFields/TagInput.vue'
import Select2 from '@/components/FormFields/Select2.vue'
import Switcher from '@/components/FormFields/Switcher.vue'
export default {
name: 'ValueField',
components: { Switcher, TagInput, Select2 },
props: {
value: {
type: [String, Number, Boolean, Array, Object],
default: () => ''
},
match: {
type: String,
default: 'exact'
},
attr: {
type: Object,
default: () => ({})
}
},
data() {
return {
loading: true,
type: 'string'
}
},
computed: {
iValue: {
get() {
const multipleTypes = ['array', 'select']
let newValue = this.value
if (multipleTypes.includes(this.type)) {
if (!Array.isArray(this.value)) {
newValue = []
}
} else if (this.type === 'bool') {
newValue = !!this.value
} else {
if (Array.isArray(this.value)) {
newValue = ''
} else {
newValue = this.value.toString()
}
}
if (this.value !== newValue) {
this.handleInput(newValue)
}
return newValue
}
}
},
watch: {
match() {
this.changeValueType()
},
attr: {
handler() {
this.changeValueType()
},
deep: true
}
},
mounted() {
this.changeValueType()
},
methods: {
handleInput(value) {
this.$emit('input', value)
},
changeValueType() {
this.loading = true
this.type = this.getType()
this.$nextTick(() => {
this.loading = false
})
},
getType() {
const attrType = this.attr.type || 'str'
this.$log.debug('Value field attr type: ', attrType, this.attr, this.match)
if (attrType === 'm2m') {
return 'select'
} else if (attrType === 'bool') {
return 'bool'
} else if (attrType === 'select') {
return 'select'
}
if (['in', 'ip_in'].includes(this.match)) {
return 'array'
} else {
return 'string'
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,90 @@
<template>
<span v-if="attr.type === 'bool'">
<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>
</template>
<script>
import BaseFormatter from '@/components/TableFormatters/base.vue'
import { setUrlParam } from '@/utils/common'
export default {
name: 'ValueFormatter',
extends: BaseFormatter,
props: {
formatterArgsDefault: {
type: Object,
default() {
return {
attrs: {}
}
}
}
},
data() {
const formatterArgs = Object.assign(this.formatterArgsDefault, this.col.formatterArgs)
return {
formatterArgs: formatterArgs,
loading: true,
attr: {},
value: ''
}
},
watch: {
cellValue: {
handler() {
this.getValue()
},
deep: true
},
formatterArgs: {
handler() {
this.getValue()
},
deep: true
},
row: {
handler() {
this.getValue()
},
deep: true
}
},
mounted() {
setTimeout(() => {
this.getValue()
}, 100)
},
methods: {
async getValue() {
this.attr = this.formatterArgs.attrs.find(attr => attr.name === this.row.name)
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) || []
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') {
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
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,25 @@
import i18n from '@/i18n/i18n'
export const strMatchValues = ['exact', 'not', 'in', 'contains', 'startswith', 'endswith', 'regex']
export const typeMatchMapper = {
str: strMatchValues,
bool: ['exact', 'not'],
m2m: ['m2m'],
ip: [...strMatchValues, 'ip_in'],
int: [...strMatchValues, 'gte', 'lte'],
select: ['in']
}
export const attrMatchOptions = [
{ label: i18n.t('common.Equal'), value: 'exact' },
{ label: i18n.t('common.NotEqual'), value: 'not' },
{ label: i18n.t('common.MatchIn'), value: 'in' },
{ label: i18n.t('common.Contains'), value: 'contains' },
{ label: i18n.t('common.Startswith'), value: 'startswith' },
{ label: i18n.t('common.Endswith'), value: 'endswith' },
{ label: i18n.t('common.Regex'), value: 'regex' },
{ label: i18n.t('common.BelongTo'), value: 'm2m' },
{ label: i18n.t('common.IPMatch'), value: 'ip_in' },
{ label: i18n.t('common.GreatEqualThan'), value: 'gte' },
{ label: i18n.t('common.LessEqualThan'), value: 'lte' }
]

View File

@@ -0,0 +1,240 @@
<template>
<div>
<el-radio-group v-model="iValue.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="iValue.type === 'ids'" v-model="ids" v-bind="select2" @change="onChangeEmit" />
<div v-if="iValue.type === 'attrs'">
<DataTable :config="tableConfig" class="attr-list" />
<div class="actions">
<el-button size="mini" type="primary" @click="handleAttrAdd">
{{ $t('common.Add') }}
</el-button>
<span style="padding-left: 10px; font-size: 13px">
<span class="help-tips; ">{{ $t('common.MatchedCount') }}:</span>
<a class="text-link" style="padding: 0 5px;" @click="showAttrMatchTable">{{ attrMatchCount }}</a>
</span>
</div>
</div>
<AttrFormDialog
v-if="attrFormVisible"
:attrs="attrs"
:attrs-added="attrsAdded"
:form="attrForm"
:visible.sync="attrFormVisible"
@confirm="handleAttrDialogConfirm"
/>
<AttrMatchResultDialog
v-if="attrMatchTableVisible"
:attrs="attrs"
:url="attrMatchTableUrl"
:visible.sync="attrMatchTableVisible"
/>
</div>
</template>
<script>
import Select2 from '../Select2.vue'
import DataTable from '@/components/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 { toM2MJsonParams } from '@/utils/jms'
export default {
name: 'JSONManyToManySelect',
components: { AttrFormDialog, DataTable, Select2, AttrMatchResultDialog },
props: {
value: {
type: Object,
default: () => {
return {
type: 'all'
}
}
},
select2: {
type: Object,
required: true
},
attrs: {
type: Array,
default: () => ([])
},
resource: {
type: String,
default: ''
},
attrTableColumns: {
type: Array,
default: () => (['name'])
}
},
data() {
const tableFormatter = (colName) => {
return (row, col, cellValue) => {
const value = cellValue
switch (colName) {
case 'name':
return this.attrs.find(attr => attr.name === value)?.label || value
case 'match':
return attrMatchOptions.find(opt => opt.value === value).label || value
case 'value':
return Array.isArray(value) ? value.join(', ') : value
default:
return value
}
}
}
return {
iValue: Object.assign({ type: 'all' }, this.value),
attrFormVisible: false,
attrForm: {},
attrMatchCount: 0,
attrMatchTableVisible: false,
attrMatchTableUrl: '',
ids: this.value.ids || [],
editIndex: -1,
types: [
{ name: 'all', label: this.$t('common.All') + this.resource },
{ name: 'ids', label: this.$t('common.Spec') + this.resource },
{ name: 'attrs', label: this.$t('common.SelectByAttr') }
],
tableConfig: {
columns: [
{ prop: 'name', label: this.$t('common.AttrName'), formatter: tableFormatter('name') },
{ prop: 'match', label: this.$t('common.Match'), formatter: tableFormatter('match') },
{ prop: 'value', label: this.$t('common.AttrValue'), formatter: ValueFormatter, formatterArgs: { attrs: this.attrs }},
{ prop: 'action', label: this.$t('common.Action'), align: 'center', width: '120px', formatter: (row, col, cellValue, index) => {
return (
<div className='input-button'>
<el-button
icon='el-icon-edit'
size='mini'
style={{ 'flexShrink': 0 }}
type='primary'
onClick={this.handleAttrEdit({ row, col, cellValue, index })}
/>
<el-button
icon='el-icon-minus'
size='mini'
style={{ 'flexShrink': 0 }}
type='danger'
onClick={this.handleAttrDelete({ row, col, cellValue, index })}
/>
</div>
)
} }
],
totalData: this.value.attrs || [],
hasPagination: false
}
}
},
computed: {
attrsAdded() {
return this.tableConfig.totalData.map(item => item.name)
}
},
watch: {
attrFormVisible(val) {
if (!val) {
this.getAttrsCount()
}
}
},
mounted() {
if (this.value.type === 'attrs') {
this.getAttrsCount()
}
this.$emit('input', this.iValue)
},
methods: {
showAttrMatchTable() {
const [key, value] = this.getAttrFilterKey()
this.attrMatchTableUrl = setUrlParam(this.select2.url, key, value)
this.attrMatchTableVisible = true
},
getAttrFilterKey() {
if (this.tableConfig.totalData.length === 0) return ''
let attrFilter = { type: 'attrs', attrs: this.tableConfig.totalData }
attrFilter = toM2MJsonParams(attrFilter)
return attrFilter
},
getAttrsCount() {
const attrFilter = this.getAttrFilterKey()
if (!attrFilter) {
this.attrMatchCount = 0
return
}
const [key, value] = attrFilter
let url = setUrlParam(this.select2.url, key, value)
url = setUrlParam(url, 'limit', 1)
return this.$axios.get(url).then(res => {
this.attrMatchCount = res.count
})
},
handleAttrEdit({ row, index }) {
return () => {
this.attrForm = Object.assign({ index }, row)
this.editIndex = index
this.attrFormVisible = true
}
},
handleAttrDelete({ index }) {
return () => {
this.tableConfig.totalData.splice(index, 1)
this.getAttrsCount()
}
},
handleAttrAdd() {
this.attrForm = {}
this.editIndex = -1
this.attrFormVisible = true
},
onChangeEmit() {
const tp = this.iValue.type
this.handleTypeChange(tp)
},
handleTypeChange(val) {
switch (val) {
case 'ids':
this.$emit('input', { type: 'ids', ids: this.ids })
break
case 'attrs':
this.$emit('input', { type: 'attrs', attrs: this.tableConfig.totalData })
break
default:
this.$emit('input', { type: 'all' })
break
}
},
handleAttrDialogConfirm(form) {
if (this.editIndex > -1) {
this.tableConfig.totalData.splice(this.editIndex, 1)
}
const allAttrs = this.tableConfig.totalData
// 因为可能 attr 的 name 会重复,所以需要先删除再添加
const setIndex = allAttrs.findIndex(attr => attr.name === form.name)
if (setIndex === -1) {
allAttrs.push(Object.assign({}, form))
} else {
allAttrs.splice(setIndex, 1, Object.assign({}, form))
}
this.attrFormVisible = false
this.onChangeEmit()
}
}
}
</script>
<style lang="scss" scoped>
.attr-list {
width: 99%;
}
</style>

View File

@@ -2,8 +2,9 @@
<div class="json-editor">
<JsonEditor
v-model="resultInfo"
:show-btns="false"
:mode="'code'"
:show-btns="false"
:class="{resize: resize === 'vertical'}"
@json-change="onJsonChange"
@json-save="onJsonSave"
@has-error="onError"
@@ -18,8 +19,15 @@ export default {
components: { JsonEditor },
props: {
value: {
type: [String, Object, Array],
default: () => ({})
},
resize: {
type: String,
default: () => ''
validator: (value) => {
return ['none', 'vertical'].indexOf(value) !== -1
},
default: 'vertical'
}
},
data() {
@@ -29,7 +37,7 @@ export default {
}
},
created() {
this.resultInfo = JSON.parse(this.value)
this.resultInfo = typeof this.value === 'string' ? JSON.parse(this.value) : this.value
},
methods: {
// 数据改变
@@ -38,35 +46,46 @@ export default {
},
// 保存
onJsonSave(value) {
this.resultInfo = value
this.resultInfo = typeof value === 'string' ? JSON.parse(value) : value
this.hasJsonFlag = true
setTimeout(() => {
this.$emit('change', JSON.stringify(this.resultInfo))
this.$emit('change', this.resultInfo)
}, 500)
},
onError: _.debounce(function(value) {
this.$message.error(this.$t('common.FormatError'))
}, 1100)
this.$message.error(this.$tc('common.FormatError'))
}, 1500)
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
.json-editor {
&>>> .jsoneditor {
.resize {
& > > > .jsoneditor {
resize: vertical;
cursor: s-resize;
}
}
& > > > .jsoneditor {
border: 1px solid #e5e6e7;
}
&>>> .jsoneditor-compact {
& > > > .jsoneditor-compact {
display: none;
}
&>>> .jsoneditor-modes {
& > > > .jsoneditor-modes {
display: none;
}
&>>> .jsoneditor-poweredBy {
& > > > .jsoneditor-poweredBy {
display: none;
}
&>>> .jsoneditor-menu {
& > > > .jsoneditor-menu {
background: var(--color-primary);
border-bottom: 1px solid var(--color-primary);
}

View File

@@ -0,0 +1,97 @@
<template>
<div>
<div v-for="(item, index) in value || []" :key="index" class="value-item">
<el-input :value="item" class="input-z" @input="updateValue($event, index)" />
<div class="input-button">
<el-button
:disabled="disableDelete(item)"
icon="el-icon-minus"
size="mini"
style="flex-shrink: 0;"
type="danger"
@click="handleDelete(index)"
/>
<el-button
:disabled="disableAdd(item, index)"
icon="el-icon-plus"
size="mini"
style="flex-shrink: 0;"
type="primary"
@click="handleAdd(index)"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ListField',
props: {
value: {
type: [Array, String],
default: () => ([])
}
},
data() {
return {
}
},
computed: {
},
mounted() {
const value = this.value
if (!value || !Array.isArray(value) || value.length === 0) {
this.$emit('input', [''])
}
},
methods: {
updateValue(v, index) {
const value = this.value
value[index] = v
this.$emit('input', value)
},
disableDelete() {
return false
},
disableAdd() {
return false
},
handleAdd(index) {
const value = this.value
value.splice(index + 1, 0, '')
this.$emit('input', value)
},
handleDelete(index) {
const value = this.value
value.splice(index, 1)
this.$emit('input', value)
}
}
}
</script>
<style lang="scss" scoped>
.input-z {
flex-shrink: 1;
width: calc(100% - 80px) !important;
}
.value-item {
display: flex;
margin: 4px 0;
}
.input-button {
display: flex;
margin-left: 20px;
margin-top: 4px;
}
.input-button ::v-deep .el-button.el-button--mini {
height: 25px;
padding: 5px;
}
</style>

View File

@@ -0,0 +1,105 @@
<template>
<Select2
v-model="iValue"
:multiple="multiple"
v-bind="attrsWithoutValue"
@change="onChange"
@change-options="onChangeOptions"
/>
</template>
<script>
import Select2 from './Select2'
export default {
name: 'NestedObjectSelect2',
components: {
Select2
},
props: {
value: {
type: [Array, String, Number, Boolean, Object],
default: () => ([])
},
multiple: {
type: Boolean,
default: true
},
// 自定义label字段的name
customLabelKeyName: {
type: String,
default: 'name'
}
},
data() {
return {}
},
computed: {
attrsWithoutValue() {
const attrs = Object.assign({}, this.$attrs)
delete attrs.value
return attrs
},
iValue: {
set(val) {
const value = this.valuesToObjects(val)
this.$log.debug('set iValue', value)
this.$emit('input', value)
},
get() {
const value = this.objectsToValues(this.value)
return value
}
}
},
methods: {
onChange(val) {
val = this.valuesToObjects(val)
this.$log.debug('onChange .... ', val)
this.$emit('change', val)
},
onChangeOptions(val) {
val = this.valuesToObjects(val)
this.$log.debug('onChangeOptions', val)
this.$emit('changeOptions', val)
},
valuesToObjects(values) {
let value = values
if (!this.multiple && !Array.isArray(value)) {
value = [value]
}
value = value.map(v => {
// uuid v4
const uuid = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
return typeof v === 'object' ? v
: this.$attrs?.allowCreate && !uuid.test(v) ? { [this.customLabelKeyName]: v } : { pk: v }
})
if (!this.multiple) {
value = value[0]
}
return value
},
objectsToValues(objects) {
let val = objects
if (!this.multiple) {
val = [val]
}
val = val.map((v) => {
if (v && typeof v === 'object') {
return v.pk || v.id || (this.$attrs?.allowCreate ? (v?.[this.customLabelKeyName] + ':' + v?.value) : '')
} else {
return v
}
})
if (!this.multiple) {
val = val[0]
}
return val
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,80 @@
<template>
<div>
<el-input v-model="rawValue.phone" :placeholder="$tc('users.inputPhone')" @input="OnInputChange">
<el-select
slot="prepend"
:value="rawValue.code"
:placeholder="$tc('common.Select')"
style="width: 90px;"
@change="OnChange"
>
<el-option
v-for="country in countries"
:key="country.value"
:label="country.value"
:value="country.value"
style="width: 200px;"
>
<span style="float: left">{{ country.name }}</span>
<span style="float: right; font-size: 13px">{{ country.value }}</span>
</el-option>
</el-select>
</el-input>
</div>
</template>
<script>
export default {
name: 'PhoneInput',
props: {
value: {
type: [Object, String],
default: () => ({ 'code': '+86', 'phone': '' })
}
},
data() {
return {
rawValue: {},
countries: [
{ name: 'China(中国)', value: '+86' },
{ name: 'HongKong(中国香港)', value: '+852' },
{ name: 'Macao(中国澳门)', value: '+853' },
{ name: 'Taiwan(中国台湾)', value: '+886' },
{ name: 'America(America)', value: '+1' },
{ name: 'Russia(Россия)', value: '+7' },
{ name: 'France(français)', value: '+33' },
{ name: 'Britain(Britain)', value: '+44' },
{ name: 'Germany(Deutschland)', value: '+49' },
{ name: 'Japan(日本)', value: '+81' },
{ name: 'Korea(한국)', value: '+82' },
{ name: 'India(भारत)', value: '+91' }
]
}
},
computed: {
fullPhone() {
if (!this.rawValue.phone) {
return ''
}
return `${this.rawValue.code}${this.rawValue.phone}`
}
},
mounted() {
this.rawValue = this.value || { code: '+86', phone: '' }
this.$emit('input', this.fullPhone)
},
methods: {
OnChange(countryCode) {
this.rawValue.code = countryCode
this.OnInputChange()
},
OnInputChange() {
this.$emit('input', this.fullPhone)
}
}
}
</script>
<style lang="scss" 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/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

@@ -0,0 +1,366 @@
<template>
<div v-if="!loading" :class="showSetting ? 'show-setting' : 'hide-setting'">
<div v-for="(item, index) in items" :key="item.name" class="protocol-item">
<el-input
v-model="item.port"
:class="isPortReadonly(item) ? '' : 'input-with-select'"
:placeholder="portPlaceholder"
:readonly="isPortReadonly(item)"
:title="isPortReadonly(item) ? '端口由 URL 指定' : ''"
v-bind="$attrs"
>
<template #prepend>
<el-select
:disabled="disableSelect(item)"
:value="item.display_name ? item.display_name : item.name"
class="prepend"
@change="handleProtocolChange($event, item)"
>
<el-option
v-for="p of remainProtocols"
:key="p.name"
:label="p.name"
:value="p.name"
/>
</el-select>
</template>
<template #append>
<el-button
v-if="showSetting(item)"
icon="el-icon-setting"
@click="onSettingClick(item)"
/>
</template>
</el-input>
<div v-if="!readonly" class="input-button">
<el-button
:disabled="disableDelete(item)"
icon="el-icon-minus"
size="mini"
style="flex-shrink: 0;"
type="danger"
@click="handleDelete(index)"
/>
<el-button
v-if="index === items.length - 1"
:disabled="disableAdd(item, index)"
icon="el-icon-plus"
size="mini"
style="flex-shrink: 0;"
type="primary"
@click="handleAdd(index)"
/>
</div>
</div>
<el-button
v-if="items.length === 0"
icon="el-icon-plus"
size="mini"
style="flex-shrink: 0;"
type="primary"
@click="handleAdd(0)"
/>
<ProtocolSettingDialog
v-if="showDialog"
:disabled="settingReadonly || readonly"
:protocol="currentProtocol"
:visible.sync="showDialog"
@confirm="handleSettingConfirm"
/>
</div>
</template>
<script>
import ProtocolSettingDialog from './ProtocolSettingDialog'
export default {
components: {
ProtocolSettingDialog
},
props: {
value: {
type: [String, Array],
default: () => []
},
title: {
type: String,
default: ''
},
choices: {
type: Array,
default: () => ([])
},
readonly: {
// 这个是在详情中,不可编辑,包括所有
type: Boolean,
default: false
},
settingReadonly: {
// 这个是在资产添加时设置协议使用,不能修改 setting
type: Boolean,
default: false
},
showSetting: {
type: Function,
default: (item) => true
},
instance: {
type: Object,
default: () => ({})
}
},
data() {
return {
name: '',
items: [],
currentProtocol: {},
showDialog: false,
loading: false
}
},
computed: {
selectedProtocolNames() {
return this.items.map(item => item.name)
},
remainProtocols() {
return this.choices.filter(proto => {
return this.selectedProtocolNames.indexOf(proto.name) === -1
})
},
portPlaceholder() {
if (this.settingReadonly) {
return this.$t('applications.port')
} else {
return this.$t('assets.DefaultPort')
}
},
iChoices() {
return this.choices.map(item => {
delete item?.id
return item
})
}
},
watch: {
choices: {
handler(value, oldValue) {
if (value?.length === oldValue?.length) {
return
}
this.loading = true
setTimeout(() => {
this.setDefaultItems(value)
this.loading = false
},)
},
deep: true,
immediate: true
},
items: {
handler(value) {
if (this.settingReadonly) {
value = value.map(i => {
return { name: i.name, port: i.port }
})
}
this.$emit('input', value)
},
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() {
this.setDefaultItems(this.iChoices)
this.$log.debug('Choices: ', this.choices)
this.$log.debug('Value: ', this.value)
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.currentProtocol.primary) {
const others = this.items
.filter(item => item.name !== this.currentProtocol.name)
.map(item => {
item.primary = false
return item
})
this.items = [this.currentProtocol, ...others]
}
if (this.currentProtocol.name === 'winrm') {
if (this.currentProtocol.setting?.use_ssl) {
this.currentProtocol.port = 5986
} else {
this.currentProtocol.port = 5985
}
}
},
handleDelete(index) {
this.items = this.items.filter((value, i) => i !== index)
},
isRequired(item) {
const full = this.iChoices.find(choice => {
return choice.name === item.name
})
return full?.primary || full?.required
},
disableSelect(item) {
return this.isRequired(item)
},
disableDelete(item) {
if (this.items.length === 1) {
return true
}
// 代表是设置平台
if (!this.settingReadonly) {
return false
}
return this.isRequired(item)
},
disableAdd(item) {
return this.remainProtocols.length === 0 || !item.port
},
handleAdd(index) {
this.items.push({ ...this.remainProtocols[0] })
},
handleProtocolChange(evt, item) {
const selected = this.choices.find(item => item.name === evt)
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) {
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
},
setDefaultItems(choices) {
let items = []
const requiredItems = choices.filter(item => (item.required || item.primary))
if (this.value instanceof Array && this.value.length > 0) {
const protocols = []
this.value.forEach(item => {
// 有默认值的情况下设置为只读或者有id、有setting是平台
if (!this.settingReadonly || (item?.id && item?.setting)) {
protocols.push(item)
} else {
// 获取资产协议配置
const assetDefaultItems = this.getAssetDefaultItems(item, choices)
protocols.push(...assetDefaultItems)
}
})
const notFound = requiredItems.filter(item => !protocols.find(p => p.name === item.name))
protocols.push(...notFound)
const allProtocolNames = protocols.map(item => item.name)
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) {
defaults.push(choices[0])
}
items = defaults
}
items = this.setPrimaryIfNeed(items)
this.items = items
},
getAssetDefaultItems(item, choices) {
const protocols = []
const protocol = choices.find(i => i.name === item.name) || {}
protocols.push({ ...protocol, ...item })
return protocols
},
onSettingClick(item) {
this.currentProtocol = item
this.showDialog = true
}
}
}
</script>
<style lang="scss" scoped>
.el-select >>> .el-input__inner {
width: 120px;
text-overflow: ellipsis;
white-space: nowrap;
}
.input-with-select {
flex-shrink: 1;
width: calc(100% - 80px) !important;
}
.input-with-select .el-input-group__prepend {
background-color: #fff;
}
.protocol-item {
display: flex;
margin: 5px 0;
}
.input-button {
margin-top: 4px;
display: flex;
margin-left: 20px
}
.input-button ::v-deep .el-button.el-button--mini {
height: 25px;
padding: 5px;
}
.el-input-group__append .el-button {
font-size: 14px;
color: #1a1a1a;
padding: 9px 20px;
}
</style>

View File

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

View File

@@ -2,28 +2,29 @@
<el-select
ref="select"
v-model="iValue"
v-loading="!initialized"
v-loadmore="loadMore"
:clearable="clearable"
:collapse-tags="collapseTags"
:disabled="!!selectDisabled"
:loading="!initialized"
:multiple="multiple"
:options="iOptions"
:remote="remote"
:remote-method="filterOptions"
:multiple="multiple"
:clearable="clearable"
class="select2"
filterable
popper-append-to-body
class="select2"
:disabled="selectDisabled"
v-bind="$attrs"
@change="onChange"
@visible-change="onVisibleChange"
v-on="$listeners"
@visible-change="onVisibleChange"
>
<el-option
v-for="item in iOptions"
:key="item.value"
:disabled="checkDisabled(item)"
:label="item.label"
:value="item.value"
:disabled="checkDisabled(item)"
/>
</el-select>
</template>
@@ -78,7 +79,7 @@ export default {
},
// 初始化值,也就是选中的值
value: {
type: [Array, String, Number, Boolean],
type: [Array, String, Number, Boolean, Object],
default() {
return this.multiple ? [] : ''
}
@@ -90,6 +91,10 @@ export default {
disabled: {
type: Boolean,
default: false
},
collapseTagsCount: {
type: Number,
default: 10
}
},
data() {
@@ -128,6 +133,9 @@ export default {
selectRef() {
return this.$refs.select
},
collapseTags() {
return this.multiple && this.collapseTagsCount > 0 && this.value.length > this.collapseTagsCount
},
optionsValues() {
return this.iOptions.map((v) => v.value)
},
@@ -137,7 +145,13 @@ export default {
if (noValue && !this.initialized) {
return
}
this.$emit('input', val)
if (val && val.constructor === Object && val.value) {
this.$emit('input', val.value)
} else if (val && val.constructor === Object && val.id) {
this.$emit('input', val.id)
} else {
this.$emit('input', val)
}
},
get() {
return this.value
@@ -161,6 +175,10 @@ export default {
return { label: item.name, value: item.id }
}
const transformOption = this.ajax.transformOption || defaultTransformOption
const defaultFilterOption = (item) => {
return item
}
const filterOption = this.ajax.filterOption || defaultFilterOption
const defaultProcessResults = (data) => {
let results = []
let more = false
@@ -174,7 +192,7 @@ export default {
total = data.count
}
results = results.map(transformOption)
results = results.filter(Boolean)
results = results.filter(filterOption)
return { results: results, pagination: more, total: total }
}
const defaultAjax = {
@@ -189,31 +207,28 @@ export default {
}
},
watch: {
// url(newValue, oldValue) {
// this.$log.debug('Select url changed: ', oldValue, ' => ', newValue)
// this.iAjax.url = newValue
// this.refresh()
// },
iAjax(newValue, oldValue) {
this.$log.debug('Select url changed: ', oldValue, ' => ', newValue)
this.refresh()
},
value(iNew) {
this.iValue = iNew
value: {
handler(newValue, oldValue) {
},
deep: true
}
},
async mounted() {
// this.$log.debug('Select2 url is: ', this.iAjax.url)
if (!this.initialized) {
await this.initialSelect()
setTimeout(() => {
this.$log.debug('Value is : ', this.value)
this.iValue = this.value
this.initialized = true
})
}, 100)
}
this.$nextTick(() => {
// 因为elform存在问题这个来清楚验证
const elFormItem = this.$refs.select.elFormItem
const elFormItem = this.$refs.select?.elFormItem
if (elFormItem && elFormItem.clearValidate) {
elFormItem.clearValidate()
}
@@ -308,8 +323,9 @@ export default {
if (this.iOptions.length === 0) {
this.remote = false
}
} else {
this.remote = false
}
this.iValue = this.value
},
refresh() {
this.resetParams()
@@ -319,13 +335,11 @@ export default {
addOption(option) {
this.iOptions.push(option)
},
getOptionsByValues(values) {
return this.iOptions.filter((v) => {
return values.indexOf(v.value) !== -1
})
},
getSelectedOptions() {
const values = this.iValue
let values = this.iValue
if (!Array.isArray(values)) {
values = [values]
}
return this.iOptions.filter((v) => {
return values.indexOf(v.value) !== -1
})
@@ -338,9 +352,9 @@ export default {
},
onChange(values) {
const options = this.getSelectedOptions()
this.$log.debug('Current select options: ', options)
this.$log.debug('Current select options: ', options, 'Val: ', this.value)
this.$emit('changeOptions', options)
this.$emit('change', options)
// this.$emit('change', options) // 事件重复
},
onVisibleChange(visible) {
if (!visible && this.params.search) {
@@ -354,11 +368,12 @@ export default {
</script>
<style scoped>
.select2 {
width: 100%;
}
.select2 >>> .el-tag.el-tag--info {
height: auto;
white-space: normal;
}
.select2 {
width: 100%;
}
.select2 >>> .el-tag.el-tag--info {
height: auto;
white-space: normal;
}
</style>

View File

@@ -1,8 +1,8 @@
<template>
<el-switch
v-model="iValue"
inactive-color="#dcdfe6"
:class="type"
inactive-color="#dcdfe6"
v-bind="$attrs"
v-on="$listeners"
/>
@@ -10,14 +10,14 @@
<script>
export default {
name: 'Switcher',
name: 'Switcher', // Switch js
props: {
type: {
type: String,
default: 'primary'
},
value: {
type: Boolean,
type: [Boolean, String],
default: true
}
},
@@ -31,9 +31,14 @@ export default {
this.$emit('input', newValue)
},
get: function() {
return this.value
return !!this.value
}
}
},
watch: {
value(val) {
this.$log.debug('Switcher Value changed: ', val)
}
}
}
</script>

View File

@@ -0,0 +1,143 @@
<template>
<div class="filter-field">
<el-tag
v-for="(v, k) in filterTags"
:key="k"
:disable-transitions="true"
:type="tagType(v)"
closable
size="small"
@click="handleTagClick(v, k)"
@close="handleTagClose(v)"
>
{{ v }}
</el-tag>
<component
:is="component"
ref="SearchInput"
v-model.trim="filterValue"
:fetch-suggestions="autocomplete"
:placeholder="this.$t('common.EnterToContinue')"
class="search-input"
@blur="focus = false"
@change="handleConfirm"
@focus="focus = true"
@select="handleSelect"
@keyup.enter.native="handleConfirm"
/>
</div>
</template>
<script>
import i18n from '@/i18n/i18n'
export default {
props: {
value: {
type: Array,
default: () => []
},
tagType: {
type: Function,
default: () => {
return 'info'
}
},
placeholder: {
type: String,
default: () => i18n.t('perms.Input')
},
autocomplete: {
type: Function,
default: null
}
},
data() {
return {
filterTags: this.value,
focus: false,
filterValue: '',
component: this.autocomplete ? 'el-autocomplete' : 'el-input'
}
},
watch: {
value(val) {
this.filterTags = val
}
},
methods: {
handleTagClose(tag) {
this.filterTags.splice(this.filterTags.indexOf(tag), 1)
this.$emit('change', this.filterTags)
},
handleSelect(item) {
this.filterValue = item.value
this.handleConfirm()
},
handleConfirm() {
if (this.filterValue === '') return
if (!this.filterTags.includes(this.filterValue)) {
this.filterTags.push(this.filterValue)
this.filterValue = ''
this.$emit('change', this.filterTags)
}
},
handleTagClick(v, k) {
if (this.filterValue.length !== 0) {
this.handleConfirm()
}
this.$delete(this.filterTags, k)
this.filterValue = v
this.$refs.SearchInput.focus()
}
}
}
</script>
<style lang="scss" scoped>
.el-tag + .el-tag {
margin-left: 4px;
}
.filter-field {
display: flex;
flex-wrap: wrap;
align-items: center;
padding-left: 2px;
padding-bottom: 3px;
border: 1px solid #dcdee2;
border-radius: 1px;
background-color: #fff;
line-height: 32px;
&:hover {
border-color: #C0C4CC;
}
&>>> .el-tag {
margin-top: 3px;
}
&>>> .el-autocomplete {
height: 26px;
}
}
.search-input {
flex: 1;
&>>> .el-input__inner {
max-width: 100%;
border: none;
padding-left: 5px;
}
}
.el-input >>> .el-input__inner {
border: none !important;
font-size: 13px;
}
.filter-field >>> .el-input__inner {
height: 26px;
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<div>
{{ value? trueText : falseText }}
</div>
</template>
<script>
export default {
props: {
value: {
type: [String, Boolean],
default: () => false
},
trueText: {
type: String,
default: function() {
return this.$t('common.Yes')
}
},
falseText: {
type: String,
default: function() {
return this.$t('common.No')
}
}
},
data() {
return {}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,92 @@
<template>
<div>
<el-button
v-show="!iShowSelect"
:disabled="disabled"
class="button-text"
type="text"
@click="iShowSelect=true"
>
{{ iLabel }}
<svg-icon class-name="icon" icon-class="switch" />
</el-button>
<Select2
v-show="iShowSelect"
ref="select2"
v-model="iValue"
:disabled="disabled"
v-bind="$attrs"
@change="onSelectChange"
v-on="$listeners"
/>
</div>
</template>
<script>
import Select2 from './Select2'
import { hasUUID } from '@/utils/common'
export default {
components: {
Select2
},
props: {
value: {
type: String,
default: () => ''
},
label: {
type: String,
default: () => ''
},
showSelect: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
iShowSelect: this.showSelect,
iLabel: this.label || '-'
}
},
computed: {
iValue: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
created() {
const { path } = this.$route
if (hasUUID(path) && this.value) {
this.iShowSelect = false
}
},
methods: {
onSelectChange(val) {
const options = this.$refs.select2.options.filter(item => item.value === val)
const label = options.length > 0 ? options[0].label : ''
this.iShowSelect = false
this.iLabel = val ? label : '-'
}
}
}
</script>
<style scoped>
.button-text {
color: #676a6c;
padding: 5px!important;
}
.icon {
color: #676a6c!important;
}
</style>

View File

@@ -32,6 +32,10 @@ export default {
return this.$t('common.Update')
}
},
showInput: {
type: Boolean,
default: true
},
placeholder: {
type: String,
default: () => ''
@@ -39,13 +43,13 @@ export default {
},
data() {
return {
isShow: false,
isShow: this.showInput,
curValue: this.value
}
},
created() {
if (this.$route.path.indexOf('/create') !== -1) {
this.isShow = true
if (this.$route.path.indexOf('/update') !== -1) {
this.isShow = false
}
},
methods: {

View File

@@ -1,6 +1,6 @@
<template>
<div>
<input ref="upLoadFile" type="file" style="display: none" @change="Onchange">
<input ref="upLoadFile" :accept="accept" type="file" style="display: none" @change="Onchange">
<el-button size="mini" @click.native.stop="onUpLoad">
{{ this.$t('common.SelectFile') }}
</el-button>
@@ -23,6 +23,10 @@ export default {
tip: {
type: String,
default: () => ''
},
accept: {
type: String,
default: '*'
}
},
data() {

View File

@@ -0,0 +1,115 @@
<template>
<div class="">
<el-input
v-model="iValue"
type="textarea"
:rows="rows"
:placeholder="placeholder"
/>
<el-upload
ref="upload"
class="upload-secret"
:action="''"
:accept="accept"
:auto-upload="false"
:limit="limit"
v-bind="$attrs"
:on-change="handleChange"
:on-remove="handleRemove"
:file-list="fileList"
>
<el-button size="mini" type="primary">
{{ btnText }}
</el-button>
<div v-if="tip" slot="tip" class="el-upload__tip">
{{ tip }}
</div>
</el-upload>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: () => ''
},
btnText: {
type: String,
default: function() {
return this.$t('common.SelectFile')
}
},
rows: {
type: Number,
default: () => 4
},
limit: {
type: Number,
default: () => 2
},
accept: {
type: String,
default: () => ''
},
placeholder: {
type: String,
default: () => ''
},
tip: {
type: String,
default: () => ''
}
},
data() {
return {
fileName: '',
fileList: [],
iValue: this.value
}
},
watch: {
iValue(val) {
this.$emit('input', val)
}
},
methods: {
handleChange(file, fileList) {
const vm = this
const newFileList = fileList.slice(-1)
this.fileList = newFileList
const reader = new FileReader()
reader.onload = function(res) {
const result = res.target.result
vm.iValue = result
vm.$emit('input', vm.iValue)
}
reader.readAsText(file.raw)
},
handleRemove() {
this.iValue = ''
this.fileList = []
this.$emit('input', this.iValue)
}
}
}
</script>
<style lang="scss" scoped>
.upload-secret {
display: flex;
&>>> .el-list-enter-active,
&>>> .el-list-leave-active {
transition: none;
}
&>>> .el-list-enter,
&>>> .el-list-leave-active {
opacity: 0;
}
&>>> .el-upload-list {
height: 40px;
}
}
</style>

View File

@@ -2,10 +2,10 @@
<div class="c-weektime">
<div class="c-schedue" />
<div :class="{'c-schedue': true, 'c-schedue-notransi': mode}" :style="styleValue" />
<table class="c-weektime-table" :class="{'c-min-table': colspan < 2}">
<table :class="{'c-min-table': colspan < 2}" class="c-weektime-table">
<thead class="c-weektime-head">
<tr>
<th rowspan="8" class="week-td">{{ this.$t('common.WeekCronSelect.WeekOrTime') }}</th>
<th class="week-td" rowspan="8">{{ this.$t('common.WeekCronSelect.WeekOrTime') }}</th>
<th :colspan="12 * colspan">00:00 - 12:00</th>
<th :colspan="12 * colspan">12:00 - 24:00</th>
</tr>
@@ -13,23 +13,23 @@
<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
v-for="n in t.child"
:key="`${n.row}-${n.col}`"
:data-week="n.row"
:data-time="n.col"
:class="selectClasses(n)"
:data-time="n.col"
:data-week="n.row"
class="weektime-atom-item"
@mouseenter="cellEnter(n)"
@mousedown="cellDown(n)"
@mouseenter="cellEnter(n)"
@mouseup="cellUp(n)"
/>
</tr>
<tr>
<td colspan="49" class="c-weektime-preview">
<td class="c-weektime-preview" colspan="49">
<div class="g-clearfix c-weektime-con">
<span class="g-pull-left">{{ this.$t('common.WeekCronSelect.CanDragSelect') }}</span>
<a class="g-pull-right" @click.prevent="clearWeektime">{{ this.$t('common.WeekCronSelect.ClearSelection') }}</a>
@@ -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 {
@@ -314,6 +319,7 @@ export default {
min-width: 640px;
position: relative;
display: inline-block;
padding-right: 20px;
}
.c-schedue {
background: #598fe6;

View File

@@ -1,42 +1,60 @@
import DatetimeRangePicker from './DatetimeRangePicker'
import Link from './Link'
import PasswordInput from './PasswordInput'
import Select2 from './Select2'
import Swicher from './Swicher'
import UploadField from './UploadField'
import UploadKey from './UploadKey'
import UserPassword from './UserPassword'
import WeekCronSelect from './WeekCronSelect'
import UpdateToken from './UpdateToken'
import JsonEditor from './JsonEditor'
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 {
DatetimeRangePicker,
Text,
Link,
PasswordInput,
Switcher,
Select2,
Swicher,
TagInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
WeekCronSelect,
UpdateToken,
JsonEditor,
Text
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}
export {
DatetimeRangePicker,
Text,
Link,
PasswordInput,
Switcher,
Select2,
Swicher,
TagInput,
UploadKey,
JsonEditor,
UpdateToken,
PhoneInput,
UploadField,
UserPassword,
DynamicInput,
PasswordInput,
UploadSecret,
WeekCronSelect,
UpdateToken,
JsonEditor,
Text
NestedObjectSelect2,
DatetimeRangePicker,
JSONManyToManySelect
}

View File

@@ -1,7 +1,7 @@
<template>
<div class="form-group-header">
<div v-if="line" class="hr-line-dashed" />
<h3>{{ group.title }}</h3>
<h3>{{ group['title'] }} </h3>
</div>
</template>

View File

@@ -0,0 +1,92 @@
<template>
<Dialog
v-if="iVisible"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
:title="$tc('assets.TestGatewayTestConnection')"
:visible.sync="iVisible"
top="35vh"
width="40%"
>
<el-row :gutter="20">
<el-col :md="4" :sm="24">
<div style="line-height: 34px">{{ $t('assets.SSHPort') }}</div>
</el-col>
<el-col :md="14" :sm="24">
<el-input v-model="port" />
<span class="help-tips help-block">{{ $t('assets.TestGatewayHelpMessage') }}</span>
</el-col>
<el-col :md="4" :sm="24">
<el-button
:loading="loading"
size="mini"
style="line-height:20px "
type="primary"
@click="dialogConfirm"
>
{{ this.$t('common.Confirm') }}
</el-button>
</el-col>
</el-row>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'GatewayDialog',
components: {
Dialog
},
props: {
visible: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
port: {
type: Number,
default: 0
},
cell: {
type: String,
default: ''
}
},
data() {
return {}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
methods: {
dialogConfirm() {
if (isNaN(this.port)) {
return this.$message.error(this.$tc('common.TestPortErrorMsg'))
}
this.$axios.post(
`/api/v1/assets/gateways/${this.cell}/test-connective/`,
{ port: this.port }
)
.then((res) => {
openTaskPage(res['task'])
}).finally(() => {
this.iVisible = false
})
}
}
}
</script>

View File

@@ -1,10 +1,10 @@
<template>
<TreeTable :table-config="tableConfig" :header-actions="headerActions" :tree-setting="treeSetting" />
<TreeTable :header-actions="headerActions" :table-config="tableConfig" :tree-setting="treeSetting" />
</template>
<script type="text/jsx">
import { DetailFormatter, SystemUserFormatter } from '@/components/TableFormatters'
import TreeTable from '../TreeTable'
import { DetailFormatter } from '@/components/TableFormatters'
export default {
name: 'GrantedAssets',
@@ -35,7 +35,7 @@ export default {
getShowUrl: {
type: Function,
default({ row, col }) {
return this.tableUrl.replace('/assets/', `/assets/${row.id}/system-users/?cache_policy=1`)
return this.tableUrl.replace('/assets/', `/assets/${row.id}/accounts/`)
}
}
},
@@ -57,34 +57,22 @@ export default {
tableConfig: {
url: this.tableUrl,
hasTree: true,
columns: [
{
prop: 'hostname',
label: this.$t('assets.Hostname'),
columnsExclude: ['spec_info'],
columnShow: {
min: ['name', 'address', 'accounts'],
default: ['name', 'address', 'accounts', 'actions']
},
columnsMeta: {
name: {
formatter: DetailFormatter,
sortable: true,
formatterArgs: {
route: 'AssetDetail'
},
showOverflowTooltip: true
}
},
{
prop: 'ip',
label: this.$t('assets.IP'),
width: '140px',
sortable: 'custom'
},
{
prop: 'systemUsers',
label: this.$t('assets.SystemUsers'),
align: 'center',
formatter: SystemUserFormatter,
formatterArgs: {
getUrl: this.getShowUrl.bind(this)
},
showOverflowTooltip: true
actions: {
has: false
}
]
}
},
headerActions: {
hasLeftActions: false,

View File

@@ -1,6 +1,6 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg-icon icon-class="hamburger" class="hamburger" :class="{'is-active':isActive}" />
<div style="padding: 0 20px;" @click="toggleClick">
<svg-icon icon-class="arrow-to-left" class="hamburger" style="color: #ffffff;" :class="{'is-active':isActive}" />
</div>
</template>
@@ -26,7 +26,7 @@ export default {
.hamburger {
display: inline-block;
vertical-align: middle;
font-size: 20px;
font-size: 16px;
color: $menuText;
}
.hamburger.is-active {

View File

@@ -3,7 +3,7 @@
<template #header>
<slot name="header">
<div v-if="title" slot="header" class="clearfix ibox-title">
<i v-if="fa" :class="'fa ' + fa" /> {{ title }}
<i v-if="fa" :class="'fa ' + fa" /> <h5>{{ title }}</h5>
</div>
</slot>
</template>
@@ -41,7 +41,6 @@ export default {
/*height: 100%;*/
clear: both;
padding: 0;
background-color: #ffffff;
}
.ibox >>> .el-card__header {
@@ -56,11 +55,11 @@ export default {
.ibox-title h5 {
display: inline-block;
font-size: 14px;
font-size: 13px;
margin: 0;
padding: 0;
text-overflow: ellipsis;
float: left;
font-weight: 500;
}
.ibox-tools a {
@@ -83,8 +82,7 @@ export default {
}
.ibox >>> .el-card__body {
background-color: #ffffff;
padding: 15px 20px 20px 20px;
padding: 15px 30px 20px 30px;
color: inherit;
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<el-link v-right-click-target="target" :href="url" @click.prevent="openLink">
<slot />
</el-link>
</template>
<script>
export default {
name: 'RightClickLink',
directives: {
'right-click-target': {
inserted(el, binding) {
el.addEventListener('contextmenu', (event) => {
event.preventDefault()
window.open(binding.value, '_blank')
})
}
}
},
props: {
url: {
type: String,
required: true
},
target: {
type: String,
default: '_blank'
}
},
methods: {
openLink() {
window.open(this.url, this.target)
}
}
}
</script>

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