Compare commits

...

464 Commits

Author SHA1 Message Date
老广
49bdd98812 Merge pull request #561 from jumpserver/pr@v2.6@fix_remove_unuse_func
fix: 移除未使用的函数
2021-01-06 14:07:46 +08:00
Orange
743c2ee6e9 fix: 移除未使用的函数 2020-12-21 10:24:11 +00:00
Orange
9d70eecee0 feat: 添加资产编号字段 2020-12-21 14:39:02 +08:00
Jiangjie.Bai
b65664f9c4 Merge pull request #557 from jumpserver/dev
Merge Dev
2020-12-17 18:13:49 +08:00
Orange
f64def0bec fix: 修改箭头颜色 2020-12-17 18:13:09 +08:00
Orange
06f6202bc4 fix: Filter使用后端搜索 2020-12-17 18:13:09 +08:00
Jiangjie.Bai
6fa7800d6b Merge pull request #554 from jumpserver/dev
Chore: Merge Dev
2020-12-17 15:14:11 +08:00
ibuler
54aa252c20 fix(some): 修复没有clone的列表 2020-12-17 15:12:53 +08:00
ibuler
c083f6c4a4 fix(clone): 修复一下clone丢失的问题 2020-12-17 15:12:53 +08:00
Orange
73bb854ebb fix: 去除批量移除, 去除简单写法 2020-12-17 15:03:28 +08:00
Orange
d6f9df277e fix: 修复样式异常和Bug 2020-12-17 15:03:28 +08:00
Jiangjie.Bai
ba78e33f89 Merge pull request #551 from jumpserver/dev
chore: Merge master from dev
2020-12-16 18:42:40 +08:00
Orange
09ef15cff0 fix: 修复工单提示报错 2020-12-16 17:54:38 +08:00
Orange
62d520e625 fix: 修复工单提示报错 2020-12-16 17:54:38 +08:00
Orange
f07a857813 fix: 修复命令过滤器添加系统用户问题 2020-12-16 17:54:38 +08:00
Orange
2699d5e8eb fix: 禁用命令存储文档类型修改 2020-12-16 17:54:38 +08:00
Orange
fb398ca3e4 调整页面errorMessage 2020-12-16 17:54:38 +08:00
Orange
3230c37318 fix: 调整页面保存设置, 优化页面Bug 2020-12-16 17:54:38 +08:00
Jiangjie.Bai
bc258a7ff8 Merge pull request #549 from jumpserver/dev
chore: Merge master from dev
2020-12-15 20:33:14 +08:00
Orange
64d610e282 fix: 修改系统监控页面 2020-12-15 20:32:04 +08:00
Orange
4d95461b5c fix: 添加组件负载状态 2020-12-15 20:32:04 +08:00
Orange
f364c8fdf9 fix: 批量修复2.6版本测试产生的Bug 2020-12-15 20:32:04 +08:00
Orange
88dc2d9271 Merge pull request #547 from jumpserver/dev
fix: 批量修复2.6版本测试产生的Bug
2020-12-14 19:05:38 +08:00
Orange
3aced25da4 fix: 批量修复2.6版本测试产生的Bug 2020-12-14 19:00:16 +08:00
老广
fcf142b696 Merge pull request #544 from jumpserver/dev
Dev
2020-12-11 19:33:54 +08:00
fit2bot
2123037897 fix: 添加组件总量显示 (#543)
Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-11 19:30:58 +08:00
Orange
f5bc2842ec fix: 修复日期显示问题及用户应用授权更新路由问题 2020-12-11 19:28:26 +08:00
Orange
2c95e5f10b fix: 移除中断心跳间隔设置并添加认证方式字段 2020-12-11 19:28:08 +08:00
Jiangjie.Bai
b3ff9c5bcb Merge pull request #539 from jumpserver/dev
chore(merge): dev 合并到 master
2020-12-10 23:47:30 +08:00
Orange
905e5e00b1 fix: 去掉多余JS引用 2020-12-10 23:43:43 +08:00
Orange
81db3d86fa feat: 添加系统监控页面 2020-12-10 23:43:43 +08:00
Orange
ea15515264 feat: 系统用户详情页面增加资产分页面,增加指定资产推送功能 2020-12-10 20:54:14 +08:00
fit2bot
4048a000c7 feat: 添加表格过滤字段选项 (#527)
* feat: 添加表格过滤字段选项

* fix: 如果已有Filter的情况下去掉过滤

Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-10 17:52:12 +08:00
xinwen
a60693c41c perf(asset): 资产树,右击增加计算节点数量的菜单,可以让后台去计算 #527 2020-12-10 17:51:10 +08:00
fit2bot
57d5c893d3 fix: 修复自动生成表格字段冲突问题 (#536)
Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-09 16:32:52 +08:00
fit2bot
435ce24c75 fix: 修复删除source字段引起的无法更新密码的问题 (#534)
Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-09 16:21:59 +08:00
Orange
4a757bb6bc fix: 不允许用户修改source字段 2020-12-08 20:56:11 +08:00
fit2bot
32fa4f0b11 feat: 资产允许编辑更多信息 (#530)
* feat: 资产允许编辑更多信息

* feat: 资产允许编辑更多资产信息

* feat: 资产允许编辑更多资产信息

* fix: 修改组件名称

Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-08 20:25:54 +08:00
Orange
9f12e1aa18 perf: 禁用应用的导入导出 2020-12-08 11:12:00 +08:00
jym503558564
6165709747 perf(assetBatchOperation): 资产模块添加批量删除操作 2020-12-08 11:10:15 +08:00
fit2bot
0ad1eef196 feat: 添加xlsx格式支持 (#526)
* feat: 添加xlsx格式支持

* feat: 添加xlsx格式支持

* feat: 添加xlsx格式支持

* feat: 添加xlsx格式支持

Co-authored-by: Orange <orangemtony@gmail.com>
2020-12-07 15:22:56 +08:00
Orange
d2d07555b5 fix: 修复批量更新终端存储时附带的保存并继续添加 2020-12-07 14:06:48 +08:00
Orange
7f60224c6d fix: 修复会话时间显示问题 2020-12-07 14:04:26 +08:00
Orange
bbf502c85d fix: 调整select2组件默认长度 2020-12-07 14:03:30 +08:00
Orange
e6aaa52506 perf: 恢复Web终端入口 2020-11-26 12:38:28 +08:00
ibuler
70affacfde fix(list): 修复列表克隆的bug 2020-11-26 12:37:28 +08:00
Orange
40a8da5e58 fix: 修复批量更新组件的问题 2020-11-23 14:00:34 +08:00
Orange
24266bb929 fix: 修复批量批量更新组件的问题 2020-11-22 16:53:01 +08:00
Jiangjie.Bai
14286b961e Merge pull request #514 from jumpserver/dev
Merge dev
2020-11-18 11:49:17 +08:00
Orange
0498db9a8f fix: 修复应用授权过滤系统用户的问题及系统用户创建的问题 2020-11-18 11:47:19 +08:00
ibuler
266d107ffd fix(clone): 修复会话页面产生的clone的问题 2020-11-18 10:55:13 +08:00
ibuler
4f2a9c0c6c fix(clone): 修复会话页面产生的clone的问题 2020-11-18 10:35:40 +08:00
Jiangjie.Bai
affb0ec2bb Merge pull request #509 from jumpserver/dev
Merge Dev
2020-11-17 19:45:03 +08:00
Orange
3075d50357 fix: 修复任务列表字段显示问题 2020-11-17 19:30:36 +08:00
Orange
e49da02c4d fix: 修复RemoteApp详情点击更新失败的问题 2020-11-17 19:07:20 +08:00
Orange
7df5736354 fix: 修改默认版本号以及添加修改应用详情页添加系统用户bug 2020-11-17 18:33:14 +08:00
ibuler
98886149f9 perf(tickets): 优化工单备注 2020-11-17 18:13:40 +08:00
ibuler
abb98d55b9 fix(tickets): 修复工单备注的说明 2020-11-17 18:13:40 +08:00
ibuler
f9c979af88 fix(table): 修复克隆出现在不应该出现的表单上 2020-11-17 18:13:15 +08:00
ibuler
89018a2258 fix(assets|users): 修复批量更新上保存并提交 close #469 2020-11-17 18:13:15 +08:00
Orange
a0c29563ca fix: 显示License过期提示 2020-11-17 16:57:29 +08:00
Orange
21223fddea perf: 优化用户详情中授权的应用列表 2020-11-17 16:54:58 +08:00
Orange
254a2b58cc fix: 用户来源不是本地时禁用更新密码和更新SSH 2020-11-17 16:44:42 +08:00
fit2bot
777c371070 fix: 修复工单提交时必须输入系统用户的提醒 (#503)
* fix: 修复工单提交时必须输入系统用户的提醒

* fix: 去掉多余的console.log

Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-17 16:33:40 +08:00
Orange
0cba2b3116 fix: 修复删除应用的提示框 2020-11-17 16:31:57 +08:00
Orange
c27dd0baef fix: 修复翻译缺失和更新系统用户的表单问题 2020-11-17 16:18:15 +08:00
Orange
990aebefdd Merge pull request #495 from jumpserver/dev
Dev
2020-11-12 16:14:36 +08:00
Orange
6f84312dbe fix: 修改改密计划密码默认长度 2020-11-12 14:26:23 +08:00
Orange
d4c12fb38f fix: 修复CSS和监控禁用逻辑问题 2020-11-12 12:16:49 +08:00
Orange
1bb94824df perf: 添加可中断API字段 2020-11-11 19:21:30 +08:00
Orange
5772430761 fix: 修复翻译和样式Bug 2020-11-11 19:20:53 +08:00
ibuler
790941f361 fix(common): 修复通用form的值的错误 2020-11-11 14:28:43 +08:00
fit2bot
a9ce01ac0e feat: 云管同步增加Azure模块 (#488)
* feat: 云管同步增加Azure模块


Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-10 17:02:20 +08:00
fit2bot
1cdc406e70 fix: 修复生成的表格,不该拥有克隆的,有了克隆 (#490)
* fix: 修复生成的表格,不该拥有克隆的,有了克隆

* fix: 修复生成的表格,不该拥有克隆的,有了克隆

Co-authored-by: ibuler <ibuler@qq.com>
2020-11-10 15:32:11 +08:00
Orange
cb60660272 fix: 修复应用授权翻译 2020-11-10 10:28:30 +08:00
fit2bot
8625e21077 feat(createupdate): 修改和创建的msg增加detail连接 (#487)
* feat(form): 增加可以连续增加的功能

* feat(createupdate): 修改和创建的msg增加detail连接

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-09 15:37:26 +08:00
fit2bot
2251a1653e feat(all): 增加clone创建 (#485)
* perf(lang): 优化语言切换

* perf: 优化命令获取

* feat(all): 增加clone创建

* fix: 修改排序

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-09 15:35:43 +08:00
ibuler
ff1debcbce feat(form): 增加可以连续增加的功能 2020-11-09 12:41:03 +08:00
Orange
17e5564cd7 fix: 修复用户界面字段显示问题 2020-11-08 20:40:18 -06:00
fit2bot
615576b3fd perf(passwordExpireTip): 添加密码过期提醒 (#483)
* perf(passwordExpireTip): 初步实现密码过期提醒

* perf(passwordExpireTip): 添加密码过期提醒

Co-authored-by: jym503558564 <503558564@qq.com>
2020-11-09 10:39:27 +08:00
fit2bot
c0d3fbb47a fix: 修复权限认证问题 (#482)
* fix: 修复权限认证问题

* fix: 修复权限认证问题

Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-05 18:59:08 +08:00
ibuler
09075b13b7 perf: 优化命令获取 2020-11-05 18:57:27 +08:00
ibuler
4e92c1a77c perf(lang): 优化语言切换 2020-11-05 18:57:27 +08:00
fit2bot
7cc49bc907 fix: 添加Tree加载重试组件 (#477)
* fix: 添加409错误信息

* fix(perms): 用户授权树重建冲突时弹出提示信息,并保留之前的树

* fix: 添加Tree加载重试组件

Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-05 10:50:38 +08:00
jym503558564
2e2b5bf873 perf(opsTask): 支持批量删除任务信息 2020-11-05 09:53:21 +08:00
Orange
66b1d17dd2 fix: 用户界面隐藏左侧侧边栏web终端入口 2020-11-05 09:52:32 +08:00
Orange
ee26e47c4d fix: 修复CSS样式错误 2020-11-05 09:51:36 +08:00
Orange
aedf6d2158 fix: 修复组织url拼写错误 2020-11-03 18:15:06 +08:00
Orange
6e848e65b4 feat: RDP系统用户增加AD域名字段 2020-11-03 16:13:21 +08:00
Orange
5c0108906c feat: RDP系统用户增加AD域名字段 2020-11-03 16:13:21 +08:00
fit2bot
6c1f8ec8f7 feat: 整理重构应用模块及应用授权模块 (#465)
* feat: 整理重构应用模块及应用授权模块

Co-authored-by: Orange <orangemtony@gmail.com>
2020-11-03 14:28:36 +08:00
Orange
dda36d2b40 fix: 关闭查询保存参数 2020-10-30 17:48:13 +08:00
peijianbo
1abf30c347 feat:危险命令告警 2020-10-28 21:50:24 -05:00
fit2bot
697b5a3d13 perf(permTranslate): 修改翻译 (#462)
* perf(permTranslate): 修改授权一些翻译

* perf(permTranslate): 修改翻译

Co-authored-by: jym503558564 <503558564@qq.com>
2020-10-29 10:49:29 +08:00
jym503558564
74e4c3397e perf(tableWidth): 修改数据库应用列表的宽度 2020-10-28 21:48:34 -05:00
Orange
c227bf59a6 fix: 修复删除节点下资产授权报错的问题 2020-10-28 21:47:56 -05:00
jym503558564
0092f6d6d7 perf(sessionDetail): 修改session详情中的字段翻译 2020-10-28 21:47:31 -05:00
Orange
747477b27c perf: 隐藏左侧边栏Web终端入口 2020-10-28 21:47:00 -05:00
Orange
4943dab50c perf: 去除多余的console.log() 2020-10-28 21:46:28 -05:00
jym503558564
5cac3ee1f7 perf(changeAuthPlan): 改密计划详情中的资产选择,禁选已存在的资产 2020-10-21 12:51:38 +08:00
jym503558564
fa5a227aff perf(renameNode): 修复重命名节点,同名时有两条错误提示信息的问题 2020-10-21 12:51:22 +08:00
jym503558564
792e8595b8 perf(formatterPassword): 统一密码组件 2020-10-21 12:50:55 +08:00
jym503558564
9d62614ff4 perf(formatterPassword): 统一管理用户、系统用户密码组建 2020-10-21 12:50:55 +08:00
jym503558564
48c0f6e8c6 perf(licenseTip): 修复license过期提醒,开源版本出现split提示问题 2020-10-21 12:50:29 +08:00
jym503558564
31b17b384d perf(safari): 修复表格兼容safari,不错位 2020-10-21 12:49:42 +08:00
jym503558564
858d7a9d6f perf(genericCreateUpdate): 修改漏传attr 2020-10-21 12:49:21 +08:00
jym503558564
48b6c48581 perf(userDetail): 统一用户授权详情列表的宽度 2020-10-21 12:48:54 +08:00
八千流
38be9dd367 Merge pull request #443 from jumpserver/pr@dev@perf_userpage_k8s_detail
feat: 用户详情页面添加K8S应用
2020-10-16 09:07:30 +08:00
Orange
7e5570ad72 feat: 用户详情页面添加K8S应用 2020-10-15 18:54:23 +08:00
Orange
16476caa1e Merge pull request #441 from jumpserver/dev
chore: dev to master
2020-10-15 13:05:35 +08:00
八千流
6a5c28ac26 Merge pull request #442 from jumpserver/pr@dev@fix_command_execution
fix: 修复命令执行选择资产报错问题
2020-10-15 13:02:57 +08:00
Orange
5335faa789 fix: 修复命令执行选择资产报错问题 2020-10-15 13:00:27 +08:00
老广
fd1ee6ef7d Merge pull request #439 from jumpserver/pr@dev@fix_badge_hidden
fix: 如果数量为0 隐藏工单Badge
2020-10-14 22:57:40 -05:00
老广
52d8c34bbf Merge pull request #440 from jumpserver/pr@dev@asset_disabled_style
fix: 调整未激活资产展示样式
2020-10-14 22:57:10 -05:00
Orange
9eac41c0c3 fix: 如果数量为0 隐藏工单Badge 2020-10-15 11:45:10 +08:00
Orange
6881316203 fix: 调整未激活资产展示样式 2020-10-15 11:40:11 +08:00
Orange
d4ee8379e8 fix: 如果数量为0 隐藏工单Badge 2020-10-15 10:37:40 +08:00
老广
f64e877491 Merge pull request #435 from jumpserver/dev
chore: Merge Dev to Master
2020-10-14 07:51:05 -05:00
Orange
f46a63cfcf feat: 禁止未激活资产链接 2020-10-14 07:50:34 -05:00
Orange
65a71df10e fix: 在Default组织下隐藏隐藏邀请用户按钮 2020-10-14 19:05:28 +08:00
jym503558564
fd6b0532ba perf(OrgMember): 修复添加组织成员有更多按钮出现的问题 2020-10-14 18:49:11 +08:00
八千流
e02d05a327 Merge pull request #434 from jumpserver/pr@dev@hidden_userpage_tickets
fix: 隐藏用户界面工单
2020-10-14 17:59:24 +08:00
Orange
23740cdce0 fix: 隐藏用户界面工单 2020-10-14 17:57:59 +08:00
Orange
a50f224227 fix: 修复工单数量为0不显示工单按钮的问题 2020-10-14 17:45:47 +08:00
Orange
f8ec327f11 Merge pull request #432 from jumpserver/dev
chore: merge dev to master
2020-10-14 16:04:36 +08:00
ibuler
1d76e037a4 fix: 修复用户邀请 2020-10-14 15:28:58 +08:00
jym503558564
98f5f38694 perf(licenseTip): 管理员有license过期提醒,其它用户无license过期提醒 2020-10-14 15:10:32 +08:00
Orange
b78b95e67a Merge pull request #419 from jumpserver/dev
chore: merge dev to master
2020-10-13 18:53:29 +08:00
Orange
5f60130952 fix: 修复改密计划创建时定期任务创建冲突的问题 2020-10-13 05:49:40 -05:00
Orange
5a82931fc2 fix: 修复时间选择器显示宽度问题 2020-10-13 05:49:00 -05:00
jym503558564
ad49e3250b perf(licenseExpiredTip): 去掉系统设置里面license过期提醒 2020-10-13 17:57:49 +08:00
jym503558564
7ef95f4567 perf(licenseExporeTip): 初步实现license过期提醒 2020-10-13 17:57:49 +08:00
Orange
25a9d21fd7 fix: 修改Tree的刷新Url 2020-10-13 03:06:00 -05:00
Orange
b849df1dc1 fix: 修复表格的时间过滤问题 2020-10-13 03:00:31 -05:00
Orange
1519ccb8e2 fix: 修改添加用户API 2020-10-12 05:40:14 -05:00
fit2bot
47e88e7bb4 perf(org): 添加组织成员合并成一个card (#422)
* perf(org): 添加组织成员合并成一个card

* perf(org): 添加成员后,object需重新刷新才能重新获取新值

Co-authored-by: jym503558564 <503558564@qq.com>
2020-10-12 10:55:56 +08:00
Orange
c86aef999c fix: 调整badge位置 2020-10-11 21:45:41 -05:00
jym503558564
2f9d7ab826 perf(protocol): 批量更新协议组给默认值 2020-10-11 21:41:42 -05:00
fit2bot
b4311b8a59 perf(permSelectAssetCard): 优化授权详情页中的添加资产,将已添加的资产disable掉 (#405)
* perf(permSelectAssetCard): 优化授权详情页中的添加资产,将已添加的资产disable掉

* perf(permSelectAssetCard): 修改全选时,禁用也被选择的bug

* perf(assetSelect): 修改名称

Co-authored-by: jym503558564 <503558564@qq.com>
2020-10-09 11:05:42 +08:00
Jiangjie.Bai
04a97a9923 Merge pull request #418 from jumpserver/dev
Merge Dev
2020-10-09 10:56:15 +08:00
jym503558564
c7624f9092 perf(relationCard): 优化relationCard以及添加组织成员翻译 2020-10-08 21:08:02 -05:00
fit2bot
fc29fc6c6d feat: 工单入口移动至Header栏 (#417)
* feat: 工单入口移动至Header栏

* feat: 工单入口移动至Header栏

Co-authored-by: Orange <orangemtony@gmail.com>
2020-10-09 10:00:23 +08:00
ibuler
7afc501db5 perf: 修改长度 2020-09-30 03:45:31 -05:00
Orange
8ed5672e95 fix: 修复工单审批时系统用户多选参数配置问题 2020-09-29 19:02:13 +08:00
Orange
951c9f56c5 fix: 修复工单审批时系统用户多选参数配置问题 2020-09-29 19:02:13 +08:00
Orange
2c0e079aa2 fix: 修复工单审批时系统用户多选参数配置问题 2020-09-29 16:35:11 +08:00
jym503558564
a8e7ea9c80 perf(ticket): 优化授权工单,支持填写系统用户,审批时系统用户支持选多个 2020-09-29 15:13:10 +08:00
Orange
30143f833a feat: 添加邀请用户进入组织功能 (#411)
* feat: 添加邀请用户进入组织功能
2020-09-29 15:10:48 +08:00
ibuler
ad88daef9a chore: merge xpack dev pr 2020-09-29 14:26:05 +08:00
ibuler
9eb80eb6ca chore: add package 2020-09-29 14:26:05 +08:00
Orange
112de6e81c feat: 添加403请求拦截器
Closes https://github.com/jumpserver/trello/issues/238
2020-09-28 16:51:57 +08:00
Orange
d01f903a9e fix: 临时禁用树节点移动
Closes https://github.com/jumpserver/lina/issues/383
2020-09-28 16:50:39 +08:00
Orange
af6d0aff7c fix: 使用http-equiv功能禁止index.html缓存 2020-09-28 16:49:02 +08:00
Orange
edf8621e8f fix: 修复版本更新Index.html不刷新的问题 2020-09-28 16:49:02 +08:00
Orange
eeb15c624a fix: 修复组织名称更新列表未刷新的问题 2020-09-28 16:48:15 +08:00
Orange
79e2d49a3d fix: 修复页面title设置不生效问题
Closes https://github.com/jumpserver/trello/issues/302
2020-09-28 16:47:22 +08:00
Orange
628395e447 fix: 修复命令存储更新问题 2020-09-24 15:54:23 +08:00
八千流
6cb6e6444b Merge pull request #394 from jumpserver/pr@dev@fix_command_filter
feat: 修复命令过滤详情添加系统用户的问题
2020-09-22 15:09:19 +08:00
八千流
1b9aa23761 Merge pull request #397 from jumpserver/pe@dev@fix_change_orgs_url
fix: 修复更改组织时路径跳转的问题
2020-09-22 15:08:56 +08:00
jym503558564
537c385ecf perf(licenseExpired): 优化license过期提醒 2020-09-22 15:06:39 +08:00
jym503558564
c0f7d6e7ff perf(translate): 修改界面设置的一些字段翻译 2020-09-22 15:05:41 +08:00
jym503558564
78df96f888 feat(batchUpdateProtocols): 新增批量更新协议组 2020-09-22 15:05:08 +08:00
jym503558564
829957090d fix(gateway): 修复测试网关端口数据类型:String改为Int类型 2020-09-22 15:04:42 +08:00
jym503558564
026c8f37ea perf(navHeader): 在页面右上角添加web终端 2020-09-22 15:04:02 +08:00
Orange
97340c6aac feat: 修复更改组织时路径跳转的问题 2020-09-18 15:18:55 +08:00
Orange
bbe54eae48 fix: 修复Build失败的问题 2020-09-18 11:43:19 +08:00
Orange
9137207055 feat: 修复命令过滤详情添加系统用户的问题 2020-09-17 15:10:30 +08:00
Jiangjie.Bai
0ef30ef651 Merge pull request #392 from jumpserver/dev
Merge Dev
2020-09-17 12:11:23 +08:00
Orange
5ae8a6c9e4 fix: 禁用命令记录列表导出选择项 2020-09-17 12:10:46 +08:00
Orange
ace1dcd0b8 fix: 修复切换组织时权限展示问题
Closes https://github.com/jumpserver/trello/issues/332
2020-09-17 11:06:40 +08:00
Jiangjie.Bai
5df487d6bd Merge pull request #390 from jumpserver/dev
chore: 去掉submodule
2020-09-15 17:21:32 +08:00
ibuler
6e548749e1 Removed submodule 2020-09-15 16:26:11 +08:00
ibuler
99885d9f28 chore: 去掉submodule 2020-09-15 16:16:11 +08:00
Orange
83163e11e3 Merge pull request #387 from jumpserver/dev
Merge dev
2020-09-15 16:02:49 +08:00
Orange
8c191fee67 Merge pull request #386 from jumpserver/pr@dev@feat_hidden_tickets
perf: 优化license的路由判断
2020-09-15 15:17:32 +08:00
ibuler
ff9862fa06 perf: 优化license的路由判断 2020-09-15 15:14:07 +08:00
ibuler
db0cea7051 feat: 可以设置隐藏工单 2020-09-15 14:55:38 +08:00
Orange
305c713a57 Merge pull request #382 from jumpserver/dev
chore: 更新Xpack版本
2020-09-08 20:35:35 +08:00
Orange
8a5f93e268 chore: 更新Xpack版本 2020-09-08 20:34:19 +08:00
Jiangjie.Bai
c4d262150b Merge pull request #374 from jumpserver/dev
Merge dev to master
2020-09-08 20:28:47 +08:00
Jiangjie.Bai
94f161f7e6 Merge pull request #380 from jumpserver/pr@dev@merge_Master
修复Merge冲突
2020-09-08 20:26:52 +08:00
Orange
2c5bfb3f4c 修复Merge冲突 2020-09-08 20:24:35 +08:00
Orange
8e12837a77 fix: 修复请求计时器时间问题 2020-09-08 20:22:29 +08:00
ibuler
4385d84f01 feat: 请求时刷新session age 2020-09-08 20:15:42 +08:00
Orange
214bb28c4c chore: 更新Submodule指向 2020-09-08 20:14:56 +08:00
Orange
14c2285ac8 Merge pull request #375 from jumpserver/pr@master@update_xpack_brench
chore: 更新Submodule指向
2020-09-08 20:11:41 +08:00
Orange
18cbe578f0 chore: 更新Submodule指向 2020-09-08 20:09:09 +08:00
fit2bot
e19ded8365 bug(userDetail): 修复用户详情删除其某条授权规则失败的问题 (#371)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-09-08 19:20:24 +08:00
fit2bot
0150008075 fix: 修复备注过长的显示问题 (#373)
Closes https://github.com/jumpserver/lina/issues/341

Co-authored-by: Orange <orangemtony@gmail.com>
2020-09-08 19:19:20 +08:00
Orange
b0bca65cab fix: 修复工单列表提交的问题
Closes https://github.com/jumpserver/trello/issues/312
2020-09-08 12:17:49 +08:00
jym503558564
cb95b9ba4f perf(assetCreateUpdate): 优化资产创建或更新页面的ip字段翻译 2020-09-07 20:05:25 +08:00
jym503558564
4a840288c5 pref(assetSelect): 优化资产选择表单字段翻译 2020-09-07 20:05:25 +08:00
ibuler
11b1d6638d perf(xpack): 优化license导入 2020-09-07 20:04:07 +08:00
Bai
2225807a36 feat(tickets): 工单添加comment字段 2020-09-07 20:01:22 +08:00
Bai
a8baca81d5 feat(i18n): 添加云同步实例任务的hostname_strategy翻译 2020-09-07 17:52:05 +08:00
jym503558564
30161c7178 perf(pref_ticket_badge): 优化badge的背景色 2020-09-07 17:41:33 +08:00
jym503558564
e222d147f6 pref(tickerBadge): 在ticket页面添加badge 2020-09-07 17:41:33 +08:00
jym503558564
3ddc41707c pref(storage): 修改录像存储的配置 2020-09-03 12:51:47 +08:00
jym503558564
a245055150 pref(storageHelpText): 添加录像存储endpoint提示 2020-09-03 12:51:47 +08:00
Orange
ba5fdf2027 fix: 修复LDAP部分问题 2020-09-03 12:50:50 +08:00
jym503558564
e1999e5ce8 pref(textarea): 优化textarea的minRows为3 2020-09-02 14:23:22 +08:00
jym503558564
be4e0b5e35 pref(formRequired): 统一form required 2020-09-02 14:22:50 +08:00
八千流
82c381b80d Merge pull request #359 from jumpserver/revert-356-pr@dev@pref_ticket_comment
Revert "pref(ticket): 优化工单评论显示,我的回复显示在右边,其它回复均显示在左边"
2020-09-02 10:16:53 +08:00
老广
7d71aa96b9 Revert "pref(ticket): 优化工单评论显示,我的回复显示在右边,其它回复均显示在左边 (#356)"
This reverts commit cea03df4eb.
2020-09-02 10:15:02 +08:00
Orange
93408e52c1 feat: 导入组件时按钮显示加载状态
Closes https://github.com/jumpserver/trello/issues/87
2020-09-01 11:45:59 +08:00
fit2bot
cea03df4eb pref(ticket): 优化工单评论显示,我的回复显示在右边,其它回复均显示在左边 (#356)
* pref(ticket): 优化工单评论显示,我的回复显示在右边,其它回复均显示在左边

* pref(ticket): 优化评论显示

* pref(ticket): 修改方法名

Co-authored-by: jym503558564 <503558564@qq.com>
2020-09-01 11:34:43 +08:00
fit2bot
72ee5f60b9 pref(permission): 资产授权详情页添加动作字段 (#353)
* pref(permission): 资产授权详情页添加动作字段

* pref(permission): 修改翻译

Co-authored-by: jym503558564 <503558564@qq.com>
2020-09-01 11:14:58 +08:00
jym503558564
f6a8e5634b pref(userProfile): 优化ssh公钥textarea字段为自适应高度 2020-09-01 11:00:00 +08:00
Orange
868e77c983 feat: 添加测试网关弹窗
Closes https://github.com/jumpserver/trello/issues/191
2020-09-01 10:57:57 +08:00
jym503558564
2a3fd42ca1 pref(storage): 优化存储表单页面 2020-08-31 13:45:11 +08:00
jym503558564
596a26bfb6 pref(session): 优化会话列表字段翻译 2020-08-31 13:40:19 +08:00
Orange
2fc8cea9ef fix: 修复K8S系统用户更新时令牌是必填项的问题
Closes https://github.com/jumpserver/trello/issues/276
2020-08-28 18:03:20 +08:00
Orange
6f8a5c2bfc fix: 授权Actions组件默认折叠
Closes https://github.com/jumpserver/trello/issues/287
2020-08-28 18:00:46 +08:00
Orange
260901351f 修复Core设置SECURITY_VIEW_AUTH_NEED_MFA失效的问题 2020-08-28 17:59:45 +08:00
Orange
66845e58db 修复Core设置SECURITY_VIEW_AUTH_NEED_MFA失效的问题 2020-08-28 17:59:45 +08:00
OrangeM21
0e9e549bea fix: 修改样例中的端口号 2020-08-20 16:51:46 +08:00
OrangeM21
785611414e fix: 修改样例中的端口号 2020-08-20 16:50:38 +08:00
OrangeM21
19267ee001 fix: 更新Xpack代码 2020-08-20 01:42:47 -05:00
老广
65326916ca chore: merge dev to master (#338)
* fix(systemUser): 修复创建k8s系统用户的问题 (#315)

Co-authored-by: jym503558564 <503558564@qq.com>

* fix(csrfToken): 更新CsrfToken的获取方式,改为从Cookie中获取

* pref(i18n): 修改工单详情页的字段翻译

* fix(systemUserCreate): 优化系统用户创建页面

* fix: 通用导出组件提供默认选项

Closes https://github.com/jumpserver/trello/issues/253

* fix: 修复工单列表的状态展示

Closes https://github.com/jumpserver/trello/issues/198

* fix: 修复工单关闭请求问题

* update

* update

* update

* update

* pref(K8s): 统一Kubernetes翻译

* pref(settings): 优化系统设置提示英文的问题

* fix: 优化创建系统用户时表单联动

Closes https://github.com/jumpserver/trello/issues/180

* fix: 修改翻译

其他 => 其它

Closes https://github.com/jumpserver/trello/issues/181

* fix: 创建用户字段显示隐藏问题

* update

* update

* update

* fix: 修改添加组织表单

* fix: 更新密码后刷新表单

* fix: 修改Xpack指向最新代码

* fix: 修改工单备注提交结构

* fix: 调整工单翻译以及角色顺序

* fix: 更新翻译

* fix: 更新翻译

* fix: 修复Safari时间显示问题

Closes https://github.com/jumpserver/trello/issues/237

* Update common.js

Co-authored-by: fit2bot <68588906+fit2bot@users.noreply.github.com>
Co-authored-by: jym503558564 <503558564@qq.com>
Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-20 14:42:11 +08:00
fit2bot
0b925ccf33 pref(xpack): 修改lina master xpack 指向 (#339)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-20 14:12:37 +08:00
Orange
58505d2b50 Update common.js 2020-08-19 23:42:17 -05:00
OrangeM21
ecae504a80 fix: 修复Safari时间显示问题
Closes https://github.com/jumpserver/trello/issues/237
2020-08-19 23:42:17 -05:00
OrangeM21
844bc5b44f fix: 更新翻译 2020-08-19 22:22:39 -05:00
OrangeM21
c1dcf82fbd fix: 更新翻译 2020-08-19 22:22:39 -05:00
OrangeM21
336406ddff fix: 调整工单翻译以及角色顺序 2020-08-19 21:51:41 -05:00
OrangeM21
81e8e650bf fix: 修改工单备注提交结构 2020-08-19 09:12:39 -05:00
OrangeM21
af6308e1b3 fix: 修改Xpack指向最新代码 2020-08-19 09:11:34 -05:00
OrangeM21
aae552f374 fix: 更新密码后刷新表单 2020-08-19 08:48:51 -05:00
OrangeM21
b4c1ee786a fix: 修改添加组织表单 2020-08-19 08:48:26 -05:00
OrangeM21
61da88114d update 2020-08-19 07:38:14 -05:00
OrangeM21
279859ce81 update 2020-08-19 07:38:14 -05:00
OrangeM21
820bb075a3 update 2020-08-19 07:38:14 -05:00
OrangeM21
d96bd76ca9 fix: 创建用户字段显示隐藏问题 2020-08-19 07:38:14 -05:00
OrangeM21
7c56c889f2 fix: 修改翻译
其他 => 其它

Closes https://github.com/jumpserver/trello/issues/181
2020-08-19 07:37:25 -05:00
OrangeM21
3547fb26ad fix: 优化创建系统用户时表单联动
Closes https://github.com/jumpserver/trello/issues/180
2020-08-19 07:36:57 -05:00
jym503558564
ac1363b377 pref(settings): 优化系统设置提示英文的问题 2020-08-19 07:36:11 -05:00
jym503558564
6b5c90ee86 pref(K8s): 统一Kubernetes翻译 2020-08-19 07:35:39 -05:00
OrangeM21
8164fa57ef update 2020-08-19 07:34:31 -05:00
OrangeM21
96c9f229e2 update 2020-08-19 07:34:31 -05:00
OrangeM21
58313f5fe0 update 2020-08-19 07:34:31 -05:00
OrangeM21
738a9c3da1 update 2020-08-19 07:34:31 -05:00
OrangeM21
0f10ed9ffc fix: 修复工单关闭请求问题 2020-08-19 07:34:31 -05:00
OrangeM21
294e05cb06 fix: 修复工单列表的状态展示
Closes https://github.com/jumpserver/trello/issues/198
2020-08-19 07:32:19 -05:00
OrangeM21
1598dcbfbc fix: 通用导出组件提供默认选项
Closes https://github.com/jumpserver/trello/issues/253
2020-08-19 07:31:00 -05:00
jym503558564
cf2d6a47c2 fix(systemUserCreate): 优化系统用户创建页面 2020-08-19 07:30:31 -05:00
jym503558564
c8fb334dae pref(i18n): 修改工单详情页的字段翻译 2020-08-19 07:27:55 -05:00
OrangeM21
93dba0bbee fix(csrfToken): 更新CsrfToken的获取方式,改为从Cookie中获取 2020-08-19 07:27:30 -05:00
fit2bot
2832d876fd fix(systemUser): 修复创建k8s系统用户的问题 (#315)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-17 10:33:19 +08:00
jym503558564
5cd89cee6a fix(xpack): 更新master xpack 指向 2020-08-14 14:38:29 +08:00
老广
2f69861361 chore: merge to master
Merge Dev to master
2020-08-14 12:26:03 +08:00
fit2bot
8f51d9b0ea fix(remoteApp): 创建mysql_workbench表单添加端口字段 (#307)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-13 17:06:22 +08:00
OrangeM21
3a2b6d79fb fix: 去掉API请求的加载条 2020-08-13 15:36:23 +08:00
fit2bot
67ede69685 fix(xpack): 修改Xpack指向 (#305)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-13 12:43:50 +08:00
fit2bot
17c4c9b2ef feat(sytemUser): 优化系统用户页面,新增home和groups字段 (#293)
* feat(sytemUser): 优化系统用户页面,新增home和groups字段

* feat(systemUser): 优化创建系统用户页面

* feat(systemUsers): 修改用户组字段

* feat(systemUser): 修改用户组翻译

* fix(systemUser): 去掉必填

* fix(systemUser): 系统用户表单页面,当用户名与用户相同,则username不是必填

Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-12 18:19:32 +08:00
fit2bot
0319d43942 perf(kubernetes): 优化kubernetes更新页面翻译 (#304)
Co-authored-by: jym503558564 <503558564@qq.com>
2020-08-12 17:57:19 +08:00
jym503558564
dcd088fd58 perf(kubernetes): 优化kubernetes页面 2020-08-12 14:31:23 +08:00
jym503558564
9875ded710 perf(listTable): 优化ip字段宽度,以及修改kubernetes apps翻译 2020-08-12 14:31:23 +08:00
jym503558564
e26cd95ef9 perf(detailCard): 优化详情页bool值字段的显示 2020-08-12 12:22:53 +08:00
fit2bot
1bb8e8c709 fix: 创建K8S系统用户时允许填写username (#301)
* fix: 创建K8S系统用户时允许填写username


Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-11 19:51:44 +08:00
OrangeM21
09617fa606 feat: 添加用户界面K8S应用 2020-08-11 16:45:39 +08:00
fit2bot
62a6d11332 perf: 优化用户列表和用户创建的角色 (#291)
* perf: 优化用户角色

Closes https://github.com/orgs/jumpserver/projects/1

* perf: 优化用户角色

Closes https://github.com/orgs/jumpserver/projects/1

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-11 11:06:22 +08:00
fit2bot
8f00dbf23e feat(kubenetes): 添加kubenetes应用 (#292)
* feat(kubenetes): 添加kubenetes应用

* feat(Kubernetes): 添加K8S应用支持

* feat(Kubernetes): 添加K8S应用支持

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-11 11:01:14 +08:00
jym503558564
8fd624e0b7 fix(opsTask): 去掉任务详情中多余的ID字段 2020-08-11 10:32:25 +08:00
jym503558564
cef6521a2b fix(userCreateUpdate): 修复创建用户时生成密码的问题 2020-08-10 15:10:07 +08:00
OrangeM21
da1217972a fix: 修正创建用户时生成密码的问题 2020-08-07 12:11:43 +08:00
OrangeM21
9efacb68b6 fix: 修复工单提交时候方法冲突问题及删掉多余函数 2020-08-07 12:10:52 +08:00
fit2bot
b3c22f96d8 perf(tagSearch): 优化搜索组件增加编辑选项功能 (#286)
* perf(tagSearch): 优化搜索组件增加编辑选项功能

* 优化Tag细节

* 优化Tag细节

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-07 12:10:13 +08:00
OrangeM21
6bf15655b7 perf(ticket): 优化工单细节
Closes https://github.com/orgs/jumpserver/projects/1
2020-08-07 12:02:03 +08:00
jym503558564
ee3dc30985 feat(xpackOrg): 添加组织成员列表页面的翻译 2020-08-06 17:41:11 +08:00
OrangeM21
21da017f8e fix: 修复上传组件模板下载失败问题 2020-08-06 17:40:21 +08:00
OrangeM21
38b4810d9e perf(sass): 替换node-sass为sass
BREAKING CHANGE: 替换node-sass为sass
2020-08-04 13:42:03 +08:00
fit2bot
d49aae69ab fix(Tickets): 调整工单详情样式 (#281)
* fix(Tickets): 调整工单详情样式

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-08-04 13:40:08 +08:00
OrangeM21
012fefa3ea fix(zTree): 修复zTree销毁冲突问题
Closes https://github.com/jumpserver/lina/issues/280
2020-08-04 11:41:48 +08:00
fit2bot
1f91b9a72f perf(Router): 优化外链路由 (#268)
* perf(Router): 优化外链路由

* perf(Router): 优化外链路由

* 替换BASEURL为BASE_URL

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-31 11:57:04 +08:00
八千流
e061d9eb75 Merge pull request #277 from jumpserver/pr@dev@hotfix_build_error
fix(ticket): 修复Merge冲突造成的编译问题
2020-07-31 11:15:48 +08:00
OrangeM21
00cd04e103 fix(ticket): 修复Merge冲突造成的编译问题 2020-07-31 11:12:31 +08:00
Orange
4b3b1a723f feat: 添加申请资源工单功能 (#185)
* [Feature] 添加申请资产工单

* feat: 添加资产申请工单功能

* update

* feat: 添加申请资源工单功能

* feat: 添加申请资源工单功能

* feat: 添加申请资源工单功能

* feat: 添加申请资源工单功能

* fix(终端列表): 还原终端列表的代码

* fix: 修改申请资源工单功能

* fix: 修改申请资源工单功能

* fix: 修改申请资源工单功能

* feat: 添加请求资产权限工单

* Update cn.json

* Update en.json

Co-authored-by: xinwen <coderWen@126.com>
2020-07-31 10:51:17 +08:00
OrangeM21
2d3a43c202 fix(dialog): 修复当有搜索条件时禁用导出所有选项
Closes https://github.com/jumpserver/trello/issues/74
2020-07-31 10:49:22 +08:00
fit2bot
e8e751668d feat(terminalStorage): 添加批量更新终端存储功能 (#247)
* feat(terminalStorage): 添加批量更新终端存储功能

Closes https://github.com/jumpserver/jumpserver/issues/4392
Closes https://github.com/jumpserver/jumpserver/issues/4172

* update

* update

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-31 10:46:57 +08:00
OrangeM21
c6e0a17aaa fix: 修复创建远程应用密码框显示明文的问题
Closes https://github.com/jumpserver/trello/issues/133
2020-07-31 10:44:30 +08:00
OrangeM21
066d81446c fix(preload): 开启Preload
开启preload,提高首屏加载速度
2020-07-31 10:37:13 +08:00
fit2bot
a63b07cf2e feat: 个人界面添加更新公钥快捷按钮 (#271)
* feat: 个人界面添加更新公钥快捷按钮

Closes https://github.com/jumpserver/jumpserver/issues/4361

* feat: feat: 个人界面添加更新公钥快捷按钮

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-31 10:32:26 +08:00
jym503558564
0ab96fa413 fix(detailCard): 修复详情页数据如果没有ID字段,则不显示ID 2020-07-31 10:30:27 +08:00
ibuler
e064c1cfc4 ci(docker): 使用docker缓存,使用npm mirror 2020-07-29 16:07:15 +08:00
jym503558564
2913699597 fix(tableList): 优化列表组件一些字段的宽度 2020-07-28 16:04:33 +08:00
jym503558564
c413623a22 fix(sessions_cmd_storage): 优化创建命令存储的提示文案 2020-07-28 16:03:15 +08:00
jym503558564
92f08605df fix(sessions_cmd_storage): 优化创建命令存储的提示文案 2020-07-28 16:03:15 +08:00
jym503558564
3fb32ad81c fix(sessions_cmd_storage): 优化创建命令存储的提示文案 2020-07-28 16:03:15 +08:00
jym503558564
760dbad5ac fix(ticket): 优化工单详情 2020-07-28 16:00:58 +08:00
jym503558564
878933bc07 fix(ticket): 优化工单详情 2020-07-28 16:00:58 +08:00
Orange
603ebff771 Merge pull request #217 from jumpserver/pr_dev_i18n_xpack_cloud
feat(AddTranslate): 添加云管账户详情翻译
2020-07-28 15:57:28 +08:00
jym503558564
c23ed70df4 fix(xpack):修改xpack指向 2020-07-28 15:56:18 +08:00
jym503558564
d21598cf1c fix(xpack): 更新xpack指向 2020-07-27 17:41:14 +08:00
OrangeM21
34f1b5d662 fix(CommandExecution): 修复命令过滤执行的系统用户选择 2020-07-24 11:32:37 +08:00
jym503558564
c493aca11b fix(assets): 优化资产详情中网域字段名的显示 2020-07-24 11:01:55 +08:00
jym503558564
cc937d600b fix(permissions): 优化授权列表各列宽度 2020-07-24 10:58:48 +08:00
OrangeM21
fcbe61cb92 fix(el-data-table): 修复翻页搜索结果不正确的问题
Closes https://github.com/jumpserver/trello/issues/69
Closes https://github.com/jumpserver/trello/issues/68
2020-07-24 10:53:26 +08:00
jym503558564
b39f01a023 fix(detailCard): detailCard 增加ID字段 2020-07-24 10:48:43 +08:00
jym503558564
794ad35f84 fix(sessionDetailTimeFormat): 优化会话详情中时间字段的显示格式 2020-07-24 10:46:32 +08:00
fit2bot
729b07798e feat(Clipboard): 添加剪切板权限控制 (#238)
Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-24 10:44:47 +08:00
fit2bot
f2514f68b8 fix(select2): 默认添加clearable属性 (#240)
* fix(select2): 默认添加clearable属性


Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-24 10:35:41 +08:00
fit2bot
30d4044d20 fix(perms): 优化授权列表添加刷新按钮 (#245)
* fix(perms): 优化授权列表添加刷新按钮

* fix(perms): 优化授权列表添加导入导出按钮

Co-authored-by: jym503558564 <503558564@qq.com>
2020-07-24 10:20:37 +08:00
jym503558564
e7cd6e49e8 fix(Xpack): 更新xpack指向 2020-07-21 15:45:03 +08:00
OrangeM21
75276d37e4 fix: 添加form组件的refs 2020-07-21 15:04:24 +08:00
Orange
5a92c4f3ee Merge pull request #228 from jumpserver/pr@dev@ci_add_generic_handler
ci(github): 添加通用action
2020-07-21 13:08:36 +08:00
Orange
ae6fb22fae Merge pull request #229 from jumpserver/pr@master@ci_add_generic_handler
ci(github): 添加通用action
2020-07-21 13:07:55 +08:00
github-actions
ccd98606a1 ci(github): 添加通用action 2020-07-21 05:06:02 +00:00
github-actions
7f2ed5d038 ci(github): 添加通用action 2020-07-21 05:05:59 +00:00
jym503558564
d24741ab4b feat(AddTranslate): 添加云管账户详情翻译 2020-07-20 11:38:19 +08:00
Orange
9ac5eabff2 Merge pull request #212 from jumpserver/pr_dev_ci-change
ci(pull-request): 添加自动pr打标签功能
2020-07-17 16:14:52 +08:00
ibuler
18b5fafa41 ci(pull-request): 添加自动pr打标签功能 2020-07-17 16:10:02 +08:00
Orange
8a76bb05ac Merge pull request #208 from jumpserver/jym_bug_fix
fix(settings): 修复安全设置页面更新不了的问题
2020-07-16 15:49:18 +08:00
Orange
ad5b5c7c20 Merge pull request #207 from jumpserver/jym_bug_fix
fix(settings): 修复安全设置页面更新不了的问题
2020-07-16 15:48:40 +08:00
jym503558564
fe7d43f669 fix(settings): 修复安全设置页面更新不了的问题 2020-07-16 15:35:42 +08:00
八千流
aad23f3de5 Merge pull request #202 from jumpserver/dev
merge(master): Merge from dev to master
2020-07-16 11:12:33 +08:00
八千流
9c33093b01 Merge pull request #205 from jumpserver/update_xpack
update:Xpack
2020-07-16 11:11:00 +08:00
OrangeM21
c94a5dfa1f update:Xpack 2020-07-16 11:08:24 +08:00
八千流
143973531c Merge pull request #204 from jumpserver/update_xpack_master
fix: 更新Master Xpack代码
2020-07-16 11:05:29 +08:00
OrangeM21
7db590950c fix: 更新Master Xpack代码 2020-07-16 11:04:13 +08:00
八千流
7e65a52062 Merge pull request #203 from jumpserver/update_xpack
fix: 更新Xpack代码
2020-07-16 11:01:05 +08:00
OrangeM21
226d118d28 fix: 更新Xpack代码 2020-07-16 10:58:49 +08:00
老广
0e3bd186fe Merge pull request #201 from jumpserver/v2.0
Merge v2.0
2020-07-16 10:44:27 +08:00
八千流
50e8dfc86d fix(timeFormat): 统一时间格式 (#197)
* fix(timeFormat): 统一时间格式

* fix: 更新Xpack代码

Co-authored-by: OrangeM21 <orangemtony@gmail.com>
2020-07-15 20:46:01 +08:00
OrangeM21
a023e03074 fix: 更新Xpack代码&&用户界面资产添加备注选项
Closes https://github.com/jumpserver/trello/issues/75
2020-07-15 20:43:39 +08:00
OrangeM21
a0a592f064 fix(AssetUpdate): 创建资产网域选项可清空
Closes https://github.com/jumpserver/lina/issues/141
2020-07-15 20:19:15 +08:00
八千流
4d86edd65e fix(ldapUserListFix): 优化ldap用户列表勾选后关闭页面,再次打开时,上一次选中的状态还存在的问题 (#192)
* fix(ldapUserListFix): 优化ldap用户列表勾选后关闭页面,再次打开时,上一次选中的状态还存在的问题
2020-07-15 18:34:17 +08:00
Orange
c597bc1dca fix(SessionList): 修复命令详情参数及在线会话快捷操作组件 (#198)
* fix(SessionList): 修复命令详情参数及在线会话快捷操作组件

Closes https://github.com/jumpserver/trello/issues/72

* fix: 更新API参数
2020-07-15 18:31:13 +08:00
OrangeM21
a3d45fd4b9 fix(UserProfile): 修复登录密码后没有立即提示退出登录等问题
Closes https://github.com/jumpserver/trello/issues/23
2020-07-15 18:23:00 +08:00
jym503558564
e16d3c2e3f fix(changePasswd): 添加changePassword创建页面中的翻译 2020-07-15 18:21:17 +08:00
OrangeM21
e251127f6e fix(AssetUserTable): 去掉删除资产的前端提示,改为由后端提示
Closes https://github.com/jumpserver/trello/issues/30
2020-07-15 18:19:20 +08:00
jym503558564
58b8917739 fix(ldap): 修复LDAP一键导入不选择用户,导入了全部用户的问题 2020-07-15 18:18:26 +08:00
八千流
ad423e921a fix(highlight): 修复创建资源后跳转到列表页世,左侧菜单没有高亮问题 (#191) 2020-07-15 17:54:11 +08:00
八千流
326302ea5f fix(setting): 优化安全设置的一些字段提醒 (#190) 2020-07-15 17:52:54 +08:00
八千流
be213268fa fix(firefox_time_fix): 修改有些列表页面的时间在firefox上显示不出来的问题 (#189) 2020-07-15 17:51:10 +08:00
OrangeM21
b82231f3ea fix(Userlist): 添加禁止更新和禁止删除的权限判断
Closes https://github.com/jumpserver/trello/issues/29
2020-07-15 17:49:48 +08:00
Orange
f976800cde fix: 修改弹窗按钮高亮提示 (#187) 2020-07-15 17:47:22 +08:00
OrangeM21
4973c62618 fix: 用户来源不为Local的时候禁止更新密码
Closes https://github.com/jumpserver/trello/issues/44
2020-07-15 17:46:04 +08:00
Orange
5db7538216 Merge pull request #182 from jumpserver/remote_permission_fix
fix(remote_app_permission): 修复创建远程应用页面系统用户的获取
2020-07-09 18:29:38 +08:00
Orange
786528f9b2 Merge pull request #184 from jumpserver/remote_permission_fix
fix(remote_app_permission): 修复创建远程应用页面系统用户的获取
2020-07-09 18:29:19 +08:00
Orange
661409b99d Merge pull request #183 from jumpserver/remote_permission_fix
fix(remote_app_permission): 修复创建远程应用页面系统用户的获取
2020-07-09 18:29:04 +08:00
ibuler
702bb3acfa ci(build): 修改构建,使用严格模式 2020-07-09 17:50:05 +08:00
jym503558564
448b64757c fix(remote_app_permission): 修复创建远程应用页面系统用户的获取 2020-07-09 17:44:51 +08:00
ibuler
4289c36bd4 ci(build): 修改构建,使用严格模式 2020-07-09 17:44:01 +08:00
ibuler
bbccba3731 ci(docker): 修改docker构建 2020-07-09 17:44:01 +08:00
ibuler
57b6e02960 fix(Docker): 修改Dockerfile,统一使用build.sh构建 2020-07-09 17:44:01 +08:00
ibuler
8c6d2a1150 ci(build): 修改构建,使用严格模式 2020-07-09 17:29:56 +08:00
ibuler
1295fb7fd2 ci(docker): 修改docker构建 2020-07-09 16:35:55 +08:00
BaiJiangJie
d3fbb9a391 Merge pull request #177 from jumpserver/ci
ci(docker): 修改docker构建
2020-07-09 16:31:23 +08:00
ibuler
2b14cf0225 ci(docker): 修改docker构建 2020-07-09 16:25:42 +08:00
BaiJiangJie
a78f8a3633 Merge pull request #176 from jumpserver/dev
merge: Merge to master from branch dev
2020-07-09 16:01:19 +08:00
何去何从
c4868dabac fix: 优化资产树 mini-button 添加 cursor:pointer 2020-07-09 15:40:41 +08:00
BaiJiangJie
faf848dca5 Merge pull request #175 from jumpserver/ci
fix(Docker): 修改Dockerfile,统一使用build.sh构建
2020-07-09 15:40:19 +08:00
ibuler
05edffe173 fix(Docker): 修改Dockerfile,统一使用build.sh构建 2020-07-09 15:35:44 +08:00
Orange
4b3862443a Merge pull request #173 from jumpserver/master_merge
fix: lina dev中xpack的commit号指向xpack master
2020-07-09 14:20:31 +08:00
Orange
536ebd7513 Merge pull request #172 from jumpserver/master_merge
fix: lina master中xpack的commit号指向xpack master
2020-07-09 14:16:59 +08:00
jym503558564
7dce39d79c fix: lina master中xpack的commit号指向xpack master 2020-07-09 14:14:06 +08:00
八千流
a8389304d6 Merge pull request #171 from jumpserver/master
Merge Master 代码
2020-07-09 13:53:18 +08:00
Orange
649d4ac848 Merge pull request #170 from jumpserver/v2.0
feat: 更新Master代码
2020-07-09 13:44:11 +08:00
Orange
781bbe0ffa Merge pull request #169 from jumpserver/audit_fix
fix(audit): 修复时间显示兼容firefox
2020-07-09 12:01:28 +08:00
jym503558564
2771d80749 fix(audit): 修复时间显示兼容firefox 2020-07-09 11:48:27 +08:00
八千流
86b5cb81fc Merge pull request #168 from jumpserver/v2.0
feat: 更新Master代码
2020-07-08 17:30:03 +08:00
Orange
273dc7234b Merge pull request #167 from jumpserver/ci
ci(release): 统一releaes title
2020-07-08 17:27:38 +08:00
ibuler
9927bf46b5 ci(release): 统一releaes title 2020-07-08 17:26:36 +08:00
OrangeM21
652919f827 chore: 修改版本号为2.0.2 2020-07-08 16:44:13 +08:00
Orange
9f5d121f9c Merge pull request #165 from jumpserver/v2.0_system_user
fix(system_user): 修复系统用户创建/更新页面认证信息字段显示、隐藏、翻译问题
2020-07-08 15:03:33 +08:00
Bai
efb5de9289 fix(i18n): 修改系统用户密码字段helpMessage 2020-07-08 15:01:53 +08:00
Bai
d94b3c9fc9 fix(system_user): 修复系统用户创建/更新页面认证信息字段显示隐藏问题 2020-07-08 14:57:46 +08:00
Orange
50482d5d8b Merge pull request #164 from jumpserver/update_xpack
fix(xpack): 更新Xpack依赖
2020-07-08 14:40:49 +08:00
OrangeM21
15ed63f589 fix(xpack): 更新Xpack依赖 2020-07-08 14:39:30 +08:00
八千流
1ffcf9e7b4 Merge pull request #163 from jumpserver/v2.0
revert: 撤销网域显示ID的修复
2020-07-08 14:02:27 +08:00
Orange
6afc54391b Merge pull request #162 from jumpserver/revert_domain_name
revert: 撤销网域显示ID的修复
2020-07-08 14:01:02 +08:00
OrangeM21
d1bb6b8909 revert: 撤销网域显示ID的修复 2020-07-08 14:00:17 +08:00
Orange
a665d6ed20 Merge pull request #161 from jumpserver/v2.0
ci(fix): 修改ci使用的action为node10
2020-07-08 12:03:17 +08:00
ibuler
00e2e7e433 ci(fix): 修改ci使用的action为node10 2020-07-08 12:02:08 +08:00
Orange
47c05922ae Merge pull request #159 from jumpserver/v2.0
fix(many): v2.0中修改的bug Merge到master
2020-07-08 11:51:06 +08:00
ibuler
a036562e5c ci(build&release): 添加ci, 自动化构建 2020-07-08 11:47:05 +08:00
Orange
a92f09f6af Merge pull request #157 from jumpserver/command_storage_fix
fix: 优化命令存储创建页面,主机字段提示信息的翻译问题
2020-07-08 10:59:26 +08:00
jym503558564
a2d6281a6a fix: 优化命令存储创建页面,主机字段提示信息的翻译问题 2020-07-08 10:56:55 +08:00
Orange
36fa19df89 Merge pull request #155 from jumpserver/fix_relation_card_add_bug
fix(relationCard): 修改关系卡片的bug
2020-07-07 19:14:12 +08:00
Orange
f72baa33e3 Merge pull request #153 from jumpserver/jym_fix
fix: 修改资产详情网域字段显示,以及去掉一些多余的东西
2020-07-07 19:12:11 +08:00
Orange
9c415fca87 Merge pull request #154 from jumpserver/jym_dev
fix: 修复时间兼容firefox
2020-07-07 19:11:44 +08:00
ibuler
0ef5852fd8 fix(relationCard): 修改关系卡片的bug
原来数据是从 options 中过滤获取的, 当搜索结束后就无法在获取到,所以改成从select中获取选中的
2020-07-07 19:08:30 +08:00
jym503558564
dac04cfa61 fix: 修复时间兼容firefox 2020-07-07 18:40:07 +08:00
jym503558564
68149563fc fix: 修改资产详情网域字段显示,以及去掉一些多余的东西 2020-07-07 15:59:46 +08:00
Orange
37cce2effd Merge pull request #150 from jumpserver/fix_assetslist_actions
fix: 修复资产列表批量操作提交报错的问题
2020-07-07 15:35:39 +08:00
Orange
5412e40856 Merge pull request #151 from jumpserver/v2.0_i18n
feat(i18n): 修改翻译
2020-07-07 14:50:03 +08:00
Bai
6ae70c8c41 feat(i18n): 修改翻译 2020-07-07 14:41:18 +08:00
OrangeM21
06fc671547 fix: 更新Submodule链接 2020-07-06 19:35:31 +08:00
OrangeM21
6571615643 fix: 修复资产列表批量操作提交报错的问题 2020-07-06 19:27:50 +08:00
OrangeM21
b0c03b6c1f fix: 修复系统用户添加空资产成功的问题 2020-07-06 18:37:45 +08:00
OrangeM21
6be89ba479 fix: 修复系统用户添加空资产成功的问题 2020-07-06 18:33:24 +08:00
Orange
56f58d49cc Merge pull request #147 from jumpserver/fix_rule_errors
fix: 修复用户界面可以创建节点的问题
2020-07-06 17:57:23 +08:00
OrangeM21
c4efba4c83 fix: 修复用户界面可以创建节点的问题 2020-07-06 17:56:10 +08:00
Orange
14a15efcd9 Merge pull request #146 from jumpserver/fix_rule_errors
fix: 修复已知Issues
2020-07-06 17:50:54 +08:00
OrangeM21
3e32eae8f3 fix: 修复已知Issues
修复审计员权限无法打开用户界面的问题
修复英文状态下基础列表宽度问题
修复收藏节点无法右键的问题
修复Firefox无法打开系统用户详情的问题
2020-07-06 17:49:28 +08:00
Orange
7e0f53e403 Merge pull request #139 from jumpserver/jym_dev
fix: 统一详情中左右侧布局组件
2020-07-06 11:16:05 +08:00
Orange
0d172f94b2 Merge pull request #140 from jumpserver/fix_terminal_url
fix: 修复终端详情获取异常的问题
2020-07-06 11:15:27 +08:00
OrangeM21
b1fc95db5b fix: 修复终端详情获取异常的问题 2020-07-06 11:13:28 +08:00
jym503558564
9c16321ed7 fix: 统一详情中左右侧布局组件 2020-07-06 10:46:27 +08:00
Orange
1e98827e98 Merge pull request #136 from jumpserver/fix_update_bulkdeleteUrl
fix: 修复批量删除链接的bug
2020-07-04 18:44:21 +08:00
OrangeM21
38d5b81cd0 fix: 修复批量删除链接的bug 2020-07-04 18:42:41 +08:00
Orange
fda09a6712 Merge pull request #134 from jumpserver/dev
feat: 优化表格组件
2020-07-03 17:39:26 +08:00
Orange
5bed98b991 Merge pull request #133 from jumpserver/jym_dev
fix: 优化表格宽度,优化资产树显示的位置大小可等比例缩放
2020-07-03 17:37:54 +08:00
jym503558564
6d4c9f3676 fix: 修改资产树显示位置的大小可等比例缩放 2020-07-03 16:10:05 +08:00
Orange
fe84cf42eb Merge pull request #132 from jumpserver/fix_ldap_setting
fix: 优化Ldap认证设置
2020-07-03 16:03:07 +08:00
jym503558564
e6295c9dc5 fix: 优化表格宽度 2020-07-03 16:02:38 +08:00
OrangeM21
d79b178229 fix: 优化Ldap认证设置 2020-07-03 16:00:05 +08:00
Orange
474e132f50 Merge pull request #129 from jumpserver/jym
fix: 优化lina一些细节问题
2020-07-03 14:01:45 +08:00
Orange
cad8c9aeb2 Merge pull request #131 from jumpserver/dev
feat: 更新Xpack依赖
2020-07-03 13:26:05 +08:00
八千流
d72cf1e825 Merge pull request #130 from jumpserver/update_xpack_release
feat: 更新Xpack依赖
2020-07-03 13:25:18 +08:00
OrangeM21
9e9c8639bc feat: 更新Xpack依赖 2020-07-03 13:06:52 +08:00
jym503558564
386afc9e0c fix: 整理统一 Lina List 2020-07-03 10:48:27 +08:00
jym503558564
acfe87f1c6 fix: 整理同样 Lina form 2020-07-02 18:41:53 +08:00
jym503558564
a9700e77f2 fix: 优化Lina 右上角切换用户页面的菜单对齐 2020-07-02 18:08:40 +08:00
jym503558564
36ed0a02c2 fix: 优化资产创建页面,协议组对齐 2020-07-02 17:54:59 +08:00
Orange
383d57c1c7 Merge pull request #128 from jumpserver/dev
fix: Bump websocket-extensions from 0.1.3 to 0.1.4
2020-07-02 17:13:19 +08:00
jym503558564
96863322ac fix: 优化用户页面中的资产详情dialog数据显示 2020-07-02 17:12:07 +08:00
dependabot[bot]
abf979c177 Bump websocket-extensions from 0.1.3 to 0.1.4 (#87)
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-02 17:01:35 +08:00
八千流
d9a34a898f Merge pull request #127 from jumpserver/v2.0
feat: 更新Dev分支代码
2020-07-02 16:55:57 +08:00
Orange
8105306278 Merge pull request #126 from jumpserver/feat_add_platform_chartset
feat: 添加平台编码选项
2020-07-02 16:43:43 +08:00
OrangeM21
e8073d9feb feat: 添加平台编码选项
Closes https://github.com/jumpserver/jumpserver/issues/4207
2020-07-02 16:38:18 +08:00
Orange
ac64ab7145 Merge pull request #121 from jumpserver/fix_unauthorized_error
fix: 修复登录鉴权提示
2020-07-02 15:20:29 +08:00
OrangeM21
8bd4e8b7c0 fix:修复登录鉴权提示 2020-07-02 15:15:04 +08:00
Orange
d581996e87 Merge pull request #119 from jumpserver/fix_assets_dialog_title
fix: 修复资产 Dialog Title显示错误问题
2020-07-02 12:06:22 +08:00
OrangeM21
24a850c99f fix: 修正Dialog Title 错误 2020-07-02 12:01:30 +08:00
Orange
ecaa4cfa70 Merge pull request #117 from jumpserver/change_xpack_source
feat: 更新Xpack引用链接
2020-07-01 18:20:10 +08:00
OrangeM21
8aebf366bc fix: update xpack url 2020-07-01 18:15:58 +08:00
Orange
863b89888d Merge pull request #116 from jumpserver/update_xpack_and_fix_bugs
fix: 修复资产页面Bug,更新Xpack依赖
2020-07-01 17:11:16 +08:00
OrangeM21
85012d9558 [fix]更新XPack,修复资产页面Bugs 2020-07-01 17:04:28 +08:00
八千流
7db080b418 Merge pull request #114 from jumpserver/fix_bugs_orange
fix:修复资产和前端bugs
2020-07-01 15:24:01 +08:00
Orange
622ab4cbc9 Merge pull request #113 from jumpserver/jym_dev
fix:优化导入、导出提示信息,以及优化一些表格显示不友好问题
2020-07-01 15:17:19 +08:00
jym503558564
f862a39c03 Merge branch 'v2.0' into jym_dev 2020-07-01 11:00:28 +08:00
jym503558564
c3d0367662 fix:优化表格一些显示不友好问题 2020-07-01 10:49:15 +08:00
jym503558564
75e234e3e2 fix:修改资产模块可连接提示信息 2020-07-01 10:49:02 +08:00
jym503558564
7f8aa6a65a fix:修改资产模块可连接提示信息 2020-07-01 10:48:30 +08:00
jym503558564
f6aa6fc2ac fix: 优化导出、导出、刷新按钮添加文字提示信息 2020-07-01 10:41:17 +08:00
OrangeM21
f1ad3ba85b fix: 批量修改设置管理用户为必选项 2020-06-30 17:48:10 +08:00
OrangeM21
55c959fd50 fix: 修复2.0.1的bugs 2020-06-30 14:41:04 +08:00
OrangeM21
7de33e175f fix: 优化表格宽度
优化表格宽度,调整表格宽度在窄页面和英文页面的表现

Closes https://github.com/jumpserver/jumpserver/issues/4173
2020-06-28 19:09:16 +08:00
OrangeM21
f7c3a3ac3b fix: 修复批量命令菜单联动
Closes #4180
2020-06-28 15:55:54 +08:00
OrangeM21
1d74137144 [fix]增加系统用户为自动推送时的手动推送全局按钮 2020-06-23 16:31:21 +08:00
OrangeM21
de547e6a5a [fix] 修复获取终端异常 2020-06-23 15:25:23 +08:00
Orange
d3ebdb0d61 Merge pull request #111 from jumpserver/v2.0.1
[update]修改版本号
2020-06-22 19:23:57 +08:00
OrangeM21
004c0e3f66 [update]修改版本号 2020-06-22 19:22:32 +08:00
老广
57e4b65059 Merge pull request #100 from jumpserver/dev
[hotfix]更改路由权限验证模块
2020-06-22 18:42:42 +08:00
Orange
bd0d1a1014 Merge pull request #109 from jumpserver/v2.0
[fix]更新路由权限,更新eslint Ignore
2020-06-22 18:36:20 +08:00
Orange
7b3e38ac78 Merge pull request #110 from jumpserver/v2.0.0_fix_route
[fix]抽象路由写法
2020-06-22 18:35:27 +08:00
OrangeM21
4927c6520a [fix]抽象路由写法 2020-06-22 18:31:59 +08:00
Orange
c10145c9cc Merge pull request #108 from jumpserver/v2.0.0_fix_route
[fix]Terminal路由分组,更新Eslint
2020-06-22 16:25:43 +08:00
OrangeM21
7eccb20269 [fix]更新路由权限,更新eslint Ignore 2020-06-22 16:15:56 +08:00
Orange
26ec366332 Merge pull request #107 from jumpserver/dev
[hotfix]修复系统设置页面无法提交安全设置的问题
2020-06-19 18:56:57 +08:00
OrangeM21
0ed6ad055e [hotfix]修复系统设置页面无法提交安全设置的问题 2020-06-19 18:51:43 +08:00
Orange
ff5b77c1a9 Merge pull request #106 from jumpserver/dev
[fix]修复bugs
2020-06-19 18:34:18 +08:00
OrangeM21
7f788a4610 [fix]修复修改密码页面不会退出的问题 2020-06-19 16:45:13 +08:00
OrangeM21
553805e03d [fix]修复系统设置没有初始值的问题 2020-06-19 16:03:12 +08:00
OrangeM21
f9f90e55c1 [fix]修改页面路由权重问题 2020-06-19 15:08:14 +08:00
Orange
4be2db93c7 Merge pull request #105 from jumpserver/dev
[fix]fix bugs
2020-06-18 19:35:10 +08:00
OrangeM21
65855b3e07 [fix]无路由情况打印报错信息 2020-06-18 19:29:37 +08:00
OrangeM21
3ff5519bfa [hotfix]修复初始化获取命令执行为空导致无法登陆的问题 2020-06-18 18:52:33 +08:00
Orange
a79af0a7c4 Merge pull request #103 from jumpserver/dev
[hotfix]修复会话详情页面下载URL
2020-06-18 17:16:50 +08:00
OrangeM21
4f120ae81d [hotfix]修复会话详情页面下载URL 2020-06-18 17:15:18 +08:00
Orange
9e7c570216 Merge pull request #102 from jumpserver/dev
[hotfix]修改build目录
2020-06-18 15:34:38 +08:00
OrangeM21
1cd4f1f228 [hotfix]修改build目录 2020-06-18 15:32:11 +08:00
Orange
5aa28903dd Merge pull request #99 from jumpserver/dev
[feature] v2.0 Release
2020-06-18 11:04:32 +08:00
265 changed files with 9805 additions and 2577 deletions

View File

@@ -1,2 +1,3 @@
lina
dist
node_modules

View File

@@ -2,4 +2,5 @@ build/*.js
src/assets
public
dist
lina
node_modules

45
.github/release-config.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: '🌱 新功能 Features'
labels:
- 'feature'
- 'enhancement'
- 'feat'
- '新功能'
- title: '🚀 性能优化 Optimization'
labels:
- 'perf'
- 'opt'
- 'refactor'
- 'Optimization'
- '优化'
- title: '🐛 Bug修复 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 其它 Maintenance'
labels:
- 'chore'
- 'docs'
exclude-labels:
- 'no'
- '无需处理'
- 'wontfix'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
template: |
## 版本变化 Whats Changed
$CHANGES

View File

@@ -0,0 +1,12 @@
on: [push, pull_request, release]
name: JumpServer repos generic handler
jobs:
generic_handler:
name: Run generic handler
runs-on: ubuntu-latest
steps:
- uses: jumpserver/action-generic-handler@master
env:
GITHUB_TOKEN: ${{ secrets.PRIVATE_TOKEN }}

46
.github/workflows/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release And Upload assets
jobs:
create-realese:
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Get version
id: get_version
run: |
TAG=$(basename ${GITHUB_REF})
VERSION=${TAG/v/}
echo "::set-output name=TAG::$TAG"
echo "::set-output name=VERSION::$VERSION"
- name: Create Release
id: create_release
uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config-name: release-config.yml
version: ${{ steps.get_version.outputs.TAG }}
tag: ${{ steps.get_version.outputs.TAG }}
build-and-release:
needs: create-realese
name: Build and Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build it and upload
uses: jumpserver/action-build-upload-assets@node10
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-realese.outputs.upload_url }}

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
.DS_Store
node_modules/
dist/
lina/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "src/views/xpack"]
path = src/views/xpack
url = git@github.com:fit2cloudrd/js-xpack-web.git

View File

@@ -1,12 +1,23 @@
FROM node:10 as stage-build
WORKDIR /data
ADD ./package.json /data/package.json
ADD ./yarn.lock /data/yarn.lock
RUN yarn
ADD . /data
RUN yarn build:prod
ARG VERSION
ENV VERSION=$VERSION
ARG NPM_REGISTRY="https://registry.npm.taobao.org"
ENV NPM_REGISTY=$NPM_REGISTRY
ARG SASS_BINARY_SITE="https://npm.taobao.org/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/
COPY utils /data/utils/
RUN ls && cd utils && bash -xieu build.sh dep
ADD . /data
RUN cd utils && bash -xieu build.sh build
FROM nginx:alpine
COPY --from=stage-build /data/dist /opt/lina/
COPY --from=stage-build /data/release/lina /opt/lina
COPY nginx.conf /etc/nginx/conf.d/default.conf

View File

@@ -2,8 +2,8 @@ server {
listen 80;
location /ui/ {
try_files $uri / /ui/index.html;
alias /opt/lina/;
try_files $uri / /ui/index.html;
alias /opt/lina/;
}
location / {

View File

@@ -20,6 +20,7 @@
"dependencies": {
"@ztree/ztree_v3": "3.5.44",
"axios": "0.18.1",
"axios-retry": "^3.1.9",
"deepmerge": "^4.2.2",
"echarts": "^4.7.0",
"element-ui": "2.13.2",
@@ -82,8 +83,8 @@
"less-loader": "^5.0.0",
"lint-staged": "^10.1.2",
"mockjs": "1.0.1-beta3",
"node-sass": "^4.9.0",
"runjs": "^4.3.2",
"sass": "^1.26.10",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",

View File

@@ -3,6 +3,10 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>

View File

@@ -51,6 +51,14 @@ export function refreshLdapUserCache() {
})
}
export function StartLdapUserCache() {
return request({
disableFlashErrorMsg: true,
url: '/api/v1/settings/ldap/users/?cache_police=1',
method: 'get'
})
}
export function importLdapUser(data) {
return request({
disableFlashErrorMsg: true,

8
src/api/ticket.js Normal file
View File

@@ -0,0 +1,8 @@
import request from '@/utils/request'
export function getTicketOpenCount(assign) {
return request({
url: `/api/v1/tickets/tickets/?assign=${assign}&status=open&offset=0&limit=15&display=1&draw=1/`,
method: 'get'
})
}

View File

@@ -65,3 +65,7 @@ export function logout() {
method: 'post'
})
}
export function refreshSessionIdAge() {
return getProfile()
}

View File

@@ -1,9 +1,14 @@
<template>
<div :class="grouped ? 'el-button-group' : ''">
<el-button v-for="item in iActions" :key="item.name" :size="size" v-bind="item" @click="handleClick(item.name)">
<i v-if="item.fa" :class="'fa ' + item.fa" />{{ item.title }}
<el-tooltip v-if="['actionExport', 'actionImport', 'actionRefresh'].indexOf(item.name) !== -1" effect="dark" :content="item.tip" placement="top">
<i v-if="item.fa" :class="'fa ' + item.fa" />{{ item.title }}
</el-tooltip>
<span v-else>
<i v-if="item.fa" :class="'fa ' + item.fa" />{{ item.title }}
</span>
</el-button>
<el-dropdown v-if="iMoreActions.length > 0" trigger="click" @command="handleClick">
<el-dropdown v-if="iMoreActions.length > 0" trigger="click" :placement="moreActionsPlacement" @command="handleClick">
<el-button :size="size" :type="moreActionsType" class="btn-more-actions">
{{ iMoreActionsTitle }}<i class="el-icon-arrow-down el-icon--right" />
</el-button>
@@ -47,6 +52,11 @@ export default {
moreActionsType: {
type: String,
default: 'default'
},
moreActionsPlacement: {
type: String,
default: 'bottom'
// 居中对齐
}
},
computed: {
@@ -109,6 +119,11 @@ export default {
if (!has) {
continue
}
// 是否有分割线
const divided = this.checkItem(action, 'divided', false)
delete action['divided']
action.divided = divided
// 是否是disabled
const can = this.checkItem(action, 'can')
delete action['can']

View File

@@ -3,7 +3,7 @@
<table style="width: 100%">
<tr>
<td colspan="2">
<AssetSelect ref="assetSelect" />
<AssetSelect ref="assetSelect" :can-select="canSelect" />
</td>
</tr>
<tr>
@@ -49,6 +49,12 @@ export default {
onAddSuccess: {
type: Function,
default: (objects, that) => {}
},
canSelect: {
type: Function,
default(row, index) {
return true
}
}
},
data() {

View File

@@ -34,6 +34,12 @@ export default {
value: {
type: Array,
default: () => []
},
canSelect: {
type: Function,
default(row, index) {
return true
}
}
},
data() {
@@ -68,6 +74,7 @@ export default {
tableConfig: {
url: '/api/v1/assets/assets/',
hasTree: true,
canSelect: this.canSelect,
columns: [
{
prop: 'hostname',
@@ -81,7 +88,7 @@ export default {
},
{
prop: 'ip',
label: this.$t('assets.ip'),
label: this.$t('assets.ipDomain'),
sortable: 'custom'
}
],
@@ -156,20 +163,20 @@ export default {
.el-select{
width: 100%;
}
.page /deep/ .page-heading{
.page ::v-deep .page-heading{
display: none;
}
.el-dialog__wrapper /deep/.el-dialog__body{
.el-dialog__wrapper ::v-deep .el-dialog__body{
padding: 5px 10px;
}
.page /deep/ .treebox{
.page ::v-deep .treebox{
height: inherit !important;
}
.asset-select-dialog >>> .transition-box:first-child {
background-color: #f3f3f3 ;
}
.el-dialog__wrapper /deep/.el-dialog__body .wrapper-content {
.el-dialog__wrapper ::v-deep .el-dialog__body .wrapper-content {
padding: 10px;
}

View File

@@ -114,20 +114,23 @@ export default {
columns: [
{
prop: 'hostname',
label: this.$t('assets.Hostname')
label: this.$t('assets.Hostname'),
showOverflowTooltip: true
},
{
prop: 'ip',
label: this.$t('assets.ip')
label: this.$t('assets.ip'),
width: '120px'
},
{
prop: 'username',
label: this.$t('assets.Username')
label: this.$t('assets.Username'),
showOverflowTooltip: true
},
{
prop: 'version',
label: this.$t('assets.Version'),
width: '50px'
width: '70px'
},
{
prop: 'date_created',
@@ -138,6 +141,7 @@ export default {
prop: 'id',
label: this.$t('common.Action'),
align: 'center',
width: 150,
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false, // can set function(row, value)
@@ -150,7 +154,7 @@ export default {
type: 'primary',
callback: function(val) {
this.MFAInfo.asset = val.cellValue
if (this.MFAVerifyAt + this.MFA_TTl * 1000 > (new Date()).valueOf()) {
if (!this.needMFAVerify) {
this.showMFADialog = true
this.MFAConfirmed = true
this.$axios.get(`/api/v1/assets/asset-user-auth-infos/${this.MFAInfo.asset}/`).then(res => {
@@ -172,7 +176,7 @@ export default {
this.$axios.delete(`/api/v1/assets/asset-users/${val.cellValue}/`).then(() => {
this.$message.success(this.$t('common.deleteSuccessMsg'))
this.$refs.ListTable.reloadTable()
}).catch(() => this.$message.error(this.$t('common.deleteFailedMsg')))
})
}
},
{
@@ -235,7 +239,8 @@ export default {
computed: {
...mapGetters([
'MFA_TTl',
'MFAVerifyAt'
'MFAVerifyAt',
'publicSettings'
]),
needMFAVerify() {
if (!this.publicSettings.SECURITY_VIEW_AUTH_NEED_MFA) {
@@ -308,6 +313,7 @@ export default {
key: ''
}
this.showDialog = false
this.$refs.ListTable.reloadTable()
},
Onchange(e) {
const vm = this
@@ -347,6 +353,7 @@ export default {
key: ''
}
this.showDialog = false
this.$refs.ListTable.reloadTable()
}
}
}

View File

@@ -44,7 +44,6 @@ export default {
groups: []
}
},
mounted() {
this.optionUrlMeta()
},
@@ -54,7 +53,7 @@ export default {
this.meta = data.actions[this.method.toUpperCase()] || {}
this.generateColumns()
}).catch(err => {
console.error(err)
this.$log.error(err)
}).finally(() => {
this.loading = false
})
@@ -63,9 +62,11 @@ export default {
switch (type) {
case 'choice':
type = 'radio-group'
field.options = fieldMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
if (!fieldMeta.read_only) {
field.options = fieldMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
}
break
case 'datetime':
type = 'date-picker'
@@ -76,6 +77,9 @@ export default {
case 'field':
type = ''
field.component = Select2
if (fieldMeta.required) {
field.el.clearable = false
}
break
case 'string':
type = 'input'
@@ -89,12 +93,14 @@ export default {
break
}
if (type === 'radio-group') {
const options = fieldMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
if (options.length > 4) {
type = 'select'
field.el.filterable = true
if (!fieldMeta.read_only) {
const options = fieldMeta.choices.map(v => {
return { label: v.display_name, value: v.value }
})
if (options.length > 4) {
type = 'select'
field.el.filterable = true
}
}
}
field.type = type
@@ -128,7 +134,8 @@ export default {
},
generateField(name) {
let field = { id: name, prop: name, el: {}, attrs: {}}
const fieldMeta = this.meta[name] || {}
// const fieldMeta = this.meta[name] || this.meta['attrs']['children'][name] || {}
const fieldMeta = this.meta[name] || ((this.meta['attrs']) ? (this.meta['attrs']['children'][name]) : {})
field.label = fieldMeta.label
field = this.generateFieldByType(fieldMeta.type, field, fieldMeta)
field = this.generateFieldByName(name, field)
@@ -146,12 +153,25 @@ export default {
})
return this.generateFields(fields)
},
generateFieldAttrs(name) {
const fields = []
Object.keys(this.meta[name]['children']).forEach((key, i) => {
const filed = this.generateField(key)
fields.push(filed)
})
return fields
},
generateFields(data) {
let fields = []
for (let field of data) {
if (field instanceof Array) {
const items = this.generateFieldGroup(field)
fields = [...fields, ...items]
} else if (field === 'attrs') {
const items = this.generateFieldAttrs(field)
fields = [...fields, ...items]
// 修改title插入ID
this.groups[this.groups.length - 1].name = items[0].id
} else if (typeof field === 'string') {
field = this.generateField(field)
fields.push(field)
@@ -165,15 +185,23 @@ export default {
},
generateColumns() {
this.totalFields = this.generateFields(this.fields)
this.$log.debug('Total fields: ', this.totalFields)
},
setFieldError(name, error) {
const field = this.totalFields.find((v) => v.prop === name)
if (!field) {
return
}
if (field.attrs.error === error) {
error += '.'
if (typeof error === 'object') {
const str = error
error = ''
Object.keys(str).forEach(key => {
error += `${parseInt(key) + 1}.${str[key][0]} `
})
}
// if (field.attrs.error === error) {
// error += '.'
// }
field.attrs.error = error
}
}

View File

@@ -47,10 +47,19 @@ export default {
}
const option = {
label: field.label,
type: field.type,
value: name
}
if (field.type === 'choice' && field.choices) {
option.children = field.choices.map(item => {
if (typeof (item.value) === 'boolean') {
if (item.value) {
return { label: item.display_name, value: 'True' }
} else {
return { label: item.display_name, value: 'False' }
}
}
return { label: item.display_name, value: item.value }
})
}

View File

@@ -1,5 +1,5 @@
<template>
<DataTable v-if="!loading" ref="dataTable" v-loading="loading" :config="iConfig" v-bind="$attrs" v-on="$listeners" />
<DataTable v-if="!loading" ref="dataTable" v-loading="loading" :config="iConfig" v-bind="$attrs" v-on="$listeners" @filter-change="filterChange" />
</template>
<script type="text/jsx">
@@ -15,6 +15,10 @@ export default {
config: {
type: Object,
default: () => ({})
},
filterTable: {
type: Function,
default: () => ({})
}
},
data() {
@@ -55,6 +59,7 @@ export default {
case 'name':
col.formatter = DetailFormatter
col.sortable = 'custom'
col.showOverflowTooltip = true
break
case 'actions':
col = {
@@ -117,6 +122,37 @@ export default {
}
return col
},
addFilterIfNeed(col) {
if (col.prop) {
const column = this.meta[col.prop] || {}
if (!column.filter) {
return col
}
if (column.type === 'boolean') {
col.filters = [
{ text: this.$t('common.Yes'), value: true },
{ text: this.$t('common.No'), value: false }
]
col.sortable = false
col['column-key'] = col.prop
}
if (column.type === 'choice' && column.choices) {
col.filters = column.choices.map(item => {
if (typeof (item.value) === 'boolean') {
if (item.value) {
return { text: item.display_name, value: 'True' }
} else {
return { text: item.display_name, value: 'False' }
}
}
return { text: item.display_name, value: item.value }
})
col.sortable = false
col['column-key'] = col.prop
}
}
return col
},
generateColumn(name) {
const colMeta = this.meta[name] || {}
const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {}
@@ -126,6 +162,7 @@ export default {
col = this.generateColumnByType(colMeta.type, col)
col = Object.assign(col, customMeta)
col = this.addHelpTipsIfNeed(col)
col = this.addFilterIfNeed(col)
return col
},
generateColumns() {
@@ -141,6 +178,12 @@ export default {
}
config.columns = columns
this.iConfig = config
},
filterChange(filters) {
const key = Object.keys(filters)[0]
const attr = {}
attr[key] = filters[key][0]
this.filterTable(attr)
}
}
}

View File

@@ -139,8 +139,6 @@ export default {
treeNode.name = treeNode.name + ' (' + assetsAmount + ')'
this.zTree.updateNode(treeNode)
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
})
},
onBodyMouseDown: function(event) {
@@ -167,6 +165,10 @@ export default {
if (!this.setting.showMenu) {
return
}
// 屏蔽收藏资产
if (treeNode.id === '-12') {
return
}
if (!treeNode && event.target.tagName.toLowerCase() !== 'button' && $(event.target).parents('a').length === 0) {
this.zTree.cancelSelectedNode()
this.showRMenu('root', event.clientX, event.clientY)

View File

@@ -15,6 +15,7 @@
<el-form-item>
<el-button v-for="button in moreButtons" :key="button.title" 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" size="small" :loading="isSubmitting" type="primary" @click="submitForm('form')">{{ $t('common.Submit') }}</el-button>
</el-form-item>
</ElFormRender>
@@ -35,6 +36,10 @@ export default {
type: Boolean,
default: true
},
hasSaveContinue: {
type: Boolean,
default: true
},
fields: {
type: Array,
default: () => []
@@ -60,11 +65,11 @@ export default {
},
methods: {
// 获取表单数据
submitForm(formName) {
submitForm(formName, addContinue) {
const form = this.$refs[formName]
form.validate((valid) => {
if (valid) {
this.$emit('submit', form.getFormValue(), form)
this.$emit('submit', form.getFormValue(), form, addContinue)
} else {
this.$emit('invalid', valid)
return false
@@ -77,7 +82,7 @@ export default {
},
handleClick(button) {
const callback = button.callback || function(values, form) {
console.log('Click ', button.title, ': ', values)
// console.log('Click ', button.title, ': ', values)
}
const form = this.$refs['form']
const values = form.getFormValue()
@@ -88,27 +93,27 @@ export default {
</script>
<style lang="less" scoped>
.el-form /deep/ .el-form-item {
.el-form ::v-deep .el-form-item {
margin-bottom: 12px;
}
.el-form /deep/ .el-form-item__content {
.el-form ::v-deep .el-form-item__content {
width: 75%;
}
.el-form /deep/ .el-form-item__label {
.el-form ::v-deep .el-form-item__label {
padding: 0 30px 0 0;
}
.el-form /deep/ .el-form-item__error {
.el-form ::v-deep .el-form-item__error {
position: inherit;
}
.el-form /deep/ .form-group-header {
.el-form ::v-deep .form-group-header {
margin-left: 50px;
}
.el-form /deep/ .help-block {
.el-form ::v-deep .help-block {
display: block;
margin-top: 5px;
margin-bottom: 10px;
@@ -116,7 +121,7 @@ export default {
font-size: 12px;
line-height: 18px;
}
.el-form /deep/ .help-block a {
.el-form ::v-deep .help-block a {
color: #1c84c6;
}
</style>

View File

@@ -11,9 +11,10 @@
v-bind="tableAttrs"
:data="data"
:row-class-name="rowClassName"
v-on="$listeners"
@selection-change="selectStrategy.onSelectionChange"
@select="selectStrategy.onSelect"
@select-all="selectStrategy.onSelectAll($event, selectable)"
@select-all="selectStrategy.onSelectAll($event, canSelect)"
@sort-change="onSortChange"
>
<!--TODO 不用jsx写, 感觉template逻辑有点不清晰了-->
@@ -90,11 +91,14 @@
<!--非树-->
<template v-else>
<el-data-table-column v-if="hasSelection" type="selection" :align="selectionAlign" />
<el-data-table-column v-if="hasSelection" type="selection" :align="selectionAlign" :selectable="canSelect" />
<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"
v-bind="{align: columnsAlign, ...col}"
>
<template v-if="col.formatter && typeof col.formatter !== 'function'" v-slot:default="{row, column, index}">
@@ -422,7 +426,7 @@ export default {
onEdit: {
type: Function,
default(row) {
console.log('On delete row')
// console.log('On delete row')
}
},
/**
@@ -713,6 +717,12 @@ export default {
hasDetail: {
type: Boolean,
default: true
},
canSelect: {
type: Function,
default(row, index) {
return true
}
}
},
data() {
@@ -953,6 +963,8 @@ export default {
})
},
search(attrs, reset) {
// 重置搜索结果到第一页
this.page = defaultFirstPage
// Orange 重置查询对象
if (reset) {
this.innerQuery = merge({}, attrs)
@@ -962,6 +974,8 @@ export default {
return this.getList()
},
searchDate(attrs) {
// 重置搜索结果到第一页
this.page = defaultFirstPage
this.innerQuery = merge(this.innerQuery, attrs)
return this.getList()
},

View File

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

View File

@@ -86,7 +86,6 @@ export default {
computed: {
tableConfig() {
const config = Object.assign(this.defaultConfig, this.config)
this.$log.debug('Datatable found config change')
return config
},
iListeners() {
@@ -96,7 +95,6 @@ export default {
watch: {
config: {
handler() {
this.$log.debug('DataTable: found config change', this.tableConfig.url)
// this.getList()
},
deep: true
@@ -140,16 +138,16 @@ export default {
<style lang="less" scoped>
.el-table /deep/ .el-table__row > td {
.el-table ::v-deep .el-table__row > td {
line-height: 1.5;
padding: 8px 0;
}
.el-table /deep/ .el-table__row > td> div > span {
.el-table ::v-deep .el-table__row > td> div > span {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.el-table /deep/ .el-table__header > thead > tr >th {
.el-table ::v-deep .el-table__header > thead > tr >th {
padding: 8px 0;
background-color: #F5F5F6;
font-size: 13px;
@@ -160,11 +158,11 @@ export default {
}
//分页
.el-pagination /deep/ .el-pagination__total{
.el-pagination ::v-deep .el-pagination__total{
float: left;
}
.el-pagination /deep/ .el-pagination__sizes{
.el-pagination ::v-deep .el-pagination__sizes{
float: left;
}
//修改颜色

View File

@@ -1,6 +1,9 @@
<template>
<div>
<div class="treebox">
<ul v-show="loading" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
<div v-show="!loading" class="treebox">
<ul :id="iZTreeID" class="ztree">
{{ this.$t('common.tree.Loading') }}...
</ul>
@@ -22,6 +25,7 @@
import $ from '@/utils/jquery-vendor.js'
import '@ztree/ztree_v3/js/jquery.ztree.all.min.js'
import '@/styles/ztree.css'
import axiosRetry from 'axios-retry'
const defaultObject = {
type: Object,
@@ -39,7 +43,9 @@ export default {
iZTreeID: `zTree_${this._uid}`,
iRMenuID: `rMenu_${this._uid}`,
zTree: '',
rMenu: ''
rMenu: '',
init: false,
loading: false
}
},
computed: {
@@ -52,11 +58,30 @@ export default {
// $('.treebox').css('height', window.innerHeight - 60)
},
beforeDestroy() {
$.fn.zTree.destroy()
$.fn.zTree.destroy(this.iZTreeID)
},
methods: {
initTree: function() {
this.$axios.get(this.treeSetting.treeUrl).then(res => {
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`
} else {
treeUrl = this.treeSetting.treeUrl
}
this.$axios.get(treeUrl, {
'axios-retry': {
retries: 20,
retryCondition: e => {
return axiosRetry.isNetworkOrIdempotentRequestError(e) || e.response.status === 409
},
shouldResetTimeout: true,
retryDelay: () => { return 5000 }
}
}).then(res => {
if (!res) {
res = []
}
@@ -65,6 +90,10 @@ export default {
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.showRefresh) {
this.rootNodeAddDom(
@@ -79,6 +108,9 @@ export default {
if (this.treeSetting.otherMenu) {
$('.menu-actions').append(this.otherMenu)
}
}).finally(_ => {
vm.loading = false
vm.init = true
})
},
rootNodeAddDom: function(ztree, callback) {
@@ -95,7 +127,6 @@ export default {
}
const refreshIconRef = $('#tree-refresh')
refreshIconRef.bind('click', function() {
ztree.destroy()
const result = callback()
if (result && result.then) {
result.finally(() => {
@@ -158,7 +189,7 @@ export default {
top: 100%;
z-index: 1000;
}
.ztree /deep/ .fa-refresh {
.ztree ::v-deep .fa-refresh {
font: normal normal normal 14px/1 FontAwesome !important;
}
.dropdown a:hover {

View File

@@ -37,8 +37,8 @@ export default {
showRemoveBtn: false,
showRenameBtn: false,
drag: {
isCopy: true,
isMove: true
isCopy: false,
isMove: false
}
},
callback: {
@@ -72,7 +72,7 @@ export default {
},
methods: {
defaultCallback: function(action) {
console.log(action)
// console.log(action)
}
}
}

View File

@@ -93,17 +93,17 @@ export default {
<style lang='less' scoped>
.datepicker{
width: 240px;
width: 233px;
}
.el-input__inner{
border: 1px solid #dcdee2;
border-radius: 3px;
height: 36px;
}
/*.el-date-editor /deep/ .el-input__icon{*/
/*.el-date-editor ::v-deep .el-input__icon{*/
/* line-height: 28px;*/
/*}*/
.el-date-editor /deep/ .el-range-separator{
.el-date-editor ::v-deep .el-range-separator{
line-height: 28px;
}
</style>

View File

@@ -3,7 +3,7 @@ export default {
name: 'ItemValue',
props: {
value: {
type: [String, Number, Function, Array, Object],
type: [String, Number, Function, Array, Object, Boolean],
default: ''
},
item: {
@@ -15,10 +15,21 @@ export default {
default: null
}
},
methods: {
toChoicesDisplay(value) {
if (!value) {
return this.$t('common.No')
}
return this.$t('common.Yes')
}
},
render(h) {
if (typeof this.formatter === 'function') {
return this.formatter(this.item, this.value)
}
if (typeof this.value === 'boolean') {
return <span>{this.toChoicesDisplay(this.value)}</span>
}
return <span>{this.value}</span>
}
}

View File

@@ -1,11 +1,19 @@
<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-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>

View File

@@ -10,7 +10,7 @@
<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" @click="onConfirm">{{ confirmTitle }}</el-button>
<el-button v-if="showConfirm" type="primary" size="small" :loading="loadingStatus" @click="onConfirm">{{ confirmTitle }}</el-button>
</slot>
</div>
</el-dialog>
@@ -42,6 +42,10 @@ export default {
type: Boolean,
default: true
},
loadingStatus: {
type: Boolean,
default: false
},
confirmTitle: {
type: String,
default() {

View File

@@ -65,22 +65,24 @@ export default {
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',
width: '200px',
formatter: SystemUserFormatter,
formatterArgs: {
getUrl: this.getShowUrl.bind(this)
}
},
showOverflowTooltip: true
}
]
},

View File

@@ -1,6 +1,11 @@
<template>
<Dialog v-if="showExportDialog" :title="$t('common.Export')" :visible.sync="showExportDialog" :destroy-on-close="true" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
<el-form label-position="left" style="padding-left: 50px">
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
<el-radio-group v-model="exportTypeOption">
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item class="export-form" :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
<el-radio-group v-model="exportOption">
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
@@ -51,7 +56,8 @@ export default {
data() {
return {
showExportDialog: false,
exportOption: '',
exportOption: 'all',
exportTypeOption: 'csv',
meta: {}
}
},
@@ -67,6 +73,8 @@ export default {
const query = listTableRef.dataTable.getQuery()
delete query['limit']
delete query['offset']
delete query['date_from']
delete query['date_to']
return query
},
tableHasQuery() {
@@ -77,7 +85,7 @@ export default {
{
label: this.$t('common.imExport.ExportAll'),
value: 'all',
can: this.canExportAll
can: this.canExportAll && !this.tableHasQuery
},
{
label: this.$t('common.imExport.ExportOnlySelectedItems'),
@@ -90,6 +98,20 @@ export default {
can: this.tableHasQuery && this.canExportFiltered
}
]
},
exportTypeOptions() {
return [
{
label: 'CSV',
value: 'csv',
can: true
},
{
label: 'Excel',
value: 'xlsx',
can: true
}
]
}
},
mounted() {
@@ -121,7 +143,7 @@ export default {
// delete query['limit']
// delete query['offset']
}
query['format'] = 'csv'
query['format'] = this.exportTypeOption
const queryStr =
(url.indexOf('?') > -1 ? '&' : '?') +
queryUtil.stringify(query, '=', '&')

View File

@@ -1,6 +1,18 @@
<template>
<Dialog :title="$t('common.Import')" :visible.sync="showImportDialog" :destroy-on-close="true" @confirm="handleImportConfirm" @cancel="handleImportCancel()">
<Dialog
:title="$t('common.Import')"
:visible.sync="showImportDialog"
:destroy-on-close="true"
:loading-status="loadStatus"
@confirm="handleImportConfirm"
@cancel="handleImportCancel()"
>
<el-form label-position="left" style="padding-left: 50px">
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
<el-radio-group v-model="importTypeOption">
<el-radio v-for="option of importTypeOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('common.Import' )" :label-width="'100px'">
<el-radio v-model="importOption" class="export-item" label="1">{{ this.$t('common.Create') }}</el-radio>
<el-radio v-model="importOption" class="export-item" label="2">{{ this.$t('common.Update') }}</el-radio>
@@ -26,7 +38,7 @@
:before-upload="beforeUpload"
>
<el-button size="mini" type="default">{{ this.$t('common.SelectFile') }}</el-button>
<div slot="tip" :class="uploadHelpTextClass" style="line-height: 1.5">{{ this.$t('common.imExport.onlyCSVFilesTips') }}</div>
<!-- <div slot="tip" :class="uploadHelpTextClass" style="line-height: 1.5">{{ this.$t('common.imExport.onlyCSVFilesTips') }}</div>-->
</el-upload>
</el-form-item>
</el-form>
@@ -63,19 +75,36 @@ export default {
showImportDialog: false,
importOption: '1',
isCsv: true,
errorMsg: ''
errorMsg: '',
loadStatus: false,
importTypeOption: 'csv'
}
},
computed: {
hasSelected() {
return this.selectedRows.length > 0
},
importTypeOptions() {
return [
{
label: 'CSV',
value: 'csv',
can: true
},
{
label: 'Excel',
value: 'xlsx',
can: true
}
]
},
upLoadUrl() {
return this.url
},
downloadImportTempUrl() {
const baseUrl = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)
return baseUrl + '?format=csv&template=import&limit=1'
const format = this.importTypeOption === 'csv' ? 'format=csv&template=import&limit=1' : 'format=xlsx&template=import&limit=1'
const url = (this.url.indexOf('?') === -1) ? `${this.url}?${format}` : `${this.url}&${format}`
return url
},
uploadHelpTextClass() {
const cls = ['el-upload__tip']
@@ -95,24 +124,28 @@ export default {
this.$axios.put(
this.upLoadUrl,
item.file,
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
{ headers: { 'Content-Type': this.importTypeOption === 'csv' ? 'text/csv' : 'text/xlsx' }, disableFlashErrorMsg: true }
).then((data) => {
const msg = this.$t('common.imExport.updateSuccessMsg', { count: data.length })
this.onSuccess(msg)
}).catch(error => {
this.catchError(error)
}).finally(() => {
this.loadStatus = false
})
},
performCreate(item) {
this.$axios.post(
this.upLoadUrl,
item.file,
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
{ headers: { 'Content-Type': this.importTypeOption === 'csv' ? 'text/csv' : 'text/xlsx' }, disableFlashErrorMsg: true }
).then((data) => {
const msg = this.$t('common.imExport.createSuccessMsg', { count: data.length })
this.onSuccess(msg)
}).catch(error => {
this.catchError(error)
}).finally(() => {
this.loadStatus = false
})
},
catchError(error) {
@@ -149,6 +182,7 @@ export default {
window.URL.revokeObjectURL(url)
},
handleImport(item) {
this.loadStatus = true
if (this.importOption === '1') {
this.performCreate(item)
} else {
@@ -163,7 +197,8 @@ export default {
}
const spm = await createSourceIdCache(resources)
const baseUrl = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)
const url = `${baseUrl}?format=csv&template=update&spm=` + spm.spm
const format = this.importTypeOption === 'csv' ? '?format=csv&template=update&spm=' : '?format=xlsx&template=update&spm='
const url = `${baseUrl}${format}` + spm.spm
return this.downloadCsv(url)
},
async handleImportConfirm() {
@@ -173,7 +208,12 @@ export default {
this.showImportDialog = false
},
beforeUpload(file) {
this.isCsv = _.endsWith(file.name, 'csv')
this.isCsv = this.importTypeOption === 'csv' ? _.endsWith(file.name, 'csv') : _.endsWith(file.name, 'xlsx')
if (!this.isCsv) {
this.$message.error(
this.$t('common.NeedSpecifiedFile')
)
}
return this.isCsv
}
}

View File

@@ -152,7 +152,7 @@ export default {
return v.id
})
const data = await createSourceIdCache(ids)
const url = `${this.tableUrl}?spm=` + data.spm
const url = (this.tableUrl.indexOf('?') === -1) ? `${this.tableUrl}?spm=` + data.spm : `${this.tableUrl}&spm=` + data.spm
return this.$axios.delete(url)
},
handleBulkUpdate({ selectedRows }) {

View File

@@ -1,7 +1,7 @@
<template>
<div>
<ActionsGroup :is-fa="true" :actions="rightSideActions" class="right-side-actions right-side-item" />
<ImExportDialog :selected-rows="selectedRows" :url="tableUrl" />
<ImExportDialog :selected-rows="selectedRows" :url="tableUrl" v-bind="$attrs" />
</div>
</template>
@@ -54,9 +54,9 @@ export default {
data() {
return {
defaultRightSideActions: [
{ name: 'actionExport', fa: 'fa-download', has: this.hasExport, callback: this.handleExport.bind(this) },
{ name: 'actionImport', fa: 'fa-upload', has: this.hasImport, callback: this.handleImport.bind(this) },
{ name: 'actionRefresh', fa: 'fa-refresh', has: this.hasRefresh, callback: this.handleRefresh }
{ name: 'actionExport', fa: 'fa-download', tip: this.$t('common.Export'), has: this.hasExport, callback: this.handleExport.bind(this) },
{ name: 'actionImport', fa: 'fa-upload', tip: this.$t('common.Import'), has: this.hasImport, callback: this.handleImport.bind(this) },
{ name: 'actionRefresh', fa: 'fa-refresh', tip: this.$t('common.Refresh'), has: this.hasRefresh, callback: this.handleRefresh }
],
dialogExportVisible: false,
exportValue: 2
@@ -119,7 +119,7 @@ export default {
}
.right-side-actions >>> .el-button:hover {
background-color: rgb(0, 0, 0, 0.05);
background-color: rgba(0, 0, 0, 0.05);
}
.action-search >>> .el-input__suffix i {

View File

@@ -24,6 +24,19 @@ const defaultUpdateCallback = function({ row, col }) {
this.$router.push(route)
}
const defaultCloneCallback = function({ row, col }) {
const id = row.id
let route = { query: { clone_from: id }}
const cloneRoute = this.colActions.cloneRoute
if (typeof cloneRoute === 'object') {
route = Object.assign(route, cloneRoute)
} else {
route.name = cloneRoute
}
this.$router.push(route)
}
const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
let msg = this.$t('common.deleteWarningMsg')
const name = row.name || row.hostname
@@ -71,10 +84,14 @@ export default {
canUpdate: true, // can set function(row, value)
hasDelete: true, // can set function(row, value)
canDelete: true,
hasClone: false,
canClone: true,
updateRoute: this.$route.name.replace('List', 'Update'),
cloneRoute: this.$route.name.replace('List', 'Create'),
performDelete: defaultPerformDelete,
onUpdate: defaultUpdateCallback,
onDelete: defaultDeleteCallback,
onClone: defaultCloneCallback,
extraActions: [] // format see defaultActions
}
}
@@ -89,7 +106,8 @@ export default {
type: 'primary',
has: colActions.hasUpdate,
can: colActions.canUpdate,
callback: colActions.onUpdate
callback: colActions.onUpdate,
order: 10
},
{
name: 'delete',
@@ -97,7 +115,17 @@ export default {
type: 'danger',
has: colActions.hasDelete,
can: colActions.canDelete,
callback: colActions.onDelete
callback: colActions.onDelete,
order: 20
},
{
name: 'clone',
title: this.$t('common.Clone'),
type: 'info',
has: colActions.hasClone,
can: colActions.canClone,
callback: colActions.onClone,
order: 30
}
]
return {
@@ -115,9 +143,11 @@ export default {
v.has = this.cleanBoolean(v, 'has')
v.can = this.cleanBoolean(v, 'can')
v.callback = this.cleanCallback(v)
v.order = v.order || 100
return v
})
actions = actions.filter((v) => v.has)
actions.sort((a, b) => a.order - b.order)
return actions
},
actions() {

View File

@@ -1,6 +1,7 @@
<template>
<div>
<el-tooltip v-if="formatterArgs.hasTips" :content="tips" placement="bottom" effect="dark">
<el-tooltip v-if="formatterArgs.hasTips" placement="bottom" effect="dark">
<div slot="content">{{ tipStatus }}<br>{{ tipTime }}</div>
<i :class="'fa ' + iconClass" />
</el-tooltip>
<i v-else :class="'fa ' + iconClass" />
@@ -9,6 +10,7 @@
<script>
import BaseFormatter from './base'
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'ChoicesFormatter',
extends: BaseFormatter,
@@ -25,8 +27,14 @@ export default {
return !!val
},
hasTips: false,
tips(val) {
return val.datetime
tipStatus(val, vm) {
if (val.status === 0) {
return vm.$t('assets.Unreachable')
} else if (val.status === 1) {
return vm.$t('assets.Reachable')
} else if (val.status === 2) {
return vm.$t('assets.Unknown')
}
}
}
}
@@ -42,8 +50,12 @@ export default {
const key = this.formatterArgs.typeChange(this.cellValue)
return this.formatterArgs.iconChoices[key]
},
tips() {
return this.formatterArgs.tips(this.cellValue)
tipStatus() {
const vm = this
return this.formatterArgs.tipStatus(this.cellValue, vm)
},
tipTime() {
return toSafeLocalDateStr(this.cellValue.datetime)
}
}
}

View File

@@ -43,7 +43,7 @@ export default {
}
},
mounted() {
console.log(this.col)
// console.log(this.col)
},
methods: {
checkBool(item, attr, defaults) {

View File

@@ -4,14 +4,14 @@
<script>
import BaseFormatter from './base'
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'DateFormatter',
extends: BaseFormatter,
data() {
let value
if (this.cellValue) {
const dt = new Date(this.cellValue)
value = this.$d(dt, 'medium')
value = toSafeLocalDateStr(this.cellValue)
} else {
value = ''
}

View File

@@ -33,6 +33,9 @@ export default {
}
},
iCanDelete() {
if (this.col.objects === 'all') {
return false
}
return this.col.objects.indexOf(this.cellValue) === -1
}
}

View File

@@ -2,7 +2,7 @@
<div>
<TableAction :table-url="iTableConfig.url" :search-table="search" :date-pick="handleDateChange" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable" />
<IBox class="table-content">
<AutoDataTable ref="dataTable" :config="iTableConfig" @selection-change="handleSelectionChange" v-on="$listeners" />
<AutoDataTable ref="dataTable" :filter-table="filter" :config="iTableConfig" @selection-change="handleSelectionChange" v-on="$listeners" />
</IBox>
</div>
</template>
@@ -44,8 +44,31 @@ export default {
dataTable() {
return this.$refs.dataTable.$refs.dataTable
},
hasCreateAction() {
const hasLeftAction = this.headerActions.hasLeftActions
if (hasLeftAction === false) {
return false
}
const hasCreate = this.headerActions.hasCreate
if (hasCreate === false) {
return false
}
return true
},
hasCloneAction() {
const hasClone = _.get(this.tableConfig, 'columnsMeta.actions.formatterArgs.hasClone', null)
if (hasClone) {
return true
}
if (this.hasCreateAction && hasClone == null) {
return true
}
return false
},
iTableConfig() {
const config = deepmerge(this.tableConfig, { extraQuery: this.extraQuery })
this.$log.debug('Header actions', this.headerActions)
_.set(config, 'columnsMeta.actions.formatterArgs.hasClone', this.hasCloneAction)
this.$log.debug('ListTable: iTableConfig change', config)
return config
}
@@ -58,8 +81,6 @@ export default {
deep: true
}
},
mounted() {
},
methods: {
handleSelectionChange(val) {
this.selectedRows = val
@@ -68,9 +89,10 @@ export default {
this.dataTable.getList()
},
search(attrs) {
if (Object.keys(attrs).length > 0) {
return this.dataTable.search(attrs, true)
}
return this.dataTable.search(attrs, true)
},
filter(attrs) {
this.$refs.dataTable.$refs.dataTable.search(attrs, true)
},
handleDateChange(attrs) {
this.$set(this.extraQuery, 'date_from', attrs[0].toISOString())
@@ -94,28 +116,28 @@ export default {
<style lang="scss" scoped>
.table-content {
margin-top: 10px;
.table-content {
margin-top: 10px;
& >>> .el-card__body {
padding: 0;
}
& >>> .el-table__header thead > tr > th {
background-color: white;
}
/*& >>> .el-table--striped .el-table__body tr.el-table__row--striped td {*/
/*background: white;*/
/*}*/
/*& >>> .el-table th, .el-table tr {*/
/*background-color: red;*/
/*!*background-color: #FAFAFA;*!*/
/*}*/
& >>> .el-card__body {
padding: 0;
}
& >>> .el-table__header thead > tr > th {
background-color: white;
}
//修改颜色
// .el-button--text{
// color: #409EFF;
// }
/*& >>> .el-table--striped .el-table__body tr.el-table__row--striped td {*/
/*background: white;*/
/*}*/
/*& >>> .el-table th, .el-table tr {*/
/*background-color: red;*/
/*!*background-color: #FAFAFA;*!*/
/*}*/
}
//修改颜色
// .el-button--text{
// color: #409EFF;
// }
</style>

View File

@@ -1,8 +1,8 @@
<template>
<IBox fa="fa-edit" :title="title" v-bind="$attrs">
<div class="quick-actions">
<div v-for="action of actions" :key="action.title" class="quick-actions">
<table>
<ActionItem v-for="action of actions" :key="action.title" :action="action" />
<ActionItem v-if="action.has === undefined || action.has" :action="action" />
</table>
</div>
</IBox>

View File

@@ -6,6 +6,7 @@
<Select2 ref="select2" v-model="select2.value" v-bind="select2" />
</td>
</tr>
<slot />
<tr>
<td colspan="2">
<el-button :type="type" size="small" :loading="submitLoading" @click="addObjects">{{ $t('common.Add') }}</el-button>
@@ -21,7 +22,7 @@
</td>
</tr>
</template>
<tr v-if="params.hasMore" class="item">
<tr v-if="params.hasMore && showHasMore" class="item">
<td colspan="2">
<el-button :type="type" size="small" style="width: 100%" @click="loadMore">
<i class="fa fa-arrow-down" />
@@ -37,7 +38,6 @@
import Select2 from '../Select2'
import IBox from '../IBox'
import { createSourceIdCache } from '@/api/common'
export default {
name: 'RelationCard',
components: {
@@ -83,6 +83,10 @@ export default {
type: [Array, Number, String],
default: () => []
},
showHasMore: {
type: Boolean,
default: true
},
performDelete: {
type: Function,
default: (obj, that) => {}
@@ -220,7 +224,7 @@ export default {
)
},
addObjects() {
const objects = this.$refs.select2.getOptionsByValues(this.select2.value)
const objects = this.$refs.select2.$refs.select.selected.map(item => ({ label: item.label, value: item.value }))
if (objects.length === 0) {
return
}

View File

@@ -8,6 +8,7 @@
:remote-method="filterOptions"
:multiple="multiple"
filterable
:clearable="clearable"
popper-append-to-body
class="select2"
v-bind="$attrs"
@@ -69,6 +70,10 @@ export default {
type: Boolean,
default: true
},
clearable: {
type: Boolean,
default: true
},
// 初始化值,也就是选中的值
value: {
type: [Array, String, Number, Boolean],
@@ -172,6 +177,9 @@ export default {
},
methods: {
async loadMore(load) {
if (!this.iAjax.url) {
return
}
if (!this.params.hasMore) {
return
}
@@ -240,7 +248,6 @@ export default {
this.params.spm = data.spm
await this.getInitialOptions()
}
this.$log.debug('Start get select2 options')
await this.getOptions()
if (this.iOptions.length === 0) {
this.remote = false

View File

@@ -1,14 +1,35 @@
<template>
<div class="filter-field">
<el-cascader ref="Cascade" :options="options" :props="config" @change="handleMenuItemChange" />
<el-tag v-for="(v, k) in filterTags" :key="k" :name="k" closable size="small" class="filter-tag" type="info" @close="handleTagClose(k)">
<el-tag
v-for="(v, k) in filterTags"
:key="k"
:name="k"
closable
size="small"
class="filter-tag"
type="info"
:disable-transitions="true"
@close="handleTagClose(k)"
@click="handleTagClick(v,k)"
>
<strong v-if="v.label">{{ v.label + ':' }}</strong>
<span v-if="v.valueLabel">{{ v.valueLabel }}</span>
<span v-else>{{ v.value }}</span>
</el-tag>
<span v-if="keyLabel" slot="prefix" class="filterTitle">{{ keyLabel + ':' }}</span>
<el-input ref="SearchInput" v-model="filterValue" :placeholder="placeholder" class="search-input" @blur="focus = false" @focus="focus = true" @change="handleConfirm" />
<el-input
ref="SearchInput"
v-model="filterValue"
:placeholder="placeholder"
class="search-input"
@blur="focus = false"
@focus="focus = true"
@change="handleConfirm"
/>
</div>
</template>
<script>
@@ -65,16 +86,21 @@ export default {
}
},
watch: {
filterTags: {
handler(val) {
this.$nextTick(() => this.$emit('tagSearch', this.filterMaps))
// this.$emit('tagSearch', this.filterMaps)
},
deep: true
}
// filterTags: {
// handler(val) {
// this.$nextTick(() => this.$emit('tagSearch', this.filterMaps))
// // this.$emit('tagSearch', this.filterMaps)
// },
// deep: true
// }
},
mounted() {
setTimeout(() => this.$emit('tagSearch', this.filterMaps), 400)
setTimeout(() => {
if (Object.keys(this.filterMaps).length > 0) {
return this.$emit('tagSearch', this.filterMaps)
}
}
, 400)
// this.$nextTick(() => this.$emit('tagSearch', this.filterMaps))
},
methods: {
@@ -95,7 +121,6 @@ export default {
return ''
},
handleMenuItemChange(keys) {
this.$log.debug('Tag search keys: ', keys)
if (keys.length === 0) {
return
}
@@ -112,6 +137,7 @@ export default {
},
handleTagClose(evt) {
this.$delete(this.filterTags, evt)
this.$emit('tagSearch', this.filterMaps)
return true
},
handleConfirm() {
@@ -120,9 +146,33 @@ export default {
}
const tag = { key: this.filterKey, label: this.keyLabel, value: this.filterValue, valueLabel: this.valueLabel }
this.$set(this.filterTags, this.filterKey, tag)
this.$emit('tagSearch', this.filterMaps)
this.filterKey = ''
this.filterValue = ''
this.valueLabel = ''
},
handleTagClick(v, k) {
let unableChange = false
for (const field of this.options) {
if (field.value === v.key) {
if (field.type === 'choice') {
unableChange = true
}
if (field.type === 'boolean') {
unableChange = true
}
}
}
if (unableChange) {
return
}
if (this.filterValue.length !== 0) {
this.handleConfirm()
}
this.$delete(this.filterTags, k)
this.filterKey = v.key
this.filterValue = v.value
this.$refs.SearchInput.focus()
}
}
}

View File

@@ -1,7 +1,7 @@
<template>
<el-collapse-transition>
<div style="display: flex;justify-items: center; flex-wrap: nowrap;justify-content:space-between;">
<div v-show="iShowTree" :style="iShowTree?('width:250px;'):('width:0;')" class="transition-box">
<div v-show="iShowTree" :style="iShowTree?('width:20%;'):('width:0;')" class="transition-box">
<component
:is="component"
ref="AutoDataZTree"
@@ -14,7 +14,7 @@
</div>
</component>
</div>
<div :style="iShowTree?('display: flex;width: calc(100% - 250px);'):('display: flex;width:100%;')">
<div :style="iShowTree?('display: flex;width: calc(100% - 20%);'):('display: flex;width:100%;')">
<div class="mini">
<div style="display:block" class="mini-button" @click="iShowTree=!iShowTree">
<i v-show="iShowTree" class="fa fa-angle-left fa-x" /><i v-show="!iShowTree" class="fa fa-angle-right fa-x" />
@@ -98,6 +98,7 @@ export default {
color: #FFFFFF;
border-radius: 3px;
line-height: 1.428;
cursor:pointer;
}
.el-tree{
background-color: inherit !important;

View File

@@ -2,6 +2,22 @@
"": "",
"applications": {
"": "",
"applicationsType": {
"chrome": "Chrome",
"mysql_workbench": "MySQL Workbench",
"vmware_client":"Vmware Client",
"custom":"Custom",
"mysql": "MySQL",
"oracle": "Oracle",
"postgresql": "PostgreSQL",
"mariadb": "MariaDB",
"k8s": "Kubernetes"
},
"applicationsCategory": {
"remote_app": "远程应用",
"db": "数据库应用",
"cloud": "云应用"
},
"appPath": "应用路径",
"appType": "应用类型",
"asset": "资产",
@@ -16,6 +32,7 @@
"chrome_password": "登录密码",
"mysql_workbench": "MySQL Workbench",
"mysql_workbench_ip": "数据库IP",
"mysql_workbench_port": "数据库端口",
"mysql_workbench_name": "数据库名",
"mysql_workbench_username": "数据库账号",
"mysql_workbench_password": "数据库密码",
@@ -28,7 +45,11 @@
"custom_target": "目标地址",
"custom_username": "登录账号",
"custom_password": "登录密码",
"Custom": "自定义"
"Custom": "自定义",
"cluster": "集群",
"kubernetes":"Kubernetes",
"clusterHelpTextMessage": "例如https://172.16.8.8:8443",
"DBInfo": "数据库信息"
},
"assets": {
"Action": "动作",
@@ -40,10 +61,14 @@
"AssetDetail": "资产详情",
"AssetList": "资产列表",
"AssetListHelpMessage": "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,右侧是属于该节点下的资产\n",
"TestGatewayTestConnection":"测试连接网关",
"TestGatewayHelpMessage": "如果使用了nat端口映射请设置为ssh真实监听的端口",
"SshPort": "SSH 端口",
"AssetNumber": "资产编号",
"AssetUserList": "资产用户列表",
"Assets": "资产",
"Auth": "认证",
"AccountList": "账号列表",
"AutoGenerateKey": "自动生成密钥",
"AutoPush": "自动推送",
"BasePlatform": "基础平台",
@@ -63,6 +88,8 @@
"DateUpdated": "更新日期",
"DeactiveSelected": "禁用所选",
"Disk": "硬盘",
"AdDomain": "AD域名",
"AdDomainHelpText": "提供给域用户登录的AD域名",
"Domain": "网域",
"DomainDetail": "网域详情",
"DomainHelpMessage": "网域功能是为了解决部分环境混合云无法直接连接而新增的功能原理是通过网关服务器进行跳转登录。JMS => 网域网关 => 目标资产",
@@ -87,6 +114,7 @@
"OnlyLatestVersion": "仅最新版本",
"Os": "操作系统",
"Other": "其它",
"Hardware": "硬件信息",
"Password": "密码",
"PasswordWithoutSpecialCharHelpText": "不能包含特殊字符",
"Pending": "等待",
@@ -100,10 +128,13 @@
"PushSystemUserNow": "推送系统用户",
"QuickUpdate": "快速更新",
"Reachable": "可连接",
"Unreachable": "不可连接",
"Unknown": "未知",
"Refresh": "刷新",
"RefreshHardware": "更新硬件信息",
"RemoteAppListHelpMessage": "使用此功能前,请确保已将应用加载器上传到应用服务器并成功发布为一个 RemoteApp 应用 <b><a href='https://github.com/jumpserver/Jmservisor/releases'>下载应用加载器</a></b>",
"RemoteApps": "远程应用",
"Applications": "应用",
"RemoteType": "应用类型",
"RemoveFromCurrentNode": "从节点移除",
"ReplaceNodeAssetsAdminUserWithThis": "替换资产的管理员",
@@ -111,6 +142,7 @@
"SFTPHelpMessage": "SFTP的起始路径tmp目录, 用户home目录或者自定义",
"SerialNumber": "序列号",
"SudoHelpMessage": "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig",
"PasswordHelpMessage": "密码或密钥密码",
"SystemUser": "系统用户",
"SystemUserDetail": "系统用户详情",
"SystemUserListHelpMessage": "系统用户是 JumpServer 跳转登录资产时使用的用户,可以理解为登录资产用户,如 websadba`ssh web@some-host`),而不是使用某个用户的用户名跳转登录服务器(`ssh xiaoming@some-host` 简单来说是用户使用自己的用户名登录 JumpServerJumpServer 使用系统用户登录资产。 系统用户创建时如果选择了自动推送JumpServer 会使用 Ansible 自动推送系统用户到资产中,如果资产(交换机)不支持 Ansible请手动填写账号密码。\n",
@@ -120,6 +152,7 @@
"TestConnection": "测试连接",
"Type": "类型",
"UnselectedAssets": "未选择资产",
"UnselectedNodes": "未选择节点",
"UpdateAssetUserToken": "更新资产用户认证信息",
"Username": "用户名",
"UsernameHelpMessage": "用户名是动态的,登录资产时使用当前用户的用户名登录",
@@ -129,7 +162,13 @@
"command_filter_list": "命令过滤器列表",
"date_joined": "创建日期",
"ip": "IP",
"sshkey": "sshkey"
"sshkey": "sshkey",
"GroupsHelpMessage": "请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)",
"HomeHelpMessage": "默认家目录 /home/系统用户名: /home/username",
"Home": "家目录",
"LinuxUserAffiliateGroup": "用户附属组",
"ipDomain": "IP(域名)"
},
"audits": {
"Hosts": "主机",
@@ -143,14 +182,23 @@
},
"common": {
"Action": "动作",
"RequestTickets": "申请工单",
"Actions": "操作",
"Activate": "激活",
"NeedSpecifiedFile": "需上传指定格式文件",
"TestPortErrorMsg":"端口错误,请重新输入",
"Active": "激活中",
"actionsTips":"剪切板权限控制目前仅支持 RDP/VNC 协议的连接",
"Add": "添加",
"UpdateAssetDetail": "配置更多信息",
"AddSuccessMsg": "添加成功",
"Auth": "认证",
"PushSelected":"推送所选",
"BadRequestErrorMsg": "请求错误,请检查填写内容",
"BadRoleErrorMsg": "请求错误,无该操作权限",
"BadConflictErrorMsg": "正在刷新中,请稍后再试",
"Basic": "基本",
"PleaseAgreeToTheTerms": "请同意条款",
"BasicInfo": "基本信息",
"Cancel": "取消",
"Close": "关闭",
@@ -161,6 +209,7 @@
"CreatedBy": "创建者",
"CrontabHelpTips": "eg每周日 03:05 执行 <5 3 * * 0> <br> 提示: 使用5位 Linux crontab 表达式 <分 时 日 月 星期> <a href='https://tool.lu/crontab/' target='_blank'>在线工具</a> <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行",
"DateEnd": "结束日期",
"Resource": "资源",
"DateLast24Hours": "最近一天",
"DateLast3Months": "最近三月",
"DateLastMonth": "最近一月",
@@ -174,11 +223,13 @@
"EnterForSearch": "按回车进行搜索",
"Export": "导出",
"Import": "导入",
"Refresh": "刷新",
"Info": "提示",
"MFAConfirm": "MFA 认证",
"MFARequireForSecurity": "为了安全请输入MFA",
"Members": "成员",
"More": "更多",
"Message": "消息",
"MoreActions": "更多操作",
"Name": "名称",
"No": "否",
@@ -196,11 +247,13 @@
"SelectFile": "选择文件",
"Show": "显示",
"Submit": "提交",
"SaveAndAddAnother": "保存并继续添加",
"Test": "测试",
"TestSuccessMsg": "测试成功",
"To": "至",
"Update": "更新",
"Upload": "上传",
"Clone": "克隆",
"Username": "用户名",
"Validity": "有效",
"Invalidity": "无效",
@@ -211,13 +264,17 @@
"bulkDeleteErrorMsg": "批量删除失败: ",
"bulkDeleteSuccessMsg": "批量删除成功",
"bulkRemoveErrorMsg": "批量移除失败: ",
"NeedAssetsAndSystemUserErrMsg": "请先选择授权的系统用户和资产",
"bulkRemoveSuccessMsg": "批量移除成功",
"createBy": "创建者",
"cloneFrom": "克隆自",
"createErrorMsg": "创建失败",
"createSuccessMsg": "创建成功",
"saveSuccessContinueMsg": "创建成功,更新内容后可以继续添加",
"createdBy": "创建人",
"dateCreated": "创建日期",
"dateExpired": "失效日期",
"dateFinished": "完成日期",
"dateStart": "开始日期",
"deleteErrorMsg": "删除失败",
"deleteFailedMsg": "删除失败",
@@ -239,6 +296,7 @@
"onlyCSVFilesTips": "仅支持csv文件导入",
"updateSuccessMsg": "导入更新成功,总共:{count}"
},
"fileType": "文件类型",
"isValid": "有效",
"nav": {
"APIKey": "API Key",
@@ -353,7 +411,7 @@
},
"perms": {
"": "",
"Actions": "动作",
"Actions": "权限",
"Asset": "资产",
"Basic": "基本",
"Exclude": "不包含",
@@ -364,10 +422,15 @@
"SystemUser": "系统用户",
"User": "用户",
"UserGroups": "用户组",
"DatabaseAppPermission": "数据库授权",
"RemoteAppPermission": "远程应用授权",
"addApplicationToThisPermission": "添加应用",
"KubernetesAppPermission": "Kubernetes授权",
"addAssetToThisPermission": "添加资产",
"addDatabaseAppToThisPermission": "添加数据库应用",
"addNodeToThisPermission": "添加节点",
"addRemoteAppToThisPermission": "添加远程应用",
"addK8sAppToThisPermission": "添加Kubernetes应用",
"addSystemUserToThisPermission": "添加系统用户",
"addUserGroupToThisPermission": "添加用户组",
"addUserToThisPermission": "添加用户",
@@ -376,6 +439,7 @@
"assetCount": "资产数量",
"connect": "连接",
"databaseApp": "数据库应用",
"KubernetesApp": "Kubernetes",
"dateStart": "开始日期",
"downloadFile": "下载文件",
"hostName": "主机名",
@@ -386,15 +450,23 @@
"refreshSuccess": "刷新成功",
"remoteApp": "远程应用",
"remoteAppCount": "远程应用数量",
"appsCount": "应用数量",
"appsList":"应用列表",
"DatabaseAppCount": "数据库应用数量",
"KubernetesAppCount": "Kubernetes应用数量",
"systemUserCount": "系统用户数量",
"upDownload": "上传下载",
"uploadFile": "上传文件",
"clipboardCopyPaste":"复制粘贴",
"clipboardCopy":"剪切板复制",
"clipboardPaste":"剪切板粘贴",
"userCount": "用户数量",
"userGroupCount": "用户组数量",
"usersAndUserGroups": "用户或用户组"
},
"route": {
"": "",
"Ticket":"工单",
"AdminUserCreate": "创建管理用户",
"AdminUserDetail": "管理用户详情",
"AdminUserList": "管理用户",
@@ -425,7 +497,7 @@
"CreateCommandStorage": "创建命令存储",
"CreateReplayStorage": "创建录像存储",
"Dashboard": "仪表盘",
"DatabaseApp": "数据库应用",
"DatabaseApp": "数据库",
"DatabaseAppCreate": "创建数据库应用",
"DatabaseAppDetail": "数据库详情",
"DatabaseAppPermission": "数据库授权",
@@ -433,6 +505,15 @@
"DatabaseAppPermissionDetail": "数据库授权详情",
"DatabaseAppPermissionUpdate": "更新数据库授权规则",
"DatabaseAppUpdate": "数据库应用更新",
"KubernetesApp": "Kubernetes",
"KubernetesAppCreate": "创建Kubernetes",
"KubernetesAppDetail": "Kubernetes详情",
"KubernetesAppPermission": "Kubernetes授权",
"KubernetesAppPermissionCreate": "创建Kubernetes授权规则",
"KubernetesAppPermissionDetail": "Kubernetes授权详情",
"KubernetesAppPermissionUpdate": "更新Kubernetes授权规则",
"KubernetesAppUpdate": "更新Kubernetes",
"DomainCreate": "创建网域",
"DomainDetail": "网域详情",
"DomainList": "网域列表",
@@ -462,6 +543,11 @@
"RemoteAppPermissionCreate": "创建远程应用授权规则",
"RemoteAppPermissionDetail": "远程应用授权详情",
"RemoteAppPermissionUpdate": "更新远程应用授权规则",
"ApplicationDetail": "应用详情",
"ApplicationPermission": "应用授权",
"ApplicationPermissionCreate": "创建应用授权规则",
"ApplicationPermissionDetail": "应用授权详情",
"ApplicationPermissionUpdate": "更新应用授权规则",
"RemoteAppUpdate": "更新远程应用",
"ReplayStorageUpdate": "更新录像存储",
"SessionDetail": "会话详情",
@@ -478,6 +564,7 @@
"TaskMonitor": "任务监控",
"Terminal": "终端管理",
"TicketDetail": "工单详情",
"TicketCreate": "创建工单",
"Tickets": "工单管理",
"UserCreate": "创建用户",
"UserDetail": "用户详情",
@@ -501,6 +588,7 @@
"active": "激活中",
"alive": "在线",
"asset": "资产",
"target": "目标",
"bucket": "桶名称",
"command": "命令",
"commandStorage": "命令存储",
@@ -528,6 +616,10 @@
"name": "名称",
"protocol": "协议",
"region": "地域",
"sessionActiveCount": "在线会话数量",
"systemCpuLoad": "CPU负载",
"systemDiskUsedPercent": "硬盘使用率",
"systemMemoryUsedPercent": "内存使用率",
"remoteAddr": "远端地址",
"replay": "回放",
"replaySession": "回放会话",
@@ -539,7 +631,9 @@
"systemUser": "系统用户",
"terminalDetail": "终端详情",
"terminalUpdate": "更新终端",
"terminalUpdateStorage": "更新终端存储",
"terminate": "终断",
"sessionTerminate": "会话终断",
"test": "测试",
"type": "类型",
"user": "用户",
@@ -547,7 +641,15 @@
"common": "普通"
},
"Monitor": "监控",
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新表格查看"
"sessionMonitor": "监控",
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新查看",
"helpText": {
"esUrl": "提示:如果有多台主机,请使用逗号 ( , ) 进行分割。eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com",
"esIndex": "es提供默认indexjumpserver",
"esDocType": "es默认文档类型command",
"s3Endpoint": "S3 格式: http://s3.{REGION_NAME}.amazonaws.com<br>S3(China) 格式: http://s3.{REGION_NAME}.amazonaws.com.cn<br>如: http://s3.cn-north-1.amazonaws.com.cn",
"ossEndpoint": "OSS 格式: http://{REGION_NAME}.aliyuncs.com<br>如: http://oss-cn-hangzhou.aliyuncs.com"
}
},
"setting": {
"ApiKeyList": "API Key 列表",
@@ -578,6 +680,7 @@
"authLdapSearchOu": "用户OU",
"authLdapServerUri": "LDAP地址",
"authLdapUserAttrMap": "LDAP属性映射",
"unselectedUser": "没有选择用户",
"auto": "自动",
"basicSetting": "基本设置",
"communityEdition": "社区版",
@@ -597,6 +700,9 @@
"emailTest": "测试连接",
"emailUserSSL": "使用SSL",
"emailUserTLS": "使用TLS",
"SecurityInsecureCommand": "危险命令告警",
"Insecure_Command_Alert": "危险命令告警",
"SecurityInsecureCommandEmailReceiver": "告警接收邮件",
"helpText": {
"ApiKeyList": "使用api key签名请求头每个请求的头部是不一样的, 请查阅使用文档",
"authLdapSearchFilter": "可能的选项是(cn或uid或sAMAccountName=%(user)s)",
@@ -617,7 +723,8 @@
"terminalHeartbeatInterval": "单位: 秒",
"terminalSessionKeepDuration": "单位:天。 会话、录像、命令记录超过该时长将会被删除(仅影响数据库存储, oss等不受影响)",
"terminalTelnetRegex": "登录telnet服务器成功后的提示正则表达式如: Last\\s*login|success|成功",
"userGuideUrl": "用户第一次登录修改profile后重定向到地址"
"userGuideUrl": "用户第一次登录修改profile后重定向到地址",
"SecurityInsecureCommandEmailReceiver": "多个邮箱时,以半角逗号','分隔"
},
"helpTip": {
"emailUserSSL": "如果SMTP端口是465通常需要启用SSL",
@@ -628,7 +735,13 @@
"securityPasswordNumber": "开启后,用户密码修改、重置必须包含数字字符",
"securityPasswordSpecialChar": "开启后,用户密码修改、重置必须包含特殊字符",
"securityPasswordUpperCase": "开启后,用户密码修改、重置必须包含大写字母",
"securityServiceAccountRegistration": "允许使用bootstrap token注册终端, 当终端注册成功后可以禁止"
"securityServiceAccountRegistration": "允许使用bootstrap token注册终端, 当终端注册成功后可以禁止",
"SecurityInsecureCommand": "开启后,当资产上有危险命令执行时,会发送邮件告警通知"
},
"validatorMessage": {
"EnsureThisValueIsGreaterThanOrEqualTo3": "请确保该值大于或者等于 3",
"EnsureThisValueIsGreaterThanOrEqualTo5": "请确保该值大于或者等于 5",
"EnsureThisValueIsGreaterThanOrEqualTo6": "请确保该值大于或者等于 6"
},
"import": "导入",
"importLdapUserTip": "请先提交LDAP配置再进行导入",
@@ -664,19 +777,24 @@
"testLdapLoginTitle": "测试LDAP 用户登录",
"userGuideUrl": "用户向导URL",
"username": "用户名",
"usernamePlaceholder": "请输入用户名"
"usernamePlaceholder": "请输入用户名",
"refreshLdapCache":"刷新Ldap缓存请稍后",
"LicenseExpired": "许可证已经过期",
"LicenseWillBe": "许可证即将在 ",
"Expire": " 过期"
},
"settings": {
"setting": "设置"
},
"tickets": {
"Accept": "接受",
"AssignedMe": "待处理",
"Accept": "同意",
"AssignedMe": "待我审批",
"Assignee": "处理人",
"Assignees": "待处理人",
"Close": "关闭",
"Comment": "备注",
"MyTickets": "我的工单",
"MyTickets": "我发起的",
"RequestPerm":"授权申请",
"Reject": "拒绝",
"date": "日期",
"reply": "回复",
@@ -685,7 +803,24 @@
"type": "类型",
"user": "用户",
"Status": "状态",
"Open": "打开"
"Open": "待处理",
"OpenTicket": "创建工单",
"HandleTicket": "处理工单",
"FinishedTicket": "完成工单",
"IP": "IP",
"Hostname": "主机名",
"Asset": "资产",
"SystemUser": "系统用户",
"RequestAssetPerm": "申请资产授权",
"Applicant": "申请人",
"Pending": "待处理",
"Approved": "已同意",
"Rejected": "已拒绝",
"Closed": "已完成",
"helpText": {
"ips": "请输入逗号分割的IP地址组",
"fuzzySearch": "支持模糊搜索"
}
},
"tree": {
"AddAssetToNode": "添加资产到节点",
@@ -695,6 +830,7 @@
"RenameNode": "重命名节点",
"ShowAssetAllChildrenNode": "显示所有子节点资产",
"ShowAssetOnlyCurrentNode": "仅显示当前节点资产",
"CheckAssetsAmount": "校对资产数量",
"ShowNodeInfo": "显示节点详情",
"TestNodeAssetConnectivity": "测试资产节点可连接性",
"UpdateNodeAssetHardwareInfo": "更新节点资产硬件信息"
@@ -713,11 +849,18 @@
"Email": "邮件",
"FingerPrint": "指纹",
"FirstLogin": "首次登录",
"OrgUser": "组织用户",
"OrgAdmin": "组织管理员",
"OrgAuditor": "组织审计员",
"InviteUser": "邀请用户",
"Invite": "邀请",
"InviteUserInOrg": "邀请用户加入此组织",
"Guide": "向导",
"HelpText": {
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",
"MFAOfUserFirstLoginUserGuidePage": "为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:设置复杂密码,并启用多因子认证)",
"SSHKeyOfProfileSSHUpdatePage": "复制你的公钥到这里"
"SSHKeyOfProfileSSHUpdatePage": "复制你的公钥到这里",
"OrgRoleHelpText": "组织角色是用户在当前组织中的角色"
},
"IAgree": "我同意",
"ImprovePersonalInformation": "完善个人信息",
@@ -725,6 +868,7 @@
"LoginConfirm": "登录复核",
"LoginPasswordSetting": "登录密码设置",
"MFA": "MFA",
"Existing":"已存在",
"MfaLevel": "多因子认证",
"Name": "姓名",
"NewPassword": "新密码",
@@ -736,6 +880,8 @@
"ResetAndDownloadSSHKey": "重置并下载密钥",
"ResetPublicKeyAndDownload": "重置并下载SSH密钥",
"Role": "角色",
"SuperRole": "系统角色",
"OrgRole": "组织角色",
"SSHKey": "SSH公钥",
"SSHKeySetting": "SSH公钥设置",
"Secure": "安全",
@@ -766,14 +912,21 @@
"tabs": {
"assetPermissionRules": "资产授权规则",
"databasePermissionRules": "数据库授权规则",
"k8sPermissionRules": "Kubernetes授权规则",
"grantedAssets": "授权的资产",
"grantedK8Ss": "授权的Kubernetes",
"grantedDatabases": "授权的数据库",
"grantedRemoteApps": "授权的远程应用",
"grantedApplications": "授权的应用",
"ApplicationPermissionRules": "应用授权规则",
"remoteAppPermissionRules": "远程应用授权规则"
},
"dateLastLogin": "最后登录日期",
"UpdatePassword": "更新密码",
"SetPublicKey": "设置SSH公钥"
"SetPublicKey": "设置SSH公钥",
"passwordExpired": "密码过期了",
"passwordWillExpiredPrefixMsg": "密码即将在 ",
"passwordWillExpiredSuffixMsg": "天 后过期,请尽快修改您的密码。"
},
"xpack": {
"Admin": "管理员",
@@ -798,6 +951,9 @@
"ExecutionDetail": "执行详情",
"ExecutionList": "执行列表",
"ExecutionTimes": "执行次数",
"validatorMessage": {
"EnsureThisValueIsGreaterThanOrEqualTo1": "请确保该值大于或者等于 1"
},
"HelpText": {
"CrontabOfCreateUpdatePage": "例如:每周日 03:05 执行 <5 3 * * 0> <br/> 使用5位 Linux crontab 表达式 <分 时 日 月 星期> <a href=\"https://tool.lu/crontab/\" target=\"_blank\">在线工具</a> <br/> 如果同时设置了定期执行和周期执行,优先使用定期执行",
"IntervalOfCreateUpdatePage": "单位:时",
@@ -819,17 +975,54 @@
"Username": "用户名"
},
"Cloud": {
"Aliyun": "阿里云",
"Qcloud": "腾讯云",
"AWS_China": "AWS(中国)",
"AWS_Int": "AWS(国际)",
"HuaweiCloud": "华为云",
"Azure":"Azure(中国)",
"HostnameStrategy": "用于生成资产主机名。例如1. 实例名称 (instanceDemo)2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
"IsAlwaysUpdate": "资产信息保持最新",
"AccountCreate": "创建账户",
"AccountList": "账户列表",
"AccountUpdate": "更新账户",
"AccountDetail": "账户详情",
"Cloud": "云管中心",
"CloudCenter": "云管中心",
"CoveredAlwaysHelpTips": "资产信息总是被覆盖",
"Provider": "云服务商",
"Validity": "有效",
"IsAlwaysUpdateHelpTips": "每次执行同步任务时是否同步更新资产的信息包括主机名、IP、系统平台、管理用户",
"SyncInstanceTaskCreate": "创建同步实例任务",
"SyncInstanceTaskList": "同步实例任务列表",
"SyncInstanceTaskDetail": "同步实例任务详情",
"SyncInstanceTaskUpdate": "更新同步实例任务",
"SyncInstanceTaskHistoryList": "同步历史列表",
"SyncInstanceTaskHistoryAssetList": "同步实例列表",
"CloudSource": "同步源",
"SaveSetting": "同步设置"
"SaveSetting": "同步设置",
"Name": "名称",
"Account":"账户",
"Node": "节点",
"AdminUser":"管理用户",
"Periodic":"执行周期",
"PeriodicPerform":"定时执行",
"RegularlyPerform": "定期执行",
"CyclePerform": "周期执行",
"DateLastSync":"最后同步日期",
"DateCreated":"创建日期",
"Region": "地域",
"Comment": "备注",
"RunTaskManually":"手动执行",
"True":"是",
"False": "否",
"NewCount": "新增",
"UnSyncCount": "未同步",
"SyncedCount": "已同步",
"ReleasedCount": "已释放",
"DateSync": "同步日期",
"Status": "状态",
"Log": "日志",
"DeleteReleasedAssets": "删除已释放资产"
},
"Corporation": "公司",
"Edition": "版本",
@@ -847,6 +1040,13 @@
"ImportLicenseTip": "请导入许可证",
"InterfaceSettings": "界面设置",
"License": "许可证",
"SystemMonitor": "系统监控",
"ServiceRatio": "组件负载统计",
"LoadStatus":"组件状态",
"NormalLoad":"正常",
"HighLoad":"较高",
"CriticalLoad":"严重",
"Offline": "离线",
"LicenseDetail": "许可证详情",
"LicenseFile": "许可证文件",
"NoLicense": "暂无许可证",
@@ -855,7 +1055,13 @@
"OrganizationCreate": "创建组织",
"OrganizationDetail": "组织详情",
"OrganizationList": "组织管理",
"OrganizationUpdate": "更新组织"
"OrganizationUpdate": "更新组织",
"OrganizationMembership": "组织成员",
"DeleteOrgTitle": "请确保组织内的以下信息已删除",
"DeleteOrgMsg": "用户列表、用户组、资产列表、网域列表、管理用户、系统用户、标签管理、资产授权规则",
"OrgRole": "组织角色",
"CreateOrgMsg": "请去组织详情内添加用户",
"AddOrgMembers": "添加组织成员"
},
"RestoreButton": "恢复默认",
"SubscriptionID": "订阅授权ID",
@@ -872,9 +1078,9 @@
"loginImageTip": "提示:将会显示在企业版用户登录页面(建议图片大小为: 492*472px",
"loginTitle": "登录页面标题",
"loginTitleTip": "提示将会显示在企业版用户登录页面eg: 欢迎使用JumpServer开源堡垒机)",
"logoIndex": "管理页面logo",
"logoIndex": "Logo (带文字)",
"logoIndexTip": "提示:将会显示在管理页面左上方(建议图片大小为: 185px*55px",
"logoLogout": "退出页面logo",
"logoLogout": "Logo (不带文字)",
"logoLogoutTip": "提示将会显示在企业版用户退出页面建议图片大小为82px*82px",
"restoreDialogMessage": "您确定要恢复默认初始化吗?",
"restoreDialogTitle": "你确认吗",

View File

@@ -2,6 +2,22 @@
"": "",
"applications": {
"": "",
"applicationsType": {
"chrome": "Chrome",
"mysql_workbench": "MySQL Workbench",
"vmware_client":"Vmware Client",
"custom":"Custom",
"mysql": "MySQL",
"oracle": "Oracle",
"postgresql": "PostgreSQL",
"mariadb": "MariaDB",
"k8s": "kubernetes"
},
"applicationsCategory": {
"remote_app": "Remote app",
"db": "Database app",
"cloud": "Cloud app"
},
"appPath": "App path",
"appType": "App type",
"asset": "Asset",
@@ -17,6 +33,7 @@
"mysql_workbench": "MySQL Workbench",
"mysql_workbench_ip": "DB IP",
"mysql_workbench_name": "DB Name",
"mysql_workbench_port": "DB Port",
"mysql_workbench_username": "DB Account",
"mysql_workbench_password": "DB Password",
"vmware_client": "vSphere Client",
@@ -28,7 +45,11 @@
"custom_target": "target URL",
"custom_username": "Account",
"custom_password": "Password",
"Custom": "Custom"
"Custom": "Custom",
"cluster": "Cluster",
"kubernetes":"Kubernetes",
"clusterHelpTextMessage": "Tips: https://172.16.8.8:8443",
"DBInfo": "Database Info"
},
"assets": {
"Action": "Action",
@@ -37,11 +58,16 @@
"AdminUserDetail": "Admin user detail",
"AdminUserListHelpMessage": "Admin users are asset (charged server) on the root, or have NOPASSWD: ALL sudo permissions users, JumpServer users of the system using the user to `push system user`, `get assets hardware information`, etc.\n",
"Asset": "Asset",
"Hardware": "Hardware",
"AccountList": "Account list",
"AssetDetail": "Asset detail",
"AssetList": "Asset list",
"AssetListHelpMessage": "The left side is the asset tree, right click to create, delete, and change the tree node, authorization asset is also organized as a node, and the right side is the asset under that node\n",
"AssetNumber": "Asset number",
"AssetUserList": "Asset user list",
"TestGatewayTestConnection":"Test gateway test connection",
"TestGatewayHelpMessage": "If use nat, set the ssh real port",
"SshPort": "SSH Port",
"Assets": "Assets",
"Auth": "Auth",
"AutoGenerateKey": "Auto generate ssh key",
@@ -63,6 +89,8 @@
"DateUpdated": "Date updated",
"DeactiveSelected": "Deactive selected",
"Disk": "Disk",
"AdDomain": "AD Domain",
"AdDomainHelpText": "AD domain provided to domain users for login",
"Domain": "Domain",
"DomainDetail": "Domain detail",
"DomainHelpMessage": "The domain function is added to address the fact that some environments (such as the hybrid cloud) cannot be connected directly by jumping on the gateway server.\nJMS => Domain gateway => Target assets",
@@ -100,10 +128,13 @@
"PushSystemUserNow": "Push system user now",
"QuickUpdate": "Quick update",
"Reachable": "Reachable",
"Unreachable": "Unreachable",
"Unknown": "Unknown",
"Refresh": "Refresh",
"RefreshHardware": "Refresh hardware",
"RemoteAppListHelpMessage": "Before using this feature, make sure that the application loader has been uploaded to the application server and successfully published as a RemoteApp application <b><a href='https://github.com/jumpserver/Jmservisor/releases'> Download application loader</a></b>",
"RemoteApps": "Remote apps",
"Applications": "Applications",
"RemoteType": "Remote type",
"RemoveFromCurrentNode": "Remove from node",
"ReplaceNodeAssetsAdminUserWithThis": "Replace node assets admin user with this",
@@ -111,6 +142,7 @@
"SFTPHelpMessage": "SFTP root dir, tmp, home or custom",
"SerialNumber": "Serial number",
"SudoHelpMessage": "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig",
"PasswordHelpMessage": "Password or private key password",
"SystemUser": "System user",
"SystemUserDetail": "System user detail",
"SystemUserListHelpMessage": "System user is JumpServer jump login assets used by the users, can be understood as the user login assets, such as web, sa, the dba (` ssh web@some-host `), rather than using a user the username login server jump (` ssh xiaoming@some-host `); In simple terms, users log into JumpServer using their own username, and JumpServer uses system users to log into assets. When system users are created, if you choose auto push JumpServer to use Ansible push system users into the asset, if the asset (Switch) does not support ansible, please manually fill in the account password.\n",
@@ -120,6 +152,7 @@
"TestConnection": "Test connection",
"Type": "Type",
"UnselectedAssets": "Unselected assets",
"UnselectedNodes": "Unselected nodes",
"UpdateAssetUserToken": "Update asset user auth",
"Username": "Username",
"UsernameHelpMessage": "Username is dynamic, When connect asset, using current user's username",
@@ -129,7 +162,12 @@
"command_filter_list": "Command filter list",
"date_joined": "Date joined",
"ip": "IP",
"sshkey": "sshkey"
"sshkey": "sshkey",
"GroupsHelpMessage": "Please fill in user groups, separated by commas if there are multiple user groups(Please fill in the existing user groups)",
"HomeHelpMessage": "Default home directory: /home/system username",
"Home": "Home",
"LinuxUserAffiliateGroup": "Linux user affiliate group",
"ipDomain": "IP(Domain)"
},
"audits": {
"Hosts": "Host",
@@ -144,13 +182,22 @@
"common": {
"Nothing": "Nothing",
"Action": "Action",
"RequestTickets": "Request tickets",
"Actions": "Actions",
"NeedSpecifiedFile": "Required to upload the specified format file",
"TestPortErrorMsg":"Port Error, please check",
"Activate": "Activate",
"actionsTips":"Clipboard's copy and paste control only support RDP/VNC protocol.",
"Active": "Active",
"Add": "Add",
"PleaseAgreeToTheTerms": "Please agree to the terms",
"PushSelected":"Push selected",
"UpdateAssetDetail": "Update more detail",
"AddSuccessMsg": "Add success",
"Auth": "Authorization",
"BadRequestErrorMsg": "Bad request, please check again",
"BadRoleErrorMsg": "Bad request, no permission for this operation",
"BadConflictErrorMsg": "Refreshing, please try again later",
"Basic": "Basic",
"BasicInfo": "Basic info",
"Cancel": "Cancel",
@@ -162,6 +209,7 @@
"CreatedBy": "Created by",
"CrontabHelpTips": "eg: Every Sunday 03:05 run <5 3 * * 0> <br>Tips:Using 5 digits linux crontab expressions<min hour day month week> (<a href='https://tool.lu/crontab/' target='_blank'>Online tools</a>) <br>Note:If both Regularly perform and Cycle perform are set,give priority to Regularly perform",
"DateEnd": "End date",
"Resource": "Resource",
"DateLast24Hours": "Last 24 hours",
"DateLast3Months": "Last 3 months",
"DateLastMonth": "Last month",
@@ -175,11 +223,13 @@
"EnterForSearch": "Press enter to search",
"Export": "Export",
"Import": "Import",
"Refresh": "Refresh",
"Info": "Info",
"MFAConfirm": "MFA Confirm",
"MFARequireForSecurity": "MFA required for security",
"Members": "Members",
"More": "More",
"Message": "Message",
"MoreActions": "Actions",
"Name": "Name",
"No": "No",
@@ -202,6 +252,7 @@
"To": "To",
"Update": "Update",
"Upload": "Upload",
"Clone": "Clone",
"Username": "Username",
"Validity": "Validity",
"Invalidity": "Invalidity",
@@ -213,11 +264,15 @@
"bulkDeleteSuccessMsg": "Bulk delete success",
"bulkRemoveErrorMsg": "Bulk remove failed: ",
"bulkRemoveSuccessMsg": "Bulk remove success",
"NeedAssetsAndSystemUserErrMsg": "Need assets and systemuser",
"createBy": "Create by",
"cloneFrom": "Clone from",
"createErrorMsg": "Create error",
"createSuccessMsg": "Create success",
"saveSuccessContinueMsg": "Create success, you may add another",
"createdBy": "Created by",
"dateCreated": "Date created",
"dateFinished": "Date finished",
"dateExpired": "Date expired",
"dateStart": "Date start",
"deleteErrorMsg": "Delete failed",
@@ -228,6 +283,7 @@
"disableSelected": "Disable selected",
"fieldRequiredError": "This field is required",
"getErrorMsg": "Get failed",
"fileType": "File type",
"imExport": {
"ExportAll": "Export all",
"ExportOnlyFiltered": "Export only filtered",
@@ -353,7 +409,7 @@
},
"perms": {
"": "",
"Actions": "Actions",
"Actions": "Permission",
"Asset": "Asset",
"Basic": "Basic",
"Exclude": "Exclude",
@@ -364,8 +420,13 @@
"SystemUser": "System user",
"User": "User",
"UserGroups": "UserGroups",
"DatabaseAppPermission": "Databases permissions",
"RemoteAppPermission": "Remote apps permissions",
"KubernetesAppPermission": "Kubernetes permissions",
"addAssetToThisPermission": "Add asset to this permission",
"addDatabaseAppToThisPermission": "Add DatabaseApp to this permission",
"addK8sAppToThisPermission": "Add KubernetesApp to this permission",
"addApplicationToThisPermission": "Add Application to this permission",
"addNodeToThisPermission": "Add node to this permission",
"addRemoteAppToThisPermission": "Add RemoteApp to this permission",
"addSystemUserToThisPermission": "System user",
@@ -376,6 +437,7 @@
"assetCount": "Asset count",
"connect": "Connect",
"databaseApp": "DatabaseApp",
"KubernetesApp": "KubernetesApp",
"dateStart": "Date start",
"downloadFile": "Download file",
"hostName": "Hostname",
@@ -386,15 +448,23 @@
"refreshSuccess": "Refresh success",
"remoteApp": "RemoteApp",
"remoteAppCount": "RemoteApp count",
"appsCount": "App count",
"appsList":"App list",
"DatabaseAppCount": "DatabaseApp count",
"KubernetesAppCount": "KubernetesApp count",
"systemUserCount": "System user count",
"upDownload": "Upload download",
"uploadFile": "Upload file",
"clipboardCopyPaste":"Copy Paste",
"clipboardCopy":"Clipboard copy",
"clipboardPaste":"Clipboard paste",
"userCount": "User count",
"userGroupCount": "User group count",
"usersAndUserGroups": "Users and user groups"
},
"route": {
"": "",
"Ticket": "Tickets",
"AdminUserCreate": "Admin user create",
"AdminUserDetail": "Admin user detail",
"AdminUserList": "Admin users",
@@ -433,6 +503,14 @@
"DatabaseAppPermissionDetail": "Databases permissions detail",
"DatabaseAppPermissionUpdate": "Databases permissions update",
"DatabaseAppUpdate": "Database app update",
"KubernetesApp": "Kubernetes apps",
"KubernetesAppCreate": "Kubernetes app create",
"KubernetesAppDetail": "Kubernetes app detail",
"KubernetesAppPermission": "Kubernetes permissions",
"KubernetesAppPermissionCreate": "Kubernetes permissions create",
"KubernetesAppPermissionDetail": "Kubernetes permissions detail",
"KubernetesAppPermissionUpdate": "Kubernetes permissions update",
"KubernetesAppUpdate": "Kubernetes app update",
"DomainCreate": "Domain create",
"DomainDetail": "Domain detail",
"DomainList": "Domains",
@@ -459,6 +537,7 @@
"RemoteApp": "Remote apps",
"RemoteAppDetail": "Remote app detail",
"RemoteAppPermission": "Remote apps permissions",
"ApplicationPermission": "Application permissions",
"RemoteAppPermissionCreate": "Remote apps permission create",
"RemoteAppPermissionDetail": "Remote apps permissions detail",
"RemoteAppPermissionUpdate": "Remote app permission update",
@@ -478,6 +557,7 @@
"TaskMonitor": "Task monitor",
"Terminal": "Terminal",
"TicketDetail": "Ticket detail",
"TicketCreate": "Ticket create",
"Tickets": "Tickets",
"UserCreate": "User create",
"UserDetail": "User detail",
@@ -501,6 +581,7 @@
"active": "active",
"alive": "alive",
"asset": "Asset",
"target": "Target",
"bucket": "Bucket",
"command": "Command",
"commandStorage": "Command storage",
@@ -516,6 +597,10 @@
"duration": "Duration",
"endPoint": "Endpoint",
"endpointSuffix": "Endpoint suffix",
"sessionActiveCount": "session active count",
"systemCpuLoad": "cpu load",
"systemDiskUsedPercent": "disk used percent",
"systemMemoryUsedPercent": "memory used percent",
"go": "Go",
"goto": "Goto",
"hosts": "Hosts",
@@ -533,13 +618,15 @@
"replaySession": "Replay session",
"replayStorage": "Replay storage",
"riskLevel": "Risk level",
"session": "session",
"session": "Session",
"sshPort": "SSH port",
"storage": "Storage",
"systemUser": "System user",
"terminalDetail": "Terminal detail",
"terminalUpdate": "Update terminal",
"terminalUpdateStorage": "Update terminal storage",
"terminate": "Terminate",
"sessionTerminate": "Session Terminate",
"test": "Test",
"type": "Type",
"user": "Use",
@@ -547,7 +634,15 @@
"common": "common"
},
"Monitor": "Monitor",
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later"
"sessionMonitor": "Session Monitor",
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later",
"helpText": {
"esUrl": "Tip: If you have multiple hosts, use comma (,) to split (eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com)",
"esIndex":"Es provides the default index: jumpserver",
"esDocType": "Es provides the default document type: command",
"s3Endpoint": "S3: http://s3.{REGION_NAME}.amazonaws.com<br>S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn<br>Example: http://s3.cn-north-1.amazonaws.com.cn",
"ossEndpoint": "OSS: http://{REGION_NAME}.aliyuncs.com<br>Example: http://oss-cn-hangzhou.aliyuncs.com"
}
},
"setting": {
"ApiKeyList": "Api key list",
@@ -578,6 +673,7 @@
"authLdapSearchOu": "User OU",
"authLdapServerUri": "LDAP server",
"authLdapUserAttrMap": "User attr map",
"unselectedUser": "Unselected user",
"auto": "Auto",
"basicSetting": "Basic setting",
"communityEdition": "Community edition",
@@ -630,6 +726,11 @@
"securityPasswordUpperCase": "After opening, the user password changes and resets must contain uppercase letters",
"securityServiceAccountRegistration": "Allow using bootstrap token register service account, when terminal setup, can disable it"
},
"validatorMessage": {
"EnsureThisValueIsGreaterThanOrEqualTo3": "Ensure this value is greater than or equal to 3",
"EnsureThisValueIsGreaterThanOrEqualTo5": "Ensure this value is greater than or equal to 5",
"EnsureThisValueIsGreaterThanOrEqualTo6": "Ensure this value is greater than or equal to 6"
},
"import": "Import",
"importLdapUserTip": "Please submit the LDAP configuration before import",
"importLdapUserTitle": "LDAP user list",
@@ -664,7 +765,11 @@
"testLdapLoginTitle": "Test LDAP user login",
"userGuideUrl": "User Guide URL",
"username": "Username",
"usernamePlaceholder": "Please input username"
"usernamePlaceholder": "Please input username",
"refreshLdapCache":"Refreshing Ldap cache ",
"LicenseExpired": "License expired",
"LicenseWillBe": "License will expire at ",
"Expire": ""
},
"settings": {
"setting": "Setting"
@@ -673,6 +778,10 @@
"Accept": "Accept",
"AssignedMe": "Assigned me",
"Assignee": "Assignee",
"RequestPerm":"Request Perm",
"OpenTicket": "Open Ticket",
"HandleTicket": "Handle Ticket",
"FinishedTicket": "Finished Ticket",
"Assignees": "Assignees",
"Close": "Close",
"Comment": "Comment",
@@ -685,7 +794,21 @@
"type": "Type",
"user": "User",
"Status": "Status",
"Open": "Open"
"Open": "Open",
"IP": "IP",
"Hostname": "Hostname",
"Asset": "Asset",
"SystemUser": "System user",
"Applicant": "Applicant",
"RequestAssetPerm": "Request asset perm",
"Pending": "Open",
"Approved": "Approved",
"Rejected": "Rejected",
"Closed": "Closed",
"helpText": {
"ips": "Enter the IP address group, separated by commas",
"fuzzySearch": "Support for fuzzy search"
}
},
"tree": {
"AddAssetToNode": "Add asset to node",
@@ -695,12 +818,14 @@
"RenameNode": "Rename node",
"ShowAssetAllChildrenNode": "Show asset all children node",
"ShowAssetOnlyCurrentNode": "Show asset only current node",
"CheckAssetsAmount": "Check assets amount",
"ShowNodeInfo": "Show node information",
"TestNodeAssetConnectivity": "Test node asset connectivity",
"UpdateNodeAssetHardwareInfo": "Update node asset hardware information"
},
"users": {
"Account": "Account",
"Existing":"Existing",
"Authentication": "Account",
"Comment": "Comment",
"ConfirmPassword": "Confirm password",
@@ -713,11 +838,19 @@
"Email": "Email",
"FingerPrint": "Fingerprint",
"FirstLogin": "First login",
"InviteUser": "Invite user",
"InviteUserInOrg": "Invite user in this org",
"Invite": "Invite",
"Guide": "Guide",
"OrgUser": "Org User",
"OrgAdmin": "Org Admin",
"OrgAuditor": "Org Auditor",
"HelpText": {
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "Enable multi-factor authentication to make the account more secure <br/> After is enabled, you will enter the multi-factor authentication binding process on your next login <br/> You can also bind directly in (personal information -> fast modifier -> modifier multiple factor Settings)",
"MFAOfUserFirstLoginUserGuidePage": "To protect the security of you and the company <br/> please properly keep your account, password, key and other important and sensitive information <br/> (e.g., set a complex password and enable multi-factor authentication)",
"SSHKeyOfProfileSSHUpdatePage": "Copy your public key here"
"SSHKeyOfProfileSSHUpdatePage": "Copy your public key here",
"OrgRoleHelpText": "Organizational roles are the user's role in the current organization"
},
"IAgree": "I agree",
"ImprovePersonalInformation": "Improve personal information",
@@ -736,6 +869,8 @@
"ResetAndDownloadSSHKey": "Reset and download SSH Key",
"ResetPublicKeyAndDownload": "Reset public key and download",
"Role": "Role",
"SuperRole": "Super role",
"OrgRole": "Org role",
"SSHKey": "SSH Key",
"SSHKeySetting": "SSH Key setting",
"Secure": "Secure",
@@ -766,13 +901,20 @@
"tabs": {
"assetPermissionRules": "Asset permission rules",
"databasePermissionRules": "Database Permission rules",
"k8sPermissionRules": "Kubernetes Permission rules",
"grantedAssets": "Granted assets",
"grantedK8Ss":"Granted K8Ss",
"grantedDatabases": "Granted databases",
"grantedRemoteApps": "Granted remote apps",
"grantedApplications": "Granted applications",
"ApplicationPermissionRules": "Application permission rules",
"remoteAppPermissionRules": "Remote app permission rules"
},
"UpdatePassword": "",
"UpdatePublicKey": ""
"UpdatePublicKey": "",
"passwordExpired": "Password expired",
"passwordWillExpiredPrefixMsg": "The password will expire in ",
"passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible."
},
"xpack": {
"Admin": "Admin",
@@ -797,6 +939,9 @@
"ExecutionDetail": "Execution detail",
"ExecutionList": "Execution list",
"ExecutionTimes": "Execution times",
"validatorMessage": {
"EnsureThisValueIsGreaterThanOrEqualTo1": "Ensure this value is greater than or equal to 1"
},
"HelpText": {
"CrontabOfCreateUpdatePage": "For example: every Sunday at 03:05 execute <5 3 * * 0> <br/> Using the 5-bit Linux crontab expression <minute hour day month week> (<a href=\"https://tool.lu/crontab/\" target=\"_blank\"> Online tool </a>) <br/> If both regularly perform and cycle perform execution are set, use regularly perform first",
"IntervalOfCreateUpdatePage": "Unit: hour",
@@ -818,17 +963,54 @@
"Username": "Username"
},
"Cloud": {
"Aliyun": "Ali Cloud",
"Qcloud": "Tencent Cloud",
"AWS_China": "AWS(China)",
"AWS_Int": "AWS(International)",
"HuaweiCloud": "Huawei Cloud",
"Azure":"Azure(China)",
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo)2. Instance name and Partial IP (instanceDemo-250.1)",
"IsAlwaysUpdate": "Asset info is kept up-to-date",
"AccountCreate": "Create account",
"AccountList": "Account list",
"AccountUpdate": "Update account",
"AccountDetail": "Account detail",
"Cloud": "Cloud center",
"CloudCenter": "Cloud center",
"CoveredAlwaysHelpTips": "The asset information is always covered",
"Provider": "Provider",
"Validity": "Validity",
"IsAlwaysUpdateHelpTips": "Whether the asset information, including Hostname, IP, Platform, and AdminUser, is updated synchronously each time a synchronization task is performed",
"SyncInstanceTaskCreate": "Create sync instance task",
"SyncInstanceTaskList": "Sync instance task list",
"SyncInstanceTaskDetail": "Sync instance task detail",
"SyncInstanceTaskUpdate": "Update sync instance task",
"SyncInstanceTaskHistoryList": "Sync task history",
"SyncInstanceTaskHistoryAssetList": "Sync instance list",
"CloudSource": "Cloud source",
"SaveSetting": "Save setting"
"SaveSetting": "Save setting",
"Name": "Name",
"Account":"Account",
"Node": "Node",
"AdminUser":"Admin user",
"PeriodicPerform":"Periodic perform",
"Periodic":"Periodic",
"RegularlyPerform": "Regularly perform",
"CyclePerform": "Cycle perform",
"DateLastSync":"Date last sync",
"DateCreated":"Date created",
"Region": "Region",
"RunTaskManually":"Run task manually",
"Comment": "Comment",
"True":"True",
"False": "False",
"NewCount": "New count",
"UnSyncCount": "Unsync count",
"SyncedCount": "Synced count",
"ReleasedCount": "Released count",
"DateSync": "Date sync",
"Status": "Status",
"Log": "Log",
"DeleteReleasedAssets": "Delete released assets"
},
"Corporation": "Corporation",
"Edition": "Edition",
@@ -847,6 +1029,13 @@
"InterfaceSettings": "Interface setting",
"License": "License",
"LicenseDetail": "License detail",
"SystemMonitor": "System Monitor",
"ServiceRatio": "Service ratio",
"LoadStatus":"Status",
"NormalLoad":"Normal",
"HighLoad":"High",
"Offline": "Offline",
"CriticalLoad":"Critical",
"LicenseFile": "License file",
"NoLicense": "No License",
"Node": "Node",
@@ -854,7 +1043,13 @@
"OrganizationCreate": "Create organization",
"OrganizationDetail": "Org detail",
"OrganizationList": "Organlizations",
"OrganizationUpdate": "Update org"
"OrganizationUpdate": "Update org",
"OrganizationMembership": "Organization membership",
"DeleteOrgTitle":"Please ensure that the following information in the organization has been deleted",
"DeleteOrgMsg":"User list、User group、Asset list、Domain list、Admin user、System user、Labels、Asset permission",
"OrgRole": "Org role",
"CreateOrgMsg": "Please go to Organization Details to add users",
"AddOrgMembers": "Add organization members"
},
"RestoreButton": "Restore Default",
"SubscriptionID": "Subscription ID",
@@ -871,9 +1066,9 @@
"loginImageTip": "Tips: This will be displayed on the enterprise user login page. (suggest image size: 492px*472px)",
"loginTitle": "Title of login page",
"loginTitleTip": "Tips: This will be displayed on the enterprise user login page. (eg: Welcome to the JumpServer open source fortress)",
"logoIndex": "Logo of management page",
"logoIndex": "Logo (It contains text)",
"logoIndexTip": "Tips: This will appear at the top left of the administration page. (suggest image size: 185px*55px)",
"logoLogout": "Logo of logout page",
"logoLogout": "Logo (It contains no text)",
"logoLogoutTip": "Tips: This will be displayed on the enterprise user logout page. (suggest image size: 82px*82px)",
"restoreDialogMessage": "This will restore default Settings of the interface !!!",
"restoreDialogTitle": "Are you sure?",

View File

@@ -1,7 +1,7 @@
<template>
<div class="footer" :style="style">
<div class="pull-right">
Version <strong>2.0.0</strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
</div>
<div v-if="!publicSettings.XPACK_LICENSE_IS_VALID" style="padding-left:20px;">
<strong>Copyright</strong> FIT2CLOUD 飞致云 © 2014-2020

View File

@@ -5,6 +5,8 @@
:method="method"
:form="form"
:url="iUrl"
:has-save-continue="iHasSaveContinue"
:has-reset="iHasReset"
:is-submitting="isSubmitting"
v-bind="$attrs"
v-on="$listeners"
@@ -13,50 +15,66 @@
</template>
<script>
import AutoDataForm from '@/components/AutoDataForm'
import deepmerge from 'deepmerge'
export default {
name: 'GenericCreateUpdateForm',
components: {
AutoDataForm
},
props: {
// 创建对象的地址
url: {
type: String,
default: ''
},
// 更新的对象
object: {
type: Object,
default: null
},
// form的默认值
initial: {
type: Object,
default: () => ({})
},
// 提交前清理form的值
cleanFormValue: {
type: Function,
default: (value) => value
},
// 当提交的时候,怎么处理
onSubmit: {
type: Function,
default: null
},
// 如何提交数据
performSubmit: {
type: Function,
default(validValues) {
return this.$axios[this.method](this.iUrl, validValues)
}
},
// 创建成功的msg
createSuccessMsg: {
type: String,
default: function() {
return this.$t('common.createSuccessMsg')
}
},
// 更新成功的msg
saveSuccessContinueMsg: {
type: String,
default: function() {
return this.$t('common.saveSuccessContinueMsg')
}
},
updateSuccessMsg: {
type: String,
default: function() {
return this.$t('common.updateSuccessMsg')
}
},
// 创建成功的跳转路由
createSuccessNextRoute: {
type: Object,
default: function() {
@@ -64,6 +82,7 @@ export default {
return { name: routeName }
}
},
// 更新成功的跳转路由
updateSuccessNextRoute: {
type: Object,
default: function() {
@@ -71,12 +90,21 @@ export default {
return { name: routeName }
}
},
objectDetailRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Update', 'Detail').replace('Create', 'Detail')
return { name: routeName }
}
},
// 获取下一个路由
getNextRoute: {
type: Function,
default(res, method) {
return method === 'post' ? this.createSuccessNextRoute : this.updateSuccessNextRoute
}
},
// 获取提交的方法
getMethod: {
type: Function,
default: function() {
@@ -88,6 +116,7 @@ export default {
}
}
},
// 获取创建和更新的url function
getUrl: {
type: Function,
default: function() {
@@ -101,12 +130,47 @@ export default {
},
onPerformSuccess: {
type: Function,
default(res, method, vm) {
const msg = method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
default(res, method, vm, addContinue) {
let msg = method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
if (addContinue) {
msg = this.saveSuccessContinueMsg
}
let msgLinkName = this.$t('common.Resource')
if (res.name) {
msgLinkName = res.name
} else if (res.hostname) {
msgLinkName = res.hostname
}
const detailRoute = this.objectDetailRoute
detailRoute['params'] = { 'id': res.id }
const route = this.getNextRoute(res, method)
this.$emit('submitSuccess', res)
this.$message.success(msg)
setTimeout(() => this.$router.push(route), 100)
const h = this.$createElement
this.$log.debug('router is: ', detailRoute)
if (this.hasDetailInMsg) {
this.$message({
message: h('p', null, [
h('el-link', {
on: {
click: () => this.$router.push(detailRoute)
},
style: { 'vertical-align': 'top' }
}, msgLinkName),
h('span', { style: {
'padding-left': '5px',
'height': '18px',
'line-height': '18px',
'font-size': '13.5px',
'font-weight': ' 400' }}, msg)
]),
type: 'success'
})
} else {
this.$message.success(msg)
}
if (!addContinue) {
setTimeout(() => this.$router.push(route), 100)
}
}
},
onPerformError: {
@@ -125,13 +189,22 @@ export default {
}
}
}
},
hasSaveContinue: {
type: Boolean,
default: null
},
hasDetailInMsg: {
type: Boolean,
default: true
}
},
data() {
return {
form: {},
loading: true,
isSubmitting: false
isSubmitting: false,
clone: false
}
},
computed: {
@@ -140,44 +213,77 @@ export default {
},
iUrl() {
return this.getUrl()
},
iHasSaveContinue() {
if (this.hasSaveContinue != null) {
return this.hasSaveContinue
}
return this.method === 'post'
},
iHasReset() {
if (this.hasReset != null) {
return this.hasReset
}
return this.method === 'put'
}
},
async created() {
this.$log.debug('Object init is: ', this.object)
this.loading = true
try {
const values = await this.getFormValue()
this.$log.debug('Final object is: ', values)
this.form = Object.assign(this.form, values)
} finally {
this.loading = false
}
},
methods: {
handleSubmit(values) {
handleSubmit(values, formName, addContinue) {
let handler = this.onSubmit || this.defaultOnSubmit
handler = handler.bind(this)
values = this.cleanFormValue(values)
return handler(values)
return handler(values, formName, addContinue)
},
defaultOnSubmit(validValues) {
defaultOnSubmit(validValues, formName, addContinue) {
this.isSubmitting = true
this.performSubmit(validValues)
.then((res) => this.onPerformSuccess.bind(this)(res, this.method, this))
.then((res) => this.onPerformSuccess.bind(this)(res, this.method, this, addContinue))
.catch((error) => this.onPerformError(error, this.method, this))
.finally(() => { this.isSubmitting = false })
},
async getFormValue() {
if (this.method !== 'put') {
const cloneFrom = this.$route.query['clone_from']
if (this.method !== 'put' && !cloneFrom) {
return Object.assign(this.form, this.initial)
}
let object = this.object
if (object === null) {
object = await this.getObjectDetail()
if (!object) {
if (cloneFrom) {
this.$log.debug('Clone from: ', cloneFrom)
const url = `${this.url}${cloneFrom}/`
object = await this.getObjectDetail(url)
if (object['name']) {
object.name = this.$t('common.cloneFrom') + ' ' + object.name
} else if (object['hostname']) {
object.hostname = this.$t('common.cloneFrom') + ' ' + object.hostname
}
} else {
object = await this.getObjectDetail(this.iUrl)
}
}
if (object) {
if (object['attrs']) {
object = deepmerge(object, object['attrs'])
}
this.$log.debug('Object is: ', object)
this.$emit('update:object', object)
}
return object
},
async getObjectDetail() {
return this.$axios.get(this.iUrl)
async getObjectDetail(url) {
this.$log.debug('Get object detail: ', url)
return this.$axios.get(url)
}
}
}

View File

@@ -1,7 +1,7 @@
<template>
<Page>
<Page v-bind="$attrs">
<IBox>
<GenericCreateUpdateForm v-bind="$attrs" v-on="$listeners" />
<GenericCreateUpdateForm ref="createUpdateForm" v-bind="$attrs" v-on="$listeners" />
</IBox>
</Page>
</template>

View File

@@ -1,6 +1,6 @@
<template>
<Page v-bind="$attrs">
<ListTable v-bind="$attrs" />
<ListTable ref="ListTable" v-bind="$attrs" />
</Page>
</template>

View File

@@ -1,6 +1,5 @@
<template>
<Dialog
v-if="dialogSetting.dialogVisible"
:title="this.$t('common.updateSelected')"
:visible.sync="dialogSetting.dialogVisible"
width="70%"
@@ -99,6 +98,7 @@ export default {
const url = this.url
const msg = this.updateSuccessMsg
this.$axios.patch(url, validValues).then((res) => {
vm.$emit('update')
this.$message.success(msg)
vm.dialogSetting.dialogVisible = false
}).catch(error => {

View File

@@ -8,14 +8,10 @@
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-user" command="profile">{{ $t('common.nav.Profile') }}</el-dropdown-item>
<div v-if="currentOrgRoles.length > 1 || hasAdminOrg ">
<el-dropdown-item v-if="isInAdminRole " icon="el-icon-guide" command="userPage">
{{ $t('common.nav.UserPage') }}
</el-dropdown-item>
<el-dropdown-item v-else icon="el-icon-guide" command="adminPage">
{{ $t('common.nav.AdminPage') }}
</el-dropdown-item>
</div>
<template v-if="currentOrgRoles.length > 1 || hasAdminOrg ">
<el-dropdown-item v-if="isInAdminRole " icon="el-icon-guide" command="userPage">{{ $t('common.nav.UserPage') }}</el-dropdown-item>
<el-dropdown-item v-else icon="el-icon-guide" command="adminPage">{{ $t('common.nav.AdminPage') }}</el-dropdown-item>
</template>
<el-dropdown-item icon="el-icon-key" command="apiKey">{{ $t('common.nav.APIKey') }}</el-dropdown-item>
<el-dropdown-item divided command="logout">{{ $t('common.nav.Logout') }}</el-dropdown-item>
</el-dropdown-menu>
@@ -86,7 +82,7 @@ export default {
case 'userPage':
if (this.currentOrgUsePagePerm) {
this.$store.dispatch('users/setCurrentRole', rolec.USER)
console.log('Switch to: ', rolec.USER)
// console.log('Switch to: ', rolec.USER)
window.location.href = `/ui/`
}
break
@@ -101,7 +97,7 @@ export default {
},
logout() {
// Clean Status
const statusList = ['currentOrg', 'currentRole', 'jms_current_org', 'jms_current_role', 'sidebarStatus', 'django_language', 'X-JMS-ORG', 'activeTab']
const statusList = ['currentOrg', 'currentRole', 'jms_current_org', 'jms_current_role', 'sidebarStatus', 'X-JMS-ORG', 'activeTab']
for (const i in statusList) {
this.$cookie.delete(statusList[i])
}

View File

@@ -1,6 +1,6 @@
<template>
<div>
<Dialog width="60%" :visible.sync="showDialog" :title="this.$t('setting.ApiKeyList')" :show-cancel="false" :show-confirm="false">
<Dialog :destroy-on-close="true" width="60%" :visible.sync="showDialog" :title="this.$t('setting.ApiKeyList')" :show-cancel="false" :show-confirm="false">
<div>
<el-alert type="success"> {{ helpMessage }} </el-alert>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />

View File

@@ -31,25 +31,46 @@ export default {
}
},
computed: {
supportedLangMapper() {
return this.supportLanguages.reduce((map, obj) => {
map[obj.code] = obj
return map
})
},
currentLang() {
const cookieCode = this.$cookie.get(this.LANG_COOKIE_NAME)
let lang = this.supportLanguages.find((v) => v.cookieCode === cookieCode)
const langCode = this.getLangCode()
let lang = this.supportedLangMapper[langCode]
if (!lang) {
lang = this.supportLanguages[0]
this.changeLangTo(lang)
}
if (lang.code !== this.$i18n.locale) {
this.changeLangTo(lang)
}
return lang
}
},
mounted() {
if (this.currentLang.code !== this.$i18n.locale) {
this.changeLangTo(this.currentLang)
}
},
methods: {
changeLangTo(item) {
this.$i18n.locale = item.code
localStorage.setItem('lang', item.code)
this.$cookie.set(this.LANG_COOKIE_NAME, item.cookieCode)
window.location.reload()
},
getLangCode() {
let langCode = localStorage.lang
if (!langCode) {
langCode = this.$cookie.get(this.LANG_COOKIE_NAME)
}
if (!langCode) {
langCode = navigator.language || navigator.userLanguage
}
langCode = langCode.substr(0, 2)
langCode = langCode.replace('zh', 'cn')
if (langCode) {
return langCode
}
}
}
}

View File

@@ -0,0 +1,46 @@
<template>
<div>
<!-- <el-link class="el-link" target="_blank" @click="goToTickets">{{ $t('route.Ticket') }}</el-link>-->
<el-badge :value="assignedTicketCount" :hidden="assignedTicketCount===0" size="mini" type="primary">
<el-link class="el-link" target="_blank" @click="goToTickets">{{ $t('route.Ticket') }}</el-link>
</el-badge>
</div>
</template>
<script>
import { getTicketOpenCount } from '@/api/ticket'
export default {
name: 'WebTerminal',
data() {
return {
assignedTicketCount: 0
}
},
created() {
this.ticketsOpenedCount()
},
methods: {
ticketsOpenedCount() {
getTicketOpenCount(1).then(data => {
this.assignedTicketCount = data.count
})
},
goToTickets() {
this.$router.push({ name: 'TicketList' })
}
}
}
</script>
<style scoped>
.el-link {
color: #606266 !important;
font-size: 13px;
font-weight: 400
}
.el-badge ::v-deep .el-badge__content.is-fixed{
top:10px;
}
</style>

View File

@@ -0,0 +1,24 @@
<template>
<el-link class="el-link" :href="webTerminalUrl" target="_blank">{{ $t('route.WebTerminal') }}</el-link>
</template>
<script>
import { BASE_URL } from '@/utils/common'
export default {
name: 'WebTerminal',
computed: {
webTerminalUrl() {
return `${BASE_URL}/luna/?_=${Date.now()}`
}
}
}
</script>
<style scoped>
.el-link {
color: #606266 !important;
font-size: 13px;
font-weight: 400
}
</style>

View File

@@ -10,6 +10,19 @@
<div class="header-item">
<Language />
</div>
<div
v-if="
publicSettings.TICKETS_ENABLED
&& publicSettings.XPACK_LICENSE_IS_VALID
&& !isOrgAuditor
"
class="header-item"
>
<Tickets />
</div>
<div class="header-item">
<WebTerminal />
</div>
<div class="header-item header-profile">
<AccountDropdown />
</div>
@@ -23,6 +36,9 @@ import Hamburger from '@/components/Hamburger'
import AccountDropdown from './AccountDropdown'
import Help from './Help'
import Language from './Language'
import WebTerminal from './WebTerminal'
import Tickets from './Tickets'
import rolc from '@/utils/role'
export default {
components: {
@@ -30,7 +46,9 @@ export default {
Hamburger,
AccountDropdown,
Language,
Help
Help,
Tickets,
WebTerminal
},
data() {
return {
@@ -38,8 +56,11 @@ export default {
},
computed: {
...mapGetters([
'sidebar'
])
'sidebar', 'publicSettings', 'currentOrgRoles'
]),
isOrgAuditor() {
return rolc.getRolesDisplay(this.currentOrgRoles).includes('OrgAuditor') || rolc.getRolesDisplay(this.currentOrgRoles).includes('Auditor')
}
},
methods: {
toggleSideBar() {

View File

@@ -0,0 +1,64 @@
<template>
<div v-if="!loading">
<el-alert v-if="isExpire" type="error">
{{ isExpire }}
</el-alert>
</div>
</template>
<script>
import { toSafeLocalDateStr } from '@/utils/common'
import { mapGetters } from 'vuex'
export default {
name: 'LicenseExpireTip',
data() {
return {
loading: true,
licenseData: {}
}
},
computed: {
...mapGetters([
'publicSettings',
'currentUser'
]),
isExpire() {
if (!this.publicSettings.XPACK_ENABLED || this.currentUser.role !== 'Admin') {
return false
}
const intervalDays = this.getIntervalDays(this.licenseData.date_expired)
if (intervalDays < 0) {
return this.$t('setting.LicenseExpired')
}
if (intervalDays < 7) {
return this.$t('setting.LicenseWillBe') + this.licenseData.date_expired + this.$t('setting.Expire')
}
return false
}
},
mounted() {
if (this.publicSettings.XPACK_ENABLED && this.currentUser.role === 'Admin') {
this.$axios.get('/api/v1/xpack/license/detail').then(res => {
this.licenseData = res
}).finally(() => {
this.loading = false
})
} else {
this.loading = false
}
},
methods: {
getIntervalDays(date) {
const dateExpired = new Date(toSafeLocalDateStr(date))
const dateNow = new Date()
const intervalTime = dateExpired.getTime() - dateNow.getTime()
return Math.floor(intervalTime / (24 * 3600 * 1000))
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,22 +1,34 @@
<template>
<div class="page-heading">
<el-row :gutter="0">
<el-col :span="16" class="page-heading-left">
<slot><h2>{{ title }}</h2></slot>
</el-col>
<el-col :span="8">
<div class="page-heading-right">
<slot name="rightSide" />
</div>
</el-col>
</el-row>
<div>
<slot name="globalNotification">
<LicenseExpireTip />
<PasswordExpireTip />
</slot>
<div class="page-heading">
<el-row :gutter="0">
<el-col :span="16" class="page-heading-left">
<slot><h2>{{ title }}</h2></slot>
</el-col>
<el-col :span="8">
<div class="page-heading-right">
<slot name="rightSide" />
</div>
</el-col>
</el-row>
</div>
</div>
<!-- <Breadcrumb />-->
</template>
<script>
import LicenseExpireTip from '@/layout/components/Page/LicenseExpireTip'
import PasswordExpireTip from '@/layout/components/Page/PasswordExpireTip'
export default {
name: 'PageHeading',
components: {
LicenseExpireTip,
PasswordExpireTip
},
props: {
title: {
type: String,

View File

@@ -0,0 +1,55 @@
<template>
<div>
<el-alert v-if="isExpire" type="error">
{{ isExpire }}
</el-alert>
</div>
</template>
<script>
import { toSafeLocalDateStr } from '@/utils/common'
import { mapGetters } from 'vuex'
export default {
name: 'PasswordExpireTip',
data() {
return {
loading: true,
securityData: {}
}
},
computed: {
...mapGetters([
'publicSettings',
'currentUser'
]),
isExpire() {
// 用户来源不是Local时不显示密码过期提示
if (this.currentUser.source !== 'local') {
return false
}
const intervalTime = this.getIntervalDays(this.currentUser.date_password_last_updated)
const securityPasswordExpirationTime = this.publicSettings.SECURITY_PASSWORD_EXPIRATION_TIME
if (intervalTime >= securityPasswordExpirationTime) {
return this.$t('users.passwordExpired')
}
if (securityPasswordExpirationTime - intervalTime <= 5) {
return this.$t('users.passwordWillExpiredPrefixMsg') + (securityPasswordExpirationTime - intervalTime) + this.$t('users.passwordWillExpiredSuffixMsg')
}
return false
}
},
methods: {
getIntervalDays(date) {
const dateExpired = new Date(toSafeLocalDateStr(date))
const dateNow = new Date()
const intervalTime = dateNow.getTime() - dateExpired.getTime()
return Math.floor(intervalTime / (24 * 3600 * 1000))
}
}
}
</script>
<style scoped>
</style>

View File

@@ -9,7 +9,14 @@
<div>
<el-tabs v-if="submenu.length > 0" slot="submenu" v-model="iActiveMenu" class="page-submenu" @tab-click="handleTabClick">
<el-tab-pane v-for="item in submenu" :key="item.name" :label="item.title" :label-content="item.labelContent" :name="item.name" />
<template v-for="item in submenu">
<el-tab-pane :key="item.name" :label-content="item.labelContent" :name="item.name">
<span slot="label">
{{ item.title }}
<slot name="badge" :tab="item.name" />
</span>
</el-tab-pane>
</template>
</el-tabs>
<transition name="fade-transform" mode="out-in">
<slot />

View File

@@ -77,7 +77,7 @@ export default {
position: relative;
overflow: hidden;
width: 100%;
/deep/ {
::v-deep {
.el-scrollbar__bar {
bottom: 0px;
}

View File

@@ -1,32 +1,41 @@
import i18n from '@/i18n/i18n'
import empty from '@/layout/empty'
export default [
{
path: 'remote-apps',
name: 'RemoteAppList',
component: () => import('@/views/applications/RemoteApp/RemoteAppList'),
meta: { title: i18n.t('route.RemoteApp'), licenseRequired: true }
},
{
path: 'remote-apps/create',
name: 'RemoteAppCreate',
component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'),
meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps', action: 'create', licenseRequired: true },
hidden: true
},
{
path: 'remote-apps/:id/update',
name: 'RemoteAppUpdate',
component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'),
meta: { title: i18n.t('route.RemoteAppUpdate'), activeMenu: '/applications/remote-apps', action: 'update', licenseRequired: true },
hidden: true
},
{
path: 'remote-apps/:id',
name: 'RemoteAppDetail',
component: () => import('@/views/applications/RemoteApp/RemoteAppDetail/index'),
meta: { title: i18n.t('route.RemoteAppDetail'), activeMenu: '/applications/remote-apps', licenseRequired: true },
hidden: true
redirect: '',
component: empty,
meta: { title: i18n.t('route.RemoteApp'), licenseRequired: true },
children: [
{
path: '',
name: 'RemoteAppList',
meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps' },
component: () => import('@/views/applications/RemoteApp/RemoteAppList')
},
{
path: 'create',
name: 'RemoteAppCreate',
component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'),
meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps', action: 'create' },
hidden: true
},
{
path: ':id/update',
name: 'RemoteAppUpdate',
component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'),
meta: { title: i18n.t('route.RemoteAppUpdate'), activeMenu: '/applications/remote-apps', action: 'update' },
hidden: true
},
{
path: ':id',
name: 'RemoteAppDetail',
component: () => import('@/views/applications/RemoteApp/RemoteAppDetail/index'),
meta: { title: i18n.t('route.RemoteAppDetail'), activeMenu: '/applications/remote-apps' },
hidden: true
}
]
},
{
path: 'database-apps',
@@ -54,5 +63,32 @@ export default [
component: () => import('@/views/applications/DatabaseApp/DatabaseAppDetail/index'),
meta: { title: i18n.t('route.DatabaseAppDetail'), activeMenu: '/applications/database-apps' },
hidden: true
},
{
path: 'kubernetes-apps',
name: 'KubernetesAppList',
component: () => import('@/views/applications/KubernetesApp/KubernetesAppList'),
meta: { title: i18n.t('route.KubernetesApp') }
},
{
path: 'kubernetes-apps/create',
name: 'KubernetesAppCreate',
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
meta: { title: i18n.t('route.KubernetesAppCreate'), activeMenu: '/applications/kubernetes-apps', action: 'create' },
hidden: true
},
{
path: 'kubernetes-apps/:id/update',
name: 'KubernetesAppUpdate',
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
meta: { title: i18n.t('route.KubernetesAppUpdate'), activeMenu: '/applications/kubernetes-apps', action: 'update' },
hidden: true
},
{
path: 'kubernetes-apps/:id',
name: 'KubernetesAppDetail',
component: () => import('@/views/applications/KubernetesApp/KubernetesAppDetail/index'),
meta: { title: i18n.t('route.KubernetesAppDetail'), activeMenu: '/applications/kubernetes-apps' },
hidden: true
}
]

View File

@@ -12,7 +12,7 @@ export default [
path: '',
name: 'AssetList',
component: () => import('@/views/assets/Asset/AssetList.vue'),
meta: { title: i18n.t('route.AssetList') }
meta: { title: i18n.t('route.AssetList'), activeMenu: '/assets/assets' }
},
{
path: 'create',
@@ -34,6 +34,13 @@ export default [
component: () => import('@/views/assets/Asset/AssetCreateUpdate.vue'),
meta: { title: i18n.t('route.AssetUpdate'), activeMenu: '/assets/assets' },
hidden: true
},
{
path: 'detail/:id/update',
name: 'AssetMoreInformationEdit',
component: () => import('@/views/assets/Asset/AssetMoreInformationEdit.vue'),
meta: { title: i18n.t('common.UpdateAssetDetail'), activeMenu: '/assets/assets' },
hidden: true
}
]
},
@@ -47,7 +54,7 @@ export default [
path: '',
name: 'DomainList',
component: () => import('@/views/assets/Domain/DomainList.vue'),
meta: { title: i18n.t('route.DomainList') }
meta: { title: i18n.t('route.DomainList'), activeMenu: '/assets/domains' }
},
{
path: 'create',
@@ -104,7 +111,7 @@ export default [
path: '',
name: 'AdminUserList',
component: () => import('@/views/assets/AdminUser/AdminUserList'),
meta: { title: i18n.t('route.AdminUserList') }
meta: { title: i18n.t('route.AdminUserList'), activeMenu: '/assets/admin-users' }
},
{
path: 'create',
@@ -174,7 +181,7 @@ export default [
path: '',
name: 'CommandFilterList',
component: () => import('@/views/assets/CommandFilter/CommandFilterList.vue'),
meta: { title: i18n.t('route.CommandFilterList') }
meta: { title: i18n.t('route.CommandFilterList'), activeMenu: '/assets/cmd-filters' }
},
{
path: ':id/update',
@@ -265,7 +272,7 @@ export default [
path: '',
name: 'LabelList',
component: () => import('@/views/assets/Label/LabelList.vue'),
meta: { title: i18n.t('route.LabelList') }
meta: { title: i18n.t('route.LabelList'), activeMenu: '/assets/labels' }
},
{
path: 'create',

View File

@@ -105,6 +105,7 @@ export const allRoleRoutes = [
component: Layout,
redirect: '/applications/remote-apps/',
name: 'applications',
alwaysShow: true,
meta: { title: i18n.t('route.Applications'), icon: 'th' },
children: ApplicationsRoute
},
@@ -129,6 +130,7 @@ export const allRoleRoutes = [
component: Layout,
redirect: '/ops/tasks/',
name: 'JobCenter',
alwaysShow: true,
meta: { title: i18n.t('route.JobCenter'), icon: 'coffee' },
children: OpsRoutes
},
@@ -138,8 +140,12 @@ export const allRoleRoutes = [
component: Layout,
redirect: '/tickets/tickets/',
children: TicketsRoutes,
hidden: true,
meta: {
licenseRequired: true
// hidden: ({ settings }) => {
// return !settings.TICKETS_ENABLED
// }
}
},
{

View File

@@ -1,4 +1,6 @@
import i18n from '@/i18n/i18n'
import rolec from '@/utils/role'
import { BASE_URL } from '@/utils/common'
export default [
{
@@ -32,7 +34,7 @@ export default [
path: 'command-executions/create',
name: 'BatchCommand',
component: () => import('@/views/ops/CommandExecution'),
meta: { title: i18n.t('route.BatchCommand'), commandExecutionRequired: true }
meta: { title: i18n.t('route.BatchCommand'), hidden: ({ settings }) => !settings.SECURITY_COMMAND_EXECUTION }
},
// {
// path: 'celery/task/:id',
@@ -42,9 +44,9 @@ export default [
// meta: { title: i18n.t('route.CeleryTaskLog') }
// },
{
path: 'task/monitor',
path: `${BASE_URL}/core/flower?_=${Date.now()}`,
name: 'TaskMonitor',
component: () => window.open(`/core/flower?_=${Date.now()}`),
meta: { title: i18n.t('route.TaskMonitor') }
// component: () => window.open(`/core/flower?_=${Date.now()}`),
meta: { title: i18n.t('route.TaskMonitor'), permissions: [rolec.PERM_SUPER] }
}
]

View File

@@ -1,4 +1,5 @@
import i18n from '@/i18n/i18n'
import empty from '@/layout/empty'
const assetPermissionRoutes = [
{
@@ -30,68 +31,45 @@ const assetPermissionRoutes = [
}
]
const remoteAppPermissionRoutes = [
const ApplicationPermissionRoutes = [
{
path: 'remote-app-permissions',
name: 'RemoteAppPermissionList',
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionList'),
meta: { title: i18n.t('route.RemoteAppPermission') }
},
{
path: 'remote-app-permissions/create',
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'),
name: 'RemoteAppPermissionCreate',
hidden: true,
meta: { title: i18n.t('route.RemoteAppPermissionCreate'), activeMenu: '/perms/remote-app-permissions', action: 'create' }
},
{
path: 'remote-app-permissions/update',
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'),
name: 'RemoteAppPermissionUpdate',
hidden: true,
meta: { title: i18n.t('route.RemoteAppPermissionUpdate'), activeMenu: '/perms/remote-app-permissions', action: 'update' }
},
{
path: 'remote-app-permissions/:id',
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionDetail/index'),
name: 'RemoteAppPermissionDetail',
hidden: true,
meta: { title: i18n.t('route.RemoteAppPermissionDetail'), activeMenu: '/perms/remote-app-permissions' }
path: 'app-permissions',
component: empty,
meta: { title: i18n.t('route.ApplicationPermission') },
redirect: '',
children: [
{
path: '',
name: 'ApplicationPermissionList',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionList'),
meta: { title: i18n.t('route.ApplicationPermission'), activeMenu: '/perms/app-permissions' }
},
{
path: 'create',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionCreateUpdate'),
name: 'ApplicationPermissionCreate',
hidden: true,
meta: { title: i18n.t('route.ApplicationPermissionCreate'), activeMenu: '/perms/app-permissions', action: 'create' }
},
{
path: ':id',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionDetail/index'),
name: 'ApplicationPermissionDetail',
hidden: true,
meta: { title: i18n.t('route.ApplicationPermissionDetail'), activeMenu: '/perms/remote-app-permissions' }
},
{
path: ':id/update',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionCreateUpdate'),
name: 'ApplicationPermissionUpdate',
hidden: true,
meta: { title: i18n.t('route.ApplicationPermissionUpdate'), activeMenu: '/perms/app-permissions', action: 'update' }
}]
}
]
const databasePermissionRoutes = [
{
path: 'database-app-permissions',
name: 'DatabaseAppPermissionList',
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionList'),
meta: { title: i18n.t('route.DatabaseAppPermission') }
},
{
path: 'database-app-permissions/create',
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionCreateUpdate'), // Parent router-view
name: 'DatabaseAppPermissionCreate',
hidden: true,
meta: { title: i18n.t('route.DatabaseAppPermissionCreate'), activeMenu: '/perms/database-app-permissions' }
},
{
path: 'database-app-permissions/update',
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionCreateUpdate'), // Parent router-view
name: 'DatabaseAppPermissionUpdate',
hidden: true,
meta: { title: i18n.t('route.DatabaseAppPermissionUpdate'), activeMenu: '/perms/database-app-permissions', action: 'update' }
},
{
path: 'database-app-permissions/:id',
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionDetail/index'),
name: 'DatabaseAppPermissionDetail',
hidden: true,
meta: { title: i18n.t('route.DatabaseAppPermissionDetail'), activeMenu: '/perms/database-app-permissions' }
}
]
export default [
... assetPermissionRoutes,
... remoteAppPermissionRoutes,
... databasePermissionRoutes
... ApplicationPermissionRoutes
]

View File

@@ -1,5 +1,8 @@
import i18n from '@/i18n/i18n'
import rolec from '@/utils/role'
import empty from '@/layout/empty'
import { BASE_URL } from '@/utils/common'
export default [
{
path: 'session',
@@ -21,70 +24,79 @@ export default [
hidden: true
},
{
path: 'luna',
path: `${BASE_URL}/luna/?_=${Date.now()}`,
name: 'WebTerminal',
component: () => window.open(`/luna/?_=${Date.now()}`),
// component: () => window.open(`/luna/?_=${Date.now()}`),
meta: { title: i18n.t('route.WebTerminal') }
// hidden: true
},
{
path: 'sftp',
path: `${BASE_URL}/koko/elfinder/sftp/?`,
name: 'FileManager',
component: () => window.open(`/koko/elfinder/sftp/?`),
// component: () => window.open(`/koko/elfinder/sftp/?`),
meta: { title: i18n.t('route.FileManager') }
},
{
path: 'terminal',
name: 'TerminalList',
component: () => import('@/views/sessions/TerminalList'),
meta: { title: i18n.t('route.Terminal') }
},
{
path: 'terminals/:id',
name: 'TerminalDetail',
component: () => import('@/views/sessions/TerminalDetail'),
meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' },
hidden: true
},
{
path: 'terminals/:id/update',
name: 'TerminalUpdate',
component: () => import('@/views/sessions/TerminalUpdate'),
meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' },
hidden: true
component: empty,
redirect: '',
meta: { title: i18n.t('route.Terminal'), permissions: [rolec.PERM_SUPER] },
children: [
{
path: '',
name: 'TerminalList',
component: () => import('@/views/sessions/TerminalList'),
meta: { title: i18n.t('route.Terminal') }
},
{
path: ':id',
name: 'TerminalDetail',
component: () => import('@/views/sessions/TerminalDetail'),
meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' },
hidden: true
},
{
path: ':id/update',
name: 'TerminalUpdate',
component: () => import('@/views/sessions/TerminalUpdate'),
meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' },
hidden: true
}
]
},
{
path: 'storages',
name: 'Storage',
component: () => import('@/views/sessions/Storage/index'),
meta: { activeMenu: '/terminal/terminal' },
meta: { activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true
},
{
path: 'replay-storage/create',
name: 'CreateReplayStorage',
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal' },
meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true
},
{
path: 'command-storage/create',
name: 'CreateCommandStorage',
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal' },
meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true
},
{
path: 'replay-storage/:id/update',
name: 'ReplayStorageUpdate',
component: () => import('@/views/sessions/ReplayStorageCreateUpdate'),
meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal' },
meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true
},
{
path: 'command-storage/:id/update',
name: 'CommandStorageUpdate',
component: () => import('@/views/sessions/CommandStorageCreateUpdate'),
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal' },
meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] },
hidden: true
}
]

View File

@@ -4,7 +4,8 @@ export default [
path: 'tickets',
name: 'TicketList',
component: () => import('@/views/tickets/TicketList'),
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o' }
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o', activeMenu: '/tickets/tickets' },
hidden: true
},
{
path: 'tickets/:id',
@@ -12,5 +13,19 @@ export default [
component: () => import('@/views/tickets/TicketDetail/index'),
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets' },
hidden: true
},
{
path: 'tickets/request-asset-perm/create',
name: 'RequestAssetPermTicketCreateUpdate',
component: () => import('@/views/tickets/RequestAssetPerm/RequestAssetPermTicketCreateUpdate'),
meta: { title: i18n.t('route.TicketCreate'), activeMenu: '/tickets/tickets' },
hidden: true
},
{
path: 'tickets/request-asset-perm/:id',
name: 'AssetsTicketDetail',
component: () => import('@/views/tickets/RequestAssetPerm/Detail/index'),
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets' },
hidden: true
}
]

View File

@@ -1,10 +1,7 @@
import Layout from '@/layout/index'
import i18n from '@/i18n/i18n'
import rolec from '@/utils/role'
const scheme = document.location.protocol
const port = document.location.port ? ':' + document.location.port : ''
const URL = scheme + '//' + document.location.hostname + port
import { BASE_URL } from '@/utils/common'
export default [
// 404 page must be placed at the end !!!
@@ -33,19 +30,26 @@ export default [
name: 'Apps',
component: Layout,
redirect: '/apps/remoteapp',
alwaysShow: true,
meta: { title: i18n.t('route.MyApps'), icon: 'th', permissions: [rolec.PERM_USE] },
children: [
{
path: '/apps/remoteapp',
name: 'MyRemoteApps',
component: () => import('@/userviews/apps/RemoteApp'),
meta: { title: i18n.t('route.RemoteApp'), permissions: [rolec.PERM_USE] }
meta: { title: i18n.t('route.RemoteApp'), permissions: [rolec.PERM_USE], licenseRequired: true }
},
{
path: '/apps/database',
name: 'MyDatebases',
component: () => import('@/userviews/apps/DatabaseApp'),
meta: { title: i18n.t('route.DatabaseApp'), permissions: [rolec.PERM_USE] }
},
{
path: '/apps/kubernetes',
name: 'MyKubernetes',
component: () => import('@/userviews/apps/KubernetesApp'),
meta: { title: i18n.t('route.KubernetesApp'), permissions: [rolec.PERM_USE] }
}
]
},
@@ -54,7 +58,7 @@ export default [
component: Layout,
meta: {
permissions: [rolec.PERM_USE],
commandExecutionRequired: true
hidden: ({ settings }) => !settings.SECURITY_COMMAND_EXECUTION
},
children: [
{
@@ -65,6 +69,49 @@ export default [
}
]
},
{
path: '/tickets',
component: Layout,
hidden: true,
meta: {
title: i18n.t('route.Tickets'),
icon: 'history',
permissions: [rolec.PERM_USE],
licenseRequired: true,
hidden: ({ settings }) => {
return !settings.TICKETS_ENABLED
}
},
children: [
{
path: '',
name: 'TicketList',
component: () => import('@/views/tickets/TicketList'),
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o', activeMenu: '/tickets', permissions: [rolec.PERM_USE] }
},
{
path: 'tickets/request-asset-perm/create',
name: 'RequestAssetPermTicketCreateUpdate',
component: () => import('@/views/tickets/RequestAssetPerm/RequestAssetPermTicketCreateUpdate'),
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
hidden: true
},
{
path: 'tickets/request-asset-perm/:id',
name: 'AssetsTicketDetail',
component: () => import('@/views/tickets/RequestAssetPerm/Detail/index'),
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
hidden: true
},
{
path: 'tickets/:id',
name: 'TicketDetail',
component: () => import('@/views/tickets/TicketDetail/index'),
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
hidden: true
}
]
},
{
path: `external-luna`,
component: Layout,
@@ -73,7 +120,7 @@ export default [
},
children: [
{
path: `${URL}/luna/`,
path: `${BASE_URL}/luna/`,
meta: { title: i18n.t('route.WebTerminal'), icon: 'window-maximize', activeMenu: '/assets', permissions: [rolec.PERM_USE] }
}
]
@@ -86,7 +133,7 @@ export default [
},
children: [
{
path: `${URL}/koko/elfinder/sftp/`,
path: `${BASE_URL}/koko/elfinder/sftp/`,
meta: { title: i18n.t('route.WebFTP'), icon: 'file', activeMenu: '/assets', permissions: [rolec.PERM_USE] }
}
]

View File

@@ -17,38 +17,26 @@ function hasPermission(roles, route) {
// console.log('Has route permission: ', route.path, requirePermsSum, userRolesSum, ' => ', has, roles)
return has
}
function hasLicense(licState, route) {
if (licState) {
return licState
function hasLicense(route, rootState) {
const licenseIsValid = rootState.settings.publicSettings.XPACK_LICENSE_IS_VALID
const licenseRequired = route.meta ? route.meta.licenseRequired : false
if (!licenseIsValid && licenseRequired) {
return false
}
let requireLic = route.meta ? route.meta.licenseRequired : null
if (!requireLic) {
requireLic = false
}
return licState === requireLic
return true
}
function hasCommand(cmdState, route) {
if (cmdState) {
return cmdState
}
let requireCmd = route.meta ? route.meta.commandExecutionRequired : null
if (!requireCmd) {
requireCmd = false
}
return cmdState === requireCmd
}
export function filterLicRoutes(routes, roles) {
export function filterLicenseRequiredRoutes(routes, rootState) {
const res = []
routes.forEach(route => {
const tmp = {
...route
}
if (hasLicense(roles, tmp)) {
if (hasLicense(route, rootState)) {
if (tmp.children) {
tmp.children = filterLicRoutes(tmp.children, roles)
tmp.children = filterLicenseRequiredRoutes(tmp.children, rootState)
}
res.push(tmp)
}
@@ -57,16 +45,24 @@ export function filterLicRoutes(routes, roles) {
return res
}
export function filterCmdRoutes(routes, roles) {
function isNeedHidden(route, rootState) {
let hidden = route.meta ? route.meta.hidden : false
if (typeof hidden === 'function') {
hidden = hidden({ route: route, settings: rootState.settings.publicSettings })
}
return hidden
}
export function filterHiddenRoutes(routes, rootState) {
const res = []
routes.forEach(route => {
const tmp = {
...route
}
if (hasCommand(roles, tmp)) {
if (!isNeedHidden(route, rootState)) {
if (tmp.children) {
tmp.children = filterCmdRoutes(tmp.children, roles)
tmp.children = filterHiddenRoutes(tmp.children, rootState)
}
res.push(tmp)
}
@@ -83,18 +79,18 @@ export function filterCmdRoutes(routes, roles) {
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
for (const route of routes) {
const tmp = {
...route
}
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
}
return res
}
@@ -113,10 +109,12 @@ const mutations = {
const actions = {
generateRoutes({ commit, rootState }, roles) {
return new Promise(resolve => {
console.log(rootState)
let accessedRoutes = filterAsyncRoutes(allRoleRoutes, roles)
accessedRoutes = filterCmdRoutes(accessedRoutes, rootState.settings.publicSettings.SECURITY_COMMAND_EXECUTION)
accessedRoutes = filterLicRoutes(accessedRoutes, rootState.settings.publicSettings.XPACK_LICENSE_IS_VALID)
accessedRoutes = filterHiddenRoutes(accessedRoutes, rootState)
accessedRoutes = filterLicenseRequiredRoutes(accessedRoutes, rootState)
if (accessedRoutes.length === 0) {
// console.log('No route find')
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})

View File

@@ -35,6 +35,10 @@ const actions = {
link.rel = 'shortcut icon'
link.href = response.data.LOGO_URLS.favicon
document.getElementsByTagName('head')[0].appendChild(link)
// 动态修改Title
if (response.data.LOGIN_TITLE) { document.title = response.data.LOGIN_TITLE }
commit('SET_PUBLIC_SETTINGS', response.data)
resolve(response)
}).catch(error => {

View File

@@ -37,6 +37,16 @@ const mutations = {
SET_ORGS: (state, orgs) => {
state.orgs = orgs
},
MODIFY_ORG: (state, org) => {
// console.log(state.orgs)
state.orgs = state.orgs.map(oldOrg => {
if (oldOrg.id === org.id) {
oldOrg.name = org.name
}
return oldOrg
}
)
},
ADD_ORG: (state, org) => {
state.orgs.push(org)
},
@@ -89,7 +99,7 @@ const actions = {
commit('SET_PROFILE', response)
resolve(response)
}).catch(error => {
console.log(error)
// console.log(error)
reject(error)
})
})
@@ -125,6 +135,9 @@ const actions = {
addAdminOrg({ commit, state }, org) {
commit('ADD_ORG', org)
},
modifyOrg({ commit, state }, org) {
commit('MODIFY_ORG', org)
},
// user logout
logout({ commit, state }) {
return new Promise((resolve, reject) => {

View File

@@ -96,7 +96,7 @@ td .el-button.el-button--mini {
font-weight: 600;
}
.el-button.el-button--default:focus:not(.is-disabled), .el-button.el-button--default:hover:not(.is-disabled) {
.el-button.el-button--default:hover:not(.is-disabled) {
color: #606266;
border-color: #d2d2d2;
background-color: #e6e6e6;
@@ -214,6 +214,10 @@ td .el-button.el-button--mini {
color: white;
}
.el-select-dropdown__item.is-disabled:hover{
color:#c0c4cc;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after {
color: $--color-primary;
}
@@ -431,7 +435,7 @@ a {
.el-button--danger.is-plain {
color: $--color-danger;
background: white;
background: #ffffff;
border-color: $--color-danger;
}

View File

@@ -148,3 +148,12 @@ input[type=file] {
font-size: 12px;
opacity: 80;
}
.el-table__body {
width: 100%;
table-layout: fixed !important;
}
.el-table__column-filter-trigger i {
color: #888888 !important;
}

View File

@@ -84,7 +84,7 @@ li.is-active {
// line-height: 30px !important;
//}
////重置字体大小 菜单宽度
//.el-submenu /deep/ .el-submenu__title, .submenu-title-noDropdown{
//.el-submenu ::v-deep .el-submenu__title, .submenu-title-noDropdown{
// height: 46px !important;
// line-height: 46px !important;
//}

View File

@@ -21,7 +21,7 @@ export default {
data() {
return {
tableConfig: {
url: `/api/v1/perms/users/database-apps/`,
url: `/api/v1/perms/users/applications/?category=db`,
columns: [
{
prop: 'name',
@@ -30,18 +30,19 @@ export default {
sortable: true
},
{
prop: 'get_type_display',
prop: 'type_display',
align: 'center',
label: this.$t('assets.Type')
},
{
prop: 'database',
prop: 'attrs.database',
align: 'center',
label: this.$t('assets.Database')
},
{
prop: 'comment',
align: 'center',
showOverflowTooltip: true,
label: this.$t('assets.Comment')
},
{
@@ -52,6 +53,7 @@ export default {
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'connect',
@@ -69,13 +71,13 @@ export default {
headerActions: {
hasExport: false,
hasImport: false,
hasRefresh: false,
hasRefresh: true,
hasCreate: false,
hasBulkDelete: false,
hasBulkUpdate: false,
hasLeftActions: false,
hasSearch: true,
hasRightActions: false
hasRightActions: true
}
}
},

View File

@@ -0,0 +1,96 @@
<template>
<Page>
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
</Page>
</template>
<script>
import ListTable from '@/components/ListTable/index'
import Page from '@/layout/components/Page/index'
import { ActionsFormatter } from '@/components/ListTable/formatters'
export default {
name: 'KubernetesApp',
components: {
ListTable,
Page
},
props: {
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/users/applications/?category=cloud`,
columns: [
{
prop: 'name',
align: 'center',
label: this.$t('assets.Name'),
sortable: true
},
{
prop: 'type_display',
align: 'center',
label: this.$t('assets.Type')
},
{
prop: 'attrs.cluster',
align: 'center',
label: this.$t('applications.cluster')
},
{
prop: 'comment',
align: 'center',
showOverflowTooltip: true,
label: this.$t('assets.Comment')
},
{
prop: 'id',
align: 'center',
label: this.$t('assets.Action'),
formatter: ActionsFormatter,
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'connect',
fa: 'fa-terminal',
type: 'primary',
callback: function({ row, col, cellValue, reload }) {
window.open(`/luna/?type=k8s_app&login_to=${cellValue}`, '_blank')
}
}
]
}
}
]
},
headerActions: {
hasExport: false,
hasImport: false,
hasRefresh: true,
hasCreate: false,
hasBulkDelete: false,
hasBulkUpdate: false,
hasLeftActions: false,
hasSearch: true,
hasRightActions: true
}
}
},
computed: {
},
mounted() {
},
methods: {
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -20,7 +20,7 @@ export default {
data() {
return {
tableConfig: {
url: `/api/v1/perms/users/remote-apps/`,
url: `/api/v1/perms/users/applications/?category=remote_app`,
columns: [
{
prop: 'name',
@@ -29,18 +29,19 @@ export default {
sortable: true
},
{
prop: 'get_type_display',
prop: 'type_display',
align: 'center',
label: this.$t('assets.RemoteType')
label: this.$t('assets.Type')
},
{
prop: 'asset_info.hostname',
prop: 'attrs.asset_info.hostname',
align: 'center',
label: this.$t('assets.Asset')
},
{
prop: 'comment',
align: 'center',
showOverflowTooltip: true,
label: this.$t('assets.Comment')
},
{
@@ -51,6 +52,7 @@ export default {
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'connect',
@@ -68,13 +70,13 @@ export default {
headerActions: {
hasExport: false,
hasImport: false,
hasRefresh: false,
hasRefresh: true,
hasCreate: false,
hasBulkDelete: false,
hasBulkUpdate: false,
hasLeftActions: false,
hasSearch: true,
hasRightActions: false
hasRightActions: true
}
}
},

View File

@@ -13,7 +13,7 @@ export default {
return {
allFavorites: [],
treeSetting: {
showMenu: true,
showMenu: false,
showRefresh: true,
showAssets: false,
url: '/api/v1/perms/users/assets/',
@@ -40,7 +40,7 @@ export default {
formatter: DialogDetailFormatter,
showOverflowTooltip: true,
formatterArgs: {
getDialogTile: function({ col, row, cellValue }) { this.$t('assets.AssetDetail') }.bind(this),
getDialogTitle: function({ col, row, cellValue }) { this.$t('assets.AssetDetail') }.bind(this),
getDetailItems: function({ col, row, cellValue }) {
return [
{
@@ -60,8 +60,12 @@ export default {
value: row.platform
},
{
key: this.$t('assets.Domain'),
value: row.domain
key: this.$t('common.Activate'),
value: row.is_active
},
{
key: this.$t('assets.Comment'),
value: row.comment
}
]
}.bind(this)
@@ -86,6 +90,12 @@ export default {
}
}
},
{
prop: 'comment',
label: this.$t('assets.Comment'),
showOverflowTooltip: true,
width: '180px'
},
{
prop: 'id',
align: 'center',
@@ -95,12 +105,16 @@ export default {
formatterArgs: {
hasDelete: false,
loading: true,
hasClone: false,
hasUpdate: false,
extraActions: [
{
name: 'connect',
fa: 'fa-terminal',
type: 'primary',
can: (row, cellValue) => {
return row.is_active
},
callback: function({ row, col, cellValue, reload }) {
window.open(`/luna/?login_to=${cellValue}`, '_blank')
}
@@ -121,7 +135,12 @@ export default {
]
}
}
]
],
tableAttrs: {
rowClassName({ row }) {
return !row.is_active ? 'row_disabled' : ''
}
}
},
headerActions: {
hasExport: false,
@@ -136,10 +155,10 @@ export default {
},
methods: {
refreshAllFavorites() {
this.tableConfig.columns[3].formatterArgs.loading = true
this.tableConfig.columns[4].formatterArgs.loading = true
this.$axios.get('/api/v1/assets/favorite-assets/').then(resp => {
this.allFavorites = resp
this.tableConfig.columns[3].formatterArgs.loading = false
this.tableConfig.columns[4].formatterArgs.loading = false
})
},
addOrDeleteFavorite(assetId) {
@@ -172,4 +191,11 @@ export default {
</script>
<style>
.el-card {
border: 0 !important;
}
.row_disabled,.row_disabled:hover,.row_disabled:hover > td{
cursor: not-allowed;
background-color:rgba(192,196,204,0.28) !important;
}
</style>

View File

@@ -8,6 +8,8 @@
:update-success-next-route="updateSuccessNextRoute"
:clean-form-value="cleanFormValue"
:get-method="getMethod"
:on-perform-success="onPerformSuccess"
:perform-submit="performSubmit"
/>
</IBox>
</template>
@@ -15,6 +17,7 @@
<script>
import GenericCreateUpdateForm from '@/layout/components/GenericCreateUpdateForm/index'
import { IBox } from '@/components'
import { Required } from '@/components/DataForm/rules'
export default {
name: 'ProfileUpdate',
@@ -68,9 +71,7 @@ export default {
label: this.$t('users.IAgree'),
type: 'checkbox',
checked: false,
rules: [
{ required: true }
],
rules: [Required],
helpText: this.$t('users.HelpText.MFAOfUserFirstLoginUserGuidePage')
}
},
@@ -87,6 +88,17 @@ export default {
methods: {
getMethod() {
return 'put'
},
performSubmit(validValues) {
if (!validValues.terms) {
this.$message.error(this.$t('common.PleaseAgreeToTheTerms'))
return Promise.reject()
}
return this.$axios['put'](this.url, validValues)
},
onPerformSuccess() {
this.$message.success(this.$t('common.updateSuccessMsg'))
setTimeout(() => this.$router.push({ name: 'UserGuide' }), 100)
}
}
}

View File

@@ -7,6 +7,7 @@
:url="url"
:get-method="getMethod"
class="password-update"
:update-success-next-route="updateSuccessNextRoute"
/>
</IBox>
</template>
@@ -50,6 +51,9 @@ export default {
type: 'password'
}
}
},
updateSuccessNextRoute: {
path: '/'
}
}
},

View File

@@ -7,7 +7,7 @@
<QuickActions type="primary" :actions="quickActions" />
</el-col>
</el-row>
</template>a
</template>
<script type="text/jsx">
import DetailCard from '@/components/DetailCard'
@@ -54,12 +54,39 @@ export default {
type: 'primary',
label: this.$t('common.Update')
},
has: this.object.mfa_enabled,
callbacks: {
click: function() {
window.location.href = `/core/auth/profile/otp/update/?next=${this.$route.fullPath}`
}.bind(this)
}
},
{
title: this.$t('users.UpdatePassword'),
attrs: {
type: 'primary',
label: this.$t('common.Update'),
disabled: this.$store.state.users.profile.source !== 'local'
},
callbacks: {
click: function() {
this.$emit('update:activeMenu', 'PasswordUpdate')
}.bind(this)
}
},
{
title: this.$t('users.UpdateSSHKey'),
attrs: {
type: 'primary',
label: this.$t('common.Update'),
disabled: this.$store.state.users.profile.source !== 'local'
},
callbacks: {
click: function() {
this.$emit('update:activeMenu', 'SSHUpdate')
}.bind(this)
}
},
{
title: this.$t('users.ResetPublicKeyAndDownload'),
attrs: {

View File

@@ -1,12 +1,14 @@
<template>
<IBox>
<GenericCreateUpdateForm
ref="GenericCreateUpdateForm"
:fields="fields"
:fields-meta="fieldsMeta"
:initial="object"
:url="url"
:get-method="getMethod"
:more-buttons="moreButtons"
:on-perform-success="onPerformSuccess"
/>
</IBox>
</template>
@@ -46,7 +48,8 @@ export default {
public_key: {
el: {
type: 'textarea',
placeholder: 'ssh-rsa AAAA...'
placeholder: 'ssh-rsa AAAA...',
autosize: { minRows: 3 }
},
helpText: this.$t('users.HelpText.SSHKeyOfProfileSSHUpdatePage')
}
@@ -64,6 +67,10 @@ export default {
methods: {
getMethod() {
return 'put'
},
onPerformSuccess() {
this.$refs.GenericCreateUpdateForm.$refs.form.$refs.dataForm.resetForm('form')
this.$message.success(this.$t('common.updateSuccessMsg'))
}
}
}

View File

@@ -1,7 +1,7 @@
<template>
<GenericDetailPage :object.sync="user" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
<keep-alive>
<component :is="config.activeMenu" :object="user" />
<component :is="config.activeMenu" :object="user" @update:activeMenu="handleUpdate" />
</keep-alive>
</GenericDetailPage>
</template>
@@ -60,6 +60,9 @@ export default {
])
}
return submenu
},
handleUpdate(value) {
this.config.activeMenu = value
}
}
}

View File

@@ -17,7 +17,7 @@ export function getCurrentRoleFromCookie() {
}
export function saveCurrentRoleToCookie(role) {
console.log('Save current role to cookie: ', role)
// console.log('Save current role to cookie: ', role)
return VueCookie.set(CURRENT_ROLE_KEY, role, 14)
}
@@ -26,7 +26,7 @@ export function getCurrentOrgFromCookie() {
try {
org = JSON.parse(VueCookie.get(CURRENT_ORG_KEY))
} catch (e) {
console.log('Current org in cookie: ', org)
// console.log('Current org in cookie: ', org)
}
return org
}

View File

@@ -65,12 +65,17 @@ function cleanDateStr(d) {
case 1:
d = d.split('+')[0].trimRight()
break
case 2:
d = d.replace(/-/g, '/')
}
}
return null
return d
}
export function toSafeLocalDateStr(d) {
if (d === '') {
return ''
}
const date = safeDate(d)
// let date_s = date.toLocaleString(getUserLang(), {hour12: false});
const date_s = date.toLocaleString(getUserLang(), { hourCycle: 'h23' })
@@ -136,6 +141,20 @@ export function getDaysAgo(days, now) {
return new Date(now.getTime() - 3600 * 1000 * 24 * days)
}
export function getDaysFuture(days, now) {
if (!now) {
now = new Date()
}
return new Date(now.getTime() + 3600 * 1000 * 24 * days)
}
export function getDayEnd(now) {
if (!now) {
now = new Date()
}
return new Date(new Date(now.toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1)
}
export function setUrlParam(url, name, value) {
const urlArray = url.split('?')
if (urlArray.length === 1) {
@@ -157,3 +176,16 @@ export function setUrlParam(url, name, value) {
}
return url
}
export function getDayFuture(days, now) {
if (!now) {
now = new Date()
}
return new Date(now.getTime() + 3600 * 1000 * 24 * days)
}
const scheme = document.location.protocol
const port = document.location.port ? ':' + document.location.port : ''
const BASE_URL = scheme + '//' + document.location.hostname + port
export { BASE_URL }

View File

@@ -1,4 +1,4 @@
import { hasUUID } from '@/utils/common'
import { hasUUID, BASE_URL } from '@/utils/common'
import store from '@/store'
function getPropOrg() {
@@ -36,17 +36,20 @@ function hasCurrentOrgPermission() {
return orgInList
}
function changeOrg(orgId) {
async function changeOrg(orgId) {
const org = getOrgIdMapper()[orgId]
if (!org) {
console.debug('Error: org not found')
} else {
console.debug('Change to org: ', org)
}
// 重置Role为空
await store.dispatch('users/setCurrentRole', null)
store.dispatch('users/setCurrentOrg', org).then(() => {
console.log('Set current org to: ', org)
// console.log('Set current org to: ', org)
if (hasUUID(location.href)) {
location.href = process.env.VUE_APP_PUBLIC_PATH
location.href = BASE_URL
} else {
window.location.reload(true)
}

View File

@@ -1,9 +1,10 @@
import axios from 'axios'
import i18n from '@/i18n/i18n'
import NProgress from 'nprogress' // progress bar
import { getTokenFromCookie } from '@/utils/auth'
import { refreshSessionIdAge } from '@/api/users'
import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import axiosRetry from 'axios-retry'
// create an axios instance
const service = axios.create({
@@ -13,11 +14,12 @@ const service = axios.create({
})
function beforeRequestAddToken(config) {
if (store.getters.token) {
const csrfToken = getTokenFromCookie()
if (csrfToken) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-CSRFToken'] = store.getters.token
config.headers['X-CSRFToken'] = csrfToken
}
if (store.getters.currentOrg) {
config.headers['X-JMS-ORG'] = store.getters.currentOrg.id
@@ -36,7 +38,7 @@ function beforeRequestAddTimezone(config) {
service.interceptors.request.use(
config => {
// do something before request is sent
NProgress.start()
// NProgress.start()
beforeRequestAddToken(config)
beforeRequestAddTimezone(config)
return config
@@ -49,9 +51,12 @@ service.interceptors.request.use(
)
function ifUnauthorized({ response, error }) {
if (response.status === 401 && response.request.url.indexOf('/users/profile') !== -1) {
if (response.status === 401) {
response.config.disableFlashErrorMsg = true
// 未授权重定向到登录页面
if (response.request.responseURL.indexOf('/users/profile/') !== -1) {
window.location = '/core/auth/login/'
return
}
const title = i18n.t('common.Info')
const msg = i18n.t('auth.LoginRequiredMsg')
MessageBox.confirm(msg, title, {
@@ -68,6 +73,13 @@ function ifBadRequest({ response, error }) {
if (response.status === 400) {
error.message = i18n.t('common.BadRequestErrorMsg')
}
if (response.status === 403) {
error.message = i18n.t('common.BadRoleErrorMsg')
}
if (response.status === 409) {
error.response.status = 409
error.message = i18n.t('common.BadConflictErrorMsg')
}
}
export function flashErrorMsg({ response, error }) {
@@ -85,6 +97,19 @@ export function flashErrorMsg({ response, error }) {
}
}
let timer = null
function refreshSessionAgeDelay(response) {
if (response.request.responseURL.indexOf('/users/profile/') !== -1) {
return
}
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
refreshSessionIdAge()
}, 60 * 10 * 1000)
}
// response interceptor
service.interceptors.response.use(
/**
@@ -98,7 +123,8 @@ service.interceptors.response.use(
* You can also judge the status by HTTP Status Code
*/
response => {
NProgress.done()
// NProgress.done()
refreshSessionAgeDelay(response)
const res = response.data
if (response.config.raw === 1) {
@@ -107,7 +133,7 @@ service.interceptors.response.use(
return res
},
error => {
NProgress.done()
// NProgress.done()
if (!error.response) {
return Promise.reject(error)
}
@@ -120,4 +146,9 @@ service.interceptors.response.use(
}
)
axiosRetry(service, {
// 默认不开启请求重试
retries: 0
})
export default service

View File

@@ -7,9 +7,9 @@ const PERM_SUPER = 0b10000000
const PERM_NONE = 0b00000000
const SUPER_ADMIN = PERM_SUPER | PERM_ADMIN | PERM_AUDIT
const SUPER_AUDITOR = PERM_SUPER | PERM_AUDIT
const SUPER_AUDITOR = PERM_SUPER | PERM_AUDIT | PERM_USE
const ORG_ADMIN = PERM_ADMIN | PERM_AUDIT
const ORG_AUDITOR = PERM_AUDIT
const ORG_AUDITOR = PERM_AUDIT | PERM_USE
const USER = PERM_USE
const ANON = PERM_NONE

View File

@@ -57,7 +57,7 @@ async function changeCurrentOrgIfNeed({ to, from, next }) {
}
const currentOrg = store.getters.currentOrg
if (!currentOrg || typeof currentOrg !== 'object') {
console.log('Not has current org')
// console.log('Not has current org')
orgUtil.change2PropOrg()
return reject('change prop org')
}

View File

@@ -10,10 +10,11 @@ export default {
},
data() {
return {
fields: [
[this.$t('common.Basic'), ['name', 'type']],
[this.$t('applications.mysql'), ['host', 'port', 'database']],
[this.$t('common.Others'), ['comment']]
[this.$t('common.Basic'), ['name', 'type', 'domain']],
[this.$t('applications.DBInfo'), ['attrs']],
[this.$t('common.Other'), ['comment']]
],
fieldsMeta: {
type: {
@@ -23,14 +24,56 @@ export default {
value: 'mysql'
}],
disabled: true
},
host: {
type: 'input'
},
domain: {
el: {
multiple: false,
clearable: true,
ajax: {
url: '/api/v1/assets/domains/'
}
}
}
},
url: '/api/v1/applications/database-apps/'
url: '/api/v1/applications/applications/',
getUrl() {
const params = this.$route.params
let url = `/api/v1/applications/applications/`
const method = this.getMethod()
if (params.id) {
url = `${url}${params.id}/`
}
return method === 'post' ? `${url}?type=${this.$route.query.type}` : `${url}?category=db`
},
performSubmit(validValues) {
const params = this.$route.params
const baseUrl = `/api/v1/applications/applications/`
const url = (params.id) ? `${baseUrl}${params.id}/` : baseUrl
const method = this.getMethod()
validValues.attrs = {
host: validValues.host,
port: validValues.port,
database: validValues.database
}
validValues.category = 'db'
return this.$axios[method](`${url}?type=${validValues.type}`, validValues)
}
}
},
computed: {
initial() {
return this.$route.query
},
getMethod() {
const params = this.$route.params
if (params.id) {
return 'put'
} else {
return 'post'
}
}
}
}

View File

@@ -33,19 +33,19 @@ export default {
},
{
key: this.$t('applications.type'),
value: this.object.get_type_display
value: this.object.type_display
},
{
key: this.$t('applications.host'),
value: this.object.host
value: this.object.attrs.host
},
{
key: this.$t('applications.port'),
value: JSON.stringify(this.object.port)
value: JSON.stringify(this.object.attrs.port)
},
{
key: this.$t('applications.database'),
value: this.object.database
value: this.object.attrs.database
},
{
key: this.$t('common.dateCreated'),

View File

@@ -19,7 +19,7 @@ export default {
data() {
return {
DatabaseApp: {
name: '', get_type_display: '', host: '', port: '', database: '', date_created: '', created_by: '', comment: ''
name: '', get_type_display: '', host: '', port: '', database: '', date_created: '', created_by: '', comment: '', attrs: ''
},
config: {
activeMenu: 'DatabaseAppDetail',
@@ -28,7 +28,11 @@ export default {
title: this.$t('route.DatabaseAppDetail'),
name: 'DatabaseAppDetail'
}
]
],
actions: {
detailApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`,
deleteApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`
}
}
}
}

View File

@@ -1,9 +1,10 @@
<template>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
<GenericListPage ref="GenericListTable" :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import { GenericListPage } from '@/layout/components'
import { mapGetters } from 'vuex'
export default {
components: {
@@ -12,18 +13,49 @@ export default {
data() {
return {
tableConfig: {
url: '/api/v1/applications/database-apps/',
url: '/api/v1/applications/applications/?category=db',
columns: [
'name', 'get_type_display', 'host', 'port', 'database', 'comment', 'actions'
'name', 'type_display', 'attrs.host', 'attrs.port', 'attrs.database', 'comment', 'actions'
],
columnsMeta: {
get_type_display: {
label: this.$t('applications.type')
type_display: {
label: this.$t('applications.type'),
width: '120px'
},
'attrs.host': {
label: this.$t('applications.host'),
width: '140px'
},
'attrs.port': {
label: this.$t('applications.port'),
width: '80px'
},
'attrs.database': {
label: this.$t('applications.database'),
showOverflowTooltip: true
},
actions: {
prop: '',
formatterArgs: {
hasClone: true,
performDelete: function({ row, col, cellValue, reload }) {
this.$axios.delete(
`/api/v1/applications/applications/${row.id}/`
).then(res => {
this.$refs.GenericListTable.$refs.ListTable.reloadTable()
// this.$message.success(this.$t('common.deleteSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.deleteErrorMsg' + ' ' + error))
})
}.bind(this)
}
}
}
},
headerActions: {
hasCreate: false,
hasExport: false,
hasImport: false,
hasBulkDelete: false,
createRoute: 'DatabaseAppCreate',
moreActionsTitle: this.$t('common.Create'),
@@ -33,16 +65,55 @@ export default {
name: 'MySQL',
title: 'MySQL',
type: 'primary',
can: true,
has: true,
callback: this.createMysql.bind(this)
},
{
name: 'PostgreSQL',
title: 'PostgreSQL',
type: 'primary',
has: this.isValidateLicense,
callback: this.createPostgreSQL.bind(this)
},
{
name: 'MariaDB',
title: 'MariaDB',
type: 'primary',
has: this.isValidateLicense,
callback: this.createMariaDB.bind(this)
},
{
name: 'Oracle',
title: 'Oracle',
type: 'primary',
has: this.isValidateLicense,
callback: this.createOracle.bind(this)
}
]
}
}
},
computed: {
...mapGetters(['publicSettings', 'currentOrg'])
},
methods: {
createMysql() {
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'mysql' }})
},
createPostgreSQL() {
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'postgresql' }})
},
createMariaDB() {
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'mariadb' }})
},
createOracle() {
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'oracle' }})
},
isValidateLicense() {
if (this.publicSettings.XPACK_ENABLED) {
return this.publicSettings.XPACK_LICENSE_IS_VALID
}
return false
}
}
}

View File

@@ -0,0 +1,76 @@
<template>
<GenericCreateUpdatePage v-bind="$data" />
</template>
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
export default {
components: {
GenericCreateUpdatePage
},
data() {
return {
initial: {
type: 'k8s'
},
fields: [
[this.$t('common.Basic'), ['name', 'type', 'domain']],
[this.$t('applications.kubernetes'), ['attrs']],
[this.$t('common.Other'), ['comment']]
],
fieldsMeta: {
type: {
disabled: true
},
cluster: {
helpText: this.$t('applications.clusterHelpTextMessage')
},
domain: {
el: {
multiple: false,
clearable: true,
ajax: {
url: '/api/v1/assets/domains/'
}
}
}
},
url: '/api/v1/applications/applications/',
getUrl() {
const params = this.$route.params
let url = `/api/v1/applications/applications/`
if (params.id) {
url = `${url}${params.id}/`
}
return `${url}?type=k8s`
},
performSubmit(validValues) {
const params = this.$route.params
const baseUrl = `/api/v1/applications/applications/`
const url = (params.id) ? `${baseUrl}${params.id}/` : baseUrl
const method = this.getMethod()
validValues.attrs = {
cluster: validValues.cluster
}
validValues.category = 'cloud'
return this.$axios[method](`${url}?type=${validValues.type}`, validValues)
}
}
},
computed: {
getMethod() {
const params = this.$route.params
if (params.id) {
return 'put'
} else {
return 'post'
}
}
}
}
</script>
<style lang="less" scoped>
</style>

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