Compare commits

...

1101 Commits

Author SHA1 Message Date
Bai
65392f1d0c perf: ZTree Search Input support select node or asset 2025-12-29 18:09:04 +08:00
Bai
777b139fde perf: modify create asset field nodes to node; modify user-detail-tree and workbench-tree 2025-12-26 18:03:39 +08:00
Bai
cccd2cbb7a perf: ztree filterTree, add shouldCollapseNodes 2025-12-24 16:48:24 +08:00
Bai
f75a4007f6 perf: ztree filterTree, default expand matchNodes parents, not include childrens 2025-12-24 16:31:33 +08:00
Bai
a9c1e06706 refactor: while search tree, re-initial ZTree use API data. 2025-12-23 18:47:52 +08:00
Bai
b66b779e79 perf: modify AssetTreeTable to async:false, and fix sync filter tree nodes expand all children 2025-12-22 18:50:23 +08:00
feng
841ba521f6 perf: assistant content 2025-12-12 10:17:18 +08:00
feng
d2feaa021e perf: Chat input tool switch css 2025-12-11 15:24:13 +08:00
feng
c231f66e4a perf: remove typeOptions 2025-12-10 18:36:42 +08:00
feng
7fe6ab5f1b perf: mcp tools 2025-12-10 18:17:38 +08:00
feng
c037b52bb6 perf: tools 2025-12-10 17:11:07 +08:00
feng
37a45cbc6e perf: thinking 2025-12-10 17:11:07 +08:00
github-actions[bot]
3d90d56373 perf: Update Dockerfile with new base image tag 2025-12-10 17:11:07 +08:00
feng
587f49286f perf: To kael 2025-12-10 17:11:07 +08:00
feng
5e1b32aaf9 perf: Open web ui settigns 2025-12-10 17:11:07 +08:00
feng
e1bc8245c9 fix: Ticket comment not display 2025-12-10 17:11:07 +08:00
w940853815
6b6de2b2c5 perf: Update asset detection logic in AccountRiskList for improved menu display 2025-12-10 17:11:07 +08:00
feng
7913979b4b perf: Account bulk error prompt 2025-12-10 17:11:07 +08:00
w940853815
16d8c7c9ac perf: Enhance error message handling for nested plain objects in getErrorResponseMsg 2025-12-10 17:11:07 +08:00
zhaojisen
768210ef86 Fixed: Fix the issue where the global organization text is not displayed completely in the organization dropdown. 2025-12-10 17:11:07 +08:00
w940853815
ce9d598683 fix: Ensure progress display is shown correctly during job execution 2025-12-10 17:11:07 +08:00
zhaojisen
2d75514aa1 Fixed: Fix the issue where creating an SSH public key for a third-party user redirects to the login password tab. 2025-12-10 17:11:07 +08:00
w940853815
669831c533 fix: Click Review to enter comments, and the page will be dimmed 2025-12-10 17:11:07 +08:00
w940853815
eb3f3ba441 perf: Add support for error message extraction from plain objects in getErrorResponseMsg 2025-12-10 17:11:07 +08:00
feng
46cf67e10f fix: Account push show params 2025-12-10 17:11:07 +08:00
w940853815
4e0b20b8e8 perf: Add condition to check node type in AccountRiskList for asset detection 2025-12-10 17:11:07 +08:00
w940853815
a6faad4b93 perf: Refactor error handling and improve parameter assignment in job forms 2025-12-10 17:11:07 +08:00
w940853815
cb51ccae61 perf: Improve error message formatting for array of strings 2025-12-10 17:11:07 +08:00
w940853815
5a9d94aad0 perf: Enhance AccountFormatter with options to exclude accounts 2025-12-10 17:11:07 +08:00
w940853815
69bdc7c0a2 perf: Job execution detail content add text-overflow class 2025-12-10 17:11:07 +08:00
w940853815
2441c08da5 perf: Support batch import of leak passwords 2025-12-10 17:11:07 +08:00
ibuler
f9c244f006 perf: small size some png 2025-12-10 17:11:07 +08:00
fit2bot
9c5ff2b3a8 perf: upgrade vue version (#5260)
* perf: upgrade vue version

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-10 17:11:07 +08:00
w940853815
91bfb4d723 perf: Add confirmation dialog before syncing platform protocols 2025-12-10 17:11:07 +08:00
feng
8d69418613 perf: Bulk account support node 2025-10-31 17:19:11 +08:00
w940853815
2d798053b3 perf: Translate select assets 2025-10-31 10:35:56 +08:00
ibuler
e48385c70e perf: revert keyword to search 2025-10-30 16:27:40 +08:00
fit2bot
4ed529bbfb perf: remove sub mod (#5254)
* perf: remove sub mod

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-10-30 15:23:58 +08:00
fit2bot
ca5350cc96 perf: update lodash version 2025-10-30 14:09:50 +08:00
w940853815
9046245cdb perf: Add header to file uploader with clear selection 2025-10-28 18:50:07 +08:00
fit2bot
991a512e85 perf: Optimize form uniqueness validation (#5250)
* perf: Optimize form uniqueness validation

* perf: Add some comments

* perf: check logical

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-10-28 16:41:49 +08:00
dependabot[bot]
6c008e3879 chore(deps): bump dompurify from 3.1.6 to 3.2.4
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.6 to 3.2.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.6...3.2.4)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.2.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 15:25:17 +08:00
zhaojisen
d16fbc3b13 Fixed: Fix ESLint errors 2025-10-27 14:38:12 +08:00
fit2bot
a0354e30c7 perf: org select style 2025-10-27 12:04:31 +08:00
mikebofs
0661bb0ea0 perf: all assets can add to zone 2025-10-24 10:39:09 +08:00
ibuler
e72fe04525 perf: add stat load helptip 2025-10-24 10:38:30 +08:00
feng
59cec3d6a9 perf: getDrawerTitle 2025-10-24 10:36:58 +08:00
w940853815
829f4ceaa4 fix: Replace alert with console.log for error handling 2025-10-22 18:22:51 +08:00
w940853815
b615e35e49 fix: Update help message rendering to use v-html for proper display 2025-10-22 14:59:55 +08:00
w940853815
cda282ac6b fix: Details page does not display labels. 2025-10-20 10:35:02 +08:00
w940853815
f2d44a2fd1 perf: Enhance email report success feedback with response message 2025-10-16 11:24:58 +08:00
w940853815
52f3ba012b perf: Hide vertical overflow in terminal display for improved UI 2025-10-16 10:11:32 +08:00
Chenyang Shen
d43e6a19bf Merge pull request #5236 from jumpserver/pr@dev@feat_add_tip_for_data_masking_form
feat: add fields tip for data masking form
2025-10-15 19:35:48 +08:00
Aaron3S
1f628e0d40 feat: add fields tip for data masking form 2025-10-15 19:33:47 +08:00
Chenyang Shen
9922a495eb Merge pull request #5235 from jumpserver/pr@dev@feat_update_column_show
feat: update data masking column show
2025-10-15 16:52:14 +08:00
Aaron3S
ae7549a00d feat: update data masking column show 2025-10-15 16:50:34 +08:00
Chenyang Shen
a5e870035e Merge pull request #5234 from jumpserver/pr@dev@feat_data_masking_license
feat: datamasking require license
2025-10-15 16:17:20 +08:00
Aaron3S
38f1ab3075 feat: datamasking require license 2025-10-15 16:15:10 +08:00
feng
c05248a1ab perf: Del remote account 2025-10-15 15:22:58 +08:00
w940853815
efacae517a perf: Add success message on successful update of system message subscription 2025-10-15 10:16:34 +08:00
Chenyang Shen
70b71a44d3 Merge pull request #5230 from jumpserver/pr@dev@feat_data_masking_detail
feat: add detail for data masking
2025-10-14 18:04:03 +08:00
Aaron3S
0ac220341e feat: add detail for data masking 2025-10-14 18:02:21 +08:00
w940853815
fc8fd2c8eb perf:Risk detection: When operating assets in batch, there is no prompt that the task is running 2025-10-14 16:49:39 +08:00
Chenyang Shen
f575eaafb6 Merge pull request #5228 from jumpserver/pr@dev@feat_change_some_translate
feat: change some translate
2025-10-14 16:05:06 +08:00
Aaron3S
2f79134023 feat: change some translate 2025-10-14 15:58:19 +08:00
feng
c59e6268b3 perf: remve chat fa-arrows-alt 2025-10-14 14:54:26 +08:00
w940853815
3344e01a9c perf: Asset selection optimization 2025-10-13 15:58:21 +08:00
zhaojisen
0a42031220 Fixed: Fix the issue where updating the SSH public key incorrectly redirects to a page. 2025-10-13 11:21:48 +08:00
feng
686e48f273 perf: Translate 2025-10-11 15:22:12 +08:00
w940853815
f16830adfe fix: In rule selection, the global organization will display all assets and users. 2025-10-11 10:52:51 +08:00
Chenyang Shen
be8d09b777 Merge pull request #5221 from jumpserver/pr@dev@feat_update_menu_name
feat: update menu name
2025-10-11 00:03:48 +08:00
Aaron3S
5ed2b6d9c8 feat: update menu name 2025-10-11 00:01:06 +08:00
feng
ece3ebc6e9 perf: Global can update and create ssh key 2025-10-09 18:01:55 +08:00
Aaron3S
1afd8dc934 feat: data masking 2025-10-09 10:39:05 +08:00
feng
a239060798 perf: Open web ui 2025-09-25 15:53:35 +08:00
w940853815
05032d6c78 perf: Remove useless code 2025-09-25 15:34:35 +08:00
w940853815
9dc35a603e perf: File transfer select asset component replacement 2025-09-25 15:34:35 +08:00
w940853815
43448aa482 perf: Style adjustment 2025-09-25 15:34:35 +08:00
w940853815
8887e98249 perf: Group platform 2025-09-25 15:34:35 +08:00
w940853815
43e4dcd760 perf: User checkbox select 2025-09-25 15:34:35 +08:00
w940853815
94d4be7555 perf: User checkbox select 2025-09-25 15:34:35 +08:00
w940853815
8210e2810f perf: Optimize the asset selection method of Adhoc 2025-09-25 15:34:35 +08:00
w940853815
05be6876f3 perf: Optimize file upload progress bar display 2025-09-22 17:39:01 +08:00
zhaojisen
38f8d88cdf Fixed: Fix the issue of incorrect form error messages 2025-09-22 14:14:43 +08:00
feng
3b0def17d7 perf: Translate 2025-09-22 11:21:24 +08:00
w940853815
57b0fa0b0e perf: Community edition hide report export button 2025-09-19 15:34:53 +08:00
w940853815
9611eb9c73 fix: Improve chart management by using a global _echarts object for tracking active charts 2025-09-17 19:02:24 +08:00
w940853815
a2bbb6555b fix: Optimize data fetching in AccountSummary and UserAssetActivity components 2025-09-17 18:01:03 +08:00
zhaojisen
ddd25208d8 Fixed: Fix the issue where error message prompts are being obscured. 2025-09-17 17:48:08 +08:00
w940853815
fe8db5831b fix: Edit template onPerformError error 2025-09-17 16:26:54 +08:00
feng
0c29ade399 perf: Compatible v3 ssh_key_change_strategy 2025-09-17 14:32:40 +08:00
zhaojisen
f8b2840d89 Fixed: Restore component update component settings logic 2025-09-17 14:11:40 +08:00
zhaojisen
52a18c3c35 Fixed: Fix the error reporting issue in risk detection review 2025-09-17 10:35:49 +08:00
w940853815
ace9cdcd68 perf: Translate msg template 2025-09-16 19:14:22 +08:00
w940853815
7098c2266e fix: Copy name field failed 2025-09-16 17:56:11 +08:00
w940853815
58d3489c33 fix: There is something wrong with the format of the site message 2025-09-16 17:56:11 +08:00
w940853815
396d20f31e fix: Remove priority fields in ACL components 2025-09-16 17:46:21 +08:00
zhaojisen
c8b866412a Fixed: Restore the logic for adding gateway lists 2025-09-16 17:33:13 +08:00
feng
63b163e382 perf: Translate 2025-09-16 16:14:46 +08:00
zhaojisen
e1acc642ca perf: Optimize the way connection methods are displayed in the table. 2025-09-16 11:35:45 +08:00
w940853815
e3f4cc68d2 fix: Export report pdf failed 2025-09-15 18:48:24 +08:00
w940853815
983aff62f2 fix: Update account existence check 2025-09-15 17:52:26 +08:00
zhaojisen
26e1ffdbdd Fixed: Fix Dashboard export issue on the Audit Workbench 2025-09-15 17:25:51 +08:00
zhaojisen
2002519f30 Fixed: Fix the issue of storage failure when updating components. 2025-09-15 14:40:58 +08:00
zhaojisen
c8f3e71d2c Fixed: Fixed the issue of failing to add a gateway in domain details. 2025-09-15 14:22:30 +08:00
w940853815
bd8f21e17a perf: Init template name 2025-09-12 18:32:13 +08:00
w940853815
0981b1854b perf: Remember select template 2025-09-12 18:32:13 +08:00
w940853815
94ab823b50 fix: Trim whitespace in email template content 2025-09-12 18:32:13 +08:00
w940853815
b378f41c07 fix: vue el-autocomplete flashes 2025-09-12 16:39:35 +08:00
zhaojisen
6cce077441 Confirm dialog for new announcement content 2025-09-11 17:11:40 +08:00
ibuler
361e522c5e perf: tag input min width 2025-09-11 16:53:26 +08:00
w940853815
08161c892e fix: LineChart component error 2025-09-11 15:09:05 +08:00
ibuler
39e4fdf40c perf: 优化 action btn 的大小 2025-09-11 15:03:37 +08:00
w940853815
11011f6b68 fix: Modify Dialog components import 2025-09-11 14:51:34 +08:00
mikebofs
7eb2e08f03 perf: add search place holder 2025-09-10 18:18:47 +08:00
w940853815
7d422bea51 perf: And license validation in msg template page 2025-09-10 17:24:58 +08:00
feng
3367ec624c perf: Ticket not display comment 2025-09-10 17:07:55 +08:00
fit2bot
091db8e6aa feat: setting email template content (#5173)
* feat: setting email template content

* perf: template list

* perf: show variable help text

* perf: custom template render to string

* perf: help text

* perf: update email template variable structure and improve formatting

* perf: Template content reset

* perf: typo MsgTemplate

* fix: email page error

* fix: package.json conflict

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: w940853815 <940853815@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 16:49:14 +08:00
feng
5d0f2c5c60 perf: Message zIndex 20000 2025-09-09 15:09:20 +08:00
feng
71b9e87786 perf: Update mysql db_name not required 2025-09-09 11:09:14 +08:00
fit2bot
ae0b3572f8 perf: Complete the search (#5175)
* perf: global search

* perf: Update Dockerfile with new base image tag

* perf: 完成基本搜索

* perf: show search direct

* perf: change search style

* perf: 优化 panel 格式,不再用 select

* perf: search add route

* perf: add route search

* perf: change view

* perf: add to body

* perf: 再次优化格式

* perf: 优化了一些显示

* perf: 基本完成搜索功能

* perf: 完成搜索

* perf: Update Dockerfile with new base image tag

* perf: merge with remote

---------

Co-authored-by: mikebofs <mikebofs@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: ibuler <ibuler@qq.com>
2025-09-05 17:23:37 +08:00
fit2bot
217a09ebd6 perf: global search (#5171)
* perf: global search

* perf: Update Dockerfile with new base image tag

* perf: 完成基本搜索

* perf: show search direct

* perf: change search style

* perf: 优化 panel 格式,不再用 select

* perf: search add route

* perf: add route search

* perf: change view

---------

Co-authored-by: ibuler <ibuler@qq.com>
2025-09-05 16:39:37 +08:00
w940853815
ca61a75997 perf: refine layout of card body to avoid affecting el-progress 2025-09-01 10:09:19 +08:00
ibuler
3310459b2c perf: reports menus 2025-08-28 15:08:20 +08:00
w940853815
b000ca46c9 perf: update event handler from rendered to finished in Echart component 2025-08-26 16:23:23 +08:00
mikebofs
36bdf6db2b perf: echarts to components 2025-08-26 16:23:23 +08:00
mikebofs
5f20a79c0a perf: support exclude some account on permission 2025-08-26 14:58:24 +08:00
zhaojisen
67eee7bb45 Fixed: Fix the issue where the number of exported items does not match the number of items selected. 2025-08-25 16:45:17 +08:00
feng
4b54c07a42 perf: Report menu perm 2025-08-22 18:51:32 +08:00
feng626
c907e158eb Merge pull request #5152 from jumpserver/pr@dev@dashboard_export
perf: export dashboard
2025-08-22 17:57:54 +08:00
feng626
7a7d41803c Merge branch 'dev' into pr@dev@dashboard_export 2025-08-22 17:57:19 +08:00
feng
b9604a6d02 perf: report perm 2025-08-22 17:50:32 +08:00
mikebofs
794b612b8b perf: change echarts define 2025-08-22 15:26:56 +08:00
mikebofs
8a965daa39 perf: remove line chart 2025-08-22 15:15:14 +08:00
mikebofs
c0705e72e3 perf: export dashboard 2025-08-22 14:42:04 +08:00
wrd
d755fd37bd fix: Account automation report show error 2025-08-21 22:18:36 +08:00
feng
14f41b886b perf: Translate 2025-08-21 18:52:14 +08:00
mikebofs
ed8e6b479f stash it 2025-08-21 18:25:18 +08:00
w940853815
f89b7ea7c4 fix: Enhance search and filter functionality with merged query support 2025-08-21 16:44:36 +08:00
w940853815
bfb668ef3c fix: User asset activity print error 2025-08-21 16:43:10 +08:00
mikebofs
c42e922d36 merge: with remote 2025-08-21 16:30:29 +08:00
w940853815
328926f924 perf: Msg appears immediately 2025-08-21 16:27:05 +08:00
mikebofs
cd6208674b perf: change export days 2025-08-21 16:20:45 +08:00
feng
568b2e4928 perf: add active state with font color highlight for chart menu 2025-08-21 16:00:13 +08:00
feng
d850f6f60a perf: Account template hasIport perm 2025-08-21 15:31:59 +08:00
mikebofs
fd7e32bbbd perf: export dashboard 2025-08-21 15:30:37 +08:00
zhaojisen
d84c403672 Fixed: change card page 2025-08-21 14:02:20 +08:00
zhaojisen
4cb322c72b Fixed: change paginationSize 2025-08-21 12:01:17 +08:00
zhaojisen
56b98b027b Fixed: Fixed the issue where no prompt message was displayed after successfully creating an organization. 2025-08-21 11:36:46 +08:00
feng
e3b4d43c76 perf: echars pie fontSize 15 2025-08-21 11:36:22 +08:00
feng
2b2e7d70ee perf: Role import update perms 2025-08-21 11:23:19 +08:00
w940853815
ab0aefb6cb perf: Set print layout to A4 landscape 2025-08-21 11:17:02 +08:00
zhaojisen
ac47c06e87 Fixed: Fix the issue of printing charts. 2025-08-21 10:59:41 +08:00
Bai
feb9c27ba7 fix: import table No.2 page data when edit it's show No.1 page data with same row No. 2025-08-21 10:58:19 +08:00
w940853815
c79ef68ce6 perf: Export pdf using days parameter 2025-08-21 10:39:40 +08:00
feng
8c986bf9af perf: change risk perm 2025-08-21 10:39:23 +08:00
feng
a983e490d0 perf: settings perms 2025-08-20 18:18:55 +08:00
feng
9802f04c5b perf: Translate 2025-08-20 18:17:24 +08:00
feng
5f1ff695f3 perf: Account template import perm 2025-08-20 17:41:37 +08:00
feng
42a89ad311 perf: account risk change perm 2025-08-20 17:26:28 +08:00
feng
6b0a6eb4a3 perf: settings perms 2025-08-20 17:11:37 +08:00
LastWise
3b10ba7263 perf: vue config 2025-08-20 17:08:39 +08:00
LastWise
b3f804374f perf: report width on print 2025-08-20 16:52:31 +08:00
feng
f1d0e0d70d perf: Translate 2025-08-19 15:30:12 +08:00
w940853815
431041b00e fix: Prevent query parameter update when event primary key is missing 2025-08-19 14:55:03 +08:00
feng
ff122acca0 perf: Pam rbac 2025-08-18 17:41:06 +08:00
fit2bot
0a58c4bbcc Fixed: Fixed the issue where command history was not being requested. (#5127) 2025-08-18 14:50:58 +08:00
w940853815
d55647998f fix: Profile improvement can be edited by mfa_level 2025-08-18 14:30:26 +08:00
w940853815
0f3cc9c0d5 perf: Send report email 2025-08-18 14:02:39 +08:00
feng
dce39288f4 perf: Action perm 2025-08-15 18:57:59 +08:00
w940853815
74a516f3b6 fix: Route click active css 2025-08-15 14:33:05 +08:00
feng
627073a95c perf: User report 2025-08-14 18:54:43 +08:00
feng
88af2516b8 perf: Donut chart style 2025-08-14 11:14:37 +08:00
feng
6df37b148b perf: report 2025-08-13 18:51:16 +08:00
zhaojisen
88610db1c3 Fixed: Fix issue where MFA dialog is not displayed 2025-08-13 16:11:43 +08:00
zhaojisen
13dcd09ccd Fixed: Fix the issue of the drawer opening to a blank display. 2025-08-13 11:04:46 +08:00
feng
de298991a9 fix: report 2025-08-12 19:19:15 +08:00
feng
168b1d593c perf: report css 2025-08-12 14:48:46 +08:00
zhaojisen
1a3643dc3c Fixed: Fix the issue where pressing Enter while creating a command filter group refreshes the page. 2025-08-11 16:15:59 +08:00
zhaojisen
dcf178a010 Fixed: Fixes an issue where creating or updating command rules fails due to command filtering. 2025-08-11 15:49:59 +08:00
feng
4676e3ded5 perf: Rbac pam 2025-08-08 11:56:31 +08:00
ibuler
1ad9438614 chore: reslove git conflict 2025-08-07 09:56:04 +08:00
w940853815
f2d87651d5 perf: Add comment, labels columns 2025-08-06 19:20:52 +08:00
feng
31f7814c0e perf: Account check drawer 2025-08-06 17:19:38 +08:00
fit2bot
ba57c00141 pref: move dashboard to report (#5032)
* perf: init report

* perf: stage1

* perf: base report

* perf: change report chatrt

* pref: move dashboard to report

* perf: Update Dockerfile with new base image tag

* perf: change secret to report

* perf: clean utils

* perf: change report

* perf: basic finished

* perf: change card

* perf: rename

* perf: revert name

* perf: revert name

* perf: Update Dockerfile with new base image tag

* perf: Use user report api

* perf: some open draw error

* perf: remote first

* perf: change password

* perf: Update Dockerfile with new base image tag

* perf: translate

* perf: Asset report

* perf: account report

* perf: Translate

* perf: Account automation

* perf: element-ui

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: w940853815 <940853815@qq.com>
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2025-08-06 14:06:45 +08:00
feng
912c93b1ac fix: new Date invalid 2025-08-05 22:04:44 +08:00
ibuler
db8d45c9e0 perf: global org display label width 2025-08-01 11:06:01 +08:00
zhaojisen
2b6aae4c0b Fixed: Fix word wrapping issues 2025-07-30 15:08:18 +08:00
ibuler
df585a32e4 perf: default code and table load twice 2025-07-29 19:04:15 +08:00
jiangweidong
d36f58b642 feat: Add an embedded form to ChatAI 2025-07-29 14:14:05 +08:00
ibuler
337b8e9115 perf: change asset permission create account 2025-07-29 14:02:16 +08:00
feng
fa11f7ac82 perf: Account backup support is_active 2025-07-29 11:31:46 +08:00
ibuler
91456fe216 perf: oidc setting 2025-07-29 10:19:40 +08:00
w940853815
b2c9255a53 fix: Replace Select2 component with AssetSelect for asset selection 2025-07-23 16:04:43 +08:00
zhaojisen
16a6e7b0e7 Fixed: Fix remote application style issues 2025-07-23 15:14:17 +08:00
feng
fe5825c44a perf: Pam rbac 2025-07-22 19:02:28 +08:00
w940853815
57b8fe3318 perf: Update email settings to use SECURITY_PROTOCOL instead of EMAIL_USE_SSL 2025-07-22 16:39:08 +08:00
zhaojisen
eb6fa2e982 Fixed: Fix issue where account authorization prevents modification of specified users. 2025-07-22 10:47:57 +08:00
jiangweidong
0636bb4805 feat: cloud sync support proxmox 2025-07-18 15:04:53 +08:00
fit2bot
e83e4420fd perf: Optimize remote application style layout (#5091) 2025-07-16 15:53:35 +08:00
w940853815
d51cdbb4a8 fix: Import ldap users use default org id 2025-07-16 10:48:48 +08:00
zhaojisen
80e42d12f3 Fixed: Fix the issue of direct connection organizations not synchronizing. 2025-07-15 20:23:21 +08:00
ibuler
958de2badf perf: add prettier config 2025-07-15 19:13:15 +08:00
w940853815
5efe66b481 fix: el-alert width css 2025-07-15 17:12:10 +08:00
w940853815
df69e93cca fix: Remove account date_expired 2025-07-15 16:57:42 +08:00
w940853815
4bd14e340c fix: View account be covered 2025-07-14 15:29:25 +08:00
w940853815
d5f8bc85f2 fix: Remove import btn in audit ticket list 2025-07-14 15:03:59 +08:00
zhaojisen
8d349a874b Fixed: Fix the issue where submitting without specifying an account in asset authorization defaults to all accounts. 2025-07-09 15:12:33 +08:00
zhaojisen
a1cc4c9263 fixed: remove log 2025-07-09 14:43:03 +08:00
github-actions[bot]
834073fae1 perf: Update Dockerfile with new base image tag 2025-07-09 14:43:03 +08:00
zhaojisen
2d5aa403a2 perf: Fix the issue where the recording size has no unit 2025-07-09 14:43:03 +08:00
w940853815
74fcd9e1db perf: Add account date_expired 2025-07-09 10:47:50 +08:00
github-actions[bot]
e90a3f701a perf: Update Dockerfile with new base image tag 2025-07-08 11:05:38 +08:00
halo
0a54151b9a perf: update elementui version 2025-07-08 11:05:38 +08:00
fit2bot
f310eb9855 perf: add tiket audit 2025-07-08 11:04:35 +08:00
jiangweidong
aa02a19793 perf: Optimize cloud sync strategy cannot search 2025-07-08 11:03:42 +08:00
w940853815
083b7762b1 fix: Prevent rendering of empty phone number in UserList 2025-06-30 10:55:45 +08:00
w940853815
b45257b284 perf: Translate 2025-06-27 16:58:37 +08:00
w940853815
d6051d6bcb perf: Add ID column in GrantedAssets page 2025-06-27 15:31:42 +08:00
w940853815
f8e7d12252 fix: Update time cost display and calculation interval 2025-06-27 15:02:00 +08:00
jiangweidong
8a74ce1d4b perf: Add a config to the cloud sync task: is always update. 2025-06-26 18:36:01 +08:00
zhaojisen
6715465dda Fixed: Tree icons 2025-06-26 15:20:53 +08:00
feng
aaca037e02 perf: Applet detail table 2025-06-25 11:07:02 +08:00
feng
d1552e67d1 perf: Translate 2025-06-23 11:05:47 +08:00
w940853815
926967111a fix: Delete gather account failed 2025-06-20 13:32:00 +08:00
w940853815
0b27a01013 fix: A scroll bar appears in the asset tree on the left side of the adhoc 2025-06-19 17:53:32 +08:00
feng
eb4aebf637 perf: Translate 2025-06-19 11:52:26 +08:00
ibuler
91eb4b1c0d perf: some create title 2025-06-18 20:17:55 +08:00
Eric
8614798362 perf: fix loading when upload applet or virtualapp 2025-06-18 18:56:49 +08:00
Eric
405054034b perf: fix chat action name i18n 2025-06-18 18:56:12 +08:00
w940853815
d8766e1bdb Revert "fix: A scroll bar appears in the asset tree on the left side of the a…"
This reverts commit 59d6df5dce.
2025-06-18 18:54:47 +08:00
Chenyang Shen
6b11d284da Merge pull request #5057 from jumpserver/pr@dev@perf_perf_face_verify_style
perf: perf face verify dialog style
2025-06-18 18:28:32 +08:00
Aaron3S
12b41f5abb perf: perf face verify dialog style 2025-06-18 18:25:44 +08:00
w940853815
398c8b0eb6 fix: There is a problem with task description typesetting in system task English mode. 2025-06-18 17:58:06 +08:00
w940853815
357f68b3d2 fix: Playbook template clone variable lose 2025-06-18 14:20:39 +08:00
zhaojisen
5d74b0cd84 Fixed: Fix the error where the number of password change attempts redirects incorrectly. 2025-06-18 13:20:53 +08:00
fit2bot
d72671d2c9 perf: add insert event (#5052)
* perf: add insert event

perf: receive insert code

perf: add content

perf: update code

perf: save panel to LocalStorage

* perf: only terminal add insert action

---------

Co-authored-by: Eric <xplzv@126.com>
2025-06-17 19:23:19 +08:00
w940853815
8f17fa82a2 fix: Adhoc template clone variable lose 2025-06-17 14:34:20 +08:00
Chenyang Shen
111957b6e6 Merge pull request #5050 from jumpserver/pr@dev@feat_remove_port_disabled
feat: remove oracle endpoint form field oracle_port disabled
2025-06-17 14:20:07 +08:00
Aaron3S
aa3292f988 feat: remove oracle endpoint form field oracle_port disabled 2025-06-17 14:18:40 +08:00
halo
cc0a72cecc perf: update message 2025-06-17 10:13:38 +08:00
halo
fae8b57456 feat: Add batch activation and disable options in account push tasks 2025-06-17 10:13:38 +08:00
zhaojisen
f2c3beff13 Fixed: Fix the issue of being able to replay magnus proxy's mongodb without recordings 2025-06-16 18:48:33 +08:00
Chenyang Shen
03790194ac Merge pull request #5046 from jumpserver/pr@dev@feat_add_endpoint_form_field
feat: add update endpoint form field
2025-06-16 18:24:51 +08:00
Aaron3S
2b5aebbc1b feat: add update endpoint form field 2025-06-16 18:10:36 +08:00
github-actions[bot]
6183f38d8a perf: Update Dockerfile with new base image tag 2025-06-16 17:59:54 +08:00
ewall555
29567c5392 feat: Remove vue-moment dependency, use moment library directly 2025-06-16 17:59:54 +08:00
Jackbewater
43f9b8cf68 perf: change secret add bulk action 2025-06-16 14:40:46 +08:00
w940853815
783070c74d fix: Improve text representation for boolean values in ChoicesFormatter 2025-06-16 14:33:33 +08:00
w940853815
59d6df5dce fix: A scroll bar appears in the asset tree on the left side of the adhoc. 2025-06-16 14:07:57 +08:00
w940853815
5fc93f61a2 perf: Clean up error message formatting in form validation 2025-06-16 11:08:54 +08:00
Eric
abee8aa7c9 perf: fix new chat click window 2025-06-16 11:08:13 +08:00
Eric
18d5194c38 perf: chat websocket init 2025-06-16 11:05:26 +08:00
ibuler
4f794d299a fix: bitwarden passkey reigster error 2025-06-16 10:58:53 +08:00
w940853815
623499b13b perf: Help text as tooltip for var_name field 2025-06-13 17:36:23 +08:00
feng
d48cb6b1f3 perf: Translate 2025-06-11 16:35:39 +08:00
zhaojisen
945ff8fc44 Fixed: Fix the issue of incomplete display of the action column in different languages 2025-06-11 15:07:21 +08:00
zhaojisen
3a823c786e Fixed: Fix the issue of platform list content exceeding the visible range and the problem of asset quantity not refreshing when renaming the node tree 2025-06-11 14:47:24 +08:00
zhaojisen
68a474644c Fix the issue of missing Oracle port in the endpoint order. 2025-06-11 11:25:16 +08:00
feng
c8b2ec9cdb perf: Translate 2025-06-10 19:14:42 +08:00
feng
67d4fdd175 perf: Change secret after successful login 2025-06-10 16:59:13 +08:00
feng
0f40b38abe perf: create account template secret type 2025-06-10 16:14:42 +08:00
w940853815
714350d40e fix: Update last published time field 2025-06-10 15:13:39 +08:00
w940853815
d6ac0db0e6 perf: Remove username hint 2025-06-09 17:00:09 +08:00
Chenyang Shen
ddae51cefc Merge pull request #5023 from jumpserver/pr@dev@feat_add_mongodb_endpoint
feat: add mongodb endpoint
2025-06-09 16:11:53 +08:00
Aaron3S
eb9f7c6cb5 feat: add mongodb endpoint 2025-06-09 16:09:46 +08:00
w940853815
a22f46087f perf: leak password can bulk delete 2025-06-06 17:09:34 +08:00
w940853815
2eedb361a0 perf: add SECURITY_EXPIRED_TOKEN_RECORD_KEEP_DAYS to password settings 2025-06-04 19:08:32 +08:00
w940853815
d893964947 perf: Language settings in personal settings 2025-05-29 11:13:35 +08:00
halo
13838f66a9 feat: Cloud sync support smartx 2025-05-28 15:12:25 +08:00
feng
6dccdae9b4 fix: login title does not exist 2025-05-23 11:02:26 +08:00
w940853815
3f31fa9810 fix: Community edition open watermark 2025-05-16 18:06:14 +08:00
w940853815
a17025bd3a fix: open monitor link in a new tab 2025-05-16 15:42:07 +08:00
ibuler
f08ce0ee1a perf: change session id width 2025-05-16 14:46:11 +08:00
ibuler
60634349ae perf: set timeout to 20 2025-05-14 19:31:43 +08:00
w940853815
14ce39116b fix: watermark line height 2025-05-14 17:46:59 +08:00
feng
edb6be1d51 perf: Applets drop account template 2025-05-14 16:18:27 +08:00
zhaojisen
8e2f79aea1 Fixed: Fix the issue of the account list tree being draggable. 2025-05-14 15:04:10 +08:00
w940853815
d6c4a9d2f6 perf: Confirm run assets ip display optimization 2025-05-13 14:38:28 +08:00
zhaojisen
d16a9f9d46 Fix the issue with the width of the menu tooltip. 2025-05-13 14:09:28 +08:00
zhaojisen
b817c7ac27 perf: Add directory services field to asset details. 2025-05-13 12:08:22 +08:00
jiangweidong
7a48949461 fix: Cloud account update strategy can only be selected from the same category 2025-05-13 10:48:44 +08:00
w940853815
f1bad07c67 fix: Update WeekCronSelect failed 2025-05-12 16:52:52 +08:00
zhaojisen
d2469f6313 Fixed: Fix the issue of the create asset button not being disabled under the global organization. 2025-05-12 16:14:20 +08:00
zhaojisen
f0ff8f7370 Fixed: Fix the issue of the asset type tree being draggable. 2025-05-12 15:27:54 +08:00
w940853815
37cf3d6b1a perf: Enhance WatermarkHelpDialog with session and console variables 2025-05-12 14:44:37 +08:00
ibuler
8bda898480 perf: confirm dialog btn 2025-05-09 18:58:13 +08:00
zhaojisen
4ca26c9104 Fixed: Fix the issue with the OAuth2 component. 2025-05-09 18:35:37 +08:00
zhaojisen
265b95fc9e Fixed: Fix the issue of the checked state not syncing after refreshing the page in the authentication settings. 2025-05-09 18:29:25 +08:00
ibuler
44619725c6 perf: update auth integration 2025-05-09 17:44:02 +08:00
ibuler
41ec908f37 perf: update auth intergration 2025-05-09 17:44:02 +08:00
zhaojisen
b5ea5b21fd Fixed: Fix the issue with the display error of the verification button. 2025-05-09 15:09:06 +08:00
jiangweidong
85763fa409 perf: Solve some problems with database sync 2025-05-09 11:20:28 +08:00
fit2bot
803c3cad7a feat: table columns support drag 2025-05-08 17:14:32 +08:00
feng
2323008079 perf: Add rdp error 2025-05-08 16:11:52 +08:00
zhaojisen
dcdcc5c557 Perf: Optimize the display of tabs on the authentication settings page 2025-05-08 11:33:23 +08:00
feng
a20d20dfce perf: connectivity choice 2025-05-07 17:51:06 +08:00
w940853815
8a72826050 feat: Add LeakPasswords config 2025-05-07 17:46:27 +08:00
w940853815
5c4aa457fa perf: Support watermark customization 2025-05-07 16:53:37 +08:00
ibuler
989b4d5695 perf: update confirm dialog 2025-05-07 16:25:18 +08:00
ibuler
0e89b8ac3f perf: mfa confirm support passkey 2025-05-07 14:39:55 +08:00
ibuler
efebf795e4 perf: asset permission accounts select 2025-04-30 14:57:39 +08:00
ibuler
fbdcd541e1 perf: revert click focus 2025-04-30 14:57:39 +08:00
ibuler
8e7d8370a1 perf: asset permission set 2025-04-30 14:57:39 +08:00
ibuler
73c593cc4e perf: asset permission set 2025-04-30 14:57:39 +08:00
w940853815
5b627350d8 fix: Show actions column by default in list view 2025-04-29 16:36:03 +08:00
feng
d634c76040 perf: connectivity meta icon 2025-04-27 18:50:44 +08:00
zhaojisen
55f7855cf8 Fixed: Fix the issue with direct connection for SFTP. 2025-04-27 11:17:27 +08:00
feng
f157ab9453 perf: ko translate 2025-04-25 15:03:49 +08:00
feng
49c80cd76b perf: gather facts gpu info 2025-04-22 17:48:29 +08:00
ibuler
cad15986bf perf: asset always can set zone 2025-04-21 10:36:41 +08:00
ibuler
9a0158da3a perf: change domain to zone 2025-04-21 10:36:41 +08:00
feng
deea38c704 perf: lina translate 2025-04-18 18:22:00 +08:00
ibuler
bc4fb455a3 perf: change profile api 2025-04-18 14:10:49 +08:00
O-Jiangweidong
411317194c feat: Cloud sync support ali rds (v4.10) 2025-04-18 14:08:08 +08:00
fit2bot
42e9fac6f0 Fixed: Fix the error issue with direct connection in asset authorization details. (#4973) 2025-04-17 20:10:54 +08:00
zhaojisen
82d618cc03 Fixed: Cloud Async Card Style 2025-04-17 17:55:26 +08:00
zhaojisen
9ebefdb1e8 Fixed: Account Cloud Style 2025-04-17 17:51:34 +08:00
feng
5943158b3b perf: asset exclude spec_info 2025-04-17 16:18:41 +08:00
ibuler
e8fe386c1b perf: ds add help message 2025-04-17 16:03:03 +08:00
feng
5766833bd2 perf: user login acl time_period 2025-04-17 14:20:20 +08:00
jiangweidong
56f05e09ca perf: Optimize cloud account update error reporting to prompt on the corresponding field 2025-04-17 14:20:16 +08:00
w940853815
b4ba209a8b fix: Allow superusers delete adhoc and playbook 2025-04-17 10:55:26 +08:00
ibuler
75e2ed71be perf: change asset account url 2025-04-16 18:24:31 +08:00
feng
1e0f0cc5c7 perf: account filter 2025-04-16 15:43:14 +08:00
zhaojisen
e3626c2f9e Fixed: Fix the issue with the automation names in the table. 2025-04-16 15:00:24 +08:00
w940853815
6a13526c87 fix: Add BaseJob component periodic_display,is_periodic columns 2025-04-16 11:31:42 +08:00
ibuler
5f1b71520f perf: change diretory service account 2025-04-15 20:23:06 +08:00
zhaojisen
bf687802d0 Fixed: Fix the styling issue of the connect button when it is disabled. 2025-04-15 18:35:43 +08:00
zhaojisen
9b127470e2 Fixed: Temporarily hide the SFTP protocol and restrict the winrm protocol 2025-04-15 18:19:24 +08:00
w940853815
7cfb1c6ee7 fix: Modify QuickJob to handle selected nodes or assets issues 2025-04-15 16:46:26 +08:00
jiangweidong
bcd96c08cf perf: The global organization strategy is not operational. 2025-04-15 14:52:13 +08:00
jiangweidong
26f5516398 fix: Fixed the issue where the drawer would close when updating the cloud account 2025-04-15 14:51:48 +08:00
w940853815
67eb359f15 fix: update ConfirmRunAssetsDialog to conditionally show buttons based on running status 2025-04-15 14:43:18 +08:00
zhaojisen
60163a6026 Fixed: Fix the issue with searching account details for the publisher. 2025-04-15 11:04:41 +08:00
w940853815
cebbcd3c6c fix: add 'crontab' and 'interval' columns to BaseJob component and update interval default value 2025-04-15 10:02:47 +08:00
fit2bot
03d1e9a881 Fixed: Fix the issue of losing the automation status when cloning the platform list. (#4951)
* Fixed: Fix the issue of losing the automation status when cloning the platform list.

* Fixed: Remove console

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-04-14 19:00:51 +08:00
zhaojisen
6fa4efaa5f Fixed: Fix the issues with deleting an account and retrieving account information in the asset details. 2025-04-14 18:25:42 +08:00
w940853815
52ca8f55a2 fix: update AutoDetailCard to exclude specified fields in AdhocDetail component 2025-04-14 11:34:20 +08:00
w940853815
8b1c964082 fix: update input number ranges for hours and minutes in crontab components 2025-04-11 17:03:08 +08:00
zhaojisen
171ab3a1ec Fixed: Fix the error when deleting an account in the asset details 2025-04-11 16:55:50 +08:00
w940853815
1b3e97512b fix: ensure warning message triggers when both hosts and nodes are absent 2025-04-10 18:34:04 +08:00
w940853815
92a863b078 perf: add default logo 2025-04-10 16:08:33 +08:00
w940853815
e693353d49 perf: Adjust style of import alert for better spacing 2025-04-10 15:05:53 +08:00
w940853815
025487a5eb perf: Enhance account actions with organization root checks 2025-04-10 14:51:55 +08:00
w940853815
e19c0090de perf: Add org ID column 2025-04-10 11:28:59 +08:00
w940853815
c6568f57fe perf: Optimized operation logic 2025-04-09 19:23:53 +08:00
w940853815
d5d9f8024c perf: Style adjustment 2025-04-09 19:23:53 +08:00
w940853815
292aad0d59 perf: add check_all 2025-04-09 19:23:53 +08:00
w940853815
39c0ae8cf7 perf: optimize adhoc asset selection experience 2025-04-09 19:23:53 +08:00
feng
5ac386d56d perf: ad platform create or update 2025-04-09 18:24:19 +08:00
zhaojisen
a3ff882847 Fixed: startup error 2025-04-09 15:50:01 +08:00
zhaojisen
2cd6682cdf Fixed: Plateform jump 2025-04-09 14:53:15 +08:00
老广
a3f17ea4d3 Merge pull request #4931 from jumpserver/pr@dev@feat_ad_domain
feat: ad domain as asset
2025-04-08 19:30:13 +08:00
ibuler
1b8c5e66bc merge: with dev 2025-04-08 19:29:07 +08:00
ibuler
0777ecd818 perf: rename to dc 2025-04-08 19:27:01 +08:00
fit2bot
e309d7e049 perf: Added cloud sync global released asset tab (#4929) 2025-04-08 18:27:02 +08:00
halo
61bb8c07c4 fix: Optimize UserConfirmDialog to send code via email 2025-04-08 18:13:02 +08:00
jiangweidong
a3a875bc28 perf: Optimize the display of cloud sync strategy details 2025-04-08 18:12:27 +08:00
ibuler
4e72e955ed perf: ds var 2025-04-08 18:04:22 +08:00
zhaojisen
24483ade28 Fixed: Hidden SFTP Options 2025-04-08 15:17:17 +08:00
w940853815
38fee74250 perf: LDAP strict sync 2025-04-08 14:36:32 +08:00
Bai
f34da5afe5 perf: change jumpserver.org to jumpserver.com 2025-04-08 14:21:39 +08:00
ibuler
08c26a461e perf: connect ad account 2025-04-08 14:03:36 +08:00
fit2bot
7f8f2d9dda perf: change support email (#4933) 2025-04-08 13:22:38 +08:00
ibuler
0a7704c06c perf: rename ad to ds 2025-04-07 19:10:33 +08:00
ibuler
a45d86c568 feat: ad domain as asset 2025-04-02 19:14:40 +08:00
Chenyang Shen
99e7ebee99 Merge pull request #4927 from jumpserver/pr@dev@feat_add_oracle_port
feat: add oracle port
2025-04-01 17:34:55 +08:00
Aaron3S
ec7ac4a036 feat: add oracle port 2025-04-01 17:33:50 +08:00
w940853815
9e5059fb38 fix: Job audit: Search job list, filter failures based on command 2025-03-31 15:18:44 +08:00
feng
9af896898e perf: Translate 2025-03-28 16:23:44 +08:00
w940853815
1259052b68 perf: prevent navigation until user agrees to terms 2025-03-28 13:59:24 +08:00
zhaojisen
80976b4141 Perf: Remove Reload 2025-03-28 10:47:01 +08:00
github-actions[bot]
af1f14f293 perf: Update Dockerfile with new base image tag 2025-03-28 10:11:31 +08:00
ibuler
cd175d50c1 perf: applet card list 2025-03-28 10:11:31 +08:00
ibuler
17a1026696 perf: fix applet host detail org error 2025-03-27 19:07:06 +08:00
feng
ce4c09c373 perf: Privacy mode 2025-03-27 18:33:19 +08:00
github-actions[bot]
105aca42a6 perf: Update Dockerfile with new base image tag 2025-03-27 17:16:06 +08:00
zhaojisen
a54190adfc Perf: Add Lina Watermark 2025-03-27 17:16:06 +08:00
halo
eda3eaa9a6 feat: Email as a method for multi-factor authentication 2025-03-27 16:45:26 +08:00
zhaojisen
47366b3cf0 Fixed: Change Connect Route 2025-03-26 17:01:38 +08:00
zhaojisen
6e2c591822 Fixed: Amount Detail 2025-03-26 16:33:01 +08:00
zhaojisen
5740ecd49c Fixed: XSS 2025-03-25 18:18:07 +08:00
zhaojisen
4c6d63bde8 Fixed: Search Qeurt 2025-03-25 17:54:42 +08:00
ibuler
a31e2295ee perf: update crontab update 2025-03-25 10:12:09 +08:00
w940853815
c0ff9a8502 fix: Help message no display 2025-03-24 19:20:17 +08:00
ibuler
6bcf8b1b15 perf: 修改账号创建更新 2025-03-24 18:07:12 +08:00
feng
8a836faa25 perf: User system_roles required 2025-03-24 16:08:55 +08:00
ibuler
5a2028786a fix: applet host update error 2025-03-24 15:28:35 +08:00
ibuler
8a0f642d95 fix: applet host create protocol err 2025-03-24 11:28:10 +08:00
feng
59a2180f2c perf: Login acl license 2025-03-21 14:25:56 +08:00
ibuler
2519edc6a7 perf: add enterprise upgrade handler 2025-03-21 10:54:56 +08:00
zhaojisen
42560d6603 Fixed: Asset Clone 2025-03-21 10:36:10 +08:00
w940853815
9cbdfacfd2 fix: remove TaskList from AccountPushExecutionInfo 2025-03-20 18:29:17 +08:00
ibuler
2dec820a0a perf: add default conn btn 2025-03-20 18:13:53 +08:00
ibuler
84a66d8c5a perf: asset update 2025-03-20 18:01:03 +08:00
ibuler
6eedfe994e perf: update automation submit 2025-03-20 17:37:54 +08:00
ibuler
f1982c2d8f perf: add no cache meta interface 2025-03-20 17:10:16 +08:00
zhaojisen
4dac455575 Fixed: Role Edit 2025-03-20 17:04:19 +08:00
ibuler
affb9e405e perf: update platform automation update 2025-03-20 16:54:20 +08:00
ibuler
2bf8090b60 perf: update clone error 2025-03-20 16:45:40 +08:00
ibuler
266ddc7b51 pr@dev@perf_update_role_etail 2025-03-20 16:45:40 +08:00
fit2bot
5831940be0 perf: update some clone (#4882)
* pr@dev@perf_update_role_etail

* perf: update clone error

* perf: update query set

* perf: update some clone

---------

Co-authored-by: ibuler <ibuler@qq.com>
2025-03-20 16:44:26 +08:00
zhaojisen
8ae747b9a5 Drawer 2025-03-20 16:28:20 +08:00
zhaojisen
8b69f25e7b Fixed: Account Change Secret 2025-03-20 16:13:41 +08:00
zhaojisen
883d44cede Fixed: Translate 2025-03-20 16:03:50 +08:00
zhaojisen
024051df76 Fixed: Plateform Clone 2025-03-20 15:53:19 +08:00
zhaojisen
564e530a96 Fixed: Amount Prevent 2025-03-20 15:38:16 +08:00
ibuler
d3a0f69b4c perf: update platform detail 2025-03-20 15:17:13 +08:00
w940853815
69f263e491 fix: Failed to change secret in batch. 2025-03-20 15:07:07 +08:00
zhaojisen
ad82040a54 Fixed: Account Detail 2025-03-20 15:01:47 +08:00
ibuler
d994c60378 perf: update account detail 2025-03-20 14:53:33 +08:00
zhaojisen
d7fddf405f Fixed: Drawer Detail 2025-03-20 14:44:23 +08:00
ibuler
ad9660b1f2 perf: update perm detail 2025-03-20 14:20:46 +08:00
ibuler
8a5c60a9bc perf: 优化 detail 中 component 2025-03-20 14:20:46 +08:00
zhaojisen
1782c8af74 Fixed: PAM Asset Detail 2025-03-20 12:46:42 +08:00
zhaojisen
ad55f6f6a6 Fixed: Resource Translate 2025-03-20 12:39:52 +08:00
ibuler
377d17b19d perf: after close action 2025-03-20 12:08:55 +08:00
老广
51e8b82bbf Merge pull request #4866 from jumpserver/pr@dev@update_drawer_title
perf: update title draw again
2025-03-20 11:56:19 +08:00
ibuler
881e2d05c7 perf: update title draw again 2025-03-20 11:53:21 +08:00
feng
44c39de459 perf: report 2025-03-20 11:23:31 +08:00
老广
e2f87e62f2 Merge pull request #4864 from jumpserver/pr@dev@update_title
perf: update get draw title
2025-03-20 11:18:42 +08:00
ibuler
f27d6f0e97 perf: update get draw title 2025-03-20 11:17:41 +08:00
feng
42d8414834 perf: report 2025-03-20 11:16:51 +08:00
zhaojisen
138bdad7ef Fixed: Execution Record 2025-03-20 11:08:35 +08:00
zhaojisen
9575936849 Fixed: Auth 2025-03-20 10:54:26 +08:00
老广
de3338c3f1 Merge pull request #4860 from jumpserver/pr@dev@perf_drawer_title
perf: for perfect drawer create update detail or any
2025-03-20 10:52:56 +08:00
ibuler
f95a78bec1 merge: with dev 2025-03-20 10:52:22 +08:00
ibuler
4be9e048e1 perf: for perfect drawer create update detail or any 2025-03-20 10:47:59 +08:00
老广
4f70bf770c Revert "perf: update detail drawer show"
This reverts commit 3361b00bd1.
2025-03-19 23:16:40 +08:00
ibuler
3361b00bd1 perf: update detail drawer show 2025-03-19 21:05:53 +08:00
ibuler
ac6a0f49da perf: update drawer show before and after handler 2025-03-19 19:02:51 +08:00
feng
c08f446464 perf: Change secret 2025-03-19 18:56:37 +08:00
jiangweidong
849d2829f4 fix: CTYun cannot sync 2025-03-19 17:59:20 +08:00
zhaojisen
5d6b48831c Fixed: Record 2025-03-19 17:53:31 +08:00
zhaojisen
d557957b34 Fixed: Connect Direct Filter SFTP 2025-03-19 17:20:29 +08:00
zhaojisen
08821663ce Fixed: Authj 2025-03-19 17:15:22 +08:00
w940853815
3d5ea46930 fix: Account filter error 2025-03-19 16:33:46 +08:00
zhaojisen
06c87b05cf Fixed: View Secret 2025-03-19 16:25:27 +08:00
ibuler
24ba0e38c1 perf: 解决 tab 中创建更新的问题 2025-03-19 16:17:41 +08:00
ibuler
adc80ce74a perf: update applet host 2025-03-19 16:17:41 +08:00
zhaojisen
d03fe5d95a Fixed: Asset Account Detail 2025-03-19 16:12:12 +08:00
w940853815
05499d6430 fix: Add account_deleted_accounts to RiskSummary 2025-03-19 15:26:29 +08:00
zhaojisen
74f619c961 Fixed: Asset Add Account Template 2025-03-19 15:22:24 +08:00
w940853815
b0aec69060 fix: Add statusMap for account status 2025-03-19 14:45:52 +08:00
zhaojisen
d7b7704b21 Fixed: Tickect Session 2025-03-19 12:42:46 +08:00
feng
2f8480eea6 perf: Asset domain 2025-03-19 11:26:55 +08:00
feng
bdb5c83814 perf: Licese 2025-03-18 18:56:13 +08:00
w940853815
082ecb15f7 fix: add change_password_add to discover confirm handler 2025-03-18 18:02:32 +08:00
zhaojisen
8981a8f74f Fixed: Tickect Session 2025-03-18 18:01:09 +08:00
ibuler
b8efbf1e82 perf: update handler formatter 2025-03-18 17:53:35 +08:00
ibuler
f7520b87bf perf: update risk handler 2025-03-18 17:53:35 +08:00
ibuler
a146c26e20 perf: risk handler add delete account action 2025-03-18 17:53:35 +08:00
w940853815
d0b8efc796 fix: update remote_present status on delete_remote command 2025-03-18 16:48:48 +08:00
zhaojisen
61e5b061e9 Fixed: Plateform Automation Update 2025-03-18 16:20:12 +08:00
w940853815
84bbe4de8b fix: Restrict add asset and gateway permissions for non-root organizations 2025-03-18 15:48:36 +08:00
zhaojisen
7c20d08ce2 Fixed: Change Secret Dashboard Jump 2025-03-18 15:24:48 +08:00
w940853815
1d288f6212 fix: Update IP group display format in detail view 2025-03-18 15:14:34 +08:00
w940853815
7664487a1c perf: Translate processing 2025-03-18 14:50:03 +08:00
feng
4502375ed0 perf: change secret 2025-03-18 13:30:21 +08:00
w940853815
6aab902762 fix: Create ssh_key set is_active error 2025-03-18 11:28:42 +08:00
ibuler
597b5ac4cf perf: update loading spinner 2025-03-18 11:24:57 +08:00
ibuler
e26fecfee8 perf: update detail tab page loading 2025-03-18 11:24:32 +08:00
ibuler
661fc3a3d8 perf: update drawer size and ticket detail 2025-03-18 11:23:59 +08:00
jiangweidong
f601e25302 fix: No account when syncing with the cloud 2025-03-18 09:47:51 +08:00
zhaojisen
63e4776355 Fixed: Remote Ttile 2025-03-17 18:18:10 +08:00
ibuler
d67d275ae3 perf: update cloud sync err 2025-03-17 18:04:11 +08:00
ibuler
a8a1a56f3d perf: 统一 automations 历史 2025-03-17 17:58:08 +08:00
zhaojisen
f730611102 Fixed: Word Spell 2025-03-17 17:54:04 +08:00
w940853815
2344203563 fix: Job detail error 2025-03-17 17:46:22 +08:00
zhaojisen
f1a79cc36d Fixed: Filter SFTP 2025-03-17 16:35:41 +08:00
zhaojisen
194ea09cab Fixed: Session Record 2025-03-17 16:20:11 +08:00
w940853815
b672288725 fix: Update counter naming for group and sudo changes in RiskSummary 2025-03-17 16:01:58 +08:00
zhaojisen
25974c7cf1 Fixed: Fail Account Pagegation 2025-03-17 15:45:57 +08:00
ibuler
155da5aecd perf: save to localStorage except cookie 2025-03-17 15:28:11 +08:00
w940853815
7c72bcf84a fix: Create/clone ssh public key failed 2025-03-17 15:16:57 +08:00
ibuler
5a40280baa perf: 优化 tab detail 中的一些问题 2025-03-17 15:08:26 +08:00
zhaojisen
1254a4105a Fixed: Tickets Session 2025-03-17 14:54:11 +08:00
zhaojisen
9a868ec50a Fixed: Ticket 2025-03-17 14:25:20 +08:00
zhaojisen
534f784fda Fixed: Remove _ 2025-03-17 11:19:50 +08:00
zhaojisen
6d83b868ed Fixed: Connect Token 2025-03-17 11:19:50 +08:00
zhaojisen
e37b813028 Fixed: Passkeys 2025-03-17 11:05:50 +08:00
ibuler
01d44bc84e perf: 优化计数卡 2025-03-17 10:54:05 +08:00
fit2bot
fa5f4348ea perf: 优化数量计算 (#4808)
Co-authored-by: ibuler <ibuler@qq.com>
2025-03-14 19:08:14 +08:00
feng
90b481c71d perf: translate 2025-03-14 18:27:36 +08:00
zhaojisen
6e8b9b4df8 Fixed: Account 2025-03-14 18:22:40 +08:00
w940853815
52ef1daa25 fix: Add loading state to AccountInfoFormatter for async data fetching 2025-03-14 17:04:21 +08:00
feng
7902a8f038 perf: perm 2025-03-14 17:02:10 +08:00
zhaojisen
3cef144119 Fixed: Dashboard Filter 2025-03-14 16:46:46 +08:00
zhaojisen
555210547b Fixed: Remove Mappint 2025-03-14 16:42:52 +08:00
zhaojisen
72e08adfc1 Fixed: Drawer Ttile 2025-03-14 16:31:47 +08:00
w940853815
266e46ebfa fix: Modify ListTable components import 2025-03-14 16:24:58 +08:00
ibuler
449f3d334d perf: update using draw table in attr match 2025-03-14 16:17:22 +08:00
zhaojisen
aa8c2da715 Fixed: Label Click 2025-03-14 15:20:13 +08:00
zhaojisen
9262ce56d1 Fixed: Secret Key 2025-03-14 14:48:30 +08:00
w940853815
3198517b75 perf: Account List: Some operations are disabled on the Asset tab page 2025-03-14 11:06:40 +08:00
w940853815
77ba87c66c fix: Restrict account creation for root organizations 2025-03-14 10:52:18 +08:00
w940853815
e116dcc230 fix: Root org disable some action 2025-03-14 10:25:35 +08:00
ibuler
28a4d4761a perf: update cloud privider panel 2025-03-13 19:17:31 +08:00
zhaojisen
5a2f430815 Fixed: Gateway Clone 2025-03-13 19:11:52 +08:00
feng
7ecbff79c7 perf: change secret account failed list 2025-03-13 18:32:57 +08:00
zhaojisen
420145a12b Fixed: Domain Title 2025-03-13 18:23:49 +08:00
zhaojisen
3090f6dbc8 Fixed: Virtual Account 2025-03-13 18:04:33 +08:00
w940853815
9d587610e8 fix: AssetPermissionAccount page clone failed 2025-03-13 17:23:44 +08:00
fit2bot
2254ad80b4 Fixed: Filter Show (#4787) 2025-03-13 16:16:42 +08:00
zhaojisen
2896dfe3b1 Fixed: Session Detail 2025-03-13 15:58:14 +08:00
zhaojisen
5e12e7ea84 Fixed: Drawer Form 2025-03-13 15:38:38 +08:00
zhaojisen
446cb0b85e Fixed: Image Upload 2025-03-13 15:30:00 +08:00
zhaojisen
aaad6b8380 Fixed: Risk Asset And Node Detail 2025-03-13 15:05:31 +08:00
w940853815
367320eef9 perf: Translate 2025-03-13 14:26:53 +08:00
zhaojisen
09836df9fa Fixed: Account View 2025-03-13 13:56:54 +08:00
zhaojisen
804006f853 Fixed: Gatewaty Add 2025-03-13 13:17:06 +08:00
w940853815
18690688be perf: Translate risk handle 2025-03-13 10:01:25 +08:00
zhaojisen
45970cc61b Fixed: Domain Tab 2025-03-12 18:23:11 +08:00
ibuler
f140efd326 perf: update task process loading 2025-03-12 18:10:56 +08:00
w940853815
33568859cd perf: Translate automation 2025-03-12 17:53:13 +08:00
zhaojisen
70c0433d32 Fixed: Domain Clone 2025-03-12 17:14:25 +08:00
zhaojisen
50bcf018d2 Fixed: Storage Update 2025-03-12 16:43:24 +08:00
zhaojisen
220c621a40 Fixed: Alert Closeable 2025-03-12 15:56:59 +08:00
zhaojisen
825cf0ae46 Fixed: Dashboard Direction 2025-03-12 15:51:45 +08:00
w940853815
22cef8ef10 perf: Remove account_deleted, password_error, no_admin_account others risk 2025-03-12 15:49:12 +08:00
ibuler
727b5c3268 perf: update form object val 2025-03-12 15:19:09 +08:00
zhaojisen
f416341fd1 Fixed: Platform Edit 2025-03-12 14:47:02 +08:00
fit2bot
f2f3918b22 perf: invite user get error (#4768)
* perf: update create object command storage

* perf: invite user get error

---------

Co-authored-by: ibuler <ibuler@qq.com>
2025-03-12 14:02:06 +08:00
zhaojisen
812ee32584 Fixed: Permission Rules 2025-03-12 11:24:13 +08:00
fit2bot
e9bb18ec2f perf: update permission action (#4765)
Co-authored-by: ibuler <ibuler@qq.com>
2025-03-12 10:23:54 +08:00
ZhaoJiSen
dd1a4a5c18 Merge pull request #4764 from jumpserver/pr@dev@fix_domain
Fixed: Domain
2025-03-11 19:25:09 +08:00
zhaojisen
f6779e8ca9 Fixed: Domain 2025-03-11 19:23:59 +08:00
ZhaoJiSen
4236405db5 Merge pull request #4763 from jumpserver/pr@dev@fix_review
Fixed: Review
2025-03-11 18:24:16 +08:00
zhaojisen
41f5c6cbb7 Fixed: Review 2025-03-11 18:23:23 +08:00
w940853815
d7e2ac6e5f perf: Translate accounts 2025-03-11 18:20:35 +08:00
feng626
a3357ce26c Merge pull request #4761 from jumpserver/pr@dev@fix_review
Fixed: Review
2025-03-11 17:49:50 +08:00
zhaojisen
9d11231402 Fixed: Review 2025-03-11 17:48:10 +08:00
feng626
38dcffba2a Merge pull request #4760 from jumpserver/pr@dev@trnslate
perf: translate
2025-03-11 17:39:35 +08:00
feng
95b703645a perf: translate 2025-03-11 17:38:01 +08:00
ZhaoJiSen
339876b7a3 Merge pull request #4759 from jumpserver/pr@dev@fix_image_require
Fixed: Image Required
2025-03-11 15:49:05 +08:00
zhaojisen
edeffe2de2 Fixed: Image Required 2025-03-11 15:46:06 +08:00
ZhaoJiSen
cdb669eb81 Merge pull request #4758 from jumpserver/pr@dev@fix_connect_method
Fixed: Connect Method
2025-03-11 14:57:33 +08:00
zhaojisen
e33027e03f Fixed: Connect Method 2025-03-11 14:56:41 +08:00
ZhaoJiSen
61f822856c Merge pull request #4757 from jumpserver/pr@dev@fix_command_record
Fixed: Command Record
2025-03-11 14:41:54 +08:00
zhaojisen
61a742b64e Fixed: Command Record 2025-03-11 14:40:47 +08:00
ZhaoJiSen
721f6f5e15 Merge pull request #4756 from jumpserver/pr@dev@fix_account_labelk
Fixed: Account Labek Show
2025-03-11 11:22:59 +08:00
zhaojisen
928b7c79a7 Fixed: Account Labek Show 2025-03-11 11:22:14 +08:00
ZhaoJiSen
8d654cae33 Merge pull request #4755 from jumpserver/pr@dev@fix_account_update
Fixed: Account Update
2025-03-11 11:09:37 +08:00
zhaojisen
5c957a6c46 Fixed: Account Update 2025-03-11 11:08:20 +08:00
老广
299b06a6ea Merge pull request #4754 from jumpserver/pam
Pam
2025-03-11 11:00:55 +08:00
ibuler
7ede31b978 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-11 10:58:43 +08:00
ibuler
7c1d1278f6 perf: 修改 panel 2025-03-11 10:57:55 +08:00
w940853815
637a427d76 fix: Update searchConfig to include action filter options 2025-03-11 09:56:32 +08:00
ibuler
05e3128dbc Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-10 19:22:08 +08:00
ibuler
821fe9cb3e perf: update panel 2025-03-10 19:21:53 +08:00
Bryan
1fe99ff18b Merge pull request #4752 from jumpserver/pam
Pam
2025-03-10 19:15:37 +08:00
zhaojisen
239abdc9b0 Fixed: Account Push 2025-03-10 19:12:01 +08:00
zhaojisen
49cea9616a Fixed: Account Push 2025-03-10 18:34:01 +08:00
zhaojisen
cdbee9649b Fixed: Acl Jump 2025-03-10 18:01:12 +08:00
ibuler
f141e9c748 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-10 17:03:55 +08:00
ibuler
ae8292ebb3 perf: update accounts list can hidden actions 2025-03-10 17:03:38 +08:00
zhaojisen
e74435df1b Fixed: Search Filter 2025-03-10 15:48:52 +08:00
zhaojisen
952740a916 Fixed: Applaction Management Filter Item 2025-03-10 15:25:58 +08:00
zhaojisen
8a062d0c9a Fixed 2025-03-10 15:20:22 +08:00
feng
55454eb671 perf: usergroup translate 2025-03-10 14:48:41 +08:00
ibuler
d3ee790186 Merge branch 'pr@pam@update_panel' into pam 2025-03-10 14:25:54 +08:00
ibuler
203e984144 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-10 14:25:39 +08:00
ibuler
8a0cb6d0b4 perf: update card table 2025-03-10 14:25:03 +08:00
w940853815
ef1442fde9 perf: Translate copy 2025-03-10 14:09:43 +08:00
zhaojisen
1c8ef3250b Fixed: Hide unnecessary operations from display 2025-03-10 11:36:43 +08:00
zhaojisen
64bf8a9ec6 Fixed: Account Change 2025-03-07 18:30:40 +08:00
zhaojisen
ed93642ec5 Fixed: Account Template 2025-03-07 18:25:21 +08:00
feng
5fe00b4061 perf: Translate 2025-03-07 16:54:13 +08:00
jiangweidong
8b9229b906 perf: OpenID configuration display optimization 2025-03-07 16:24:51 +08:00
zhaojisen
858cfbec27 Fixed: Fix the issue where the execution list name remains unchanged after the execution task name changes 2025-03-07 16:08:12 +08:00
ibuler
c419c47c13 perf: update panel 2025-03-07 15:55:51 +08:00
zhaojisen
29ed35f94f Fixed: Fix the Drawer issue in the remote applications page 2025-03-07 15:26:50 +08:00
zhaojisen
a106b5e199 Fixed: Fix: Applications related to Drawer in the component settings page 2025-03-07 14:44:07 +08:00
ibuler
80973de095 perf: update sync 2025-03-07 14:17:02 +08:00
zhaojisen
ad02a57c0a Fixed: Fix the issue of missing fields in the command storage page form 2025-03-07 11:18:37 +08:00
ibuler
7e624b4b49 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-07 10:23:32 +08:00
ibuler
5a32d2359f perf: update cloud sync 2025-03-07 10:23:21 +08:00
feng
b2b1660232 perf: Translate 2025-03-06 19:13:37 +08:00
w940853815
1d667ee1b9 fix: User List: Fix NaN title when clicking session number in user session detail 2025-03-06 17:24:15 +08:00
jiangweidong
51e83f5bbc fix: Slove the problem of assets not being displayed in online sync 2025-03-06 17:03:57 +08:00
w940853815
62f482bb63 fix: Asset list: when clone, the account add failed 2025-03-06 16:56:56 +08:00
zhaojisen
fcee27b8df Fixed: Remove Unused 2025-03-06 16:35:40 +08:00
zhaojisen
1337b0ff34 Fixed: Fix the infinite viewing loop issue between viewing assets in account details and viewing accounts in asset details 2025-03-06 16:35:40 +08:00
ibuler
22170c18f8 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-06 16:21:49 +08:00
ibuler
a6210c9add perf: 优化 card table 2025-03-06 16:21:40 +08:00
zhaojisen
278c5996f1 Fixed: Fix: Issue where recipients are not displayed when creating password change tasks 2025-03-06 15:58:21 +08:00
w940853815
bef704750e fix: Asset list: when updating, the account delete failed 2025-03-06 15:10:17 +08:00
ibuler
ae7e4b6ddf perf: update lib posion 2025-03-05 19:05:21 +08:00
ibuler
13318bd642 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-05 18:48:14 +08:00
ibuler
d4bcfb3750 perf: add loading page 2025-03-05 18:45:38 +08:00
feng
9db715e375 perf: translate 2025-03-05 17:30:04 +08:00
w940853815
1121af7441 fix: Asset detail account copy to asset and move to asset failed 2025-03-05 17:14:40 +08:00
ibuler
bfab828813 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-05 15:08:43 +08:00
ibuler
9f0682638b perf: update position 2025-03-05 15:08:13 +08:00
w940853815
2d56ee7912 fix: Platform type was created is wrong 2025-03-05 10:47:30 +08:00
w940853815
be5be83dfc fix: Risk detect prohibit import csv 2025-03-05 10:22:29 +08:00
feng
9a8629aeb2 perf: updateValue 2025-03-05 10:21:46 +08:00
feng
702d26822b perf: updateValue 2025-03-05 10:21:22 +08:00
zhaojisen
d809a13b67 Fixed: User Detail 2025-03-05 10:21:22 +08:00
老广
f7202ae5fa Merge pull request #4719 from jumpserver/pr@dev@pam
Merge branch 'pam' of github.com:jumpserver/lina into pam
2025-03-04 19:18:52 +08:00
ibuler
b1101efe0e merge: with remote 2025-03-04 19:17:25 +08:00
ibuler
23fefd54ff Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-04 19:12:57 +08:00
ibuler
792950db48 perf: update i18n 2025-03-04 19:12:45 +08:00
w940853815
777c30c247 perf: Application Details - Account List remove some buttons 2025-03-04 18:40:12 +08:00
ibuler
eb6d6b11e5 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-04 18:21:16 +08:00
ibuler
f365282755 perf: update acl i18n 2025-03-04 18:21:08 +08:00
feng
eb1c0cdc7a perf: Account export 2025-03-04 16:48:19 +08:00
zhaojisen
de427b7f20 Fixed: Fix the issue where batch updates cannot be performed on the detection results page in risk detection 2025-03-04 16:46:05 +08:00
ibuler
25b60c1f2b perf: update automation style 2025-03-04 16:18:09 +08:00
ibuler
f4ccd38f07 perf: update item width 2025-03-04 15:49:50 +08:00
ibuler
6a9d51c859 perf: update automations 2025-03-04 15:45:45 +08:00
zhaojisen
4143c2dfbe Fixed: Card Style 2025-03-04 15:03:54 +08:00
fit2bot
6ebc02825e Fixed: Fix issues in the edit form of the account list (#4714)
* Fixed: Fix issues in the edit form of the account list

* Fixed: Switch Add Template And Edit

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-03-04 14:33:59 +08:00
zhaojisen
36f6c161b4 Fixed: Plateform Icon And Text 2025-03-04 10:57:22 +08:00
zhaojisen
34480648d7 Fixed: Fix form styling issues in platform list when editing or creating 2025-03-03 17:20:35 +08:00
fit2bot
cf363bf061 Fixed: Connect Button Perm (#4711) 2025-03-03 16:51:07 +08:00
ibuler
598b053841 perf: update acl i18n 2025-03-03 15:55:03 +08:00
ibuler
a03a1c17fe Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-03 14:47:19 +08:00
ibuler
5ff46a3757 merge: with remote 2025-03-03 14:47:10 +08:00
feng
82a4dd5b3b perf: change secret linkage 2025-03-03 14:09:09 +08:00
zhaojisen
72a0a200a8 Fixed: Remove Log 2025-03-03 11:20:34 +08:00
zhaojisen
156715ede5 Fixed: Empty Value Update 2025-03-03 11:20:34 +08:00
zhaojisen
880c44fdaa Fixed: Form update Validated 2025-03-03 11:08:29 +08:00
w940853815
2a0f6dc1df fix: Zone list: Click on the details page, then click on the Assets tab, but fail to retrieve asset data. 2025-03-03 11:01:31 +08:00
feng
dadfc9a240 perf: translate 2025-03-03 10:52:39 +08:00
ibuler
598d3803dc perf: rename acl 2025-03-03 10:34:54 +08:00
ibuler
f5bd0f0533 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-03-03 10:01:34 +08:00
feng
63db09a22f perf: Translate 2025-02-28 18:50:36 +08:00
zhaojisen
6c6399abc0 Perf: Some change 2025-02-28 18:43:05 +08:00
feng
0968a4d7ef perf: translate 2025-02-28 17:05:32 +08:00
zhaojisen
c5bc1ab833 Fixed: Remove Account Item 2025-02-28 16:44:15 +08:00
ibuler
819bbae3e5 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-28 15:56:08 +08:00
ibuler
0dd11735fc perf: update form label require star 2025-02-28 15:55:51 +08:00
w940853815
972e420354 fix: Account backup click Execute on the details page, and an error of 500 will be reported. 2025-02-28 15:54:38 +08:00
zhaojisen
2da3b2ac75 Fixed: Risk List Detail Drawer 2025-02-28 14:29:39 +08:00
ibuler
1fdfd8e2d8 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-28 13:54:29 +08:00
ibuler
48662ed9f4 perf: update form style 2025-02-28 13:54:21 +08:00
feng
485f45a2ea perf: risk detail 2025-02-28 11:40:38 +08:00
zhaojisen
fa93f52f87 Fixed: Detail Drawer 2025-02-28 11:34:55 +08:00
w940853815
f0b332a269 perf: update title for ExecutionRecord and add ActionsFormatter to ApplicationList 2025-02-28 11:05:06 +08:00
zhaojisen
f61a535454 Fixed: Remove isShort 2025-02-28 11:00:35 +08:00
feng
f6b0b04ad2 perf: Translate 2025-02-27 18:50:40 +08:00
zhaojisen
ebebfcd03e Fixed: Task Click 2025-02-27 18:49:37 +08:00
ibuler
3ac0ce7429 perf: 优化一下 form group 2025-02-27 18:31:07 +08:00
fit2bot
a34b2c7074 perf: update copy icon (#4692)
* perf: update change secret overview

* fix: Typo in latest_secret_change_failed

* Fixed: Fix dialog display order problem

* Fixed: Fix: Password field disappears during user update (#4687)

* fix: Update resource names and permissions for account backup automation

* Fixed: Fix: Password field disappears during user update

* Fixed: Account Change Secret Record List

* perf: update i18n

* perf: update copy icon

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: w940853815 <940853815@qq.com>
Co-authored-by: zhaojisen <1301338853@qq.com>
2025-02-27 17:13:03 +08:00
fit2bot
88a66039ce perf: change dir name too lang (#4683)
Co-authored-by: ibuler <ibuler@qq.com>
2025-02-26 14:50:17 +08:00
zhaojisen
c637f0e93a Fixed: Fix the issue of empty account backup copy list 2025-02-26 11:52:15 +08:00
zhaojisen
f3792720b7 Fixed: Clone accounts and assets in PAM overwriting original data 2025-02-26 11:25:01 +08:00
ibuler
4a1f4c88cf perf: update dashboard postion 2025-02-26 11:13:36 +08:00
feng
8546f9f735 fix: platform 2025-02-26 10:43:22 +08:00
feng
cc4b5183ea perf: report to iframe 2025-02-25 19:13:53 +08:00
ibuler
e361bcbf42 perf: fix table setting error 2025-02-25 18:24:23 +08:00
ibuler
8e461e8aed perf: update quick filter expand setting 2025-02-25 17:00:59 +08:00
zhaojisen
b6ae2aa2f8 Fixed: Fix the issue where adding account information to assets in Pam is not responding. 2025-02-25 16:42:44 +08:00
w940853815
f985c75fc5 fix: Job component with create and detail drawer functionality 2025-02-25 15:05:56 +08:00
zhaojisen
c2b176376f Fixed: Fix the issue where the common Drawer Title is displayed in English 2025-02-25 11:34:24 +08:00
feng
3d0e6fc3d1 perf: Translate 2025-02-24 19:24:15 +08:00
zhaojisen
3752d23b42 Fixed: Fix the issue where the form for creating user login rules does not match expectations 2025-02-24 18:59:38 +08:00
zhaojisen
ace605884e Fixed: Fix the issue where clicking on an asset in the account list causes the asset name in the asset details to display as Object. 2025-02-24 18:32:53 +08:00
zhaojisen
e8e3ca123b Fixed: Fix the adaptation issue of the Dashboard on the account password change page. 2025-02-24 16:20:37 +08:00
zhaojisen
137c59a1e1 Fix the issue where the Dashboard field cannot navigate 2025-02-24 15:49:27 +08:00
feng
b0d989e1da perf: account type filter 2025-02-24 15:32:49 +08:00
feng
bd4b5ec0c3 perf: Pam execution 2025-02-24 11:49:48 +08:00
zhaojisen
f13e7fd1d0 Perf: Dashboard Chart 2025-02-21 18:23:10 +08:00
老广
8be5c22ae4 Merge pull request #4664 from jumpserver/pr@dev@feat_pam
perf: update detail page
2025-02-21 17:16:27 +08:00
ibuler
4722384741 perf: remove console log 2025-02-21 16:56:47 +08:00
ibuler
0952a571b3 perf: update detail page 2025-02-21 15:31:53 +08:00
ibuler
1dd00bbfa7 merge: with dev 2025-02-21 15:13:54 +08:00
w940853815
79a1a1faef perf: streamline onUpdate actions in PlayBook and Adhoc components 2025-02-21 14:22:37 +08:00
ibuler
8ef4b466d7 perf: update execution 2025-02-20 18:43:22 +08:00
ibuler
4ccc7ac56b perf: merge with remote 2025-02-20 18:41:15 +08:00
ibuler
7fb24cadea perf: update formatter 2025-02-20 18:40:16 +08:00
feng
e89be5f278 perf: execution list 2025-02-20 14:41:50 +08:00
zhaojisen
b746e1d553 Perf: Add Dashboard Items 2025-02-20 14:17:03 +08:00
Chenyang Shen
b8b764c04c Merge pull request #4660 from jumpserver/pr@dev@feat_fix_error_i18n
fix: fix error i18n
2025-02-19 19:07:53 +08:00
Aaron3S
45532a3eb6 fix: fix error i18n 2025-02-19 19:06:41 +08:00
w940853815
ffee484d6c perf: add drawer functionality and title formatting to AccountChangeSecret and AccountPush execution lists 2025-02-19 18:49:02 +08:00
zhaojisen
9e4afd5271 Fixed: Fixed Tabel Export 2025-02-19 17:32:22 +08:00
w940853815
d5099c3a04 perf: add update actions and detail formatters to various components 2025-02-19 15:35:34 +08:00
zhaojisen
2558cfa4c2 Fixed: Dashboard 2025-02-19 11:41:30 +08:00
w940853815
6357056600 fix: table row index error 2025-02-19 11:13:21 +08:00
w940853815
c1b60e6298 perf: Session list with detail drawer 2025-02-18 19:01:17 +08:00
ibuler
f2b45c5084 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-18 16:51:33 +08:00
ibuler
a451f38701 perf: update some page 2025-02-18 16:51:26 +08:00
zhaojisen
e6efd91414 Fixed: Dashboard PRBP 2025-02-18 15:58:08 +08:00
zhaojisen
19469508f7 Fixed: PR-BT 2025-02-18 15:23:16 +08:00
Chenyang Shen
5166287b0e Merge pull request #4650 from jumpserver/pr@dev@feat_add_i18n
feat: add i18n
2025-02-18 15:11:35 +08:00
Aaron3S
494c4c5753 feat: add i18n 2025-02-18 15:08:30 +08:00
w940853815
27e2d34171 fix: Create playbook job form error 2025-02-18 11:18:36 +08:00
jiangweidong
eddff3d75b perf: Optimize the display of labels in strategy actions 2025-02-18 10:27:28 +08:00
jiangweidong
910bef6695 fix: When the scheduled synchronization interval is empty, the submission fails 2025-02-18 10:26:04 +08:00
zhaojisen
fa2faecb7c Fixed: Fix card overflow issue on screen resize 2025-02-17 17:19:40 +08:00
zhaojisen
e6cd2306c9 Fixed: Fix responsive issues 2025-02-17 17:09:48 +08:00
w940853815
59945ad798 fix: When select_default_value is null, editing the playbook reports an error 2025-02-17 11:19:18 +08:00
feng
ded7920a8a perf: translate 2025-02-13 18:57:20 +08:00
zhaojisen
60b8748b95 Fixed: PT-BR languange in Setting Show Tooltip 2025-02-13 17:02:24 +08:00
ibuler
f1956b4982 perf: update some i18n 2025-02-13 16:41:06 +08:00
feng
5708aa25c4 perf: Deepseek 2025-02-13 16:39:47 +08:00
zhaojisen
f2e6f89c08 Fixed: Fixed PT-BR language adaptation issue 2025-02-13 16:27:45 +08:00
zhaojisen
1c222c3ce0 Fixed: PT-BR languange adaptation issue 2025-02-13 16:27:45 +08:00
fit2bot
d6c28b8286 Fixed: Fixed PT-BR language adaptation issue (#4636)
* Fixed: Fixed PT-BR language adaptation issue

* Fiexed: Fixed En languange ACL Page adapation issue

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-02-13 15:55:58 +08:00
ibuler
0cd9f6dcd6 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-13 15:55:43 +08:00
ibuler
b2abee724d perf: update detail card 2025-02-13 15:55:20 +08:00
w940853815
3e3cb309ce perf: Merge More into Info and update detail page 2025-02-13 15:26:17 +08:00
ibuler
55c8dfa549 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-13 15:08:14 +08:00
ibuler
9740c58291 perf: update detail 2025-02-13 15:08:04 +08:00
feng
77558186a4 perf: Translate 2025-02-13 15:01:34 +08:00
feng
d94752a021 perf: chat help text 2025-02-13 11:29:43 +08:00
feng
b524848742 perf: Translate 2025-02-12 18:43:48 +08:00
w940853815
339c1ab227 perf: Add Java, Node, Go, and cURL demo code 2025-02-12 18:16:31 +08:00
ibuler
1bdc27ea98 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-12 18:07:40 +08:00
ibuler
19dc42cd2c perf: update detail page 2025-02-12 18:07:24 +08:00
zhaojisen
7375dc58a3 Perf: Change Mission Chart Size 2025-02-11 18:52:11 +08:00
w940853815
ee678289d4 perf: Add demo code docs 2025-02-11 18:20:10 +08:00
feng
c932fbb5f3 perf: Pam dashboard 2025-02-11 18:20:02 +08:00
ibuler
768cae7abc Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-11 15:56:11 +08:00
ibuler
5abb8a867f perf: update detail api url 2025-02-11 15:55:54 +08:00
zhaojisen
c4bba7e74d Perf: Change AccountConnectFormatter To Common Component 2025-02-11 14:47:02 +08:00
feng
e365f874bc perf: Platform 2025-02-11 14:40:51 +08:00
ibuler
f54e2c8ddc perf: 修改授权 2025-02-11 14:32:08 +08:00
feng
e93979ab5f perf: perm filter translate 2025-02-10 19:15:30 +08:00
feng
5d5e87595b perf: Login acl del license 2025-02-10 17:44:58 +08:00
ibuler
ff769179a8 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-10 17:43:36 +08:00
ibuler
8546388439 perf: update user quick filters 2025-02-10 17:39:18 +08:00
w940853815
7dcecd4421 perf: modify markdown code style 2025-02-10 16:42:27 +08:00
zhaojisen
4bc039185c Fixed: Fixed Fix account template redirection error in remote applications 2025-02-10 16:17:46 +08:00
w940853815
efef672157 perf: code copy 2025-02-08 18:26:35 +08:00
ibuler
ec8c8e7d4b Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-08 17:28:50 +08:00
ibuler
c14970e232 perf: update update 2025-02-08 17:28:44 +08:00
jiangweidong
bee45ee7a0 feat: Custom change password supports configuration of interactive items 2025-02-08 16:57:01 +08:00
feng
7bfc0ee507 perf: push record header 2025-02-08 16:03:35 +08:00
zhaojisen
9e768f4ef4 Fixed: Fixed time and thinking tip 2025-02-08 15:38:25 +08:00
zhaojisen
0e53d7e657 Perf: Support DeepSeek 2025-02-08 15:38:25 +08:00
feng
906a1accd1 feat: Chat ai setting 2025-02-08 15:38:25 +08:00
zhaojisen
1e381b06ee Fixed: Export Button Logic Differentiation 2025-02-07 11:21:25 +08:00
ibuler
731ae82bc5 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-06 19:18:24 +08:00
ibuler
8019ee550e perf: move to roles manage to form 2025-02-06 19:18:16 +08:00
w940853815
d7affe1034 perf: integrations application detail add account tab page 2025-02-06 19:11:38 +08:00
ibuler
5f35e0bb94 perf: merge with remote 2025-02-06 12:50:43 +08:00
ibuler
75b70d33ee perf: some feat free 2025-02-06 12:48:16 +08:00
zhaojisen
e3c17ef96d Perf: Add Account Valid License 2025-02-06 11:05:57 +08:00
w940853815
0f6ae3f626 fix: profile preferences api request 404 2025-02-05 18:46:03 +08:00
ibuler
175b819e8e Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-02-05 16:34:44 +08:00
ibuler
9933f68ba9 feat: add xpack lock feat 2025-02-05 16:34:17 +08:00
feng
44e05e7f80 perf: pam dashboard 2025-02-05 15:47:33 +08:00
zhaojisen
f518e4cb10 Perf: Add Cache Option 2025-02-05 11:42:19 +08:00
zhaojisen
b127849388 perf: Perf optimism build cach 2025-02-05 11:20:44 +08:00
feng
7524b6f895 perf: change secret push account record 2025-01-26 17:27:01 +08:00
feng
0a96331218 perf: Push account record 2025-01-26 16:40:41 +08:00
ibuler
caf34a96e6 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-23 14:03:17 +08:00
ibuler
5645d253e5 perf: update pam account 2025-01-23 14:01:54 +08:00
w940853815
e2ad3f3749 fix: PermUser name column is undefined 2025-01-23 10:55:19 +08:00
zhaojisen
b1137249f1 Perf: Perf Dashboard 2025-01-22 18:52:29 +08:00
ibuler
369247d987 perf: update detail header border 2025-01-22 17:47:23 +08:00
ibuler
fe8f594cb4 perf: remove footer 2025-01-22 17:09:16 +08:00
ibuler
64db1176a6 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-22 16:30:43 +08:00
ibuler
27d175a06e perf: update zone detail 2025-01-22 16:30:31 +08:00
zhaojisen
3b96b3c90b Perf: Optimism Interactive Effect 2025-01-21 18:55:51 +08:00
zhaojisen
32183336a2 Perf: Optimism Summery Card 2025-01-21 18:36:32 +08:00
ibuler
fb9d9d6480 perf: merge with remote 2025-01-21 17:50:26 +08:00
ibuler
7394ff27a5 perf: update menu 2025-01-21 17:48:44 +08:00
feng
6093d8915c perf: engine 2025-01-21 17:09:06 +08:00
ibuler
83bb13b806 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-20 19:34:34 +08:00
ibuler
c9062a9e26 perf: update i18n 2025-01-20 19:34:20 +08:00
feng
6dc7cc0b37 perf: pam perm 2025-01-20 18:11:05 +08:00
ibuler
aa631678f8 perf: add it 2025-01-20 18:05:29 +08:00
ibuler
1c36d1b3c6 perf: use close to reslove except confirm 2025-01-20 18:05:01 +08:00
feng
90050bf87d perf: checkaccountautomation perm 2025-01-20 16:37:48 +08:00
zhaojisen
58bb69c252 Perf: Remove isPam item 2025-01-20 11:07:27 +08:00
ibuler
14c3b249a7 perf: update pam 2025-01-15 17:20:17 +08:00
ibuler
4589c4abaf Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-15 17:04:49 +08:00
ibuler
94f1959d40 perf: 修改添加 update secret 2025-01-15 17:04:31 +08:00
zhaojisen
e7c63b2d41 Perf: Add Console Account Formatter 2025-01-15 13:22:08 +08:00
ibuler
e2904acff6 perf: update execution 2025-01-15 10:26:44 +08:00
ibuler
3d1a2d6833 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-14 18:12:56 +08:00
ibuler
d1e340f104 perf: update pam risk handle 2025-01-14 18:12:38 +08:00
zhaojisen
d1a48a2e56 Perf: Perf Pt Language Style 2025-01-14 15:35:11 +08:00
w940853815
6d8f159975 perf: Optimize risk action checks and filters 2025-01-14 14:52:46 +08:00
zhaojisen
5925ac448e Fixed: Fixed the issue that When switching different node export same file 2025-01-13 18:01:16 +08:00
zhaojisen
fdb1dd886b Fixed: Fixed the issue where tag deletion required double-click 2025-01-13 16:30:55 +08:00
ibuler
7075b5c90a perf: update drawer 2025-01-13 11:11:32 +08:00
ibuler
66b3018ace perf: 修改 drawer 2025-01-10 18:33:34 +08:00
ibuler
87ae6242a1 merge: with remote 2025-01-10 18:08:00 +08:00
zhaojisen
de5f1a8bd1 Fixed: Fixed z-index issue between footer and card components\ 2025-01-10 17:58:10 +08:00
ibuler
9cefe70061 perf: update pam 2025-01-10 17:53:44 +08:00
zhaojisen
73cbd4d8d2 Optimism ReviewDrawer Item Style 2025-01-10 17:44:00 +08:00
zhaojisen
02d9f6b116 Perf: Add RiskSummery Item 2025-01-10 15:52:40 +08:00
ibuler
1f5cc25b86 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-09 19:19:05 +08:00
ibuler
63200bca26 perf: 优化 platforms 2025-01-09 19:18:51 +08:00
zhaojisen
305029649e Perf: Add Mission Card 2025-01-09 18:04:08 +08:00
ibuler
cfb7292f36 perf: update tab height 2025-01-09 16:43:12 +08:00
ibuler
582b83d4f5 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-09 16:28:32 +08:00
ibuler
42eaa4996d perf: update page height 2025-01-09 16:28:21 +08:00
feng
df465eef29 perf: dashboard 2025-01-09 16:12:49 +08:00
zhaojisen
b3f8c61df0 Perf: Adjust Card Style 2025-01-09 14:09:11 +08:00
zhaojisen
6f57ef5bcf Perf: Fit SummeryCard style 2025-01-08 17:22:58 +08:00
jiangweidong
7ca47d9015 perf: Check for leaked duplicate passwords. 2025-01-08 16:07:02 +08:00
zhaojisen
b9a0bbf12d Perf: Optimize the DataSummary style 2025-01-08 16:05:07 +08:00
w940853815
4a8c84ee9d perf: Add risk change_password_add handle 2025-01-08 14:34:58 +08:00
jiangweidong
2f9ad17b1f feat: Cloud sync supports syncing tags 2025-01-08 14:34:26 +08:00
zhaojisen
e8e1b35cd3 perf: Add Dashboard Summery 2025-01-08 14:19:57 +08:00
zhaojisen
edd85e700e Fixed: Resolved the issue of duplicate requests by implementing a check for the value of zero. 2025-01-08 11:47:56 +08:00
ibuler
a7378d297f Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-08 10:47:42 +08:00
ibuler
dd75e160c3 perf: update filter 2025-01-08 10:47:29 +08:00
feng
84c78f993b perf: account backup execution detail 2025-01-07 17:54:31 +08:00
zhaojisen
25ba669f67 Perf: Disabled Password Input And Hidden Template Username Input 2025-01-07 15:21:09 +08:00
zhaojisen
3bb3361e2f Perf: Optimize some details 2025-01-07 14:59:27 +08:00
ibuler
d82e557fd1 merge: with remote 2025-01-07 14:36:47 +08:00
ibuler
3c9de27e66 perf: update i18n 2025-01-07 14:35:21 +08:00
feng
276b1a7255 perf: pam translate 2025-01-07 14:20:50 +08:00
zhaojisen
25c7d0a372 Optimize the execution efficiency of data selection 2025-01-06 18:17:06 +08:00
feng
31c630ca25 perf: account gilter 2025-01-06 17:29:53 +08:00
feng626
e5eaa05bdb Merge pull request #4575 from jumpserver/pr@pam@pam_dashboard
perf: Pam dashboard
2025-01-06 17:03:24 +08:00
feng626
2431755f2b Merge branch 'pam' into pr@pam@pam_dashboard 2025-01-06 16:55:33 +08:00
feng
29f35d590e perf: Pam dashboard 2025-01-06 16:51:32 +08:00
zhaojisen
ac9451dd1c Perf: Change Connect Formatter To More Higher-level Encapsulation 2025-01-06 15:21:21 +08:00
zhaojisen
b4ee023b93 Perf: Change Connect To Formatter Component 2025-01-06 14:46:50 +08:00
ibuler
28e7321754 perf: update account prop 2025-01-06 14:03:48 +08:00
ibuler
daab079e3c Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-06 11:27:55 +08:00
ibuler
a32f818abd perf: update pam 2025-01-06 11:27:47 +08:00
feng
d8980e66e3 perf: Change secret check_conn_after_change 2025-01-06 10:53:37 +08:00
jiangweidong
46898d2419 feat: VMware automatically syncs folders to node 2025-01-03 18:52:26 +08:00
zhaojisen
153c29fbcc Perf: Add Filer Icon 2025-01-03 18:45:47 +08:00
ibuler
feb3dbabc2 perf: 优化折叠 2025-01-03 18:37:20 +08:00
ibuler
0ac1e0d75a perf: 优化 form 折叠 2025-01-03 18:32:24 +08:00
ibuler
572e61046f Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-03 15:47:08 +08:00
ibuler
9f47b50dac perf: update icon 2025-01-03 15:46:53 +08:00
zhaojisen
5022ca9075 Perf: Remove Unused Tips and Function 2025-01-03 14:51:06 +08:00
fit2bot
fee2123b49 Perf: Add Account Change Or Move To Different Asset (#4567)
* Perf: Add Account Change Or Move To Different Asset

* Fixed: Fixed Add Account And Template input disabled

* Perf: Add Account Operation Bulk Result

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-01-03 11:05:49 +08:00
ibuler
78e6d4e367 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-02 19:21:45 +08:00
ibuler
a5b8d51747 perf: update account create 2025-01-02 19:21:31 +08:00
w940853815
e9245dfd19 perf: Add redirect and permissions to AccountCheck, update formatter 2025-01-02 18:20:38 +08:00
ibuler
f605192fe1 perf: update create drawer 2025-01-02 17:19:52 +08:00
ibuler
504adad9fe perf: 优化弹窗 2025-01-02 11:27:06 +08:00
ibuler
cd82d8ee92 Merge branch 'pam' of github.com:jumpserver/lina into pam 2025-01-02 09:47:17 +08:00
feng626
d97dbc612c Revert "perf: drawer el-radio-group css"
This reverts commit 368bad6771.
2024-12-31 16:53:24 +08:00
feng
368bad6771 perf: drawer el-radio-group css 2024-12-31 16:39:58 +08:00
ibuler
41cc618a49 perf: 修改更新 2024-12-31 16:31:10 +08:00
w940853815
4f0f1b372e perf: Account discover use drawer component 2024-12-31 16:03:45 +08:00
ibuler
acfac6d45f perf: form 上下结构 2024-12-31 15:48:23 +08:00
ibuler
1a3f483654 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-31 14:23:07 +08:00
ibuler
559177ea32 perf: 优化 detail 2024-12-31 14:22:50 +08:00
zhaojisen
c9f9264c87 Perf: Remove different jump paths for different types of hosts 2024-12-30 18:47:05 +08:00
ibuler
8fabd32426 perf: update detail card 2024-12-30 18:01:13 +08:00
ibuler
6a34bb426c Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-30 17:29:08 +08:00
ibuler
a1edc55ca0 perf: 修改详情布局 2024-12-30 17:29:01 +08:00
zhaojisen
d1366f161d Perf: Connect when select custom protocol 2024-12-30 16:57:07 +08:00
zhaojisen
b58754b6c5 Perf: Add Connect Protocol 2024-12-30 16:22:14 +08:00
feng
ee3e68f3ac perf: Change secret push account add drwaer 2024-12-30 15:21:59 +08:00
ibuler
3a0af18f74 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-27 19:09:04 +08:00
ibuler
24f30ab198 perf: update detail 2024-12-27 19:08:51 +08:00
w940853815
72b9447b12 fix: Update query param names in AssetCreateUpdate and BaseList 2024-12-27 18:08:21 +08:00
zhaojisen
7e24454743 Perf: Change Connect Params 2024-12-27 17:22:14 +08:00
ibuler
48d81dbd19 perf: update create form 2024-12-27 17:20:59 +08:00
ibuler
cdf0a9eed1 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-27 11:04:17 +08:00
ibuler
59cf22a421 perf: 优化 drawer 2024-12-27 11:04:03 +08:00
w940853815
41a34fb2d7 fix: View account discover execution detail 2024-12-27 10:41:41 +08:00
ibuler
4164ea4086 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-26 19:09:17 +08:00
ibuler
a2db27163e perf: 修改 col 宽度 2024-12-26 19:09:05 +08:00
w940853815
5a0b4ec6aa fix: Update discover AccountDetail api url 2024-12-26 19:08:28 +08:00
ibuler
4cfb1a6f37 perf: update account create 2024-12-26 17:18:04 +08:00
ibuler
e2f7fd0d77 perf: update using drawer 2024-12-26 14:34:54 +08:00
ibuler
80d530a2ed perf: update drawer create 2024-12-24 19:20:30 +08:00
ibuler
a1a06e1cbf Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-24 18:40:23 +08:00
ibuler
6bec731396 perf: update pam 2024-12-24 18:37:58 +08:00
w940853815
ac40823319 perf: Update status action to handle multiple accounts 2024-12-24 18:36:27 +08:00
zhaojisen
ef063898ca Perf: Add Windows GUI connect 2024-12-24 16:07:48 +08:00
ibuler
b27a801b04 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-24 15:35:52 +08:00
ibuler
4bcee2fc2d perf: update draw create 2024-12-24 15:35:39 +08:00
feng
b0672bb543 perf: Push account 2024-12-24 10:22:52 +08:00
ibuler
7b0ea02ad4 perf: update asset create 2024-12-23 19:25:52 +08:00
ibuler
eaf7ba5f43 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-20 18:53:50 +08:00
ibuler
28b4aa0d55 perf: update asset create 2024-12-20 18:53:35 +08:00
wangruidong
d9ec7917f3 perf: Delete gather_account 2024-12-20 18:53:02 +08:00
feng
ac6040177a perf: Account push list 2024-12-20 11:03:57 +08:00
Aaron3S
f2ac6a61ab feat: facelive add license check 2024-12-19 17:50:27 +08:00
fit2bot
5f904f99b6 perf: login redirect to next page (#4534)
Co-authored-by: ibuler <ibuler@qq.com>
2024-12-19 15:34:47 +08:00
Bai
6fbef03b33 fix: face auth bind/unbind error when open single page 2024-12-19 15:33:39 +08:00
zhaojisen
98aa11bb64 fixed: Remove Unused Style 2024-12-19 15:29:23 +08:00
zhaojisen
fba83f39bd fixed: Style Error 2024-12-19 12:49:30 +08:00
Bai
c3a2c3c23d fix: enter system org while user login 2024-12-19 12:05:45 +08:00
wangruidong
5125038e9c perf: Add default value validation to VariableCreateUpdateForm 2024-12-19 12:00:38 +08:00
zhaojisen
42ca29bdaf fixed: Side Menu text overflow 2024-12-19 11:16:08 +08:00
ibuler
48e4027525 perf: update draw 2024-12-19 11:07:47 +08:00
zhaojisen
1c4893bc22 fixed: Revert Select Strategy 2024-12-19 10:05:26 +08:00
ibuler
2955b4800f perf: update asset create 2024-12-18 19:46:57 +08:00
wangruidong
5a26589052 fix: Execute after save sometimes the variable is undefine. 2024-12-18 19:15:47 +08:00
zhaojisen
4c2cdc1232 perf: It fits the PT-BR 2024-12-18 18:43:23 +08:00
zhaojisen
cb6e40bea7 fixed: Fixed an issue where the total number of cross-page multiple selections was the number of selected pages 2024-12-18 18:39:27 +08:00
Bai
4c61a84652 fix: approve ticket special account not found 2024-12-18 16:14:27 +08:00
wangruidong
ffaca80b21 feat: Add help tips to VariableCreateUpdateForm fields 2024-12-18 15:54:06 +08:00
ibuler
395b204da3 perf: update action 2024-12-18 11:41:42 +08:00
zhaojisen
0f5f6b860b fixed: Optimize the execution efficiency of full selection and reverse selection, and solve the problem of invalid data selection in card 2024-12-18 11:22:41 +08:00
wangruidong
a9ba931bba perf: Add 'labels' column to AssetPermission and Domain tables 2024-12-18 10:55:48 +08:00
wangruidong
23fae59411 feat: Add permission checks for platform editing 2024-12-17 19:10:27 +08:00
Chenyang Shen
320613d15d Merge pull request #4520 from jumpserver/pr@dev@feat_add_translate
feat: add translate
2024-12-17 17:42:07 +08:00
Aaron3S
57ea32e785 feat: add translate 2024-12-17 17:40:44 +08:00
Eric
3e3f80c59b perf: component names use the same letter case 2024-12-17 16:21:31 +08:00
feng
c15ba5b078 fix: tag search display error 2024-12-17 10:32:18 +08:00
wangruidong
651888faab perf: Add 'labels' column to UserGroupList table 2024-12-16 19:00:00 +08:00
ibuler
71ebd6bf56 Merge branch 'pam_new_draw' into pam 2024-12-16 17:59:55 +08:00
ibuler
0494ce7f5b Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-16 17:59:40 +08:00
ibuler
fdf869cd46 perf: update pam 2024-12-16 17:59:32 +08:00
ibuler
7dfca604c2 perf: update draw create update 2024-12-16 14:41:52 +08:00
feng626
d220047fe2 Revert "perf: Platform global"
This reverts commit bbe80f0292.
2024-12-16 14:09:49 +08:00
feng
bbe80f0292 perf: Platform global 2024-12-16 11:40:35 +08:00
feng
41e73a2c9b perf: Firefox unable to download file 2024-12-13 12:51:52 +08:00
feng
7d89cf9f45 perf: Re-login after csrf expires 2024-12-13 10:23:36 +08:00
ibuler
b4abcd4c90 perf: update draw 2024-12-12 19:03:03 +08:00
Bai
8a048f692f fix: remove log 2024-12-12 18:49:39 +08:00
wangruidong
70777f8335 perf: Add AccountDetail page 2024-12-12 16:01:31 +08:00
Bai
800317346c fix: current org is system and no preorg user logout error 2024-12-12 11:35:31 +08:00
ibuler
d62c87b858 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-12 09:44:28 +08:00
wangruidong
4a1e2db7ca fix: Org admin view platform perms 2024-12-11 19:12:57 +08:00
wangruidong
743187b4b3 fix: risk check perms 2024-12-11 16:36:38 +08:00
ibuler
5c1f24af6a perf: update template 2024-12-11 11:39:27 +08:00
Bai
6702d94ba1 fix: org changed error 2024-12-11 10:37:56 +08:00
ibuler
9477bfa2c1 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-11 10:09:12 +08:00
ibuler
1ba58f476f perf: update async 2024-12-11 10:09:07 +08:00
feng
02600d7a1b perf: Remove push account extra api 2024-12-10 19:36:06 +08:00
Bai
a87d04fb9d fix: user login always change to system org 2024-12-10 19:14:13 +08:00
ibuler
2126c92e07 perf: update status 2024-12-10 16:51:22 +08:00
zhaojisen
367db0daf1 fixed: Fixed a text wrap issue 2024-12-10 16:05:55 +08:00
ibuler
af774a8835 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-10 15:46:44 +08:00
ibuler
b93fad1f91 perf: update check 2024-12-10 15:46:38 +08:00
zhaojisen
ef43be0cb7 perf: Add drawer 2024-12-09 18:52:46 +08:00
zhaojisen
583b28a6c4 fixed: Fixed an organization error after entering Settings under Global Organization manually 2024-12-09 17:19:37 +08:00
ibuler
8b6eea0267 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-09 17:10:36 +08:00
ibuler
d0da22738f perf: update handler 2024-12-09 17:10:30 +08:00
Chenyang Shen
ec5f2e69eb Merge pull request #4498 from jumpserver/pr@dev@feat_change_face_context_url
feat: change face context url
2024-12-09 16:55:22 +08:00
Aaron3S
d058f0e777 feat: change face context url 2024-12-09 16:53:52 +08:00
老广
89befaad43 Create llm-code-review.yml 2024-12-09 16:20:12 +08:00
wangruidong
18eda16851 perf: delete gather account 2024-12-09 16:17:39 +08:00
feng
610e9b9efa perf: Account push 2024-12-09 11:19:18 +08:00
ibuler
a0c7d60719 perf: update table actions 2024-12-09 09:38:49 +08:00
zhaojisen
60ba0d8f02 perf: drawer realize 2024-12-06 19:06:09 +08:00
ibuler
b9afb05f1b perf: update risk batch selected 2024-12-06 19:00:41 +08:00
ibuler
fcf9ea2b79 Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-06 11:38:40 +08:00
ibuler
430b1117c9 perf: update quick filter style 2024-12-06 11:38:27 +08:00
zhaojisen
a65023c8f7 style: Optimized style 2024-12-06 11:36:20 +08:00
zhaojisen
d6de85ffdd perf:Universal Drawer action assembly 2024-12-05 19:35:34 +08:00
ibuler
5f11d8b54f Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-05 19:10:16 +08:00
ibuler
c7ce602d4c perf: update filter 2024-12-05 19:09:52 +08:00
zhaojisen
d0988da277 perf:Universal Drawer assembly 2024-12-05 18:10:40 +08:00
ibuler
7f13ef35a7 perf: update appliations 2024-12-05 16:07:58 +08:00
zhaojisen
548d0e0670 perf:Optimize the execution efficiency of all and reverse selection 2024-12-05 12:39:17 +08:00
ibuler
44348de4ab perf: update card table 2024-12-05 11:15:35 +08:00
ibuler
be82fe1bde Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-04 18:34:42 +08:00
ibuler
2e472dad93 perf: update name space 2024-12-04 18:34:10 +08:00
zhaojisen
7b862ee0e1 fixed: Fixed an issue where all select a large number of data cards died 2024-12-04 16:58:45 +08:00
feng
bbfb237f23 perf: Account backup report 2024-12-04 16:30:19 +08:00
fit2bot
d4e37e9418 fixed: Fixed an issue where multiple selections across pages could not be reversed (#4482)
* fixed: Fixed an issue where multiple selections across pages could not be reversed

* fixed: Fixed an issue where multiple selections across pages could not be reversed

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2024-12-04 15:08:23 +08:00
Bai
b53b1d1e58 perf: languages settings 2024-12-03 17:01:12 +08:00
feng
390224613a perf: Change secret report 2024-12-02 19:10:29 +08:00
zhaojisen
7e0c677ad3 perf: Remove back icon 2024-12-02 17:23:04 +08:00
zhaojisen
9936f2b806 perf: Added pam asset drawer 2024-12-02 17:16:46 +08:00
zhaojisen
bfde8bd28b style: Adjust style 2024-12-02 16:07:24 +08:00
ibuler
4b309d950c Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-12-02 15:20:41 +08:00
zhaojisen
688f06ebac style: Adjust style 2024-12-02 14:26:02 +08:00
ibuler
6fb3b552eb perf: pam update 2024-12-02 14:24:28 +08:00
feng
f27e7bdad4 perf: Change secret record table dashboard 2024-12-02 11:37:49 +08:00
fit2bot
2ee139c92b perf: Change secret dashboard (#4473)
* perf: Change secret dashboard

* style: Modify layout

---------

Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: zhaojisen <1301338853@qq.com>
2024-12-02 10:33:46 +08:00
fit2bot
7a6c156aaa feat: PAM Service (#4474)
* feat: PAM Service

* perf: Remove useless

* perf: Add go module download value

---------

Co-authored-by: jiangweidong <1053570670@qq.com>
2024-12-02 10:33:13 +08:00
fit2bot
0342c73f07 feat: Vault adds Amazon Secrets Manager (#4455)
Co-authored-by: jiangweidong <1053570670@qq.com>
2024-11-29 18:03:26 +08:00
Aaron3S
727d9037d1 feat: move face setting to profile 2024-11-28 18:23:59 +08:00
zhaojisen
11d40b4be1 perf: Add pam template 2024-11-28 18:05:04 +08:00
wangruidong
b772580f99 feat: Add Account Activity List 2024-11-28 17:02:11 +08:00
zhaojisen
fafdb6be5b perf: Basic drawer show 2024-11-28 10:48:37 +08:00
ibuler
2f984530e3 perf: update handler 2024-11-27 19:38:58 +08:00
Bai
b24c244186 perf: remove email format check for email host account 2024-11-27 19:13:28 +08:00
fit2bot
d365aea6a0 perf: add nec and facelive for monitor (#4468)
* perf: add nec and facelive for monitor

* perf: add nec and facelive component log

---------

Co-authored-by: Eric <xplzv@126.com>
2024-11-27 18:51:18 +08:00
zhaojisen
115f1171ad fixed: Fixed an issue with button text overflow in QuickActions 2024-11-27 11:13:51 +08:00
wangruidong
b2b477d4e0 fix: Creating an asset form does not allow deleting the default protocol 2024-11-27 11:01:02 +08:00
wangruidong
1e37ecff11 perf: Add variable management to Job and Adhoc details 2024-11-26 15:05:17 +08:00
ibuler
68b39bbc3d Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-11-25 17:16:42 +08:00
ibuler
d21dc57305 perf: update pam 2024-11-25 17:16:09 +08:00
wangruidong
9cf87404be perf: Add viewAssetOnlineSessionInfo conf 2024-11-25 15:32:21 +08:00
dependabot[bot]
2e51b0dea1 chore(deps): bump elliptic from 6.5.4 to 6.6.0
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.6.0.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.4...v6.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 15:25:22 +08:00
wangruidong
a1f20c6f92 fix: adhoc and playbook detail page display many '-' 2024-11-22 15:24:21 +08:00
wangruidong
6b6a60b84f refactor: Component name and API endpoint 2024-11-22 15:03:23 +08:00
zhaojisen
c58d826898 fixed: Change path naming method 2024-11-22 15:00:11 +08:00
zhaojisen
7e80361635 perf: Add pam connect 2024-11-22 15:00:11 +08:00
zhaojisen
4e999176ed fixed: Fixed an issue where the Form button was hidden 2024-11-22 14:51:40 +08:00
wangruidong
76ff273ec7 fix: run playbook job with no variable 2024-11-21 22:01:02 +08:00
wangruidong
475a77497f fix: disable job has no perms 2024-11-21 18:57:14 +08:00
Bai
5d1301c871 fix: public playbook variables are not displayed by other users 2024-11-21 17:50:59 +08:00
zhaojisen
772f40e13d fixed: Fixed an issue where the Form button was hidden 2024-11-21 14:44:29 +08:00
wangruidong
1b2f7ad28c fix: default value not display 2024-11-21 14:26:39 +08:00
wangruidong
84778881f6 fix: playbook job clone variable error 2024-11-20 23:06:24 +08:00
wangruidong
d6d0338666 perf: Add default value col in Variable & refactor JobUpdateCreate 2024-11-20 21:51:15 +08:00
wangruidong
de6f477d05 fix: playbook clone with variable 2024-11-20 15:35:34 +08:00
wangruidong
03e07ee280 fix: Add error handling in VariableCreateUpdateForm and wrap text in ItemValue 2024-11-20 10:55:51 +08:00
wangruidong
35e2273603 perf: Enhance MFA settings and display 2024-11-20 10:12:56 +08:00
zhaojisen
7a138388b2 fixed: Fixes ESLint issues 2024-11-19 18:05:13 +08:00
Bai
b1f42dd6bf perf: License info remove subscription id 2024-11-19 17:48:49 +08:00
wangruidong
2eeba4ee4f fix: playbook set variable perms 2024-11-19 10:12:52 +08:00
fit2bot
d91579e848 fixed: Fixed an issue where the number of commands overlaps with whether there are command fields (#4437)
* fixed: Fixed an issue where the number of commands overlaps with whether there are command fields

* fixed: Fixed an issue where the number of commands overlaps with whether there are command fields

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2024-11-18 16:13:06 +08:00
wangruidong
13751f14f3 perf: Variable table overflow show tooltip and CodeEditor cursor position 2024-11-18 15:09:51 +08:00
ibuler
b25d2016a6 perf: using checkbox replace switch 2024-11-18 14:35:43 +08:00
wangruidong
7ea00e17bd perf: Cancel template selection if the command is empty 2024-11-15 17:58:32 +08:00
wangruidong
ec78370ecc fix: duplicate variable names and job audit perms issue 2024-11-15 16:01:41 +08:00
ibuler
636630fe57 perf: update pam 2024-11-14 19:01:25 +08:00
ibuler
e18726efc2 perf: update accout check 2024-11-13 18:46:24 +08:00
Aaron3S
c9f62ae5d3 feat: 添加人脸识别 MFA 2024-11-13 17:42:29 +08:00
halo
b80b69dd26 perf: VAULT_BACKEND cannot be modified from the frontend 2024-11-13 17:30:48 +08:00
wangruidong
ac49415061 fix: Solve audit job and variable bugs 2024-11-13 17:30:20 +08:00
ibuler
823c26aa5e Merge branch 'pam' of github.com:jumpserver/lina into pam 2024-11-13 11:03:05 +08:00
ibuler
c0c9d56408 perf: 修改 pam 2024-11-13 11:02:04 +08:00
wangruidong
9edb64837d fix: Job create cannot be saved without setting interval 2024-11-12 15:37:18 +08:00
wangruidong
671fa65930 perf: Admin and auditor can view and stop task 2024-11-12 11:20:06 +08:00
Eric
0da81ea60d perf: add vnc port for endpoint 2024-11-11 21:58:21 +08:00
Halo
c610d396d6 feat: azure key vault (#4418) 2024-11-11 19:42:16 +08:00
zhaojisen
ff4adde897 perf: Add pam connect 2024-11-11 18:38:01 +08:00
feng
0ed02ca7f7 fix: Modify the platform protocol cursor disappears 2024-11-08 16:48:50 +08:00
feng
c22981e2c1 perf: Translate 2024-11-08 15:34:21 +08:00
fit2bot
b0af35a4b9 perf: Create a job that supports adding node parameters (#4412)
* perf: Create a job that supports adding node parameters

* feat: add variables component

* perf: Update file tip position

* feat: Add variable support to job from template

* feat: Parameters can be set when running job

* feat: Supports setting  variable type

* feat: Supports running adhoc with parameters

* feat: Supports running playbook with parameters

* feat: Support setting variables for scheduled tasks

* perf: Translate

---------

Co-authored-by: wangruidong <940853815@qq.com>
2024-11-07 10:41:07 +08:00
ibuler
45ae7cab21 perf: 阶段完成页面 2024-11-06 16:40:35 +08:00
jiangweidong
1d16a165a5 perf: optimization 2024-11-06 15:06:27 +08:00
jiangweidong
f1f4242ad6 perf: Supports automatic release of assets and prevents accidental release of network errors 2024-11-06 15:06:27 +08:00
老广
bff8f10cd5 Create llm-code-review.yml 2024-11-05 18:23:09 +08:00
ibuler
429f5aed90 perf: change table 2024-11-05 17:20:46 +08:00
ibuler
d8999ffc06 perf: update icon 2024-11-05 17:08:37 +08:00
ibuler
fd745f0a26 perf: update account risk list 2024-11-04 18:41:20 +08:00
ibuler
322d12f27f perf: update accout check 2024-11-01 19:06:39 +08:00
Bai
305e44ea1c feat: modify asset permission default expired from settings 2024-11-01 18:23:38 +08:00
ibuler
a1bc8ac5bc perf: update accout check 2024-11-01 18:04:53 +08:00
ibuler
9271cb2e1a perf: 更新账号发现 2024-11-01 16:38:21 +08:00
ibuler
0e7c682f72 perf: update gather account 2024-10-29 19:23:29 +08:00
ibuler
c0b4029917 perf: add account status action 2024-10-28 18:57:03 +08:00
ibuler
b1acb62889 perf: update table action 2024-10-25 10:55:35 +08:00
ibuler
26fd9b1813 perf: 更新 quick filter 2024-10-24 14:42:39 +08:00
ibuler
4fabdfdc5f perf: 完善过滤 2024-10-23 18:52:50 +08:00
ibuler
6e894c31a1 perf: update route 2024-10-22 17:30:30 +08:00
ibuler
d8a6fd96ce perf: support options 2024-10-21 17:02:22 +08:00
ibuler
7c5c5f966d perf: asset add account info 2024-10-18 15:21:58 +08:00
feng
a636bb2037 perf: List preference translate 2024-10-18 14:32:45 +08:00
fit2bot
9b6f54c1ed perf: update placeholder (#4409)
* perf: update passkey create

* perf: update placeholder

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-10-17 11:10:18 +08:00
feng
611341307b fix: ticket duplicate submission 2024-10-16 19:09:18 +08:00
ibuler
f8479c53ff perf: update passkey create 2024-10-16 18:51:56 +08:00
ibuler
8b25fd198e perf: change account 2024-10-16 18:48:37 +08:00
wangruidong
e25bf46659 perf: url is null set remote false 2024-10-16 18:36:12 +08:00
wangruidong
6d07307e56 perf: users use Select2 2024-10-16 16:54:34 +08:00
wangruidong
6fb7fe8fa1 fix: interval field check 2024-10-16 11:01:44 +08:00
ibuler
762fa4c17e perf: 完成一些快速筛选 2024-10-15 18:26:53 +08:00
zhaojisen
19cd497095 fixed: Restores remote application styles 2024-10-15 17:06:06 +08:00
ibuler
73cc319e7b perf: table action flex 2024-10-15 15:15:46 +08:00
wangruidong
d858489367 fix: modify getPreference url 2024-10-15 14:13:10 +08:00
ibuler
d90aba37cf perf: update loader 2024-10-15 13:58:56 +08:00
feng
341a30ba06 perf: The platform gets activeMenu and adds a default value 2024-10-15 11:32:51 +08:00
ibuler
d775ffa501 perf: format 2024-10-14 18:10:07 +08:00
ibuler
e8cf8347e9 perf: 基本完成框架 2024-10-14 14:49:20 +08:00
ZhaoJiSen
8390fb7429 Merge pull request #4398 from jumpserver/pr@dev@help_tip
perf: Help text automatic line wrapping
2024-10-12 14:40:43 +08:00
feng
5389f1d011 perf: Help text automatic line wrapping 2024-10-12 14:39:15 +08:00
ZhaoJiSen
bde642570f Merge pull request #4397 from jumpserver/pr@dev@perf_reveiver
style: Set special receiver to optimize the scroll wheel display
2024-10-12 11:35:16 +08:00
zhaojisen
3e7b970fe7 style: Set special receiver to optimize the scroll wheel display 2024-10-12 11:32:05 +08:00
ibuler
7ff1da71d4 perf: updat asset list and account list action 2024-10-11 19:22:39 +08:00
ZhaoJiSen
2421e822b4 Merge pull request #4396 from jumpserver/pr@dev@perf_number_style
style: Optimize the number field style
2024-10-11 18:19:35 +08:00
zhaojisen
b2e474e3f6 style: Optimize the number field style 2024-10-11 18:15:46 +08:00
ibuler
a23a0d0197 perf: update perm 2024-10-11 17:59:00 +08:00
ZhaoJiSen
541836390a Merge pull request #4394 from jumpserver/pr@dev@fix_tab_change
fixed: Fixed command filtering and command group tab switching issues
2024-10-10 18:55:00 +08:00
zhaojisen
bb92e3f22b fixed: Fixed command filtering and command group tab switching issues 2024-10-10 18:51:50 +08:00
ZhaoJiSen
c9ad797b40 Merge pull request #4393 from jumpserver/pr@dev@fix_quick_job_node
fixed: Fixed the shortcut command selection node issue
2024-10-10 18:39:34 +08:00
zhaojisen
2a08310efc fixed: Fixed the shortcut command selection node issue 2024-10-10 18:37:47 +08:00
zhaojisen
3b2803b9a1 fixed: Fixed the shortcut command selection node issue 2024-10-10 18:36:33 +08:00
wangruidong
1b8ac9112e fix: user lack permission to view the type tree 2024-10-10 17:11:13 +08:00
ZhaoJiSen
9cc3dd4de9 Merge pull request #4390 from jumpserver/pr@dev@fix_add_lineHeight
style: Add Line Height
2024-10-10 14:40:30 +08:00
zhaojisen
120ef70eb1 style: Add Line Height 2024-10-10 14:36:01 +08:00
ZhaoJiSen
541f4ebc62 Merge pull request #4389 from jumpserver/pr@dev@fix_remote_app
style: Adjusting the styles of the remote application
2024-10-10 14:17:52 +08:00
zhaojisen
a47636abc7 style: Adjusting the styles of the remote application 2024-10-10 14:11:53 +08:00
ZhaoJiSen
78f6f4b36a Merge pull request #4388 from jumpserver/pr@dev@fix_comments_style
fixed: Fixed the presentation format of asset notes
2024-10-10 11:23:16 +08:00
zhaojisen
5abc0b77cf fixed: Fixed the presentation format of asset notes 2024-10-10 11:18:49 +08:00
ZhaoJiSen
464638e782 Merge pull request #4387 from jumpserver/pr@dev@fix_input_border
style: Fixed the display of the account number input box
2024-10-10 10:46:23 +08:00
zhaojisen
37cfeb2077 style: Fixed the display of the account number input box 2024-10-10 10:43:09 +08:00
ZhaoJiSen
44e297f01a Merge pull request #4386 from jumpserver/pr@dev@fix_tooltip_position
fixed: Fixed issue with sidebar toolTip placement
2024-10-10 09:50:33 +08:00
zhaojisen
febc283e36 fixed: Fixed issue with sidebar toolTip placement 2024-10-10 09:47:05 +08:00
ZhaoJiSen
dae33f55e8 Merge pull request #4385 from jumpserver/pr@dev@fix_special_chara
fixed: Fixed + and - not being special characters
2024-10-09 18:38:23 +08:00
zhaojisen
c62cd27690 fixed: Fixed + and - not being special characters 2024-10-09 18:34:31 +08:00
ZhaoJiSen
83443f8187 Merge pull request #4383 from jumpserver/pr@dev@fix_tab_refresh
fixed: Fixed An issue where adding a tag to asset does not work
2024-10-09 17:26:08 +08:00
zhaojisen
cb46f393e0 fixed: Fixed An issue where adding a tag to asset does not work 2024-10-09 17:17:12 +08:00
wangruidong
ddf5ac2151 fix: Determine the asset connection opening method based on the settings 2024-10-09 16:44:25 +08:00
wangruidong
88173f852a perf: Default endpoint cannot be disabled 2024-10-09 16:43:16 +08:00
wangruidong
d5f16e90e2 perf: add created_by field 2024-10-09 16:15:36 +08:00
ZhaoJiSen
d1c0aca4ff Merge pull request #4380 from jumpserver/pr@dev@fix_font_size
fixed: Fixed an issue where the font size of the resource is too large due to the parent element's font size being overridden
2024-10-09 14:47:42 +08:00
zhaojisen
a42edf17ec fixed: Fixed an issue where the font size of the resource is too large due to the parent element's font size being overridden 2024-10-09 14:32:06 +08:00
feng
dac5dfcd1c perf: Optimize file audit download prompt 2024-09-29 16:12:41 +08:00
ZhaoJiSen
8e6ca146e1 Merge pull request #4353 from jumpserver/dependabot/npm_and_yarn/serve-static-1.16.0
chore(deps-dev): bump serve-static from 1.15.0 to 1.16.0
2024-09-29 10:16:07 +08:00
ZhaoJiSen
9c06d36eab Merge pull request #4351 from jumpserver/dependabot/npm_and_yarn/path-to-regexp-3.3.0
chore(deps): bump path-to-regexp from 2.4.0 to 3.3.0
2024-09-29 10:14:32 +08:00
wisonic
ab7bd574f8 fix: assets proportion tooltip cause page bounced at first time 2024-09-27 17:34:25 +08:00
wangruidong
6007dc8621 perf: Endpoint add is_active field 2024-09-27 16:00:40 +08:00
wangruidong
a0e7c48dc9 perf: adhoc can clone 2024-09-27 14:12:13 +08:00
wangruidong
71dea791bf fix: xterm output truncate 2024-09-26 17:17:23 +08:00
ZhaoJiSen
e1b9184f41 Merge pull request #4372 from jumpserver/pr@dev@fix_perm_list_tree
fixed: Fixed an issue with draggable Tree nodes under asset authorization
2024-09-26 17:02:08 +08:00
zhaojisen
730d47f02a fixed: Fixed an issue with draggable Tree nodes under asset authorization 2024-09-26 16:59:18 +08:00
feng
e82ec68935 perf: The maximum length of the randomly generated password is changed to 36 2024-09-25 10:54:05 +08:00
feng
e8e5975d7f fix: fix after successfully creating an asset, the asset list cannot be partially refreshed 2024-09-24 15:44:55 +08:00
ibuler
1477712c78 perf: 修改 Pam 2024-09-19 09:57:54 +08:00
ibuler
77a0100add perf: add pam panel 2024-09-12 18:56:34 +08:00
ibuler
833e44024f perf: change pkg deps 2024-09-12 11:33:33 +08:00
dependabot[bot]
af4010e299 chore(deps-dev): bump serve-static from 1.15.0 to 1.16.0
Bumps [serve-static](https://github.com/expressjs/serve-static) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...1.16.0)

---
updated-dependencies:
- dependency-name: serve-static
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-12 02:22:33 +00:00
dependabot[bot]
879df90503 chore(deps): bump path-to-regexp from 2.4.0 to 3.3.0
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 2.4.0 to 3.3.0.
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v2.4.0...v3.3.0)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-11 18:05:18 +00:00
753 changed files with 37918 additions and 13857 deletions

View File

@@ -14,64 +14,97 @@ module.exports = {
window: true,
_: true
},
plugins: ['vue', 'spellcheck'],
// add your custom rules here
// it is base on https://github.com/vuejs/eslint-config-vue
rules: {
'vue/max-attributes-per-line': [2, {
'singleline': 10,
'multiline': {
'max': 1,
'allowFirstLine': false
'vue/max-attributes-per-line': [
2,
{
singleline: 10,
multiline: {
max: 1,
allowFirstLine: false
}
}
}],
],
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/name-property-casing': ['error', 'PascalCase'],
'vue/no-v-html': 'off',
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'arrow-spacing': [
2,
{
before: true,
after: true
}
],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'brace-style': [
2,
'1tbs',
{
allowSingleLine: true
}
],
camelcase: [
0,
{
properties: 'always'
}
],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-spacing': [
2,
{
before: false,
after: true
}
],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
curly: [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ['error', 'always', { 'null': 'ignore' }],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
eqeqeq: ['error', 'always', { null: 'ignore' }],
'generator-star-spacing': [
2,
{
before: true,
after: true
}
],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
indent: [
2,
2,
{
SwitchCase: 1
}
],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'key-spacing': [
2,
{
beforeColon: false,
afterColon: true
}
],
'keyword-spacing': [
2,
{
before: true,
after: true
}
],
'new-cap': [
2,
{
newIsCap: true,
capIsNew: false
}
],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
@@ -102,17 +135,23 @@ module.exports = {
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-labels': [
2,
{
allowLoop: false,
allowSwitch: false
}
],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-multiple-empty-lines': [
2,
{
max: 1
}
],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
@@ -140,62 +179,126 @@ module.exports = {
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unneeded-ternary': [
2,
{
defaultAssignment: false
}
],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-unused-vars': [
2,
{
vars: 'all',
args: 'none'
}
],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
'one-var': [
2,
{
initialized: 'never'
}
}],
],
'operator-linebreak': [
2,
'after',
{
overrides: {
'?': 'before',
':': 'before'
}
}
],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
quotes: [
2,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true
}
],
semi: [2, 'never'],
'semi-spacing': [
2,
{
before: false,
after: true
}
],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-before-function-paren': [
2,
{ anonymous: 'never', named: 'never', asyncArrow: 'always' }
],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'space-unary-ops': [
2,
{
words: true,
nonwords: false
}
],
'object-curly-spacing': [2, 'always'],
'spaced-comment': [
2,
'always',
{
markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}
],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
yoda: [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
'array-bracket-spacing': [2, 'never'],
'spellcheck/spell-checker': [
'warn',
{
comments: true,
strings: false,
identifiers: false,
lang: 'en_US',
skipWords: [
'echarts',
'resize',
'vue',
'eslint',
'babel',
'jsx',
'scss',
'v-deep',
'calc',
'vw',
'vh',
'px',
'rgba',
'rgb',
'var',
'lang',
'scoped',
'pdf',
'rbac'
],
skipIfMatch: [
'http://[^s]*',
'^[-\\w]+/[-\\w\\.]+$',
String.raw`^\/api\/[a-z0-9\/._-]+$`,
],
minLength: 3
}
]
}
}

View File

@@ -0,0 +1,28 @@
name: LLM Code Review
permissions:
contents: read
pull-requests: write
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
llm-code-review:
runs-on: ubuntu-latest
steps:
- uses: fit2cloud/LLM-CodeReview-Action@main
env:
GITHUB_TOKEN: ${{ secrets.FIT2CLOUDRD_LLM_CODE_REVIEW_TOKEN }}
OPENAI_API_KEY: ${{ secrets.ALIYUN_LLM_API_KEY }}
LANGUAGE: English
OPENAI_API_ENDPOINT: https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL: qwen2-1.5b-instruct
PROMPT: "Please check the following code differences for any irregularities, potential issues, or optimization suggestions, and provide your answers in English."
top_p: 1
temperature: 1
# max_tokens: 10000
MAX_PATCH_LENGTH: 10000
IGNORE_PATTERNS: "/node_modules,*.md,/dist,/.github"
FILE_PATTERNS: "*.java,*.go,*.py,*.vue,*.ts,*.js,*.css,*.scss,*.html"

28
.github/workflows/llm-code-review.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: LLM Code Review
permissions:
contents: read
pull-requests: write
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
llm-code-review:
runs-on: ubuntu-latest
steps:
- uses: fit2cloud/LLM-CodeReview-Action@main
env:
GITHUB_TOKEN: ${{ secrets.FIT2CLOUDRD_LLM_CODE_REVIEW_TOKEN }}
OPENAI_API_KEY: ${{ secrets.ALIYUN_LLM_API_KEY }}
LANGUAGE: English
OPENAI_API_ENDPOINT: https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL: qwen2-1.5b-instruct
PROMPT: "Please check the following code differences for any irregularities, potential issues, or optimization suggestions, and provide your answers in English."
top_p: 1
temperature: 1
# max_tokens: 10000
MAX_PATCH_LENGTH: 10000
IGNORE_PATTERNS: "/node_modules,*.md,/dist,/.github"
FILE_PATTERNS: "*.java,*.go,*.py,*.vue,*.ts,*.js,*.css,*.scss,*.html"

2
.gitignore vendored
View File

@@ -17,3 +17,5 @@ tests/**/coverage/
*.sln
.env.development
.python-version
helper.json

57
.prettierignore Normal file
View File

@@ -0,0 +1,57 @@
# Dependencies
node_modules/
dist/
build/
lina/
# Logs
*.log
logs/
# Runtime data
pids/
*.pid
*.seed
# Coverage directory used by tools like istanbul
coverage/
# Generated files
*.min.js
*.min.css
# Package files
*.tgz
*.tar.gz
# Lock files
package-lock.json
yarn.lock
# Build outputs
*.map
# Config files that shouldn't be formatted
.eslintrc.js
babel.config.js
jest.config.js
vue.config.js
postcss.config.js
# Theme files
src/styles/fonts/
public/fonts/
lina/fonts/
# Assets
src/assets/
public/
# Mock data
mock/
# Test files
tests/
# Documentation
*.md

11
.prettierrc.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
singleQuote: true,
semi: false,
trailingComma: 'none',
printWidth: 100,
tabWidth: 2,
useTabs: false,
bracketSpacing: true,
arrowParens: 'avoid',
endOfLine: 'auto'
}

View File

@@ -1,4 +1,4 @@
FROM jumpserver/lina-base:20240723_084702 AS stage-build
FROM jumpserver/lina-base:20251204_081759 AS stage-build
ARG VERSION
ENV VERSION=$VERSION

76
PRETTIER.md Normal file
View File

@@ -0,0 +1,76 @@
# Prettier 配置说明
本项目已配置 Prettier 代码格式化工具,**仅在保存时自动格式化**,不进行批量格式化,以保持现有代码风格。
## 配置文件
- `.prettierrc` - Prettier 配置文件
- `.prettierignore` - 忽略格式化的文件列表
- `.vscode/settings.json` - VSCode 编辑器配置(保存时自动格式化)
- `.vscode/extensions.json` - 推荐的 VSCode 扩展
## 使用方法
### 1. 安装依赖
项目已安装以下依赖:
- `prettier@^2.8.8` - Prettier 核心
- `eslint-plugin-prettier@^3.1.4` - ESLint 与 Prettier 集成
- `eslint-config-prettier@^6.15.0` - 禁用与 Prettier 冲突的 ESLint 规则
### 2. 命令行使用
```bash
# ESLint 检查和修复
npm run fix
```
**注意**:本项目配置为仅在保存时自动格式化,不提供批量格式化命令。
### 3. VSCode 编辑器配置
确保安装了推荐的扩展:
- Prettier - Code formatter (esbenp.prettier-vscode)
- ESLint (dbaeumer.vscode-eslint)
- Vetur (octref.vetur)
配置已设置为保存时自动格式化。
### 4. Git 提交钩子
项目使用 `husky``lint-staged` 在提交时进行代码检查:
- 提交时运行 ESLint 检查和修复
- 不进行批量格式化,保持原有代码风格
## Prettier 配置说明
```json
{
"semi": false, // 不使用分号
"singleQuote": true, // 使用单引号
"tabWidth": 0, // 不使用缩进
"useTabs": false, // 使用空格而不是制表符
"trailingComma": "none", // 不使用尾随逗号
"printWidth": 100, // 行宽 100 字符
"bracketSpacing": true, // 对象括号内有空格
"arrowParens": "avoid", // 箭头函数单参数时不使用括号
"endOfLine": "lf", // 使用 LF 换行符
"vueIndentScriptAndStyle": false // Vue 文件中 script 和 style 标签不缩进
}
```
## 常见问题
### Q: 如何临时禁用格式化?
A: 使用注释:
```javascript
// prettier-ignore
const uglyCode = {
a:1,b:2
}
```
### Q: 如何添加文件到忽略列表?
A: 编辑 `.prettierignore` 文件,添加文件或目录路径。
### Q: VSCode 保存时没有自动格式化?
A: 检查是否安装了 Prettier 扩展,并确认 `.vscode/settings.json` 配置正确。

View File

@@ -5,5 +5,6 @@
"@/*": ["src/*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -1,13 +1,25 @@
import Mock from 'mockjs'
import { param2Obj } from '../src/utils'
import user from './user'
import table from './table'
const mocks = [
...user,
...table
]
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}
const mocks = [...user, ...table]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,

View File

@@ -2,7 +2,7 @@
"name": "lina",
"version": "v4.0.0",
"description": "JumpServer Web UI",
"author": "JumpServer Team <support@fit2cloud.com>",
"author": "JumpServer Team <support@lxware.hk>",
"license": "GPL-3.0-or-later",
"scripts": {
"dev": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
@@ -26,19 +26,22 @@
"dependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@fontsource/open-sans": "^5.0.24",
"@kangc/v-md-editor": "^1.7.12",
"@traptitech/markdown-it-katex": "^3.6.0",
"@ztree/ztree_v3": "3.5.44",
"axios": "0.28.0",
"axios-retry": "^3.1.9",
"babel-loader": "^10.0.0",
"cache-loader": "^4.1.0",
"caniuse-lite": "^1.0.30001642",
"cron-parser": "^4.0.0",
"crypto-js": "^4.1.1",
"css-color-function": "^1.3.3",
"decimal.js": "^10.4.3",
"deepmerge": "^4.2.2",
"dompurify": "^3.1.6",
"dompurify": "^3.2.4",
"echarts": "4.7.0",
"element-ui": "2.15.14",
"element-ui": "https://github.com/jumpserver-dev/element/releases/download/v2.15.15/jumpserver-element-ui-2.15.15.tgz",
"eslint-plugin-html": "^6.0.0",
"highlight.js": "^11.9.0",
"install": "^0.13.0",
@@ -48,17 +51,6 @@
"less": "^3.10.3",
"less-loader": "^5.0.0",
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"lodash.frompairs": "^4.0.1",
"lodash.get": "^4.4.2",
"lodash.has": "^4.5.2",
"lodash.includes": "^4.3.0",
"lodash.isempty": "^4.4.0",
"lodash.isequal": "^4.5.0",
"lodash.isplainobject": "^4.0.6",
"lodash.set": "^4.3.2",
"lodash.topairs": "^4.3.0",
"lodash.values": "^4.3.0",
"markdown-it": "^13.0.2",
"markdown-it-link-attributes": "^4.0.1",
"moment": "^2.29.4",
@@ -66,21 +58,24 @@
"normalize.css": "7.0.0",
"npm": "^7.8.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"path-to-regexp": "3.3.0",
"socket.io-client": "^4.8.1",
"sortablejs": "^1.15.6",
"uuid": "8.3.2",
"v-sanitize": "^0.0.13",
"vue": "2.6.10",
"vue": "2.7.16",
"vue-codemirror": "4.0.6",
"vue-cookie": "^1.1.4",
"vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.15.5",
"vue-json-editor": "^1.4.3",
"vue-markdown": "^2.2.4",
"vue-moment": "^4.1.0",
"vue-password-strength-meter": "^1.7.2",
"vue-router": "3.0.6",
"vue-select": "^3.9.5",
"vuejs-logger": "^1.5.4",
"vuex": "3.1.0",
"watermark-js-plus": "^1.5.8",
"xss": "^1.0.14",
"xterm": "^4.5.0",
"xterm-addon-fit": "^0.3.0",
@@ -95,15 +90,17 @@
"@vue/cli-service": "3.6.0",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "7.0.0-bridge.0",
"babel-core": "6.26.3",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"compression-webpack-plugin": "^6.1.1",
"connect": "3.6.6",
"deasync": "^0.1.29",
"element-theme-chalk": "^2.13.1",
"eslint": "^5.15.3",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-spellcheck": "^0.0.20",
"eslint-plugin-vue": "5.2.2",
"eslint-plugin-vue-i18n": "^0.3.0",
"github-markdown-css": "^5.1.0",
@@ -112,20 +109,23 @@
"less-loader": "^5.0.0",
"lint-staged": "^10.1.2",
"mockjs": "1.0.1-beta3",
"prettier": "^3.6.2",
"pretty-bytes": "^5.6.0",
"runjs": "^4.3.2",
"sass": "~1.32.6",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"serve-static": "^1.16.0",
"strip-ansi": "^7.1.0",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-i18n-extract": "^1.1.1",
"vue-template-compiler": "2.6.10"
"vue-template-compiler": "2.7.16",
"webpack": "^4.28.4"
},
"engines": {
"node": ">=8.9",
"node": ">=12",
"npm": ">= 3.0.0"
},
"browserslist": [
@@ -142,5 +142,6 @@
"src/**/*.{js,vue}": [
"eslint --fix"
]
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

View File

@@ -1,38 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<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">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="0" http-equiv="Expires">
<meta content="no-cache" http-equiv="Pragma">
<meta content="no-cache" http-equiv="Cache-control">
<meta content="no-cache" http-equiv="Cache">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title><%= webpackConfig.name %></title>
<link rel="stylesheet" href="<%= BASE_URL %>theme/element-ui.css">
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<script>
window.onload = function() {
<link href="<%= BASE_URL %>theme/element-ui.css" rel="stylesheet">
<style>
#loading {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(255, 255, 255, 0.98);
z-index: 9999;
}
#loading .spinner {
width: 40px;
height: 40px;
border: 3px solid transparent;
border-top-color: var(--color-primary);
border-radius: 50%;
animation: spin 1s linear infinite;
}
#loading .spinner::after {
content: '';
position: absolute;
top: -3px;
left: -3px;
width: 40px;
height: 40px;
border: 3px solid transparent;
border-top-color: rgba(64, 158, 255, 0.2);
border-radius: 50%;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<noscript>
<strong>
We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled.
Please enable it to continue.
</strong>
</noscript>
<script>
window.onload = function () {
if (location.pathname === '/') {
location.pathname = '/ui/'
location.pathname = '/ui/'
}
const pathname = window.location.pathname
if (pathname.startsWith('/core')) {
return
}
if(pathname.indexOf('/ui') === -1) {
window.location.href = window.location.origin + '/ui/#' + pathname
if (pathname.indexOf('/ui') === -1) {
window.location.href = window.location.origin + '/ui/#' + pathname
}
if (pathname.startsWith('/ui/#/chat')) {
window.location.href = window.location.origin + pathname
window.location.href = window.location.origin + pathname
}
}
</script>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
}
</script>
<div id="app">
</div>
<div id="loading">
<div class="spinner"></div>
</div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -5,14 +5,90 @@
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import { Watermark } from 'watermark-js-plus'
export default {
name: 'App',
data() {
return {
watermark: null
}
},
computed: {
...mapState({
isRouterAlive: state => state.common.isRouterAlive
}),
...mapGetters({
currentUser: 'currentUser',
publicSettings: 'publicSettings'
})
},
watch: {
currentUser: {
handler(newVal) {
this.createWatermark()
}
},
'publicSettings.SECURITY_WATERMARK_ENABLED': {
handler(newVal) {
if (!newVal) {
return setTimeout(() => {
this.watermark?.destroy()
this.watermark = null
})
}
this.createWatermark()
}
}
},
methods: {
getWaterMarkFields() {
const user = this.currentUser
const userId = user?.id || ''
const name = user?.name || ''
const userName = user?.username || ''
const currentTime = this.$moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
return { userId, name, userName, currentTime }
},
getWaterMarkContent() {
const fields = this.getWaterMarkFields()
const template = this.publicSettings.SECURITY_WATERMARK_CONSOLE_CONTENT || ''
// 找出模板中所有的变量占位符 ${xxx}
const placeholders = template.match(/\${([^}]+)}/g) || []
const allVariables = {}
// 为模板中的每个变量准备值
placeholders.forEach(placeholder => {
const varName = placeholder.slice(2, -1) // 提取变量名,去掉 ${ 和 }
allVariables[varName] = fields[varName] !== undefined ? fields[varName] : 'N/A'
})
// 合并用户现有的字段和模板中可能缺失的字段
const safeFields = { ...fields, ...allVariables }
// 安全解析模板
return new Function(...Object.keys(safeFields), `return \`${template}\`;`)(...Object.values(safeFields))
},
createWatermark() {
if (this.currentUser?.username && this.publicSettings?.SECURITY_WATERMARK_ENABLED) {
this.watermark = new Watermark({
content: this.getWaterMarkContent(),
width: this.publicSettings?.SECURITY_WATERMARK_WIDTH,
height: this.publicSettings?.SECURITY_WATERMARK_HEIGHT,
rotate: this.publicSettings?.SECURITY_WATERMARK_ROTATE,
fontWeight: 'normal',
fontSize: this.publicSettings?.SECURITY_WATERMARK_FONT_SIZE + 'px',
fontColor: this.publicSettings?.SECURITY_WATERMARK_COLOR,
contentType: 'multi-line-text',
lineHeight: this.publicSettings?.SECURITY_WATERMARK_FONT_SIZE
})
this.watermark.create()
}
}
}
}
</script>

View File

@@ -16,9 +16,9 @@ export function getSystemUserList(data) {
})
}
export function getDomainList(data) {
export function getZoneList(data) {
return request({
url: '/api/v1/assets/domains/',
url: '/api/v1/assets/zones/',
method: 'get',
params: data
})

View File

@@ -53,7 +53,7 @@ export function createJob(form) {
})
}
export function StopJob(form) {
export function stopJob(form) {
return request({
url: '/api/v1/ops/job-executions/stop/',
method: 'post',
@@ -61,13 +61,21 @@ export function StopJob(form) {
})
}
export function JobUploadFile(form) {
export function JobUploadFile(form, config = {}) {
return request({
url: '/api/v1/ops/jobs/upload/',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 60 * 60 * 1000,
data: form
data: form,
...config
})
}
export function auditUpdateJob(id, form) {
return request({
url: `/api/v1/audits/jobs/${id}/`,
method: 'patch',
data: form
})
}

View File

@@ -18,14 +18,14 @@ export function toggleLockSession(data) {
export function getAllCommandStorage() {
return request({
url: `/api/v1/terminal/command-storages/`,
url: '/api/v1/terminal/command-storages/',
method: 'get'
})
}
export function getAllReplayStorage() {
return request({
url: `/api/v1/terminal/replay-storages/`,
url: '/api/v1/terminal/replay-storages/',
method: 'get'
})
}

View File

@@ -15,6 +15,7 @@ export function testEmailSetting(data) {
data: data
})
}
export function importLicense(formData) {
return request({
url: '/api/v1/xpack/license/import',
@@ -25,6 +26,7 @@ export function importLicense(formData) {
data: formData
})
}
export function testLdapSetting(data, refresh = true) {
let url = '/api/v1/settings/ldap/testing/config/'
if (refresh) {
@@ -96,9 +98,17 @@ export function getPublicSettings(isOpen) {
method: 'get'
})
}
export function getLogo() {
return request({
url: '/api/v1/xpack/interface/setting/',
method: 'get'
})
}
export function getPreference() {
return request({
url: '/api/v1/users/preference/?category=luna',
method: 'get'
})
}

View File

@@ -8,11 +8,20 @@ export function login(data) {
})
}
export function getProfile(token) {
return request({
export async function getProfile(token) {
let profile = await request({
url: '/api/v1/users/profile/',
method: 'get'
})
const perms = await request({
url: '/api/v1/users/profile/permissions/',
method: 'get'
})
profile = {
...profile,
...perms
}
return profile
}
export function getUserList(data) {
@@ -22,6 +31,7 @@ export function getUserList(data) {
params: data
})
}
export function getUserGroupList(params) {
return request({
url: '/api/v1/users/groups/',
@@ -29,6 +39,7 @@ export function getUserGroupList(params) {
params: params
})
}
export function getUserGroupDetail(id) {
return request({
url: `/api/v1/users/groups/${id}/`,
@@ -50,6 +61,7 @@ export function editUserGroup(data) {
data: data
})
}
export function updateUserGroup(id, data) {
return request({
url: '/api/v1/users/groups/' + id + '/',

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1752631175762" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4421" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M93.866667 234.666667c-34.133333 12.8-51.2 25.6-51.2 34.133333 0 4.266667 51.2 64 115.2 136.533333 64 68.266667 115.2 128 115.2 128s-51.2 59.733333-115.2 128C93.866667 729.6 42.666667 793.6 42.666667 797.866667c4.266667 17.066667 59.733333 42.666667 98.133333 42.666666 64 0 81.066667-12.8 217.6-162.133333 68.266667-76.8 128-140.8 128-140.8 0-4.266667-55.466667-64-123.733333-140.8-85.333333-102.4-132.266667-145.066667-153.6-157.866667-29.866667-12.8-81.066667-17.066667-115.2-4.266666z m725.333333 4.266666c-21.333333 8.533333-68.266667 59.733333-153.6 153.6-68.266667 76.8-123.733333 140.8-123.733333 140.8 0 4.266667 55.466667 68.266667 128 140.8 136.533333 153.6 153.6 162.133333 217.6 162.133334 42.666667 0 98.133333-21.333333 98.133333-42.666667 0-4.266667-51.2-68.266667-115.2-136.533333-64-68.266667-115.2-128-115.2-128s51.2-59.733333 115.2-128c64-68.266667 115.2-128 115.2-136.533334-4.266667-17.066667-55.466667-38.4-98.133333-38.4-34.133333 0-46.933333 4.266667-68.266667 12.8z" fill="#E57000" p-id="4422"></path><path d="M238.933333 136.533333c-42.666667 21.333333-42.666667 25.6-4.266666 68.266667 221.866667 243.2 273.066667 302.933333 277.333333 302.933333 4.266667 0 311.466667-332.8 315.733333-341.333333 0-4.266667-8.533333-12.8-21.333333-21.333333-17.066667-12.8-34.133333-17.066667-68.266667-17.066667-64-4.266667-85.333333 8.533333-162.133333 93.866667-34.133333 38.4-64 72.533333-64 72.533333s-29.866667-29.866667-64-68.266667c-34.133333-38.4-72.533333-76.8-89.6-85.333333-25.6-17.066667-89.6-21.333333-119.466667-4.266667zM354.133333 725.333333c-85.333333 93.866667-153.6 170.666667-153.6 174.933334 0 4.266667 8.533333 12.8 21.333334 21.333333 17.066667 12.8 34.133333 17.066667 68.266666 17.066667 59.733333 4.266667 85.333333-8.533333 162.133334-98.133334 34.133333-38.4 64-68.266667 64-68.266666s29.866667 29.866667 64 68.266666c81.066667 89.6 98.133333 102.4 162.133333 98.133334 34.133333 0 51.2-4.266667 68.266667-17.066667 12.8-8.533333 21.333333-17.066667 21.333333-21.333333-4.266667-8.533333-311.466667-345.6-315.733333-341.333334-8.533333 0-76.8 76.8-162.133334 166.4z" p-id="4423"></path></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1748326203303" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2853" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M10.24 605.184l839.168-481.28L1013.76 220.672v191.488L174.592 895.488 10.24 804.352z" fill="#0096FF" p-id="2854"></path><path d="M10.24 416.768V220.672l168.96-96.768 308.736 178.688-331.776 193.536zM541.184 717.312l331.264-195.072 141.312 88.064v194.048l-165.376 95.744z" fill="#25C764" p-id="2855"></path></svg>

After

Width:  |  Height:  |  Size: 645 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,24 +1,42 @@
import { UpdateToken, UploadSecret } from '@/components/Form/FormFields'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import AssetSelect from '@/components/Apps/AssetSelect/index.vue'
import { Required, RequiredChange } from '@/components/Form/DataForm/rules'
import AutomationParamsForm from '@/views/assets/Platform/AutomationParamsSetting.vue'
export const accountFieldsMeta = (vm) => {
const defaultPrivilegedAccounts = ['root', 'administrator']
function onPrivilegedUser(value, updateForm) {
const maybePrivileged = defaultPrivilegedAccounts.includes(value)
if (maybePrivileged) {
updateForm({ privileged: true, secret_reset: false, push_now: false })
}
}
return {
assets: {
nodes: {
component: Select2,
label: vm.$t('Assets'),
rules: [Required],
label: vm.$t('Node'),
el: {
multiple: true,
value: [],
ajax: {
url: '/api/v1/assets/assets/',
url: '/api/v1/assets/nodes/',
transformOption: (item) => {
return { label: item.name + '(' + item.address + ')', value: item.id }
return { label: item.full_value, value: item.id }
}
}
},
hidden: () => {
return !vm.addTemplate
}
},
assets: {
component: AssetSelect,
label: vm.$t('Asset'),
el: {
multiple: false
},
hidden: () => {
return vm.platform || vm.asset
}
@@ -27,7 +45,10 @@ export const accountFieldsMeta = (vm) => {
component: Select2,
rules: [Required],
el: {
multiple: false,
get disabled() {
return vm.isDisabled
},
multiple: vm.addTemplate,
ajax: {
url: '/api/v1/accounts/account-templates/',
transformOption: (item) => {
@@ -43,6 +64,11 @@ export const accountFieldsMeta = (vm) => {
rules: [Required],
label: vm.$t('AccountPolicy'),
helpTip: vm.$t('AccountPolicyHelpText'),
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: () => {
return vm.platform || vm.asset
}
@@ -50,17 +76,19 @@ export const accountFieldsMeta = (vm) => {
name: {
label: vm.$t('Name'),
rules: [RequiredChange],
el: {
get disabled() {
return vm.isDisabled
}
},
on: {
input: ([value], updateForm) => {
if (!vm.usernameChanged) {
if (!vm.account?.name) {
updateForm({ username: value })
}
const maybePrivileged = defaultPrivilegedAccounts.includes(value)
if (maybePrivileged) {
updateForm({ privileged: true })
}
}
onPrivilegedUser(value, updateForm)
}
},
hidden: () => {
@@ -69,17 +97,16 @@ export const accountFieldsMeta = (vm) => {
},
username: {
el: {
disabled: !!vm.account?.name
get disabled() {
return !!vm.account?.name || vm.isDisabled
}
},
on: {
input: ([value], updateForm) => {
vm.usernameChanged = true
},
change: ([value], updateForm) => {
const maybePrivileged = defaultPrivilegedAccounts.includes(value)
if (maybePrivileged) {
updateForm({ privileged: true })
}
onPrivilegedUser(value, updateForm)
}
},
hidden: () => {
@@ -88,6 +115,11 @@ export const accountFieldsMeta = (vm) => {
},
privileged: {
label: vm.$t('Privileged'),
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: () => {
return vm.addTemplate
}
@@ -110,6 +142,11 @@ export const accountFieldsMeta = (vm) => {
},
su_from_username: {
label: vm.$t('UserSwitchFrom'),
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => {
return vm.platform || vm.asset || vm.addTemplate
}
@@ -117,6 +154,11 @@ export const accountFieldsMeta = (vm) => {
password: {
label: vm.$t('Password'),
component: UpdateToken,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => {
return formValue.secret_type !== 'password' || vm.addTemplate
}
@@ -124,33 +166,63 @@ export const accountFieldsMeta = (vm) => {
ssh_key: {
label: vm.$t('PrivateKey'),
component: UploadSecret,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate
},
passphrase: {
label: vm.$t('Passphrase'),
component: UpdateToken,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => formValue.secret_type !== 'ssh_key' || vm.addTemplate
},
token: {
label: vm.$t('Token'),
component: UploadSecret,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => formValue.secret_type !== 'token' || vm.addTemplate
},
access_key: {
id: 'access_key',
label: vm.$t('AccessKey'),
component: UploadSecret,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => formValue.secret_type !== 'access_key' || vm.addTemplate
},
api_key: {
id: 'api_key',
label: vm.$t('ApiKey'),
component: UploadSecret,
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: (formValue) => formValue.secret_type !== 'api_key' || vm.addTemplate
},
secret_type: {
type: 'radio-group',
options: [],
el: {
get disabled() {
return vm.isDisabled
}
},
hidden: () => {
return vm.addTemplate
}
@@ -163,7 +235,8 @@ export const accountFieldsMeta = (vm) => {
!automation.ansible_enabled ||
!vm.$hasPerm('accounts.push_account') ||
(formValue.secret_type === 'ssh_key' && vm.iPlatform.type.value === 'windows') ||
vm.addTemplate
vm.addTemplate ||
!formValue.secret_reset
}
},
params: {
@@ -172,6 +245,9 @@ export const accountFieldsMeta = (vm) => {
el: {},
hidden: (formValue) => {
const automation = vm.iPlatform.automation || {}
if (!vm.iPlatform.automation) {
return true
}
vm.fieldsMeta.params.el.method = vm.iPlatform.automation.push_account_method
vm.fieldsMeta.params.el.pushAccountParams = vm.iPlatform.automation.push_account_params
return !formValue.push_now ||
@@ -184,12 +260,27 @@ export const accountFieldsMeta = (vm) => {
}
},
is_active: {
label: vm.$t('IsActive')
label: vm.$t('IsActive'),
el: {
get disabled() {
return vm.isDisabled
}
}
},
comment: {
label: vm.$t('Comment'),
hidden: () => {
return vm.addTemplate
el: {
get disabled() {
return vm.isDisabled
}
}
},
secret_reset: {
label: vm.$t('SecretReset'),
el: {
get disabled() {
return vm.isDisabled
}
}
}
}

View File

@@ -11,7 +11,7 @@
<script>
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
import { encryptPassword } from '@/utils/crypto'
import { encryptPassword } from '@/utils/secure'
import { accountFieldsMeta } from '@/components/Apps/AccountCreateUpdateForm/const'
export default {
@@ -45,6 +45,7 @@ export default {
data() {
return {
loading: true,
isDisabled: false,
usernameChanged: false,
submitBtnText: this.$t('Confirm'),
iPlatform: {
@@ -61,11 +62,12 @@ export default {
form: Object.assign({ 'on_invalid': 'error' }, this.account || {}),
encryptedFields: ['secret'],
fields: [
[this.$t('AccountTemplate'), ['template']],
[this.$t('Basic'), ['assets', 'name', 'username', 'privileged', 'su_from', 'su_from_username']],
[this.$t('Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username', 'template']],
[this.$t('Asset'), ['nodes', 'assets']],
[this.$t('Secret'), [
'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key'
'access_key', 'passphrase', 'api_key',
'secret_reset'
]],
[this.$t('Other'), ['push_now', 'params', 'on_invalid', 'is_active', 'comment']]
],
@@ -73,6 +75,16 @@ export default {
hasSaveContinue: false
}
},
watch: {
'$route.query': {
handler(nv, ov) {
if (nv && (nv.flag === 'move' || nv.flag === 'copy')) {
this.isDisabled = true
}
},
immediate: true
}
},
async mounted() {
try {
await this.getPlatform()
@@ -145,7 +157,11 @@ export default {
delete form['secret']
}
if (this.account?.name) {
this.$emit('edit', form)
if (this.account.payload && this.account.payload === 'pam_account_clone') {
this.$emit('add', form)
} else {
this.$emit('edit', form)
}
} else {
this.$emit('add', form)
}
@@ -157,16 +173,16 @@ export default {
<style lang='scss' scoped>
.account-add {
::v-deep .el-form-item {
margin-bottom: 5px;
//margin-bottom: 5px;
.help-block {
margin-bottom: 5px;
//margin-bottom: 5px;
}
}
::v-deep .form-group-header {
.hr-line-dashed {
margin: 5px 0;
//margin: 5px 0;
}
h3 {

View File

@@ -11,7 +11,7 @@
<script>
import { GenericUpdateFormDialog } from '@/layout/components'
import { accountFieldsMeta } from '@/components/Apps/AccountCreateUpdateForm/const'
import { encryptPassword } from '@/utils/crypto'
import { encryptPassword } from '@/utils/secure'
export default {
name: 'AccountBulkUpdateDialog',

View File

@@ -1,36 +1,38 @@
<template>
<Dialog
v-if="iVisible"
:close-on-click-modal="false"
:destroy-on-close="true"
:show-cancel="false"
:show-confirm="false"
<template v-if="iVisible">
<Drawer
:title="title"
:visible.sync="iVisible"
v-bind="$attrs"
width="900px"
v-on="$listeners"
:visible="iVisible"
class="drawer"
@close-drawer="handleCloseDrawer"
>
<AccountCreateUpdateForm
v-if="!loading"
ref="form"
:account="account"
:add-template="addTemplate"
:asset="asset"
@add="addAccount"
@edit="editAccount"
/>
</Dialog>
<Page :title="'null'">
<IBox class="content">
<AccountCreateUpdateForm
v-if="!loading"
ref="form"
:account="account"
:add-template="addTemplate"
:asset="asset"
@add="addAccount"
@edit="editAccount"
/>
</IBox>
</Page>
</Drawer>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import Drawer from '@/components/Drawer/index.vue'
import AccountCreateUpdateForm from '@/components/Apps/AccountCreateUpdateForm/index.vue'
import IBox from '@/components/Common/IBox/index.vue'
import Page from '@/layout/components/Page/index.vue'
export default {
name: 'CreateAccountDialog',
components: {
Dialog,
IBox,
Drawer,
Page,
AccountCreateUpdateForm
},
props: {
@@ -91,8 +93,8 @@ export default {
iVisible = true
data = formValue
url = `/api/v1/accounts/accounts/bulk/`
if (data.assets.length === 0) {
this.$message.error(this.$tc('PleaseSelectAsset'))
if ((!data.assets || data.assets.length === 0) && (!data.nodes || data.nodes.length === 0)) {
this.$message.error(this.$tc('PleaseSelectAssetOrNode'))
return
}
}
@@ -105,17 +107,32 @@ export default {
this.$emit('add', true)
}
}).catch(error => {
if (error?.response?.data?.code === 'no_valid_assets') {
this.$message.error(error?.response?.data?.detail)
return
}
this.iVisible = true
this.handleResult(null, error)
})
},
editAccount(form) {
const data = { ...form }
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, data).then(() => {
this.iVisible = false
this.$emit('add', true)
this.$message.success(this.$tc('UpdateSuccessMsg'))
}).catch(error => this.setFieldError(error))
const flag = this.$route.query.flag
switch (flag) {
case 'copy':
this.handleAccountOperation(this.account.id, 'copy-to-assets', data)
break
case 'move':
this.handleAccountOperation(this.account.id, 'move-to-assets', data)
break
default:
this.$axios.patch(`/api/v1/accounts/accounts/${this.account.id}/`, data).then(() => {
this.iVisible = false
this.$emit('add', true)
this.$message.success(this.$tc('UpdateSuccessMsg'))
}).catch(error => this.setFieldError(error))
}
},
handleResult(resp, error) {
let bulkCreate = !this.asset
@@ -168,7 +185,29 @@ export default {
refsAutoDataForm.setFieldError(current, err)
}
}
},
handleCloseDrawer() {
this.iVisible = false
// Reflect.deleteProperty(this.$route.query, 'flag')
},
handleAccountOperation(id, path, data) {
this.$axios.post(`/api/v1/accounts/accounts/${id}/${path}/`, data).then((res) => {
this.iVisible = false
this.$emit('add', true)
this.handleResult(res, null)
}).catch(error => this.handleResult(null, error))
}
}
}
</script>
<style lang="scss" scoped>
.drawer {
::v-deep .el-drawer__body {
.el-form {
margin-right: 30px;
}
}
}
</style>

View File

@@ -1,6 +1,12 @@
<template>
<div>
<ListTable ref="ListTable" :header-actions="headerActions" :table-config="tableConfig" />
<DrawerListTable
ref="ListTable"
:detail-drawer="detailDrawer"
:header-actions="headerActions"
:quick-filters="quickFilters"
:table-config="tableConfig"
/>
<ViewSecret
v-if="showViewSecretDialog"
:account="account"
@@ -16,22 +22,13 @@
<AccountCreateUpdate
v-if="showAddDialog"
:account="account"
:add-template="addTemplate"
:asset="iAsset"
:title="accountCreateUpdateTitle"
:visible.sync="showAddDialog"
@add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)"
/>
<AccountCreateUpdate
v-if="showAddTemplateDialog"
:account="account"
:add-template="true"
:asset="iAsset"
:title="accountCreateByTemplateTitle"
:visible.sync="showAddTemplateDialog"
@add="addAccountSuccess"
@bulk-create-done="showBulkCreateResult($event)"
/>
<ResultDialog
v-if="showResultDialog"
:result="createAccountResults"
@@ -44,29 +41,42 @@
v-bind="updateSelectedDialogSetting"
@update="handleAccountBulkUpdate"
/>
<PasswordHistoryDialog
v-if="showPasswordHistoryDialog"
:account="currentAccountColumn"
:visible.sync="showPasswordHistoryDialog"
/>
</div>
</template>
<script>
import ListTable from '@/components/Table/ListTable/index.vue'
import { ActionsFormatter } from '@/components/Table/TableFormatters'
import { mapGetters } from 'vuex'
import { accountOtherActions, accountQuickFilters, connectivityMeta, isDirectoryServiceAccount } from './const'
import { openTaskPage } from '@/utils/jms/index'
import {
AccountConnectFormatter,
ActionsFormatter,
PlatformFormatter,
SecretViewerFormatter
} from '@/components/Table/TableFormatters'
import ViewSecret from './ViewSecret.vue'
import UpdateSecretInfo from './UpdateSecretInfo.vue'
import AccountCreateUpdate from './AccountCreateUpdate.vue'
import { connectivityMeta } from './const'
import { openTaskPage } from '@/utils/jms'
import ResultDialog from './BulkCreateResultDialog.vue'
import AccountCreateUpdate from './AccountCreateUpdate.vue'
import PasswordHistoryDialog from './PasswordHistoryDialog.vue'
import DrawerListTable from '@/components/Table/DrawerListTable/index.vue'
import AccountBulkUpdateDialog from '@/components/Apps/AccountListTable/AccountBulkUpdateDialog.vue'
export default {
name: 'AccountListTable',
components: {
AccountBulkUpdateDialog,
ResultDialog,
ListTable,
UpdateSecretInfo,
ViewSecret,
AccountCreateUpdate
ResultDialog,
DrawerListTable,
UpdateSecretInfo,
AccountCreateUpdate,
PasswordHistoryDialog,
AccountBulkUpdateDialog
},
props: {
url: {
@@ -89,7 +99,7 @@ export default {
},
hasClone: {
type: Boolean,
default: false
default: true
},
asset: {
type: Object,
@@ -119,7 +129,7 @@ export default {
columnsDefault: {
type: Array,
default: () => ([
'name', 'username', 'asset', 'date_updated'
'name', 'username', 'secret', 'asset', 'platform', 'connect'
])
},
headerExtraActions: {
@@ -129,22 +139,34 @@ export default {
extraQuery: {
type: Object,
default: () => ({})
},
showQuickFilters: {
type: Boolean,
default: true
},
showActions: {
type: Boolean,
default: true
}
},
data() {
const vm = this
return {
addTemplate: false,
isUpdateAccount: false,
currentAccountColumn: {},
showPasswordHistoryDialog: false,
showViewSecretDialog: false,
showUpdateSecretDialog: false,
showResultDialog: false,
showAddDialog: false,
showAddTemplateDialog: false,
detailDrawer: () => import('@/views/accounts/Account/AccountDetail/index.vue'),
createAccountResults: [],
accountCreateUpdateTitle: this.$t('AddAccount'),
accountCreateByTemplateTitle: this.$t('AddAccountByTemplate'),
iAsset: this.asset,
account: {},
secretUrl: '',
quickFilters: this.showQuickFilters ? accountQuickFilters(this) : [],
tableConfig: {
url: this.url,
permissions: {
@@ -153,40 +175,86 @@ export default {
},
extraQuery: this.extraQuery,
columnsExclude: ['spec_info'],
columnsAdd: ['secret', 'platform', 'connect'],
columnsShow: {
min: ['name', 'username', 'actions'],
default: this.columnsDefault
},
columnsMeta: {
name: {
width: '120px',
formatter: function(row) {
const to = {
name: 'AssetAccountDetail',
minWidth: '60px',
formatterArgs: {
can: () => vm.$hasPerm('accounts.view_account'),
getRoute: ({ row }) => ({
name: 'AccountDetail',
params: { id: row.id }
}),
getTitle: ({ row }) => {
let title = row.name
if (row.ds && this.asset && this.asset.id !== row.asset.id) {
const dsID = row.ds.id.split('-')[0]
title = `${row.name}@${dsID}`
}
return title
},
getDrawerTitle({ row }) {
return `${row.username}@${row.asset.name}`
}
if (vm.$hasPerm('accounts.view_account')) {
return <router-link to={to}>{row.name}</router-link>
}
},
secret: {
formatter: SecretViewerFormatter,
width: '130px',
formatterArgs: {
secretFrom: 'api',
hasDownload: false,
actionLeft: true
}
},
connect: {
label: this.$t('Connect'),
width: '80px',
formatter: AccountConnectFormatter,
formatterArgs: {
asset: this.asset,
can: ({ row }) => {
return this.currentUserIsSuperAdmin
}
}
},
ds: {
width: '100px',
formatter: (row) => {
if (row.ds && row.ds['domain_name']) {
return row.ds['domain_name']
} else {
return <span>{row.name}</span>
return ''
}
}
},
platform: {
label: this.$t('Platform'),
width: '150px',
formatter: PlatformFormatter,
formatterArgs: {
platformAttr: 'asset.platform'
}
},
asset: {
minWidth: '100px',
formatter: function(row) {
const to = {
name: 'AssetDetail',
params: { id: row.asset.id }
}
if (vm.$hasPerm('assets.view_asset')) {
return <router-link to={to}>{row.asset.name}</router-link>
} else {
return <span>{row.asset.name}</span>
}
return row.asset.name
}
},
username: {
width: '120px'
minWidth: '60px',
formatter: function(row) {
if (row.ds && row.ds['domain_name']) {
return `${row.username}@${row.ds['domain_name']}`
} else {
return row.username
}
}
},
secret_type: {
formatter: function(row) {
@@ -214,77 +282,19 @@ export default {
connectivity: connectivityMeta,
actions: {
formatter: ActionsFormatter,
has: this.showActions,
formatterArgs: {
performDelete: ({ row }) => {
const id = row.id
const url = `/api/v1/accounts/accounts/${id}/`
return this.$axios.delete(url)
},
hasUpdate: false, // can set function(row, value)
hasDelete: false, // can set function(row, value)
hasClone: this.hasClone,
hasDelete: true, // can set function(row, value)
hasClone: false,
canDelete: ({ row }) => vm.$hasPerm('accounts.delete_account') && !isDirectoryServiceAccount(row, this),
moreActionsTitle: this.$t('More'),
extraActions: [
{
name: 'View',
title: this.$t('View'),
can: this.$hasPerm('accounts.view_accountsecret'),
type: 'primary',
callback: ({ row }) => {
// debugger
vm.secretUrl = `/api/v1/accounts/account-secrets/${row.id}/`
vm.account = row
vm.showViewSecretDialog = false
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
name: 'Update',
title: this.$t('Edit'),
can: this.$hasPerm('accounts.change_account') && !this.$store.getters.currentOrgIsRoot,
callback: ({ row }) => {
const data = {
...this.asset,
...row.asset
}
vm.account = row
vm.iAsset = data
vm.showAddDialog = false
vm.accountCreateUpdateTitle = this.$t('UpdateAccount')
setTimeout(() => {
vm.showAddDialog = true
})
}
},
{
name: 'Test',
title: this.$t('Test'),
can: ({ row }) =>
!this.$store.getters.currentOrgIsRoot &&
this.$hasPerm('accounts.verify_account') &&
row.asset['auto_config'].ansible_enabled &&
row.asset['auto_config'].ping_enabled,
callback: ({ row }) => {
this.$axios.post(
`/api/v1/accounts/accounts/tasks/`,
{ action: 'verify', accounts: [row.id] }
).then(res => {
openTaskPage(res['task'])
})
}
},
{
name: 'ClearSecret',
title: this.$t('ClearSecret'),
can: this.$hasPerm('accounts.change_account'),
type: 'primary',
callback: ({ row }) => {
this.$axios.patch(
`/api/v1/accounts/accounts/clear-secret/`,
{ account_ids: [row.id] }
).then(() => {
this.$message.success(this.$tc('ClearSuccessMsg'))
})
}
}
]
extraActions: accountOtherActions(this)
}
},
...this.columnsMeta
@@ -313,15 +323,15 @@ export default {
type: 'primary',
icon: 'plus',
can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
return vm.$hasPerm('accounts.add_account') && !vm.$store.getters.currentOrgIsRoot
},
callback: async() => {
await this.getAssetDetail()
callback: () => {
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.showAddDialog = true
})
this.addTemplate = false
this.showAddDialog = true
}, 200)
}
},
{
@@ -329,14 +339,15 @@ export default {
title: this.$t('TemplateAdd'),
has: !(this.platform || this.asset),
can: () => {
return vm.$hasPerm('accounts.add_account') && !this.$store.getters.currentOrgIsRoot
return vm.$hasPerm('accounts.add_account') && !vm.$store.getters.currentOrgIsRoot
},
callback: async() => {
callback: async () => {
await this.getAssetDetail()
setTimeout(() => {
vm.iAsset = this.asset
vm.account = {}
vm.showAddTemplateDialog = true
vm.showAddDialog = true
vm.addTemplate = true
})
}
},
@@ -347,11 +358,11 @@ export default {
name: 'TestSelected',
title: this.$t('TestSelected'),
type: 'primary',
icon: 'fa-link',
icon: 'verify',
can: ({ selectedRows }) => {
return selectedRows.length > 0 &&
['clickhouse', 'redis', 'website', 'chatgpt'].indexOf(selectedRows[0].asset.type.value) === -1 &&
!this.$store.getters.currentOrgIsRoot
['clickhouse', 'redis', 'website', 'chatgpt'].indexOf(selectedRows[0].asset.type.value) === -1 &&
!this.$store.getters.currentOrgIsRoot && vm.$hasPerm('accounts.verify_account')
},
callback: function({ selectedRows }) {
const ids = selectedRows.map(v => {
@@ -416,6 +427,18 @@ export default {
}
}
},
computed: {
...mapGetters(['currentUserIsSuperAdmin']),
accountCreateUpdateTitle() {
if (this.addTemplate) {
return this.$t('AddAccountByTemplate')
} else if (this.isUpdateAccount) {
return this.$t('UpdateAccount')
} else {
return this.$t('AddAccount')
}
}
},
watch: {
url(iNew) {
this.$set(this.tableConfig, 'url', iNew)
@@ -423,56 +446,39 @@ export default {
}
},
mounted() {
if (this.columns.length > 0) {
this.tableConfig.columns = this.columns
}
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
if (this.hasDeleteAction) {
this.tableConfig.columnsMeta.actions.formatterArgs.extraActions.push(
{
name: 'Delete',
title: this.$t('Delete'),
can: this.$hasPerm('accounts.delete_account'),
type: 'primary',
callback: ({ row }) => {
const msg = this.$t('AccountDeleteConfirmMsg')
this.$confirm(msg, this.$tc('Info'), {
type: 'warning',
confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => {
if (action !== 'confirm') return done()
this.$axios.delete(`/api/v1/accounts/accounts/${row.id}/`).then(() => {
done()
this.$refs.ListTable.reloadTable()
this.$message.success(this.$tc('DeleteSuccessMsg'))
})
}
})
}
}
)
}
this.setActions()
},
activated() {
// 由于组件嵌套较深,有可能导致 Error in activated hook: "TypeError: Cannot read properties of undefined (reading 'getList')" 的问题
setTimeout(() => {
this.refresh()
}, 300)
if (this.tabDeactivated) {
setTimeout(() => this.refresh(), 300)
}
},
deactivated() {
this.tabDeactivated = true
},
methods: {
setActions() {
if (this.columns.length > 0) {
this.tableConfig.columns = this.columns
}
if (this.otherActions) {
const actionColumn = this.tableConfig.columns[this.tableConfig.columns.length - 1]
for (const item of this.otherActions) {
actionColumn.formatterArgs.extraActions.push(item)
}
}
},
onUpdateAuthDone(account) {
Object.assign(this.account, account)
},
addAccountSuccess() {
// Reflect.deleteProperty(this.$route.query, 'flag')
this.isUpdateAccount = false
this.$refs.ListTable.reloadTable()
},
async getAssetDetail() {
const { query: { asset }} = this.$route
const { query: { asset } } = this.$route
if (asset) {
this.iAsset = await this.$axios.get(`/api/v1/assets/assets/${asset}/`)
}
@@ -507,7 +513,7 @@ export default {
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.cell a {
color: var(--color-info);
}

View File

@@ -49,6 +49,10 @@ export default {
prop: 'asset',
label: this.$t('Asset')
},
{
prop: 'account',
label: this.$t('Account')
},
{
prop: 'state',
label: this.$t('Status'),

View File

@@ -4,7 +4,7 @@
<script>
import { GenericListTableDialog } from '@/layout/components'
import { ShowKeyCopyFormatter } from '@/components/Table/TableFormatters'
import { SecretViewerFormatter } from '@/components/Table/TableFormatters'
export default {
components: {
@@ -33,7 +33,7 @@ export default {
columnsMeta: {
secret: {
label: this.$t('Password'),
formatter: ShowKeyCopyFormatter,
formatter: SecretViewerFormatter,
formatterArgs: {
hasDownload: false,
name: this.account.name

View File

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

View File

@@ -1,44 +1,36 @@
<template>
<Dialog
:destroy-on-close="true"
:show-buttons="false"
:title="$tc('UpdateAssetUserToken')"
:visible.sync="visible"
width="50"
@cancel="handleCancel()"
@confirm="handleConfirm()"
:visible.sync="iVisible"
width="800px"
v-on="$listeners"
>
<el-form label-position="right" label-width="90px">
<el-form-item :label="$tc('Name')">
<el-input v-model="account['asset_name']" readonly />
</el-form-item>
<el-form-item :label="$tc('Username')">
<el-input v-model="account['username']" readonly />
</el-form-item>
<el-form-item :label="$tc('Password')">
<UpdateToken v-model="authInfo.password" />
</el-form-item>
<el-form-item :label="$tc('SSHSecretKey')">
<UploadKey @input="getFile" />
</el-form-item>
<el-form-item :label="$tc('Passphrase')">
<UpdateToken v-model="authInfo.passphrase" />
</el-form-item>
</el-form>
<AutoDataForm
:fields="fields"
:fields-meta="fieldsMeta"
:form="init"
:has-reset="false"
:has-save-continue="false"
:url="''"
method="patch"
@submit="handleConfirm"
/>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import { UpdateToken, UploadKey } from '@/components/Form/FormFields'
import { encryptPassword } from '@/utils/crypto'
import { accountFieldsMeta } from '@/components/Apps/AccountCreateUpdateForm/const'
import { encryptPassword } from '@/utils/secure'
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
export default {
name: 'UpdateSecretInfo',
components: {
Dialog,
UploadKey,
UpdateToken
AutoDataForm,
Dialog
},
props: {
account: {
@@ -51,49 +43,59 @@ export default {
}
},
data() {
const accountMeta = accountFieldsMeta(this)
return {
secretInfo: {
password: '',
private_key: '',
passphrase: ''
fields: [
'name', 'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key'
],
fieldsMeta: {
...accountMeta,
name: {
...accountMeta.name,
readonly: true
},
secret_type: {
hidden: () => true
}
},
init: {
...this.account
}
}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
methods: {
handleConfirm() {
const data = {}
if (this.secretInfo.password !== '') {
data.password = encryptPassword(this.secretInfo.password)
}
if (this.secretInfo.private_key !== '') {
data.private_key = encryptPassword(this.secretInfo.private_key)
if (this.secretInfo.passphrase) data.passphrase = this.secretInfo.passphrase
handleConfirm(form) {
const secretType = this.account.secret_type.value
const data = {
secret: encryptPassword(form[secretType])
}
this.$axios.patch(
`/api/v1/accounts/accounts/${this.account.id}/`,
data,
{ disableFlashErrorMsg: true }
).then(res => {
this.authInfo = { password: '', private_key: '' }
this.$message.success(this.$tc('UpdateSuccessMsg'))
this.$emit('updateAuthDone', res)
this.$emit('update:visible', false)
this.iVisible = false
}).catch(err => {
const errMsg = Object.values(err.response.data).join(', ')
this.$message.error(this.$tc('UpdateErrorMsg') + ' ' + errMsg)
this.$emit('update:visible', true)
this.iVisible = false
})
},
handleCancel() {
this.$emit('update:visible', false)
},
getFile(file) {
this.secretInfo.private_key = file
}
}
}
</script>
<style scoped>
</style>

View File

@@ -18,7 +18,7 @@
<span>{{ account['username'] }}</span>
</el-form-item>
<el-form-item :label="secretTypeLabel">
<ShowKeyCopyFormatter
<SecretViewerFormatter
:cell-value="secretInfo.secret"
:col="{ formatterArgs: {
name: account['name'],
@@ -60,15 +60,15 @@
<script>
import Dialog from '@/components/Dialog/index.vue'
import PasswordHistoryDialog from './PasswordHistoryDialog.vue'
import { ShowKeyCopyFormatter } from '@/components/Table/TableFormatters'
import { encryptPassword } from '@/utils/crypto'
import { SecretViewerFormatter } from '@/components/Table/TableFormatters'
import { encryptPassword } from '@/utils/secure'
export default {
name: 'ShowSecretInfo',
components: {
Dialog,
PasswordHistoryDialog,
ShowKeyCopyFormatter
SecretViewerFormatter
},
props: {
account: {

View File

@@ -1,4 +1,5 @@
import { ChoicesFormatter } from '@/components/Table/TableFormatters'
import { openTaskPage } from '@/utils/jms/index'
export const connectivityMeta = {
formatter: ChoicesFormatter,
@@ -6,11 +7,23 @@ export const connectivityMeta = {
faChoices: {
'-': '',
ok: 'fa-check-circle',
err: 'fa-times-circle'
err: 'fa-times-circle',
auth_err: 'fa-times-circle',
rdp_err: 'fa-times-circle',
password_err: 'fa-times-circle',
openssh_key_err: 'fa-times-circle',
ntlm_err: 'fa-times-circle',
create_temp_err: 'fa-times-circle'
},
classChoices: {
ok: 'text-primary',
err: 'text-danger'
err: 'text-danger',
auth_err: 'text-danger',
rdp_err: 'text-danger',
password_err: 'text-danger',
openssh_key_err: 'text-danger',
ntlm_err: 'text-danger',
create_temp_err: 'text-danger'
},
getText({ cellValue }) {
if (cellValue?.value === '-' || cellValue?.value === 'unknown') {
@@ -22,3 +35,316 @@ export const connectivityMeta = {
},
width: '130px'
}
export function isDirectoryServiceAccount(account, vm) {
return vm.asset && vm.asset.id !== account.asset.id
}
export const accountOtherActions = vm => {
return [
{
name: 'View',
title: vm.$t('View'),
can: vm.$hasPerm('accounts.view_accountsecret'),
type: 'primary',
order: 1,
callback: ({ row }) => {
// debugger
vm.secretUrl = `/api/v1/accounts/account-secrets/${row.id}/`
vm.account = row
vm.showViewSecretDialog = false
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
name: 'Update',
title: vm.$t('Edit'),
can: ({ row }) => {
return (
vm.$hasPerm('accounts.change_account') &&
!vm.$store.getters.currentOrgIsRoot &&
!isDirectoryServiceAccount(row, vm)
)
},
callback: ({ row }) => {
vm.isUpdateAccount = true
const data = {
...vm.asset,
...row.asset
}
vm.iAsset = data
vm.account = row
vm.addTemplate = false
vm.showAddDialog = false
setTimeout(() => {
vm.showAddDialog = true
})
}
},
{
name: 'UpdateSecret',
title: vm.$t('EditSecret'),
can: ({ row }) => {
return (
vm.$hasPerm('accounts.change_account') &&
!vm.$store.getters.currentOrgIsRoot &&
!isDirectoryServiceAccount(row, vm)
)
},
callback: ({ row }) => {
const data = {
...vm.asset,
...row.asset
}
vm.account = row
vm.iAsset = data
vm.showUpdateSecretDialog = false
vm.accountCreateUpdateTitle = vm.$t('UpdateAccount')
setTimeout(() => {
vm.showUpdateSecretDialog = true
})
}
},
{
name: 'Clone',
title: vm.$t('Duplicate'),
has: () => {
return !vm.asset
},
can: ({ row }) => {
return (
vm.$hasPerm('accounts.add_account') &&
!vm.$store.getters.currentOrgIsRoot &&
!isDirectoryServiceAccount(row, vm)
)
},
callback: ({ row }) => {
vm.account = {
name: `${row.name} - ${vm.$t('Duplicate').toLowerCase()}`,
username: `${row.username} - ${vm.$t('Duplicate').toLowerCase()}`,
payload: 'pam_account_clone'
}
vm.iAsset = vm.asset
vm.showAddDialog = false
setTimeout(() => {
vm.showAddDialog = true
})
}
},
{
name: 'Test',
title: vm.$t('VerifySecret'),
divided: true,
can: ({ row }) =>
!vm.$store.getters.currentOrgIsRoot &&
vm.$hasPerm('accounts.verify_account') &&
row.asset['auto_config'].ansible_enabled &&
row.asset['auto_config'].ping_enabled,
callback: ({ row }) => {
vm.$axios
.post(`/api/v1/accounts/accounts/tasks/`, { action: 'verify', accounts: [row.id] })
.then(res => {
openTaskPage(res['task'])
})
}
},
{
name: 'ClearSecret',
title: vm.$t('ClearSecret'),
can: ({ row }) => {
return vm.$hasPerm('accounts.change_account') && !isDirectoryServiceAccount(row, vm)
},
type: 'primary',
callback: ({ row }) => {
vm.$axios
.patch(`/api/v1/accounts/accounts/clear-secret/`, { account_ids: [row.id] })
.then(() => {
vm.$message.success(vm.$tc('ClearSuccessMsg'))
})
}
},
{
name: 'SecretHistory',
title: vm.$t('HistoryPassword'),
can: () => vm.$hasPerm('accounts.view_accountsecret'),
type: 'primary',
callback: ({ row }) => {
vm.account = row
vm.currentAccountColumn = row
vm.showViewSecretDialog = false
vm.secretUrl = `/api/v1/accounts/account-secrets/${row.id}/`
setTimeout(() => {
vm.showViewSecretDialog = true
})
}
},
{
name: 'CopyToOther',
title: vm.$t('CopyToAsset'),
type: 'primary',
divided: true,
can: ({ row }) => {
return (
vm.$hasPerm('accounts.add_account') &&
!vm.$store.getters.currentOrgIsRoot &&
!isDirectoryServiceAccount(row, vm)
)
},
has: () => {
return !vm.asset
},
callback: ({ row }) => {
vm.accountCreateUpdateTitle = vm.$t('CopyToOther')
vm.$route.query.flag = 'copy'
vm.iAsset = vm.asset
vm.account = row
vm.showAddDialog = true
}
},
{
name: 'MoveToOther',
title: vm.$t('MoveToAsset'),
type: 'primary',
can: ({ row }) => {
return (
vm.$hasPerm('accounts.delete_account') &&
!vm.$store.getters.currentOrgIsRoot &&
!isDirectoryServiceAccount(row, vm)
)
},
has: () => {
return !vm.asset
},
callback: ({ row }) => {
vm.accountCreateUpdateTitle = vm.$t('MoveToOther')
vm.$route.query.flag = 'move'
vm.iAsset = vm.asset
vm.account = row
vm.showAddDialog = true
}
}
]
}
export const accountQuickFilters = vm => [
{
label: vm.$t('Recent (7 days)'),
options: [
{
label: vm.$t('RecentlyDiscovered'),
filter: {
latest_discovery: '1'
}
},
{
label: vm.$t('RecentlyLoggedIn'),
filter: {
latest_accessed: '1'
}
},
{
label: vm.$t('RecentlyModified'),
filter: {
latest_updated: '1'
}
},
{
label: vm.$t('RecentlyChangedPassword'),
filter: {
latest_secret_changed: '1'
}
},
{
label: vm.$t('RecentPasswordChangeFailed'),
filter: {
latest_secret_change_failed: '1'
}
}
]
},
{
label: vm.$t('RiskyAccount'),
options: [
{
label: vm.$t('NoLoginLongTime'),
filter: {
long_time_no_login: 'true'
}
},
{
label: vm.$t('AddAccount'),
filter: {
risk: 'new_found'
}
},
{
label: vm.$t('WeakPassword'),
filter: {
risk: 'weak_password'
}
},
{
label: vm.$t('EmptyPassword'),
filter: {
has_secret: 'false'
}
},
{
label: vm.$t('LongTimePassword'),
filter: {
long_time_no_change_secret: 'true'
}
}
]
},
{
label: vm.$t('AccountType'),
options: [
{
label: vm.$t('All'),
filter: {
category: ''
}
},
{
label: vm.$t('Host'),
filter: {
category: 'host'
}
},
{
label: vm.$t('Database'),
filter: {
category: 'database'
}
},
{
label: vm.$t('Cloud'),
filter: {
category: 'cloud'
}
},
{
label: vm.$t('Device'),
filter: {
category: 'device'
}
},
{
label: 'Web',
filter: {
category: 'web'
}
},
{
label: vm.$t('Other'),
filter: {
category: 'custom'
}
}
]
}
]

View File

@@ -16,7 +16,7 @@
</template>
<script>
import IBox from '@/components/IBox/index.vue'
import IBox from '@/components/Common/IBox/index.vue'
import AssetSelect from '@/components/Apps/AssetSelect/index.vue'
export default {
@@ -48,11 +48,13 @@ export default {
},
performAdd: {
type: Function,
default: (objects, that) => {}
default: (objects, that) => {
}
},
onAddSuccess: {
type: Function,
default: (objects, that) => {}
default: (objects, that) => {
}
},
canSelect: {
type: Function,
@@ -62,8 +64,7 @@ export default {
}
},
data() {
return {
}
return {}
},
methods: {
addObjects() {
@@ -77,18 +78,18 @@ export default {
</script>
<style scoped>
b, strong {
font-weight: 700;
font-size: 13px;
}
b, strong {
font-weight: 700;
font-size: 13px;
}
tr td {
line-height: 1.42857;
padding: 8px;
vertical-align: top;
}
tr td {
line-height: 1.42857;
padding: 8px;
vertical-align: top;
}
tr.item td {
border-top: 1px solid #e7eaec;
}
tr.item td {
border-top: 1px solid #e7eaec;
}
</style>

View File

@@ -2,7 +2,6 @@
<Dialog
:close-on-click-modal="false"
:title="$tc('Assets')"
:disabled-status="!isLoaded"
custom-class="asset-select-dialog"
top="2vh"
v-bind="$attrs"
@@ -23,8 +22,8 @@
:url="baseUrl"
class="tree-table"
v-bind="$attrs"
v-on="$listeners"
@loaded="handleTableLoaded"
v-on="$listeners"
/>
</Dialog>
</template>
@@ -83,7 +82,7 @@ export default {
},
{
prop: 'address',
label: this.$t('IpDomain'),
label: this.$t('Address'),
sortable: 'custom'
},
{

View File

@@ -56,6 +56,10 @@ export default {
treeSetting: {
type: Object,
default: () => ({})
},
disabled: {
type: [Boolean, Function],
default: false
}
},
data() {
@@ -71,6 +75,7 @@ export default {
dialogVisible: false,
initialValue: _.cloneDeep(iValue),
select2Config: {
disabled: this.disabled,
value: iValue,
multiple: true,
clearable: true,

View File

@@ -20,7 +20,7 @@
<script>
import TreeTable from '../../Table/TreeTable/index.vue'
import { setRouterQuery, setUrlParam } from '@/utils/common'
import { setRouterQuery, setUrlParam } from '@/utils/common/index'
import $ from '@/utils/jquery-vendor'
export default {
@@ -32,6 +32,10 @@ export default {
type: String,
default: '/api/v1/assets/assets/'
},
typeUrl: {
type: String,
default: '/api/v1/assets/nodes/category/tree/'
},
nodeUrl: {
type: String,
default: '/api/v1/assets/nodes/'
@@ -105,11 +109,16 @@ export default {
showAssets: false,
showSearch: false,
customTreeHeaderName: this.$t('TypeTree'),
url: '/api/v1/assets/nodes/category/tree/',
url: this.typeUrl,
nodeUrl: this.treeSetting?.nodeUrl || this.nodeUrl,
treeUrl: `/api/v1/assets/nodes/category/tree/?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,
treeUrl: `${this.typeUrl}?assets=${showAssets ? '1' : '0'}&count_resource=${this.treeSetting.countResource || 'asset'}`,
callback: {
onSelected: (event, treeNode) => this.getAssetsUrl(treeNode)
},
edit: {
drag: {
isMove: false
}
}
}
}
@@ -138,6 +147,9 @@ export default {
treeSetting.showDelete = this.$hasPerm('assets.delete_node')
},
methods: {
reloadTable() {
this.$refs.TreeList.reloadTable()
},
setTreeUrlQuery() {
let str = ''
for (const key in this.treeUrlQuery) {

View File

@@ -3,7 +3,7 @@
</template>
<script>
import ListTable from '@/components/Table/ListTable/index.vue'
import { DrawerListTable as ListTable } from '@/components'
export default {
name: 'BlockedIPList',

View File

@@ -12,7 +12,7 @@
>
<el-form :model="secretInfo" class="password-form" label-position="right" label-width="100px">
<el-form-item :label="$tc('OldSecret')">
<ShowKeyCopyFormatter
<SecretViewerFormatter
:cell-value="secretInfo.old_secret"
:col="{ formatterArgs: {
name: 'old_secret'
@@ -20,7 +20,7 @@
/>
</el-form-item>
<el-form-item :label="$tc('NewSecret')">
<ShowKeyCopyFormatter
<SecretViewerFormatter
:cell-value="secretInfo.new_secret"
:col="{ formatterArgs: {
name: 'new_secret'
@@ -34,13 +34,13 @@
<script>
import Dialog from '@/components/Dialog/index.vue'
import { ShowKeyCopyFormatter } from '@/components/Table/TableFormatters'
import { SecretViewerFormatter } from '@/components/Table/TableFormatters'
export default {
name: 'RecordViewSecret',
components: {
Dialog,
ShowKeyCopyFormatter
SecretViewerFormatter
},
props: {
visible: {

View File

@@ -1,12 +1,60 @@
<template>
<div class="container">
<div class="chat-action">
<Select2
v-model="select.value"
:disabled="isLoading || isSelectDisabled"
v-bind="select"
@change="onSelectChange"
/>
<div class="model-select">
<Select2
v-model="select.value"
:disabled="isLoading || isSelectDisabled || loading || !options.length"
v-bind="select"
@change="onSelectChange"
/>
</div>
<el-dropdown
:hide-on-click="false"
trigger="click"
>
<span class="el-dropdown-link">
<i class="fa fa-plug" />
</span>
<el-dropdown-menu slot="dropdown">
<div class="menu-section">
<div v-if="toolsLoading">
<i class="el-icon-loading" /> {{ $t('Loading') }}
</div>
<div v-else class="menu-body">
<div>
<div
v-for="item in toolOptions"
:key="item.value"
>
<div style="padding: 0 10px">
<i class="fa fa-wrench item-icon" />
<span class="item-label">{{ item.label }}</span>
&nbsp;&nbsp;&nbsp;
<el-switch
:value="selectedToolsSet.has(item.value)"
@change="() => toggleTool(item.value)"
/>
</div>
</div>
<div
v-for="item in toolServerOptions"
:key="item.value"
>
<div>
<i class="fa fa-server item-icon" />
<span class="item-label">{{ item.label }}</span>
<el-switch
:value="selectedToolServersSet.has(item.value)"
@change="() => toggleToolServer(item.value)"
/>
</div>
</div>
</div>
</div>
</div>
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="chat-input">
<el-input
@@ -36,6 +84,38 @@ export default {
expanded: {
type: Boolean,
default: false
},
modelOptions: {
type: Array,
default: () => []
},
selectedModel: {
type: String,
default: ''
},
loading: {
type: Boolean,
default: false
},
toolOptions: {
type: Array,
default: () => []
},
toolServerOptions: {
type: Array,
default: () => []
},
selectedTools: {
type: Array,
default: () => []
},
selectedToolServers: {
type: Array,
default: () => []
},
toolsLoading: {
type: Boolean,
default: false
}
},
data() {
@@ -43,15 +123,10 @@ export default {
isIM: false,
inputValue: '',
select: {
url: '/api/v1/settings/chatai-prompts/',
value: '',
multiple: false,
placeholder: this.$t('Prompt'),
ajax: {
transformOption: (item) => {
return { label: item.name, value: item.content }
}
}
placeholder: this.$t('Model'),
options: []
}
}
},
@@ -60,7 +135,32 @@ export default {
isLoading: state => state.chat.loading
}),
isSelectDisabled() {
return !!this.select.value
return false
},
options() {
return (this.modelOptions || []).map(item => {
return { label: item.name || item.id, value: item.id }
})
},
selectedToolsSet() {
return new Set(this.selectedTools || [])
},
selectedToolServersSet() {
return new Set(this.selectedToolServers || [])
}
},
watch: {
modelOptions: {
immediate: true,
handler(val) {
this.select.options = (val || []).map(item => ({ label: item.name || item.id, value: item.id }))
}
},
selectedModel: {
immediate: true,
handler(val) {
this.select.value = val || ''
}
}
},
methods: {
@@ -80,7 +180,25 @@ export default {
this.inputValue = ''
},
onSelectChange(value) {
this.$emit('select-prompt', value)
this.$emit('select-model', value)
},
toggleTool(id) {
const set = new Set(this.selectedTools || [])
if (set.has(id)) {
set.delete(id)
} else {
set.add(id)
}
this.$emit('select-tools', Array.from(set))
},
toggleToolServer(id) {
const set = new Set(this.selectedToolServers || [])
if (set.has(id)) {
set.delete(id)
} else {
set.add(id)
}
this.$emit('select-tool-servers', Array.from(set))
}
}
}
@@ -95,9 +213,18 @@ export default {
.chat-action {
width: 100%;
margin: 6px 0;
display: flex;
align-items: center;
gap: 8px;
.model-select {
flex: 0 0 48%;
max-width: 240px;
min-width: 160px;
}
&::v-deep .el-select {
width: 50%;
width: 100%;
.el-input__inner {
height: 28px;

View File

@@ -1,42 +1,77 @@
<template>
<div :class="{'user-role': isUserRole}" class="chat-item">
<div class="avatar">
<el-avatar :src="isUserRole ? userUrl : chatUrl" class="header-avatar" />
</div>
<div class="content">
<div class="operational">
<span class="date">
{{ $moment(item.message.create_time).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<div :class="{ 'user-role': isUserRole }" class="chat-item">
<div class="chart-item-container">
<div class="avatar">
<el-avatar
v-if="isUserRole"
:src="userUrl"
class="header-avatar"
/>
<el-avatar v-else class="header-avatar" :style="{ backgroundColor: 'transparent' }">
<ModelIcon :name="modelIconName" class-name="model-icon" />
</el-avatar>
</div>
<div class="message">
<div class="message-content">
<span v-if="isSystemError" class="error">
{{ item.message.content }}
</span>
<span v-else class="chat-text">
<MessageText :message="item.message" />
</span>
<div class="content">
<div class="operational">
<div v-if="!item.message.is_reasoning" class="date">
{{
$moment(item.message.create_time).format("YYYY-MM-DD HH:mm:ss")
}}
</div>
<div v-else class="thinking-time">{{ $i18n.t('DeeplyThoughtAbout') }}</div>
</div>
<div class="action">
<el-tooltip
v-if="isSystemError && isLoading"
:content="$tc('Reconnect')"
:open-delay="500"
placement="top"
>
<svg-icon icon-class="refresh" @click="onRefresh" />
</el-tooltip>
<el-dropdown v-else size="small" @command="handleCommand">
<span class="el-dropdown-link">
<i class="fa fa-ellipsis-v" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="i in dropdownOptions" :key="i.action" :command="i.action">
{{ i.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div :class="item.reasoning ? 'reasoning' : 'message'">
<div class="message-content">
<div v-if="!item.reasoning">
<span v-if="isSystemError" class="error">
{{ item.message.content }}
</span>
<span v-else class="chat-text">
<MessageText :message="item.message" />
</span>
</div>
<div v-else class="thinking-wrapper">
<div class="thinking-content">
<!-- eslint-disable-next-line -->
<div class="divider"></div>
<p>
<MessageText :message="item.reasoning" @insert-code="handleInsertCode" />
</p>
</div>
<div class="thinking-result">
<span v-if="isServerError" class="error">
{{ isServerError }}
</span>
<MessageText :message="item.result" :is-terminal="isTerminal" @insert-code="handleInsertCode" /></div>
</div>
</div>
<div class="action">
<el-tooltip
v-if="isSystemError && isLoading"
:content="$tc('Reconnect')"
:open-delay="500"
placement="top"
>
<svg-icon icon-class="refresh" @click="onRefresh" />
</el-tooltip>
<el-dropdown v-else size="small" @command="handleCommand">
<span class="el-dropdown-link">
<i class="fa fa-ellipsis-v" />
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="i in dropdownOptions"
:key="i.action"
:command="i.action"
>
{{ i.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</div>
@@ -45,27 +80,36 @@
<script>
import MessageText from './MessageText.vue'
import { mapState } from 'vuex'
import { copy } from '@/utils/common'
import ModelIcon from '../../models/ModelIcon.vue'
import { mapGetters, mapState } from 'vuex'
import { copy } from '@/utils/common/index'
import { useChat } from '../../useChat.js'
import { reconnect } from '@/utils/socket'
import { reconnect } from '@/utils/request'
const { setLoading, removeLoadingMessageInChat } = useChat()
export default {
components: {
MessageText
MessageText,
ModelIcon
},
props: {
item: {
type: Object,
default: () => {
}
},
selectedModel: {
type: String,
default: ''
},
isTerminal: {
type: Boolean,
default: false
}
},
data() {
return {
chatUrl: require('@/assets/img/chat.png'),
userUrl: '/api/v1/settings/logo/',
dropdownOptions: [
{
@@ -79,11 +123,24 @@ export default {
...mapState({
isLoading: state => state.chat.loading
}),
...mapGetters([
'publicSettings'
]),
isUserRole() {
return this.item.message?.role === 'user'
},
isSystemError() {
return this.item.type === 'error' && this.item.message?.role === 'assistant'
return (
this.item.type === 'error' && this.item?.role === 'assistant'
)
},
isServerError() {
return (this.item.type === 'finish' && this.item.result.content === '')
? this.$i18n.t('ServerBusyRetry')
: ''
},
modelIconName() {
return (this.item?.message?.model || this.selectedModel || this.publicSettings.CHAT_AI_TYPE || '').toString()
}
},
methods: {
@@ -94,8 +151,11 @@ export default {
},
handleCommand(value) {
if (value === 'copy') {
copy(this.item.message.content)
copy(this.item.result.content)
}
},
handleInsertCode(code) {
this.$emit('insert-code', code)
}
}
}
@@ -104,101 +164,167 @@ export default {
<style lang="scss" scoped>
.chat-item {
display: flex;
padding: 16px 14px 0;
padding: 0.5rem;
&:last-child {
padding-bottom: 16px;
}
.chart-item-container {
display: flex;
gap: 0.5rem;
.avatar {
width: 22px;
height: 22px;
margin-top: 2px;
.avatar {
width: 24px;
height: 24px;
margin-top: 2px;
.header-avatar {
width: 100%;
height: 100%;
.header-avatar {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: transparent;
&::v-deep img {
background-color: #e5e5e7;
&::v-deep img {
background-color: #fff;
}
}
.model-icon {
width: 100%;
height: 100%;
display: block;
}
}
}
.content {
margin-left: 6px;
overflow: hidden;
.operational {
.content {
display: flex;
justify-content: space-between;
flex-direction: column;
// gap: 0.5rem;
overflow: hidden;
.copy {
float: right;
cursor: pointer;
}
}
.operational {
display: flex;
justify-content: space-between;
overflow: hidden;
.message {
display: -webkit-box;
.message-content {
flex: 1;
padding: 6px 10px;
border-radius: 2px 12px 12px;
background-color: #f0f1f5;
}
.action {
.svg-icon {
transform: translateY(50%);
margin-left: 3px;
cursor: pointer;
.date {
padding-top: 5px;
}
.el-dropdown {
height: 32px;
line-height: 37px;
font-size: 13px;
.thinking-time {
width: 6rem;
display: flex;
justify-content: center;
padding: 5px 10px;
border-radius: 0.5rem;
background-color: #f5f5f5;
}
.el-dropdown-link {
i {
padding: 4px 5px;
font-size: 15px;
color: #8d9091;
.copy {
float: right;
cursor: pointer;
}
}
&:hover {
color: #7b8085
.reasoning {
display: flex;
gap: 0.5rem;
align-items: flex-end;
.message-content .thinking-wrapper {
display: flex;
flex-direction: column;
gap: 0.5rem;
.thinking-content {
position: relative;
color: #8b8b8b;
.divider {
position: absolute;
top: 0;
left: 0;
height: 100%;
border-left: 2px solid #e5e5e5;
}
p {
margin: unset;
padding-left: 0.5rem;
::v-deep p {
color: #8b8b8b;
}
}
}
}
}
.error {
color: red;
.message {
display: -webkit-box;
.message-content {
flex: 1;
padding: 6px 10px;
border-radius: 2px 12px 12px;
background-color: #f0f1f5;
}
.action {
.svg-icon {
transform: translateY(50%);
margin-left: 3px;
cursor: pointer;
}
.el-dropdown {
height: 32px;
line-height: 37px;
font-size: 13px;
.el-dropdown-link {
i {
padding: 4px 5px;
font-size: 15px;
color: #8d9091;
&:hover {
color: #7b8085;
}
}
}
}
}
.error {
color: red;
}
}
}
}
}
.user-role {
flex-direction: row-reverse;
&:last-child {
padding-bottom: 16px;
}
.content {
margin-right: 10px;
&.user-role {
flex-direction: row-reverse;
.operational {
.chart-item-container {
flex-direction: row-reverse;
}
.message {
flex-direction: row-reverse;
.content {
margin-right: 10px;
.message-content {
background-color: var(--menu-hover);
border-radius: 12px 2px 12px 12px;
.operational {
flex-direction: row-reverse;
}
.message {
flex-direction: row-reverse;
.message-content {
background-color: var(--menu-hover);
border-radius: 12px 2px 12px 12px;
}
}
}
}

View File

@@ -17,7 +17,7 @@ import mdKatex from '@traptitech/markdown-it-katex'
import mila from 'markdown-it-link-attributes'
import hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css'
import { copy } from '@/utils/common'
import { copy } from '@/utils/common/index'
export default {
props: {
@@ -25,6 +25,10 @@ export default {
type: Object,
default: () => {
}
},
isTerminal: {
type: Boolean,
default: false
}
},
data() {
@@ -36,7 +40,7 @@ export default {
text() {
const value = this.message?.content || ''
if (value && this.markdown) {
return this.markdown?.render(value)
return this.renderContentWithDetails(value)
}
return this.$xss.process(value)
}
@@ -45,10 +49,10 @@ export default {
this.init()
},
updated() {
this.addCopyEvents()
this.addEvents()
},
destroyed() {
this.removeCopyEvents()
this.removeEvents()
},
methods: {
init() {
@@ -65,30 +69,139 @@ export default {
return vm.highlightBlock(hljs.highlightAuto(code).value, '')
}
})
this.markdown.use(mila, { attrs: { target: '_blank', rel: 'noopener', class: 'link-style' }})
this.markdown.use(mila, { attrs: { target: '_blank', rel: 'noopener', class: 'link-style' } })
this.markdown.use(mdKatex, { blockClass: 'katexmath-block rounded-md', errorColor: ' #cc0000' })
},
highlightBlock(str, lang) {
return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${'Copy'}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
let insertSpanHtml = `<span class="code-block-header__insert">${this.$t('Insert')}</span>`
if (!this.isTerminal) {
insertSpanHtml = ''
}
return `<pre class="code-block-wrapper">
<div class="code-block-header">
<span class="code-block-header__lang">${lang}</span>
<span class="code-block-header__actions">
${insertSpanHtml}
<span class="code-block-header__copy">${this.$t('Copy')}</span>
</span>
</div>
<code class="hljs code-block-body ${lang}">${str}</code></pre>`
},
addCopyEvents() {
const copyBtn = document.querySelectorAll('.code-block-header__copy')
copyBtn.forEach((btn) => {
btn.addEventListener('click', () => {
const code = btn.parentElement?.nextElementSibling?.textContent
if (code) {
copy(code)
}
addEvents() {
this.addBtnClickEvents('.code-block-header__copy', this.handlerClickCopy)
this.addBtnClickEvents('.code-block-header__insert', this.handlerClickInsert)
},
handlerClickCopy(event) {
const wrapper = event.target.closest('.code-block-wrapper')
if (wrapper) {
// 查找里面的 code 元素
const codeElement = wrapper.querySelector('code.code-block-body')
if (codeElement) {
const codeText = codeElement.textContent
copy(codeText)
}
}
},
handlerClickInsert(event) {
const wrapper = event.target.closest('.code-block-wrapper')
if (wrapper) {
// 查找里面的 code 元素
const codeElement = wrapper.querySelector('code.code-block-body')
if (codeElement) {
const codeText = codeElement.textContent
this.$emit('insert-code', codeText)
}
}
},
addBtnClickEvents(selector, callback) {
const buttons = this.$refs.textRef.querySelectorAll(selector)
buttons.forEach((btn) => {
btn.addEventListener('click', callback)
})
},
renderContentWithDetails(value) {
// Kael responses may wrap reasoning/thinking in <details type="reasoning">; render them with a custom block.
const detailRegex = /<details[^>]*>[\s\S]*?<\/details>/gi
let result = ''
let lastIndex = 0
let match
let hasDetails = false
while ((match = detailRegex.exec(value))) {
hasDetails = true
const preceding = value.slice(lastIndex, match.index)
if (preceding.trim()) {
result += this.markdown.render(preceding)
}
result += this.renderDetailBlock(match[0])
lastIndex = match.index + match[0].length
}
if (!hasDetails) {
return this.markdown.render(value)
}
const remaining = value.slice(lastIndex)
if (remaining.trim()) {
result += this.markdown.render(remaining)
}
return result
},
renderDetailBlock(detailStr) {
const attributes = this.extractAttributes(detailStr)
const inner = detailStr.replace(/^<details[^>]*>/i, '').replace(/<\/details>$/i, '')
const summaryMatch = inner.match(/<summary>([\s\S]*?)<\/summary>/i)
const summary = summaryMatch ? this.decodeHtml(summaryMatch[1]) : ''
const body = summaryMatch ? inner.replace(summaryMatch[0], '') : inner
const bodyHtml = body.trim() ? this.markdown.render(this.decodeHtml(body.trim())) : ''
const baseClass = 'kael-detail'
if (attributes.type === 'reasoning') {
const statusClass = attributes.done === 'true' ? 'is-done' : 'is-pending'
const title = summary || this.$t('DeeplyThoughtAbout')
return `<div class="${baseClass} ${baseClass}--reasoning ${statusClass}">
<div class="${baseClass}__header">
<span class="${baseClass}__status-dot"></span>
<span class="${baseClass}__title">${title}</span>
</div>
${bodyHtml ? `<div class="${baseClass}__body">${bodyHtml}</div>` : ''}
</div>`
}
return `<div class="${baseClass}">
${summary ? `<div class="${baseClass}__header">${summary}</div>` : ''}
${bodyHtml ? `<div class="${baseClass}__body">${bodyHtml}</div>` : ''}
</div>`
},
extractAttributes(detailStr) {
const attrs = {}
const attrMatch = detailStr.match(/^<details([^>]*)>/i)
const attrStr = (attrMatch && attrMatch[1]) || ''
attrStr.replace(/(\w+)="(.*?)"/g, (all, key, val) => {
attrs[key] = val
return all
})
return attrs
},
decodeHtml(str) {
if (!str) return ''
const textArea = document.createElement('textarea')
textArea.innerHTML = str
return textArea.value
},
removeBtnClickEvent(selector) {
const buttons = this.$refs.textRef.querySelectorAll(selector)
buttons.forEach((btn) => {
btn.removeEventListener('click', () => {
})
})
},
removeCopyEvents() {
removeEvents() {
if (this.$refs.textRef) {
const copyBtn = this.$refs.textRef.querySelectorAll('.code-block-header__copy')
copyBtn.forEach((btn) => {
btn.removeEventListener('click', () => {
})
})
this.removeBtnClickEvent('.code-block-header__copy')
this.addBtnClickEvents('.code-block-header__insert')
}
}
}
@@ -98,6 +211,7 @@ export default {
<style lang="scss" scoped>
.markdown-body {
font-size: 13px;
max-width: 300px;;
&::v-deep p {
margin-bottom: 0 !important;
@@ -115,26 +229,46 @@ export default {
&::v-deep .code-block-wrapper {
background: #1F2329;
padding: 2px 6px;
padding: 0;
margin: 5px 0;
display: flex;
flex-direction: column;
overflow: hidden;
.code-block-body {
padding: 5px 10px 0;
padding: 5px 10px;
}
;
.code-block-header {
margin-bottom: 4px;
overflow: hidden;
background: #353946;
color: #c2d1e1;
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 8px;
width: 100%;
box-sizing: border-box;
.code-block-header__copy {
float: right;
cursor: pointer;
.code-block-header__actions {
display: flex;
gap: 8px;
&:hover {
color: #6e747b;
.code-block-header__copy {
cursor: pointer;
&:hover {
color: #6e747b;
}
}
.code-block-header__insert {
cursor: pointer;
&:hover {
color: #6e747b;
}
}
}
}
@@ -178,6 +312,7 @@ export default {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
@@ -194,4 +329,64 @@ export default {
.loading-box span:nth-child(3) {
animation-delay: 0.49s;
}
.kael-detail {
margin: 8px 0;
padding: 8px 10px;
border-radius: 8px;
border: 1px solid #e5e5e5;
background: #f7f8fa;
&__header {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: #6b7280;
}
&__title {
font-weight: 600;
}
&__status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: #10b981;
}
&__body {
margin-top: 6px;
padding-left: 8px;
border-left: 2px solid #e5e5e5;
}
&--reasoning.is-pending {
border-color: #f59e0b40;
background: #fff8e6;
.kael-detail__status-dot {
background: #f59e0b;
animation: kael-pulse 1.2s ease-in-out infinite;
}
}
&--reasoning.is-done {
border-color: #dbeafe;
background: #f4f6ff;
}
}
@keyframes kael-pulse {
0% {
opacity: 0.45;
}
50% {
opacity: 1;
}
100% {
opacity: 0.45;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,8 @@
</template>
<script>
import { BASE_URL } from '@/utils/common/index'
export default {
props: {
active: {
@@ -41,6 +43,16 @@ export default {
},
handleExpand() {
this.$emit('expand-full')
},
async openWebsite() {
let url = `${BASE_URL}/?_=${Date.now()}`
if (process.env.NODE_ENV !== 'production') {
url = url.replace('9528', '5173')
}
const newUrl = new URL(url)
window.open(newUrl.toString(), '_blank')
return url
}
}
}

View File

@@ -1,5 +1,6 @@
<template>
<DrawerPanel
v-if="visible"
ref="drawer"
:default-show-panel="!!defaultShowPanel"
:expanded="expanded"
@@ -45,9 +46,11 @@
import Sidebar from './components/Sidebar/index.vue'
import Chat from './components/ChitChat/index.vue'
import { getInputFocus } from './useChat.js'
import { ws } from '@/utils/socket'
import DrawerPanel from '@/components/Apps/DrawerPanel/index.vue'
import { ObjectLocalStorage } from '@/utils/common'
import { mapGetters } from 'vuex'
const aiPannelLocalStorage = new ObjectLocalStorage('ai_panel_settings')
export default {
components: {
DrawerPanel,
@@ -72,23 +75,76 @@ export default {
},
data() {
return {
visible: false,
active: 'chat',
robotUrl: require('@/assets/img/robot-assistant.png'),
height: '400px',
expanded: false,
clientOffset: {}
clientOffset: {},
currentTerminalContent: {},
initialized: false
}
},
computed: {
...mapGetters([
'publicSettings'
])
},
watch: {
'publicSettings.CHAT_AI_METHOD': {
handler(newVal) {
this.visible = newVal === 'api'
}
}
},
mounted() {
this.handlePostMessage()
this.handleStartChat()
},
methods: {
handleStartChat() {
if (this.publicSettings.CHAT_AI_METHOD === 'api') {
this.visible = true
const expanded = aiPannelLocalStorage.get('expanded')
this.updateExpandedState(expanded)
this.handlePostMessage()
} else if (this.publicSettings.CHAT_AI_METHOD === 'embed') {
const embedScriptId = 'chat-ai-embed-id'
if (document.getElementById(embedScriptId)) {
return
}
const script = document.createElement('script')
script.id = embedScriptId
script.src = this.publicSettings.CHAT_AI_EMBED_URL
script.async = true
script.onload = () => {
const loadEvent = new Event('load', { bubbles: false, cancelable: false })
window.dispatchEvent(loadEvent)
}
document.body.appendChild(script)
}
},
initAssistant() {
if (this.initialized) return
this.initialized = true
this.$nextTick(() => {
this.$refs.component?.init()
})
},
handlePostMessage() {
window.addEventListener('message', (event) => {
if (event.data === 'show-chat-panel') {
this.$refs.drawer.show = true
this.initAssistant()
return
}
const msg = event.data
switch (msg.name) {
case 'current_terminal_content':
// {content: '...', terminalId: '',sessionId: '',viewId: '',viewName: ''}
this.$log.debug('current_terminal_content', msg)
this.currentTerminalContent = msg.data
this.$refs.component?.onTerminalContext(msg.data)
break
}
})
},
@@ -96,23 +152,30 @@ export default {
this.$refs.drawer.handleHeaderMoveDown(event)
},
handleMouseMoveUp(event) {
this.$refs.drawer.handleHeaderMoveUp(event)
},
initWebSocket() {
if (!ws) {
this.$refs.component?.init()
// Prevent the new chat button from triggering the header move up
const newButton = event.target.closest('.new')
if (newButton) {
return
}
this.$refs.drawer.handleHeaderMoveUp(event)
},
onClose() {
this.$refs.drawer.show = false
},
expandFull() {
this.height = '100%'
this.expanded = true
this.updateExpandedState(true)
this.save_pannel_settings()
},
compress() {
this.height = '400px'
this.expanded = false
this.updateExpandedState(false)
this.save_pannel_settings()
},
save_pannel_settings() {
aiPannelLocalStorage.set('expanded', this.expanded)
},
updateExpandedState(expanded) {
this.expanded = expanded
this.height = expanded ? '100%' : '400px'
},
onNewChat() {
this.active = 'chat'
@@ -122,8 +185,8 @@ export default {
})
},
onToggle(status) {
this.initWebSocket()
if (status) {
this.initAssistant()
getInputFocus()
}
}

View File

@@ -0,0 +1,33 @@
<template>
<svg
:stroke-width="strokeWidth"
width="20"
height="20"
viewBox="0 0 20 20"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
:class="className"
>
<path
fill="#6b7280"
style="fill: #6b7280 !important"
d="M11.2475 18.25C10.6975 18.25 10.175 18.1455 9.67999 17.9365C9.18499 17.7275 8.74499 17.436 8.35999 17.062C7.94199 17.205 7.50749 17.2765 7.05649 17.2765C6.31949 17.2765 5.63749 17.095 5.01049 16.732C4.38349 16.369 3.87749 15.874 3.49249 15.247C3.11849 14.62 2.93149 13.9215 2.93149 13.1515C2.93149 12.8325 2.97549 12.486 3.06349 12.112C2.62349 11.705 2.28249 11.2375 2.04049 10.7095C1.79849 10.1705 1.67749 9.6095 1.67749 9.0265C1.67749 8.4325 1.80399 7.8605 2.05699 7.3105C2.30999 6.7605 2.66199 6.2875 3.11299 5.8915C3.57499 5.4845 4.10849 5.204 4.71349 5.05C4.83449 4.423 5.08749 3.862 5.47249 3.367C5.86849 2.861 6.35249 2.465 6.92449 2.179C7.49649 1.893 8.10699 1.75 8.75599 1.75C9.30599 1.75 9.82849 1.8545 10.3235 2.0635C10.8185 2.2725 11.2585 2.564 11.6435 2.938C12.0615 2.795 12.496 2.7235 12.947 2.7235C13.684 2.7235 14.366 2.905 14.993 3.268C15.62 3.631 16.1205 4.126 16.4945 4.753C16.8795 5.38 17.072 6.0785 17.072 6.8485C17.072 7.1675 17.028 7.514 16.94 7.888C17.38 8.295 17.721 8.768 17.963 9.307C18.205 9.835 18.326 10.3905 18.326 10.9735C18.326 11.5675 18.1995 12.1395 17.9465 12.6895C17.6935 13.2395 17.336 13.718 16.874 14.125C16.423 14.521 15.895 14.796 15.29 14.95C15.169 15.577 14.9105 16.138 14.5145 16.633C14.1295 17.139 13.651 17.535 13.079 17.821C12.507 18.107 11.8965 18.25 11.2475 18.25ZM7.17199 16.1875C7.72199 16.1875 8.20049 16.072 8.60749 15.841L11.7095 14.059C11.8195 13.982 11.8745 13.8775 11.8745 13.7455V12.3265L7.88149 14.62C7.63949 14.763 7.39749 14.763 7.15549 14.62L4.03699 12.8215C4.03699 12.8545 4.03149 12.893 4.02049 12.937C4.02049 12.981 4.02049 13.047 4.02049 13.135C4.02049 13.696 4.15249 14.213 4.41649 14.686C4.69149 15.148 5.07099 15.511 5.55499 15.775C6.03899 16.05 6.57799 16.1875 7.17199 16.1875ZM7.33699 13.498C7.40299 13.531 7.46349 13.5475 7.51849 13.5475C7.57349 13.5475 7.62849 13.531 7.68349 13.498L8.92099 12.7885L4.94449 10.4785C4.70249 10.3355 4.58149 10.121 4.58149 9.835V6.2545C4.03149 6.4965 3.59149 6.8705 3.26149 7.3765C2.93149 7.8715 2.76649 8.4215 2.76649 9.0265C2.76649 9.5655 2.90399 10.0825 3.17899 10.5775C3.45399 11.0725 3.81149 11.4465 4.25149 11.6995L7.33699 13.498ZM11.2475 17.161C11.8305 17.161 12.3585 17.029 12.8315 16.765C13.3045 16.501 13.6785 16.138 13.9535 15.676C14.2285 15.214 14.366 14.697 14.366 14.125V10.561C14.366 10.429 14.311 10.33 14.201 10.264L12.947 9.538V14.1415C12.947 14.4275 12.826 14.642 12.584 14.785L9.46549 16.5835C10.0045 16.9685 10.5985 17.161 11.2475 17.161ZM11.8745 11.122V8.878L10.01 7.822L8.12899 8.878V11.122L10.01 12.178L11.8745 11.122ZM7.05649 5.8585C7.05649 5.5725 7.17749 5.358 7.41949 5.215L10.538 3.4165C9.99899 3.0315 9.40499 2.839 8.75599 2.839C8.17299 2.839 7.64499 2.971 7.17199 3.235C6.69899 3.499 6.32499 3.862 6.04999 4.324C5.78599 4.786 5.65399 5.303 5.65399 5.875V9.4225C5.65399 9.5545 5.70899 9.659 5.81899 9.736L7.05649 10.462V5.8585ZM15.4385 13.7455C15.9885 13.5035 16.423 13.1295 16.742 12.6235C17.072 12.1175 17.237 11.5675 17.237 10.9735C17.237 10.4345 17.0995 9.9175 16.8245 9.4225C16.5495 8.9275 16.192 8.5535 15.752 8.3005L12.6665 6.5185C12.6005 6.4745 12.54 6.458 12.485 6.469C12.43 6.469 12.375 6.4855 12.32 6.5185L11.0825 7.2115L15.0755 9.538C15.1965 9.604 15.2845 9.692 15.3395 9.802C15.4055 9.901 15.4385 10.022 15.4385 10.165V13.7455ZM12.122 5.3635C12.364 5.2095 12.606 5.2095 12.848 5.3635L15.983 7.195C15.983 7.118 15.983 7.019 15.983 6.898C15.983 6.37 15.851 5.8695 15.587 5.3965C15.334 4.9125 14.9655 4.5275 14.4815 4.2415C14.0085 3.9555 13.4585 3.8125 12.8315 3.8125C12.2815 3.8125 11.803 3.928 11.396 4.159L8.29399 5.941C8.18399 6.018 8.12899 6.1225 8.12899 6.2545V7.6735L12.122 5.3635Z"
/>
</svg>
</template>
<script>
export default {
name: 'ChatGPTIcon',
props: {
className: {
type: String,
default: 'size-8'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
}
}
</script>

View File

@@ -0,0 +1,45 @@
<template>
<svg
:stroke-width="strokeWidth"
viewBox="0 0 24 16"
overflow="visible"
width="20"
height="20"
:class="className"
>
<g style="transform: translateX(13px) rotateZ(0deg); transform-origin: 4.775px 7.73501px;">
<path
shape-rendering="geometricPrecision"
fill-opacity="1"
fill="#8c653f"
style="fill: #8c653f !important"
d=" M0,0 C0,0 6.1677093505859375,15.470022201538086 6.1677093505859375,15.470022201538086 C6.1677093505859375,15.470022201538086 9.550004005432129,15.470022201538086 9.550004005432129,15.470022201538086 C9.550004005432129,15.470022201538086 3.382294178009033,0 3.382294178009033,0 C3.382294178009033,0 0,0 0,0 C0,0 0,0 0,0z"
/>
</g>
<g opacity="1" style="transform: none; transform-origin: 7.935px 7.73501px;">
<path
shape-rendering="geometricPrecision"
fill-opacity="1"
fill="#8c653f"
style="fill: #8c653f !important"
d=" M5.824605464935303,9.348296165466309 C5.824605464935303,9.348296165466309 7.93500280380249,3.911694288253784 7.93500280380249,3.911694288253784 C7.93500280380249,3.911694288253784 10.045400619506836,9.348296165466309 10.045400619506836,9.348296165466309 C10.045400619506836,9.348296165466309 5.824605464935303,9.348296165466309 5.824605464935303,9.348296165466309 C5.824605464935303,9.348296165466309 5.824605464935303,9.348296165466309 5.824605464935303,9.348296165466309z M6.166755199432373,0 C6.166755199432373,0 0,15.470022201538086 0,15.470022201538086 C0,15.470022201538086 3.4480772018432617,15.470022201538086 3.4480772018432617,15.470022201538086 C3.4480772018432617,15.470022201538086 4.709278583526611,12.22130012512207 4.709278583526611,12.22130012512207 C4.709278583526611,12.22130012512207 11.16093635559082,12.22130012512207 11.16093635559082,12.22130012512207 C11.16093635559082,12.22130012512207 12.421928405761719,15.470022201538086 12.421928405761719,15.470022201538086 C12.421928405761719,15.470022201538086 15.87000560760498,15.470022201538086 15.87000560760498,15.470022201538086 C15.87000560760498,15.470022201538086 9.703250885009766,0 9.703250885009766,0 C9.703250885009766,0 6.166755199432373,0 6.166755199432373,0 C6.166755199432373,0 6.166755199432373,0 6.166755199432373,0z"
/>
</g>
</svg>
</template>
<script>
export default {
name: 'ClaudeIcon',
props: {
className: {
type: String,
default: 'size-4'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
}
}
</script>

View File

@@ -0,0 +1,34 @@
<template>
<svg
id="图层_1"
xmlns="http://www.w3.org/2000/svg"
data-name="图层 1"
viewBox="0 0 71.69 52.76"
:class="className"
:stroke-width="strokeWidth"
>
<path
id="path"
fill="#4d6bfe"
style="fill: #4d6bfe !important"
d="M523.77,276.34c-.76-.38-1.08.33-1.53.69a4,4,0,0,0-.41.41,5.07,5.07,0,0,1-4.1,1.87,8,8,0,0,0-6.46,2.53,5.82,5.82,0,0,0-3.72-4.62,6.39,6.39,0,0,1-2.85-1.94,7.76,7.76,0,0,1-.92-2.31c-.16-.48-.32-1-.87-1.05s-.83.41-1.07.82a11,11,0,0,0-1.26,5.5,11.9,11.9,0,0,0,5.49,10.14.75.75,0,0,1,.39,1c-.25.84-.54,1.65-.79,2.49-.17.53-.41.65-1,.42a16.63,16.63,0,0,1-5.18-3.52c-2.56-2.48-4.88-5.21-7.76-7.35-.68-.5-1.36-1-2.06-1.41-2.94-2.86.39-5.2,1.16-5.48s.28-1.29-2.33-1.28-5,.88-8,2a8.23,8.23,0,0,1-1.39.41,28.67,28.67,0,0,0-8.61-.3,18.57,18.57,0,0,0-13.44,7.83c-4,5.47-4.91,11.67-3.76,18.15a27.68,27.68,0,0,0,10,16.88,26.8,26.8,0,0,0,19.23,6.39c4.43-.25,9.36-.84,14.92-5.55a13.84,13.84,0,0,0,5.32,1.18,17.24,17.24,0,0,0,5.09-.38c2.2-.46,2.05-2.5,1.25-2.87-6.43-3-5-1.78-6.3-2.77,3.27-3.87,8.2-7.89,10.13-20.92a12.44,12.44,0,0,0,0-2.52c0-.51.1-.71.68-.76a12.55,12.55,0,0,0,4.62-1.42c4.17-2.28,5.85-6,6.25-10.51A1.57,1.57,0,0,0,523.77,276.34Zm-36.34,40.37c-6.24-4.9-9.27-6.52-10.52-6.45s-1,1.41-.7,2.28a8.49,8.49,0,0,0,1.11,2.21,1.14,1.14,0,0,1-.34,1.8c-2,1.24-5.5-.42-5.66-.5a26.08,26.08,0,0,1-9.87-9.88,30.15,30.15,0,0,1-3.87-13.39c-.06-1.15.28-1.56,1.42-1.77a14.31,14.31,0,0,1,4.57-.11,28.56,28.56,0,0,1,16.33,8.29,54.06,54.06,0,0,1,6.58,8.63,41.46,41.46,0,0,0,7.41,8.71,24.36,24.36,0,0,0,2.66,2C494.16,318.82,490.16,318.87,487.43,316.71Zm3-19.23a.92.92,0,0,1,.92-.92.83.83,0,0,1,.32.06.8.8,0,0,1,.34.22.9.9,0,0,1,.25.64.92.92,0,0,1-1.83,0Zm9.29,4.76a5.27,5.27,0,0,1-1.77.48,3.75,3.75,0,0,1-2.38-.76,3.57,3.57,0,0,1-1.65-2.26,5.16,5.16,0,0,1,0-1.76,2,2,0,0,0-.71-2.17,3.1,3.1,0,0,0-2.06-.59,1.63,1.63,0,0,1-.76-.24.75.75,0,0,1-.34-1.07,3.47,3.47,0,0,1,.57-.62,3.9,3.9,0,0,1,3.43,0,10,10,0,0,1,3,2.34,18.62,18.62,0,0,1,2,2.73,10.9,10.9,0,0,1,1.33,2.53C500.65,301.47,500.4,302,499.71,302.24Z"
transform="translate(-452.83 -271.91)"
/>
</svg>
</template>
<script>
export default {
name: 'DeepSeekIcon',
props: {
className: {
type: String,
default: 'size-4'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
}
}
</script>

View File

@@ -0,0 +1,33 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
width="800px"
height="800px"
viewBox="0 0 512 512"
:class="className"
:stroke-width="strokeWidth"
>
<path
fill="#4285f4"
style="fill: #4285f4 !important"
d="M473.16,221.48l-2.26-9.59H262.46v88.22H387c-12.93,61.4-72.93,93.72-121.94,93.72-35.66,0-73.25-15-98.13-39.11a140.08,140.08,0,0,1-41.8-98.88c0-37.16,16.7-74.33,41-98.78s61-38.13,97.49-38.13c41.79,0,71.74,22.19,82.94,32.31l62.69-62.36C390.86,72.72,340.34,32,261.6,32h0c-60.75,0-119,23.27-161.58,65.71C58,139.5,36.25,199.93,36.25,256S56.83,369.48,97.55,411.6C141.06,456.52,202.68,480,266.13,480c57.73,0,112.45-22.62,151.45-63.66,38.34-40.4,58.17-96.3,58.17-154.9C475.75,236.77,473.27,222.12,473.16,221.48Z"
/>
</svg>
</template>
<script>
export default {
name: 'GeminiIcon',
props: {
className: {
type: String,
default: 'size-4'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
}
}
</script>

View File

@@ -0,0 +1,33 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
fill="currentColor"
:class="className"
:stroke-width="strokeWidth"
>
<path
fill="#000000"
style="fill: #000000 !important"
d="m3.005 8.858 8.783 12.544h3.904L6.908 8.858zM6.905 15.825 3 21.402h3.907l1.951-2.788zM16.585 2l-6.75 9.64 1.953 2.79L20.492 2zM17.292 7.965v13.437h3.2V3.395z"
/>
</svg>
</template>
<script>
export default {
name: 'GrokIcon',
props: {
className: {
type: String,
default: 'size-4'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
}
}
</script>

View File

@@ -0,0 +1,50 @@
<template>
<component
:is="resolvedIcon"
v-if="resolvedIcon"
:class-name="className"
:stroke-width="strokeWidth"
/>
</template>
<script>
import ChatGPTIcon from './ChatGPT.vue'
import DeepSeekIcon from './DeepSeek.vue'
import GrokIcon from './Grok.vue'
import ClaudeIcon from './Claude.vue'
import GeminiIcon from './Gemini.vue'
export default {
name: 'ModelIcon',
props: {
name: {
type: String,
default: ''
},
className: {
type: String,
default: 'size-5'
},
strokeWidth: {
type: [String, Number],
default: '1.5'
}
},
computed: {
normalizedName() {
return (this.name || '').toLowerCase()
},
resolvedIcon() {
const name = this.normalizedName
if (!name) return null
if (name.includes('gpt')) return ChatGPTIcon
if (name.includes('deep-seek')) return DeepSeekIcon
if (name.includes('deepseek')) return DeepSeekIcon
if (name.includes('grok')) return GrokIcon
if (name.includes('claude')) return ClaudeIcon
if (name.includes('gemini')) return GeminiIcon
return null
}
}
}
</script>

View File

@@ -1,5 +1,5 @@
import store from '@/store'
import { pageScroll } from '@/utils/common'
import { pageScroll } from '@/utils/common/index'
export const getInputFocus = () => {
const dom = document.querySelector('.chat-input .el-textarea__inner')
@@ -9,11 +9,11 @@ export const getInputFocus = () => {
export function useChat() {
const chatStore = {}
const setLoading = (loading) => {
const setLoading = loading => {
store.commit('chat/setLoading', loading)
}
const onNewChat = (name) => {
const onNewChat = name => {
const data = {
name: name || `new chat`,
id: 1,
@@ -27,7 +27,7 @@ export function useChat() {
store.commit('chat/clearChats')
}
const addMessageToActiveChat = (chat) => {
const addMessageToActiveChat = chat => {
store.commit('chat/addMessageToActiveChat', chat)
}
@@ -35,7 +35,7 @@ export function useChat() {
store.commit('chat/removeLoadingMessageInChat')
}
const addChatMessageById = (chat) => {
const addChatMessageById = chat => {
store.commit('chat/addMessageToActiveChat', chat)
if (chat?.conversation_id) {
store.commit('chat/setActiveChatConversationId', chat.conversation_id)
@@ -54,7 +54,7 @@ export function useChat() {
addChatMessageById(temporaryChat)
}
const newChatAndAddMessageById = (chat) => {
const newChatAndAddMessageById = chat => {
onNewChat(chat.message.content)
addChatMessageById(chat)
}

View File

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

View File

@@ -7,10 +7,11 @@
/>
</template>
<script type="text/jsx">
<script>
import AssetTreeTable from '@/components/Apps/AssetTreeTable'
import { AccountInfoFormatter, DetailFormatter } from '@/components/Table/TableFormatters'
import { connectivityMeta } from '@/components/Apps/AccountListTable/const'
import { setUrlParam } from '@/utils/common/index'
export default {
name: 'GrantedAssets',
@@ -34,7 +35,7 @@ export default {
}
const initialUrl = vm.tableConfig.initialUrl
const nodeId = node.meta.data.id
const url = initialUrl.replace('/assets/', `/nodes/${nodeId}/assets/`)
const url = setUrlParam(initialUrl, 'node_id', nodeId)
vm.tableConfig.url = url
}
},
@@ -70,7 +71,7 @@ export default {
showMenu: false,
showRefresh: true,
showAssets: false,
showSearch: false,
showSearch: true,
url: this.tableUrl,
// ?assets=0不显示资产. =1显示资产
treeUrl: this.treeUrl,
@@ -78,6 +79,9 @@ export default {
callback: {
onSelected: (event, node) => vm.onSelected(node, vm),
refresh: vm.refreshObjectAssetPermission
},
async: {
enable: false
}
},
tableConfig: {
@@ -85,9 +89,10 @@ export default {
hasTree: true,
columnsExtra: ['view_account'],
columnsExclude: ['spec_info'],
columns: ['id', 'name', 'address', 'comment', 'labels', 'connectivity', 'platform', 'view_account', 'actions'],
columnsShow: {
min: ['name', 'address', 'accounts'],
default: ['name', 'address', 'platform', 'connectivity', 'view_account', 'actions']
default: ['name', 'address', 'platform', 'view_account', 'actions']
},
columnsMeta: {
name: {
@@ -108,11 +113,6 @@ export default {
},
connectivity: connectivityMeta,
comment: { ...this.comment }
},
tableAttrs: {
rowClassName({ row }) {
return !row.is_active ? 'row_disabled' : ''
}
}
},
headerActions: {

View File

@@ -0,0 +1,63 @@
<template>
<ListTable ref="ListTable" :header-actions="headerActions" :table-config="tableConfig" :create-drawer="createDrawer" />
</template>
<script>
import { DrawerListTable as ListTable } from '@/components'
export default {
name: 'LeakPasswordList',
components: {
ListTable
},
props: {
object: {
type: Object,
required: false,
default: () => ({})
}
},
data() {
return {
createDrawer: () => import('@/components/Apps/LeakPasswords/LeakPasswordsCreateUpdate.vue'),
tableConfig: {
url: '/api/v1/settings/leak-passwords/',
columns: [
'password'
],
columnsMeta: {
actions: {
formatterArgs: {
hasClone: false,
canDelete: this.$hasPerm('settings.change_security'),
canUpdate: this.$hasPerm('settings.change_security')
}
}
}
},
headerActions: {
hasExport: true,
hasImport: true,
importOptions: {
encryptFields: [''], // 这里不加密 password''只是为了保证数组有值
canImportUpdate: false
},
hasCreate: true,
hasSearch: true,
hasRefresh: true,
hasBulkDelete: true,
hasBulkUpdate: false,
hasLeftActions: true,
hasRightActions: true,
canCreate: this.$hasPerm('settings.change_security'),
canBulkDelete: this.$hasPerm('settings.change_security')
}
}
}
}
</script>
<style lang='less' scoped>
</style>

View File

@@ -0,0 +1,41 @@
<template>
<div v-loading="loading">
<GenericCreateUpdatePage
v-if="!loading"
class="user-create-update"
v-bind="$data"
:title="null"
v-on="$listeners"
/>
</div>
</template>
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
export default {
name: 'LeakPasswordsCreateUpdate',
components: {
GenericCreateUpdatePage
},
data() {
return {
loading: true,
fields: [
[this.$t('Basic'), ['password']]
],
encryptedFields: [],
url: '/api/v1/settings/leak-passwords/'
}
},
async mounted() {
this.loading = false
},
methods: {}
}
</script>
<style lang="scss" scoped>
</style>

View File

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

View File

@@ -1,28 +1,31 @@
<template>
<el-row :gutter="24">
<el-col :md="20" :sm="22">
<ListTable v-bind="config" />
</el-col>
</el-row>
<TwoCol>
<ListTable v-bind="config" />
</TwoCol>
</template>
<script>
import ListTable from '@/components/Table/ListTable/index.vue'
import { toM2MJsonParams } from '@/utils/jms'
import { DrawerListTable as ListTable } from '@/components'
import { toM2MJsonParams } from '@/utils/jms/index'
import { DetailFormatter } from '@/components/Table/TableFormatters'
import TwoCol from '@/layout/components/Page/TwoColPage.vue'
export default {
name: 'AssetJsonTab',
components: {
TwoCol,
ListTable
},
props: {
object: {
type: Object,
default: () => {}
default: () => {
}
}
},
data() {
const [key, value] = toM2MJsonParams(this.object.assets)
const org_id = this.object.org_id || this.$store.getters.currentOrg.id
return {
config: {
headerActions: {
@@ -31,22 +34,19 @@ export default {
hasExport: false
},
tableConfig: {
url: `/api/v1/assets/assets/?${key}=${value}`,
columns: ['name', 'address', 'platform',
'type', 'is_active'
],
url: `/api/v1/assets/assets/?${key}=${value}&oid=${org_id}`,
columns: ['name', 'address', 'platform', 'type', 'is_active'],
columnsShow: {
min: ['name', 'address'],
default: ['name', 'address', 'platform']
},
columnsMeta: {
name: {
label: this.$t('Asset'),
formatter: (row) => {
const to = {
name: 'AssetDetail',
params: { id: row.id }
}
if (this.$hasPerm('assets.view_asset')) {
return <router-link to={to} class='text-link'>{row.name}</router-link>
} else {
return <span>{row.name}</span>
formatter: DetailFormatter,
formatterArgs: {
getRoute: ({ row }) => {
return { name: 'AssetDetail', params: { id: row.id } }
}
}
},
@@ -65,7 +65,3 @@ export default {
}
}
</script>
<style scoped>
</style>

View File

@@ -1,18 +1,19 @@
<template>
<el-row :gutter="24">
<el-col :md="20" :sm="22">
<ListTable v-bind="config" />
</el-col>
</el-row>
<TwoCol>
<ListTable v-bind="config" />
</TwoCol>
</template>
<script>
import ListTable from '@/components/Table/ListTable/index.vue'
import { toM2MJsonParams } from '@/utils/jms'
import { DrawerListTable as ListTable } from '@/components'
import { toM2MJsonParams } from '@/utils/jms/index'
import TwoCol from '@/layout/components/Page/TwoColPage.vue'
import { DetailFormatter } from '@/components/Table/TableFormatters'
export default {
name: 'User',
components: {
TwoCol,
ListTable
},
props: {
@@ -24,6 +25,7 @@ export default {
},
data() {
const [key, value] = toM2MJsonParams(this.object.users)
const org_id = this.object.org_id || this.$store.getters.currentOrg.id
return {
config: {
headerActions: {
@@ -32,24 +34,25 @@ export default {
hasExport: false
},
tableConfig: {
url: `/api/v1/users/users/?${key}=${value}`,
url: `/api/v1/users/users/?${key}=${value}&oid=${org_id}`,
columns: [
'name', 'username', 'groups', 'system_roles',
'name', 'username', 'email', 'groups', 'system_roles',
'org_roles', 'source', 'is_valid'
],
columnsShow: {
min: ['name', 'username'],
default: ['name', 'username', 'email']
},
columnsMeta: {
name: {
label: this.$t('Name'),
width: 85,
formatter: (row) => {
const to = {
name: 'UserDetail',
params: { id: row.id }
}
if (this.$hasPerm('users.view_user')) {
return <router-link to={to} class='text-link'>{row.name}</router-link>
} else {
return <span>{row.name}</span>
formatter: DetailFormatter,
formatterArgs: {
getRoute: ({ row }) => {
return {
name: 'UserDetail',
params: { id: row.id }
}
}
}
},
@@ -87,7 +90,3 @@ export default {
}
}
</script>
<style scoped>
</style>

View File

@@ -1,43 +1,43 @@
<template>
<div>
<el-row :gutter="20">
<el-col :md="16" :sm="24">
<IBox :title="title" class="block" v-bind="$attrs">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:size="activity.size"
:timestamp="activity.timestamp"
:type="activity.type"
placement="bottom"
<TwoCol>
<IBox :title="title" class="block" v-bind="$attrs">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:size="activity.size"
:timestamp="activity.timestamp"
:type="activity.type"
placement="bottom"
>
{{ activity.content }}
<el-link
v-if="activity['detail_url']"
type="primary"
@click.native="onClick(activity)"
>
{{ activity.content }}
<el-link
v-if="activity['detail_url']"
type="primary"
@click.native="onClick(activity)"
>
{{ $tc('Detail') }}
</el-link>
</el-timeline-item>
</el-timeline>
</IBox>
</el-col>
</el-row>
{{ $tc('Detail') }}
</el-link>
</el-timeline-item>
</el-timeline>
</IBox>
</TwoCol>
<DiffDetail ref="DetailDialog" :title="$tc('OperateLog')" />
</div>
</template>
<script>
import IBox from '@/components/IBox/index.vue'
import IBox from '@/components/Common/IBox/index.vue'
import DiffDetail from '@/components/Dialog/DiffDetail.vue'
import { openTaskPage } from '@/utils/jms'
import { toSafeLocalDateStr } from '@/utils/time'
import { openTaskPage } from '@/utils/jms/index'
import { toSafeLocalDateStr } from '@/utils/common/time'
import TwoCol from '@/layout/components/Page/TwoColPage.vue'
export default {
name: 'ResourceActivity',
components: {
TwoCol,
IBox,
DiffDetail
},

View File

@@ -13,17 +13,12 @@
v-on="$listeners"
>
<div v-if="confirmTypeRequired === 'relogin'">
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24">
<el-alert
:title="$tc('ReLoginTitle')"
center
style="margin-bottom: 20px;"
type="error"
/>
<el-alert :title="$tc('ReLoginTitle')" center style="margin-bottom: 20px" type="error" />
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="logout">
{{ this.$t('ReLogin') }}
@@ -32,11 +27,11 @@
</el-row>
</div>
<div v-else>
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24" :span="24" class="add">
<el-select
v-model="subTypeSelected"
style="width: 100%; margin-bottom: 20px;"
style="width: 100%; margin-bottom: 20px"
@change="handleSubTypeChange"
>
<el-option
@@ -49,32 +44,73 @@
</el-select>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24" style="display: flex; align-items: center; margin-bottom: 20px;">
<el-row v-if="!noCodeMFA.includes(subTypeSelected)" :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24" style="display: flex; align-items: center">
<el-input
v-model="secretValue"
:placeholder="inputPlaceholder"
:show-password="showPassword"
@keyup.enter.native="handleConfirm"
/>
<span v-if="subTypeSelected === 'sms'" style="margin: -1px 0 0 20px;">
<span
v-if="subTypeSelected === 'sms' || subTypeSelected === 'email'"
style="margin: -1px 0 0 20px"
>
<el-button
:disabled="smsBtnDisabled"
size="mini"
style="line-height: 14px; float: right;"
style="line-height: 14px; float: right"
type="primary"
@click="sendSMSCode"
@click="sendCode"
>
{{ smsBtnText }}
</el-button>
</span>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 10px auto;">
<el-row>
<el-col>
<iframe v-if="passkeyVisible" :src="passkeyUrl" style="display: none" />
<iframe
v-if="isFaceCaptureVisible && subTypeSelected === 'face' && faceCaptureUrl"
:src="faceCaptureUrl"
allow="camera"
sandbox="allow-scripts allow-same-origin"
style="width: 100%; height: 600px; border: none"
/>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 20px auto 10px">
<el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="handleConfirm">
<el-button
v-if="!noCodeMFA.includes(subTypeSelected)"
class="confirm-btn"
size="mini"
type="primary"
@click="handleConfirm"
>
{{ this.$t('Confirm') }}
</el-button>
<el-button
v-if="subTypeSelected === 'face'"
v-show="!isFaceCaptureVisible"
class="confirm-btn"
size="mini"
type="primary"
@click="handleFaceCapture"
>
{{ this.$tc('VerifyFace') }}
</el-button>
<el-button
v-if="subTypeSelected === 'passkey'"
v-loading="passkeyVisible"
class="confirm-btn"
size="mini"
type="primary"
@click="handlePasskeyVerify"
>
{{ this.$tc('Next') }}
</el-button>
</el-col>
</el-row>
</div>
@@ -82,7 +118,7 @@
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import { encryptPassword } from '@/utils/crypto'
import { encryptPassword } from '@/utils/secure'
export default {
name: 'UserConfirmDialog',
@@ -113,7 +149,14 @@ export default {
visible: false,
callback: null,
cancel: null,
processing: false
processing: false,
isFaceCaptureVisible: false,
faceToken: null,
faceCaptureUrl: null,
noCodeMFA: ['face', 'passkey'],
sendCodeMFA: ['email', 'sms', 'otp'],
passkeyVisible: false,
passkeyUrl: '/api/v1/authentication/passkeys/login/?mfa=1'
}
},
computed: {
@@ -129,6 +172,10 @@ export default {
},
methods: {
handleSubTypeChange(val) {
if (val !== 'face') {
this.isFaceCaptureVisible = false
}
this.inputPlaceholder = this.subTypeChoices.filter(item => item.name === val)[0]?.placeholder
this.smsWidth = val === 'sms' ? 6 : 0
},
@@ -142,54 +189,117 @@ export default {
this.$log.debug('perform confirm action')
const confirmType = response.data?.code
const confirmUrl = '/api/v1/authentication/confirm/'
this.$axios.get(confirmUrl, { params: { confirm_type: confirmType }}).then((data) => {
this.confirmTypeRequired = data.confirm_type
this.$axios
.get(confirmUrl, { params: { confirm_type: confirmType } })
.then(data => {
this.confirmTypeRequired = data.confirm_type
if (this.confirmTypeRequired === 'relogin') {
this.$axios.post(confirmUrl, { 'confirm_type': 'relogin', 'secret_key': 'x' }).then(() => {
this.callback()
this.visible = false
}).catch(() => {
this.title = this.$t('NeedReLogin')
this.visible = true
})
return
}
this.subTypeChoices = data.content
const defaultSubType = this.subTypeChoices.filter(item => !item.disabled)[0]
this.subTypeSelected = defaultSubType.name
this.inputPlaceholder = defaultSubType.placeholder
this.visible = true
}).catch((err) => {
const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('GetConfirmTypeFailed')
this.$message.error(msg)
this.cancel(err)
}).finally(() => {
this.processing = false
})
if (this.confirmTypeRequired === 'relogin') {
this.$axios
.post(confirmUrl, { confirm_type: 'relogin', secret_key: 'x' })
.then(() => {
this.callback()
this.visible = false
})
.catch(() => {
this.title = this.$t('NeedReLogin')
this.visible = true
})
return
}
this.subTypeChoices = data.content
const defaultSubType = this.subTypeChoices.filter(item => !item.disabled)[0]
this.subTypeSelected = defaultSubType.name
this.inputPlaceholder = defaultSubType.placeholder
this.visible = true
})
.catch(err => {
const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('GetConfirmTypeFailed')
this.$message.error(msg)
this.cancel(err)
})
.finally(() => {
this.processing = false
})
}, 500),
logout() {
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
},
sendSMSCode() {
this.$axios.post(`/api/v1/authentication/mfa/select/`, { type: 'sms' }).then(res => {
this.$message.success(this.$tc('VerificationCodeSent'))
let time = 60
this.smsBtnDisabled = true
sendCode() {
this.$axios
.post(`/api/v1/authentication/mfa/select/`, { type: this.subTypeSelected })
.then(res => {
this.$message.success(this.$tc('VerificationCodeSent'))
let time = 60
this.smsBtnDisabled = true
const interval = setInterval(() => {
time -= 1
this.smsBtnText = `${this.$t('Pending')}: ${time}`
const interval = setInterval(() => {
time -= 1
this.smsBtnText = `${this.$t('Pending')}: ${time}`
if (time <= 0) {
clearInterval(interval)
this.smsBtnText = this.$t('SendVerificationCode')
this.smsBtnDisabled = false
}
}, 1000)
}).catch(() => {
this.$message.error(this.$tc('FailedToSendVerificationCode'))
if (time <= 0) {
clearInterval(interval)
this.smsBtnText = this.$t('SendVerificationCode')
this.smsBtnDisabled = false
}
}, 1000)
})
.catch(() => {
this.$message.error(this.$tc('FailedToSendVerificationCode'))
})
},
handlePasskeyVerify() {
this.passkeyVisible = true
this.checkPasskeyStatus()
},
checkPasskeyStatus() {
const url = '/api/v1/authentication/confirm/check/?confirm_type=mfa'
const t = setInterval(() => {
this.$axios.get(url).then(data => {
this.passkeyVisible = false
this.onSuccess()
})
}, 2000)
setTimeout(() => {
clearInterval(t)
if (this.passkeyVisible) {
this.passkeyVisible = false
this.$message.error(this.$tc('PasskeyTimeout'))
}
}, 20000)
},
startFaceCapture() {
const url = '/api/v1/authentication/face/context/'
this.$axios
.post(url)
.then(data => {
const token = data['token']
this.faceCaptureUrl = '/facelive/capture?token=' + token
this.isFaceCaptureVisible = true
const timer = setInterval(() => {
this.$axios.get(url + `?token=${token}`).then(data => {
if (data['is_finished']) {
clearInterval(timer)
this.isFaceCaptureVisible = false
this.handleConfirm()
}
})
}, 1000)
})
.catch(() => {
this.$message.error(this.$tc('FailedToStartFaceCapture'))
})
},
handleFaceCapture() {
this.startFaceCapture()
},
onSuccess() {
this.secretValue = ''
this.visible = false
this.$nextTick(() => {
this.callback()
})
},
handleConfirm() {
@@ -203,39 +313,43 @@ export default {
const data = {
confirm_type: this.confirmTypeRequired,
mfa_type: this.confirmTypeRequired === 'mfa' ? this.subTypeSelected : '',
secret_key: this.confirmTypeRequired === 'password' ? encryptPassword(this.secretValue) : this.secretValue
secret_key:
this.confirmTypeRequired === 'password'
? encryptPassword(this.secretValue)
: this.secretValue
}
this.$axios.post(`/api/v1/authentication/confirm/`, data).then(() => {
this.secretValue = ''
this.visible = false
this.$nextTick(() => {
this.callback()
this.$axios
.post(`/api/v1/authentication/confirm/`, data)
.then(() => {
this.onSuccess()
})
.catch(err => {
this.$message.error(err.message || this.$tc('ConfirmFailed'))
this.faceCaptureUrl = null
this.isFaceCaptureVisible = false
})
}).catch((err) => {
this.$message.error(err.message || this.$tc('ConfirmFailed'))
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-content ::v-deep .el-dialog__footer {
padding: 0;
}
.dialog-content ::v-deep .el-dialog__footer {
padding: 0;
}
.dialog-content ::v-deep .el-dialog {
padding: 8px;
.dialog-content ::v-deep .el-dialog {
padding: 8px;
.el-dialog__body {
padding-top: 30px;
padding-bottom: 30px;
}
.el-dialog__body {
padding-top: 30px;
padding-bottom: 30px;
}
}
.confirm-btn {
width: 100%;
line-height: 20px;
}
.confirm-btn {
width: 100%;
line-height: 20px;
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<AutoDataForm
ref="AutoDataForm"
class="variable-add"
:submit-btn-text="submitBtnText"
v-bind="$data"
@submit="confirm"
/>
</template>
<script>
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
export default {
name: 'VariableCreateForm',
components: {
AutoDataForm
},
props: {
variable: {
type: Object,
default: () => ({})
}
},
data() {
const defaultValidator = (rule, value, callback) => {
if (this.defaultValueRequired && !value) {
callback(new Error(this.$t('FieldRequiredError')))
} else {
callback()
}
}
return {
defaultValueRequired: false,
submitBtnText: this.$t('Confirm'),
url: '/api/v1/ops/variables/',
form: Object.assign({ 'on_invalid': 'error' }, this.variable || {}),
fields: [
['', ['name', 'var_name', 'type', 'text_default_value', 'select_default_value', 'extra_args', 'tips', 'required']]
],
fieldsMeta: {
var_name: {
helpTextAsTip: false
},
text_default_value: {
label: this.$t('DefaultValue'),
hidden: (formValue) => {
return formValue.type !== 'text'
},
rules: [{ validator: defaultValidator }],
helpTip: this.$t('DefaultValueTip'),
el: {
type: 'input'
}
},
select_default_value: {
label: this.$t('DefaultValue'),
helpTip: this.$t('DefaultValueTip'),
hidden: (formValue) => {
return formValue.type !== 'select'
},
rules: [{ validator: defaultValidator }],
el: { type: 'input' }
},
extra_args: {
hidden: (formValue) => {
return formValue.type !== 'select'
},
el: { type: 'textarea', rows: 4, placeholder: this.$t('ExtraArgsPlaceholder') },
rules: [
{
validator: (rule, value, callback) => {
try {
const lines = value.split('\n')
const regex = /^[^:]+:[^:]+$/
for (const line of lines) {
if (!regex.test(line.trim())) {
callback(new Error(this.$t('ExtraArgsFormatError')))
}
}
} catch (e) {
callback(new Error(this.$t('ExtraArgsFormatError')))
}
callback()
}
}
]
},
required: {
on: {
change: ([event], updateForm) => {
this.defaultValueRequired = event
}
}
}
},
hasSaveContinue: false,
method: 'get'
}
},
mounted() {
this.defaultValueRequired = this.variable?.required || false
},
methods: {
confirm(form) {
if (this.variable?.name) {
this.$emit('edit', form)
} else {
this.$emit('add', form)
}
}
}
}
</script>
<style lang='scss' scoped>
.variable-add {
::v-deep .el-form-item {
margin-bottom: 5px;
.help-block {
margin-bottom: 5px;
}
}
::v-deep .form-group-header {
.hr-line-dashed {
margin: 5px 0;
}
h3 {
margin-bottom: 10px;
}
}
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<AutoDataForm
ref="AutoDataForm"
class="variable-set"
:submit-btn-text="submitBtnText"
v-bind="$data"
:fields="fields"
@submit="confirm"
/>
</template>
<script>
import AutoDataForm from '@/components/Form/AutoDataForm/index.vue'
export default {
name: 'VariableSetForm',
components: {
AutoDataForm
},
props: {
formData: {
type: Array,
default: () => ([])
},
queryParam: {
type: String,
default: ''
}
},
data() {
return {
submitBtnText: this.$t('Confirm'),
// 防止缓存form remoteMeta
url: `/api/v1/ops/variables/form-data/?t=${new Date().getTime()}&` + this.queryParam,
form: {},
hasSaveContinue: false,
method: 'get',
hasReset: false
}
},
computed: {
fields() {
return [['', this.formData.map(item => item.var_name)]]
}
},
methods: {
confirm(form) {
this.$emit('confirm', form)
}
}
}
</script>
<style lang='scss' scoped>
.variable-set {
::v-deep .el-form-item {
margin-bottom: 5px;
.help-block {
margin-bottom: 5px;
}
}
::v-deep .form-group-header {
.hr-line-dashed {
margin: 5px 0;
}
h3 {
margin-bottom: 10px;
}
}
}
</style>

View File

@@ -0,0 +1,100 @@
<template>
<Dialog
:show-cancel="false"
:show-confirm="false"
:title="title"
:visible.sync="iVisible"
class="help-dialog"
top="1vh"
width="50%"
>
<p>{{ variablesHelpText }}</p>
<table border="1" class="help-table">
<tr>
<th>{{ $tc('Variable') }}</th>
<th>{{ $tc('Description') }}</th>
<th>{{ $tc('Example') }}</th>
</tr>
<tr v-for="(item, index) in variables" :key="index">
<td :title="$tc('ClickCopy')" class="item-td text-link" @click="onCopy(item.name)">
<label class="item-label">{{ item.name }}</label>
</td>
<td><span>{{ item.label }}</span></td>
<td><span>{{ item.default }}</span></td>
</tr>
</table>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import { copy } from '@/utils/common/index'
export default {
components: {
Dialog
},
props: {
visible: {
type: Boolean,
default: false
},
variables: {
type: Array,
default: () => []
},
variablesHelpText: {
type: String,
default() {
return this.$t('WatermarkVariableHelpText')
}
}
},
data() {
return {
title: this.$t('BuiltinVariable')
}
},
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
},
methods: {
onCopy(key) {
copy(key)
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .help-dialog.dialog .el-dialog__footer {
border-top: none;
padding: 8px;
}
.help-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #dee2e6;
}
::v-deep .help-table th,
::v-deep .help-table td {
height: 40px;
padding: 0 8px;
text-align: left;
}
::v-deep .help-table .item-td,
::v-deep .help-table .item-label {
cursor: pointer;
color: var(--color-primary);
}
</style>

View File

@@ -1,5 +1,5 @@
<script type="text/jsx">
import { toSafeLocalDateStr } from '@/utils/time'
import { toSafeLocalDateStr } from '@/utils/common/time'
export default {
name: 'ItemValue',
@@ -78,7 +78,7 @@ export default {
formatterData = data
}
return (
<span>{formatterData}</span>
<span style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', lineHeight: '1.2' }}>{formatterData}</span>
)
}
if (this.value instanceof Array) {
@@ -92,7 +92,7 @@ export default {
)
}
return (
<span title={this.displayValue}>{this.displayValue}</span>
<span style='white-space: pre-wrap;' title={this.displayValue}>{this.displayValue}</span>
)
}
}

View File

@@ -1,15 +1,20 @@
<template>
<IBox v-if="loading" style="width: 100%; height: 200px" />
<div v-else>
<DetailCard v-if="hasObject && items.length > 0" :items="validItems" :loading="loading" v-bind="$attrs" />
<DetailCard
v-if="hasObject && items.length > 0"
:items="validItems"
:loading="loading"
v-bind="$attrs"
/>
</div>
</template>
<script>
import DetailCard from './index.vue'
import { copy } from '@/utils/common'
import { toSafeLocalDateStr } from '@/utils/time'
import IBox from '@/components/IBox/index.vue'
import { copy } from '@/utils/common/index'
import { toSafeLocalDateStr } from '@/utils/common/time'
import IBox from '@/components/Common/IBox/index.vue'
import LabelsDetailFormatter from '../Formatters/LabelsDetailFormatter.vue'
export default {
@@ -32,7 +37,7 @@ export default {
type: Array,
default: null
},
showUndefine: {
showUndefined: {
type: Boolean,
default: true
},
@@ -124,8 +129,18 @@ export default {
parseArrayValue(value, excludes, label) {
if (Array.isArray(value)) {
const tp = typeof value[0]
let object = {}
if (value.length === 0) {
object = {
key: label,
value: '-'
}
return this.items.push(object)
}
// 如果是空数组,那么循环体将不会执行
for (const [index, item] of value.entries()) {
let object = {}
if (tp === 'object') {
const firstValue = value[0]
if (firstValue.hasOwnProperty('name')) {
@@ -168,7 +183,7 @@ export default {
const data = await this.$store.dispatch('common/getUrlMeta', { url: this.url })
let remoteMeta = data.actions['GET'] || {}
if (this.nested) {
remoteMeta = remoteMeta[this.nested]?.children || {}
remoteMeta = remoteMeta[this.nested]?.children || remoteMeta || {}
}
let fields = this.fields
fields = fields || Object.keys(remoteMeta)
@@ -220,7 +235,7 @@ export default {
value = this.parseValue(value, fieldMeta.type)
if (value === undefined) {
if (this.showUndefine) {
if (this.showUndefined) {
value = '-'
} else {
continue

View File

@@ -1,24 +1,25 @@
<template>
<IBox :fa="fa" :title="title">
<el-form :label-width="labelWidth" class="content" label-position="left">
<span v-for="item in items" :key="item.key">
<el-form-item v-if="item.has !== false" :class="item.class" :label="item.key">
<span slot="label"> {{ formateLabel(item.key) }}</span>
<span
:is="item.component"
v-if="item.component"
v-bind="{...item}"
/>
<ItemValue v-else :value="item.value" class="item-value" v-bind="item" />
</el-form-item>
</span>
<el-form :label-width="labelWidth" class="content detail-card" label-position="left">
<template v-for="item in items">
<div v-if="item.has !== false" :key="item.key" :class="item.class " :label="item.key" class="el-form-item">
<span slot="label" class="el-form-item__label"> {{ formateLabel(item.key) }}</span>
<span class="item-value el-form-item__content">
<component
:is="item.component"
v-if="item.component"
v-bind="{...item}"
/>
<ItemValue v-else :value="item.value" v-bind="item" />
</span>
</div>
</template>
</el-form>
<slot />
</IBox>
</template>
<script>
import IBox from '../../IBox/index.vue'
import IBox from '@/components/Common/IBox/index.vue'
import ItemValue from './ItemValue.vue'
export default {
@@ -45,7 +46,7 @@ export default {
},
labelWidth: {
type: String,
default: '25%'
default: '120px'
}
},
data() {
@@ -71,55 +72,76 @@ export default {
padding: 20px 40px;
}
.el-form-item {
border-bottom: 1px dashed #EBEEF5;
padding: 1px 0;
margin-bottom: 0;
&:last-child {
border-bottom: none;
}
&.array-item {
border-bottom: none;
::v-deep .el-form-item__content {
border-bottom: 1px dashed #EBEEF5
}
::v-deep .el-form-item__label:last-child {
border: 1px dashed #EBEEF5;
}
}
::v-deep .el-form-item__label {
padding-right: 8%;
overflow: hidden;
color: var(--color-icon-primary);
span {
display: inline-block;
line-height: 1.5;
}
}
::v-deep .el-form-item__content {
color: var(--color-text-primary);
font-size: 13px;
line-height: 40px;
}
::v-deep .el-tag--mini {
margin-right: 3px;
}
}
.item-value span {
word-break: break-word;
}
.content {
font-size: 13px;
line-height: 2.5;
line-height: 2;
::v-deep .el-form-item {
border-bottom: 1px dashed #F4F4F4;
padding: 1px 0;
margin-bottom: 0;
display: flex;
align-items: center;
//text-align: end;
line-height: 32px;
min-height: 32px;
&:last-child {
//border-bottom: none;
}
&.array-item {
border-bottom: none;
::v-deep .el-form-item__content {
border-bottom: 1px dashed #EBEEF5
}
::v-deep .el-form-item__label:last-child {
border: 1px dashed #EBEEF5;
}
}
.el-form-item__label {
//padding-right: 8%;
overflow: hidden;
color: var(--color-icon-primary);
font-size: 12px;
line-height: 1.5;
font-weight: 400;
width: 33%;
min-width: 120px;
padding: 5px 0;
span {
display: inline-block;
//line-height: 1.1;
}
}
.el-form-item__content {
color: var(--color-text-primary);
font-size: 13px;
line-height: 1.5;
width: calc(100% - 120px);
padding: 5px 0;
}
::v-deep .el-tag--mini {
margin-right: 3px;
}
}
.item-value {
::v-deep span {
//display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
vertical-align: middle;
}
}
}
</style>

View File

@@ -49,7 +49,7 @@
<script>
import { createSourceIdCache } from '@/api/common'
import { Select2 } from '@/components/Form/FormFields'
import IBox from '@/components/IBox/index.vue'
import IBox from '@/components/Common/IBox/index.vue'
import { mapGetters } from 'vuex'
export default {
@@ -340,13 +340,13 @@ b, strong {
}
tr td {
line-height: 1.42857;
padding: 8px;
line-height: 1.4;
padding: 8px 0;
vertical-align: top;
}
tr.item td {
border-top: 1px solid #e7eaec;
border-top: 1px dashed #EBEEF5;
}
.box-margin {

View File

@@ -1,18 +1,23 @@
<template>
<el-card shadow="never">
<div slot="header" class="summary-header">
<span class="header-title">{{ title }}</span>
<div>
<div class="summary-header">
<el-tooltip :content="title" :open-delay="500" placement="top">
<span class="title">{{ title }}</span>
</el-tooltip>
</div>
<slot>
<h1 class="no-margins">
<span v-if="body.disabled" class="disabled-link">{{ body.count }}</span>
<router-link v-else :to="body.route">
<span>{{ body.count }}</span>
</router-link>
</h1>
<small>{{ body.comment }}</small>
<h3 class="no-margins ">
<span
:class="{ 'can-direct': canDirect }"
class="num"
@click="handleClick"
>
<span v-if="count === null"> - </span>
<span v-else>{{ count }}</span>
</span>
</h3>
</slot>
</el-card>
</div>
</template>
<script>
@@ -23,56 +28,78 @@ export default {
type: String,
default: ''
},
rightSideLabel: {
type: Object,
default: () => ({})
count: {
type: [Number, String, Promise],
default: null
},
body: {
type: Object,
default: () => ({})
route: {
type: [String, Object],
default: ''
},
canDirect: {
type: Boolean,
default: false
},
callback: {
type: Function,
default: () => {
}
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {}
},
methods: {
handleClick() {
if (this.disabled) {
return
}
if (this.route) {
this.$router.push(this.route)
return
}
this.callback.bind(this)()
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
.pull-right {
float: right !important;
}
.summary-header {
//color: var(--color-icon-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
.header-title {
font-size: 14px;
margin: 0 0 7px;
.title {
font-style: normal;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
line-height: 1.2;
}
}
.right-side ::v-deep .el-tag {
font-weight: 600;
padding: 3px 8px;
text-shadow: none;
line-height: 1;
}
.no-margins {
margin: 0 !important;
h1 {
font-size: 30px;
font-weight: 100;
}
.num {
font-style: normal;
font-weight: 500;
font-size: 24px;
line-height: 40px;
color: var(--color-text-primary);
cursor: pointer;
.el-card__body {
background-color: #ffffff;
color: inherit;
padding: 15px 20px 20px 20px !important;
border-color: #e7eaec;
border-image: none;
border-style: solid solid none;
border-width: 1px 0;
}
.no-margins {
margin: 0 !important;
}
.disabled-link {
color: #428bca;
&.can-direct:hover {
color: var(--color-primary);
}
}
}
</style>

View File

@@ -3,7 +3,7 @@
</template>
<script>
import DataActions from '@/components/DataActions'
import DataActions from '@/components/Common/DataActions/index.vue'
export default {
name: 'ActionsGroup',

View File

@@ -5,41 +5,59 @@
v-if="action.dropdown"
v-show="action.dropdown.length > 0"
:key="action.name"
:class="[action.name, { grouped: action.grouped }]"
:size="action.size"
:split-button="!!action.split"
:type="action.type"
class="action-item"
placement="bottom-start"
trigger="click"
@click="handleClick(action)"
@command="handleDropdownCallback"
>
<el-button :size="size" class="more-action" v-bind="cleanButtonAction(action)">
<span v-if="action.icon && !action.icon.startsWith('el-')" class="pre-icon">
<i v-if="action.icon.startsWith('fa')" :class="'fa fa-fw ' + action.icon" />
<svg-icon v-else :icon-class="action.icon" />
<span v-if="action.split" :style="{ cursor: action.disabled ? 'not-allowed' : 'pointer' }">
{{ action.title }}
</span>
<el-button
v-else
:class="action.name"
:size="size"
class="more-action"
v-bind="{ ...cleanButtonAction(action), icon: '' }"
>
<span class="pre-icon">
<Icon v-if="action.icon" :icon="action.icon" />
</span>
<span v-if="action.title">
{{ action.title }}<i class="el-icon-arrow-down el-icon--right" />
</span>
</el-button>
<el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh">
<el-dropdown-menu slot="dropdown" style="overflow: auto; max-height: 60vh">
<template v-for="option in action.dropdown">
<div
v-if="option.group"
:key="'group:'+option.name"
:key="'group:' + option.name"
class="dropdown-menu-title"
style="width:130px"
style="width: 130px"
>
{{ option.group }}
</div>
<el-tooltip :key="option.name" :content="option.tip" :disabled="!option.tip" :open-delay="500" placement="top">
<el-tooltip
:key="option.name"
:content="option.tip"
:disabled="!option.tip"
:open-delay="500"
placement="top"
>
<el-dropdown-item
:key="option.name"
:command="[option, action]"
:title="option.tip"
class="dropdown-item"
v-bind="{...option, icon: ''}"
v-bind="{ ...option, icon: '' }"
>
<span v-if="option.icon" class="pre-icon">
<i v-if="option.icon.startsWith('fa')" :class="'fa fa-fw ' + option.icon" />
<svg-icon v-else :icon-class="option.icon" />
<span v-if="actionsHasIcon(action.dropdown)" class="pre-icon">
<Icon v-if="option.icon" :icon="option.icon" />
</span>
{{ option.title }}
</el-dropdown-item>
@@ -51,16 +69,16 @@
<el-button
v-else
:key="action.name"
:class="[action.name, { grouped: action.grouped }]"
:size="size"
class="action-item"
v-bind="{...cleanButtonAction(action), icon: action.icon && action.icon.startsWith('el-') ? action.icon : ''}"
v-bind="{ ...cleanButtonAction(action), icon: '' }"
@click="handleClick(action)"
>
<el-tooltip :content="action.tip" :disabled="!action.tip" :open-delay="500" placement="top">
<el-tooltip :content="action.tip" :disabled="!action.tip" placement="top">
<span>
<span v-if="action.icon && !action.icon.startsWith('el-')" style="vertical-align: initial">
<i v-if="action.icon.startsWith('fa')" :class="'fa ' + action.icon" />
<svg-icon v-else :icon-class="action.icon" />
<span v-if="action.icon" style="vertical-align: initial">
<Icon :icon="action.icon" />
</span>
{{ action.title }}
</span>
@@ -71,10 +89,14 @@
</template>
<script>
import { toSentenceCase } from '@/utils/common'
import { toSentenceCase } from '@/utils/common/index'
import Icon from '@/components/Widgets/Icon/index.vue'
export default {
name: 'DataActions',
components: {
Icon
},
props: {
grouped: {
type: Boolean,
@@ -99,6 +121,9 @@ export default {
}
},
methods: {
actionsHasIcon(actions) {
return actions.some(action => action.icon)
},
hasIcon(action, type = '') {
const icon = action.icon
if (!icon) {
@@ -156,6 +181,7 @@ export default {
delete action['callback']
delete action['name']
delete action['can']
delete action['split']
return action
},
cleanActions(actions) {
@@ -185,6 +211,10 @@ export default {
}
delete action['can']
if (!action.size) {
action.size = 'small'
}
if (action.dropdown) {
action.dropdown = this.cleanActions(action.dropdown)
}
@@ -198,9 +228,9 @@ export default {
<style lang="scss" scoped>
$btn-text-color: #ffffff;
$color-btn-background: #E8F7F4;
$color-btn-focus-background: #83CBBA;
$color-divided: #E4E7ED;
$color-btn-background: #e8f7f4;
$color-btn-focus-background: #83cbba;
$color-divided: #e4e7ed;
$color-drop-menu-title: #909399;
$color-drop-menu-border: #e4e7ed;
@@ -209,6 +239,10 @@ $color-drop-menu-border: #e4e7ed;
.action-item {
margin-left: 5px;
&.grouped {
margin-left: 0;
}
&:first-child {
margin-left: 0;
}
@@ -249,10 +283,17 @@ $color-drop-menu-border: #e4e7ed;
align-items: flex-end;
.el-button {
display: flex;
align-items: center;
padding: 2px 6px;
color: $btn-text-color;
padding: 2px 5px;
line-height: 1.3;
font-size: 13px;
&:not(.is-plain) {
color: $btn-text-color;
}
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
* {
vertical-align: baseline !important;
@@ -280,8 +321,6 @@ $color-drop-menu-border: #e4e7ed;
// options
.el-dropdown-menu {
::v-deep .more-batch-processing {
text-align: center;
&:hover {
background-color: transparent !important;
}
@@ -303,6 +342,7 @@ $color-drop-menu-border: #e4e7ed;
.dropdown-item {
color: var(--color-text-primary);
line-height: 34px;
.pre-icon {
width: 17px;
@@ -324,6 +364,8 @@ $color-drop-menu-border: #e4e7ed;
}
.el-dropdown-menu__item {
padding: 0 20px;
&.is-disabled {
color: var(--color-disabled);
cursor: not-allowed;

View File

@@ -2,7 +2,8 @@
<IBox v-bind="$attrs">
<div v-if="contentHeading" class="ibox-heading">
<slot name="content-heading">
<h3 v-if="contentHeading.title"><i v-if="contentHeading.fa" :class="'fa ' + contentHeading.fa" /> {{ contentHeading.title }}</h3>
<h3 v-if="contentHeading.title"><i v-if="contentHeading.fa" :class="'fa ' + contentHeading.fa" /> {{
contentHeading.title }}</h3>
<small v-if="contentHeading.content"><i class="fa fa-tim" /> {{ contentHeading.content }}</small>
</slot>
</div>
@@ -11,7 +12,8 @@
</template>
<script>
import IBox from './index'
import IBox from './index.vue'
export default {
name: 'HeadingIBox',
components: { IBox },
@@ -25,20 +27,22 @@ export default {
</script>
<style scoped>
.ibox-heading {
background-color: #f3f6fb;
border-bottom: none;
margin: -15px -20px 20px -20px;
padding: 20px
}
.ibox-heading h3 {
font-weight: 200;
font-size: 24px;
margin-top: 5px;
margin-bottom: 10px;
line-height: 1.1;
}
.ibox .el-card__body {
background-color: #f3f6fb;
}
.ibox-heading {
background-color: #f3f6fb;
border-bottom: none;
margin: -15px -20px 20px -20px;
padding: 20px
}
.ibox-heading h3 {
font-weight: 200;
font-size: 24px;
margin-top: 5px;
margin-bottom: 10px;
line-height: 1.1;
}
.ibox .el-card__body {
background-color: #f3f6fb;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<el-card :class="'ibox ' + type" shadow="never" v-bind="$attrs">
<el-card :class="'ibox ' + type" :shadow="shadow" v-bind="$attrs">
<template #header>
<slot name="header">
<div v-if="title" slot="header" class="clearfix ibox-title">
@@ -26,6 +26,10 @@ export default {
type: {
type: String,
default: 'default'
},
shadow: {
type: String,
default: 'never'
}
},
computed: {

View File

@@ -1,34 +1,32 @@
<template>
<tr>
<td>{{ getActionTitle(action) }}</td>
<td>
<el-popover
:content="action.attrs.tip"
:disabled="!action.attrs.showTip"
placement="left-end"
trigger="hover"
>
<span slot="reference">
<component
:is="iType"
v-model="action.attrs.model"
:title="label"
v-bind="action.attrs"
v-on="callbacks"
>
{{ label }}
</component>
</span>
</el-popover>
{{ getActionTitle(action) }}
<el-tooltip v-if="action.attrs.showTip" :content="action.attrs.tip" :open-delay="500" effect="dark">
<i class="fa fa-question-circle-o" />
</el-tooltip>
</td>
<td>
<span slot="reference">
<component
:is="iType"
v-model="action.attrs.model"
:title="label"
v-bind="action.attrs"
v-on="callbacks"
>
{{ label }}
</component>
</span>
</td>
</tr>
</template>
<script>
import Switcher from '@/components/Form/FormFields/Switcher'
import Select2 from '@/components/Form/FormFields/Select2'
import UpdateSelect from '@/components/Form/FormFields/UpdateSelect'
import { toSentenceCase } from '@/utils/common'
import Switcher from '@/components/Form/FormFields/Switcher.vue'
import Select2 from '@/components/Form/FormFields/Select2.vue'
import UpdateSelect from '@/components/Form/FormFields/UpdateSelect.vue'
import { toSentenceCase } from '@/utils/common/index'
class Action {
constructor() {

View File

@@ -9,8 +9,8 @@
</template>
<script>
import IBox from '@/components/IBox'
import ActionItem from './action'
import IBox from '@/components/Common/IBox/index.vue'
import ActionItem from './action.vue'
// views/users/users/UserDetail/UserInfo.vue 使
export default {
@@ -39,32 +39,32 @@ export default {
</script>
<style scoped>
.quick-actions ::v-deep table {
width: 100%;
}
.quick-actions ::v-deep table {
width: 100%;
}
.quick-actions ::v-deep tr > td {
line-height: 1.43;
padding: 8px;
vertical-align: top;
font-size: 13px;
width: 50%;
}
.quick-actions ::v-deep tr > td {
line-height: 1.43;
padding: 8px 0;
vertical-align: top;
font-size: 13px;
width: 50%;
}
.quick-actions ::v-deep tr > td > span:last-child {
float: right;
}
.quick-actions ::v-deep tr > td > span:last-child {
float: right;
}
.quick-actions ::v-deep button {
padding: 4px 5px;
font-size: 13px;
width: 65px;
.quick-actions ::v-deep button {
padding: 4px 5px;
font-size: 13px;
min-width: 65px;
span {
overflow: hidden;
white-space: nowrap; /* 控制文本不换行 */
text-overflow: ellipsis;
display: block;
}
span {
overflow: hidden;
white-space: nowrap; /* 控制文本不换行 */
text-overflow: ellipsis;
display: block;
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="content">
<echarts
<div>
<Echart
ref="echarts"
:options="options"
:autoresize="true"
@@ -12,9 +12,10 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: {},
components: { Echart },
props: {
datesMetrics: {
type: Array,

View File

@@ -0,0 +1,71 @@
<template>
<echarts
:options="iOptions"
v-bind="$attrs"
@finished="onFinished"
v-on="$listeners"
/>
</template>
<script>
import 'echarts'
export default {
components: {},
props: {
options: {
type: Object,
required: true
}
},
data() {
const urlParams = new URLSearchParams(window.location.search)
const isExport = urlParams.get('export') === 'true'
return {
isExport: isExport
}
},
computed: {
iOptions() {
return {
...this.options,
animation: !this.isExport
}
}
},
created() {
if (!window._echarts) {
window._echarts = {
total: new Set(),
finished: new Set()
}
}
// 唯一 id避免重复计数
this._chartId = `chart_${Date.now()}_${Math.random().toString(36).slice(2)}`
window._echarts.total.add(this._chartId)
},
beforeDestroy() {
if (window._echarts) {
window._echarts.total.delete(this._chartId)
window._echarts.finished.delete(this._chartId)
// 可选:当没有图表时清理全局对象
if (window._echarts.total.size === 0) {
delete window._echarts
delete window.echartsFinished
}
}
},
methods: {
onFinished() {
if (!window._echarts) return
window._echarts.finished.add(this._chartId)
if (window._echarts.finished.size === window._echarts.total.size) {
window.echartsFinished = true
}
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,14 +1,12 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:options="options"
:autoresize="true"
theme="light"
class="disabled-when-print"
@finished="getDataUrl"
@finished="genSnapshot"
/>
<img v-if="dataUrl" :src="dataUrl" class="enabled-when-print" style="display: none;width: 100%;">
</div>
</template>
@@ -16,9 +14,11 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
name: 'LoginMetric',
components: { Echart },
props: {
range: {
type: String,
@@ -110,7 +110,6 @@ export default {
},
axisLabel: {
textStyle: {
//
color: '#8F959E'
}
},
@@ -155,7 +154,7 @@ export default {
type: 'line',
smooth: true,
areaStyle: {
//
//
normal: {
color: new echarts.graphic.LinearGradient(
0,
@@ -187,7 +186,7 @@ export default {
type: 'line',
smooth: true,
areaStyle: {
//
//
normal: {
color: new echarts.graphic.LinearGradient(
0,
@@ -220,23 +219,58 @@ export default {
},
watch: {
range() {
this.getMetricData()
this.genSnapshot()
},
datesMetrics() {
this.genSnapshot()
},
primaryData() {
this.genSnapshot()
},
secondaryData() {
this.genSnapshot()
}
},
mounted() {
this.getMetricData()
this.genSnapshot()
this._before = () => this.genSnapshot(true)
this._after = () => this.forceResize()
window.addEventListener('beforeprint', this._before)
window.addEventListener('afterprint', this._after)
// Safari print
this._mql = window.matchMedia && window.matchMedia('print')
if (this._mql) {
const handler = e => (e.matches ? this._before() : this._after())
this._mql.addEventListener?.('change', handler)
this._mql.addListener?.(handler)
this._mql._handler = handler
}
},
beforeDestroy() {
window.removeEventListener('beforeprint', this._before)
window.removeEventListener('afterprint', this._after)
if (this._mql) {
this._mql.removeEventListener?.('change', this._mql._handler)
this._mql.removeListener?.(this._mql._handler)
}
},
methods: {
getDataUrl() {
const instance = this.$refs.echarts.echartsInstance
if (instance) {
this.dataUrl = instance.getDataURL()
}
forceResize() {
const inst = this.$refs.echarts?.echartsInstance
if (inst) inst.resize()
},
getMetricData() {
this.getDataUrl()
async genSnapshot(force = false) {
if (force) this.forceResize()
const inst = this.$refs.echarts?.echartsInstance
if (!inst) return
try {
this.dataUrl = inst.getDataURL({ pixelRatio: 2, backgroundColor: '#ffffff' })
} catch (e) {
this.dataUrl = ''
}
}
}
}
</script>
@@ -245,16 +279,4 @@ export default {
width: 100%;
height: 272px;
}
@media print {
.disabled-when-print {
display: none;
}
.enabled-when-print {
display: inherit !important;
}
.print-margin {
margin-top: 10px;
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:options="options"
:autoresize="true"
@@ -13,8 +13,10 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: { Echart },
props: {
colors: {
type: Array,
@@ -35,14 +37,15 @@ export default {
}
},
data() {
return {
}
return {}
},
computed: {
options() {
const seriesList = []
const labels = this.data.map(item => item.label)
const total = _.sumBy(this.data, function(i) { return i.total })
const total = _.sumBy(this.data, function(i) {
return i.total
})
for (let i = 0, len = this.data.length; i < len; i++) {
const current = this.data[i]
let num = (current.total / total) * 100
@@ -128,7 +131,8 @@ export default {
tip += current.label + '' + current.total + '<br/>'
}
return tip
}
},
appendToBody: true
},
grid: {
top: '60%',
@@ -176,8 +180,8 @@ export default {
</script>
<style lang="scss" scoped>
.echarts {
width: 100%;
height: 72px;
}
.echarts {
width: 100%;
height: 72px;
}
</style>

View File

@@ -9,18 +9,29 @@
class="table"
style="width: 100%"
>
<el-table-column :label="$tc('Ranking')" width="80px">
<template v-slot="scope">
<span>{{ scope.$index + 1 }}</span>
<el-table-column :label="$tc('Ranking')" width="100">
<template #header>
<el-tooltip :content="$t('Ranking')" placement="top" :open-delay="500">
<span style="cursor: pointer;">{{ $t('Ranking') }}</span>
</el-tooltip>
</template>
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column
v-for="i in config.columns"
:key="i.prop"
:label="i.label"
:prop="i.prop"
:width="i.width"
/>
:width="getColumnWidth(i)"
>
<template #header>
<el-tooltip :content="i.label" placement="top" :open-delay="500">
<span style="cursor: pointer;">{{ i.label }}</span>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</template>
@@ -56,6 +67,19 @@ export default {
this.getList()
},
methods: {
getColumnWidth(column) {
if (column.prop === 'total') {
const locale = this.$i18n.locale
switch (locale) {
case 'en':
return '120px'
case 'pt-br':
return '220px'
default:
return '100px'
}
}
},
getList() {
this.$axios.get(this.tableUrl).then(res => {
this.tableData = this.config.data ? res?.[this.config.data] : res

View File

@@ -6,7 +6,7 @@
<div class="content">
<el-row justify="space-between" type="flex">
<el-col v-for="item of summaryItems" :key="item.title" :md="8" :sm="12" :xs="12">
<SummaryCard :body="item.body" :title="item.title" />
<SummaryCard :title="item.title" v-bind="item.body" />
</el-col>
</el-row>
</div>
@@ -15,7 +15,7 @@
<script>
import Title from './Title.vue'
import SummaryCard from './SummaryCard'
import SummaryCard from '@/components/Cards/SummaryCard'
export default {
components: { Title, SummaryCard },
@@ -38,7 +38,7 @@ export default {
{
title: this.$t('OnlineSessions'),
body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' } },
count: this.counter.total_count_online_sessions,
disabled: !this.$hasPerm('terminal.view_session')
}
@@ -46,7 +46,7 @@ export default {
{
title: this.$t('CurrentConnectionUsers'),
body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' } },
count: this.counter.total_count_online_users,
disabled: !this.$hasPerm('terminal.view_session')
}
@@ -85,15 +85,18 @@ export default {
.box {
padding: 20px;
background: #FFFFFF;
.content {
.el-col {
padding-left: 16px;
border-left: 1px solid #EFF0F1;
&:first-child {
padding-left: 0;
border-left: none;
}
}
.sub {
font-style: normal;
font-weight: 400;
@@ -101,6 +104,7 @@ export default {
line-height: 20px;
color: #646A73;
}
.num {
font-style: normal;
font-weight: 500;

View File

@@ -1,6 +1,6 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:autoresize="true"
:options="options"
@@ -13,34 +13,55 @@ import 'echarts/lib/chart/line'
import 'echarts/lib/component/legend'
import Decimal from 'decimal.js'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: { Echart },
props: {
config: {
type: Object,
default: () => {}
default: () => {
}
}
},
computed: {
options() {
const { total = 0, active = 0, title, color } = this.config
const { total = 0, active = 0, title, color, colors } = this.config
const activeDecimal = new Decimal(active)
const totalDecimal = new Decimal(total)
let percentage = activeDecimal.dividedBy(totalDecimal).times(100)
percentage = isNaN(percentage) ? 0 : percentage
percentage = percentage.toFixed(2)
const formatTitle = (text) => {
if (!text) return ''
const maxLength = 25
const lines = []
for (let i = 0; i < text.length; i += maxLength) {
lines.push(text.slice(i, i + maxLength))
}
return lines.join('\n')
}
return {
title: [
{
text: this.config.chartTitle,
text: formatTitle(this.config.chartTitle),
textStyle: {
color: '#646A73',
fontSize: 12
fontSize: 12,
lineHeight: 16,
rich: {
width: 100,
overflow: 'break'
}
},
textAlign: 'center',
left: '48%',
top: '32%'
top: '32%',
width: 100,
overflow: 'break'
},
{
left: '48%',
@@ -61,7 +82,7 @@ export default {
legend: {
show: false
},
color: [color, 'rgba(43, 147, 124, 0.05)'],
color: colors || [color, 'rgba(43, 147, 124, 0.05)'],
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {d}%'
@@ -70,6 +91,7 @@ export default {
{
name: title,
type: 'pie',
minAngle: 5,
radius: ['72%', '90%'],
avoidLabelOverlap: false,
itemStyle: {

View File

@@ -4,18 +4,20 @@
<Title :config="config" />
</div>
<div class="content">
<el-row type="flex" justify="space-between">
<el-col v-for="item of items" :key="item.title" :md="8" :sm="12" :xs="12">
<SummaryCard :title="item.title" :body="item.body" />
</el-col>
</el-row>
<SummaryCard
v-for="item of items"
:key="item.title"
:title="item.title"
class="summary-card"
v-bind="item.body"
/>
</div>
</div>
</template>
<script>
import Title from '../components/Title.vue'
import SummaryCard from '../components/SummaryCard'
import Title from './Title.vue'
import SummaryCard from '@/components/Cards/SummaryCard'
export default {
components: { Title, SummaryCard },
@@ -35,8 +37,7 @@ export default {
}
},
data() {
return {
}
return {}
}
}
</script>
@@ -45,28 +46,21 @@ export default {
.box {
padding: 20px;
background: #FFFFFF;
.content {
.el-col {
display: flex;
justify-content: space-between;
padding: 0 10px;
.summary-card {
padding-left: 16px;
border-left: 1px solid #EFF0F1;
&:first-child {
padding-left: 0;
border-left: none;
}
}
.sub {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 20px;
color: #646A73;
}
.num {
font-style: normal;
font-weight: 500;
font-size: 24px;
cursor: pointer;
}
}
}
</style>

View File

@@ -16,11 +16,13 @@
<script>
export default {
props: {
days: {
name: {
type: String,
default: () => {
return localStorage.getItem('dashboardDays') || '7'
}
default: 'dashboardDays'
},
days: {
type: [String, Number],
default: null
},
options: {
type: Array,
@@ -47,8 +49,28 @@ export default {
iOptions: this.options.length > 0 ? this.options : defaultOptions
}
},
created() {
let days = this.days
if (!days) {
days = this.$route.query.days
}
if (!days) {
days = localStorage.getItem(this.name)
}
if (!days) {
days = '7'
}
if (days && days !== this.select) {
this.select = days
this.$emit('change', days)
}
},
mounted() {
this.$emit('change', this.select)
},
methods: {
onChange(val) {
localStorage.setItem(this.name, val)
this.$emit('change', val)
}
}

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