From f03367ecf3b1510f47a035edae40a3fd59a5a626 Mon Sep 17 00:00:00 2001 From: "nathan.liu" Date: Wed, 11 May 2022 10:13:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(UI=E8=87=AA=E5=8A=A8=E5=8C=96):=20?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E6=94=AF=E6=8C=81=E6=9C=AC=E5=9C=B0=E6=B5=8F?= =?UTF-8?q?=E8=A7=88=E5=99=A8=E8=BF=90=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/definition/RunDefinitionRequest.java | 2 + .../definition/request/ParameterConfig.java | 3 + .../java/io/metersphere/base/domain/User.java | 2 + .../io/metersphere/base/mapper/UserMapper.xml | 6 +- .../controller/UserController.java | 19 ++- .../member/EditSeleniumServerRequest.java | 10 ++ .../io/metersphere/dto/ProjectConfig.java | 1 + .../io/metersphere/service/UserService.java | 71 +++++++++- backend/src/main/java/io/metersphere/xpack | 2 +- .../V116_add_user_selenium_server.sql | 2 + backend/src/main/resources/permission.json | 6 + frontend/package.json | 2 + .../api/automation/scenario/DebugRun.vue | 2 + .../components/common/head/HeaderUser.vue | 6 + .../project/menu/appmanage/AppManage.vue | 26 ++++ .../settings/components/PersonRouter.vue | 21 ++- .../settings/personal/UiSetting.vue | 124 ++++++++++++++++++ frontend/src/business/components/xpack | 2 +- frontend/src/i18n/en-US.js | 6 + frontend/src/i18n/zh-CN.js | 8 +- frontend/src/i18n/zh-TW.js | 6 + 21 files changed, 310 insertions(+), 17 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/controller/request/member/EditSeleniumServerRequest.java create mode 100644 backend/src/main/resources/db/migration/V116_add_user_selenium_server.sql create mode 100644 frontend/src/business/components/settings/personal/UiSetting.vue diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/RunDefinitionRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/RunDefinitionRequest.java index 418aab4b77..30497c9c95 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/RunDefinitionRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/RunDefinitionRequest.java @@ -20,6 +20,8 @@ public class RunDefinitionRequest { private boolean saved; + private boolean runLocal; + private String requestId; private String name; diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java index 5cfc75fd74..370989c471 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java @@ -80,6 +80,9 @@ public class ParameterConfig extends MsParameter { private String scenarioId; private String reportType; + + private boolean runLocal; + /** * 排除生成临界控制器的场景 */ diff --git a/backend/src/main/java/io/metersphere/base/domain/User.java b/backend/src/main/java/io/metersphere/base/domain/User.java index a94d3fcd74..4886011ff7 100644 --- a/backend/src/main/java/io/metersphere/base/domain/User.java +++ b/backend/src/main/java/io/metersphere/base/domain/User.java @@ -33,5 +33,7 @@ public class User implements Serializable { private String platformInfo; + private String seleniumServer; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/UserMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/UserMapper.xml index 77f36664f7..537651ffb2 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/UserMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/UserMapper.xml @@ -13,6 +13,7 @@ + @@ -79,7 +80,7 @@ id, `name`, email, `password`, `status`, create_time, update_time, `language`, last_workspace_id, - phone, `source`, last_project_id, create_user + phone, `source`, selenium_server, last_project_id, create_user platform_info @@ -372,6 +373,9 @@ platform_info = #{platformInfo,jdbcType=LONGVARCHAR}, + + `selenium_server` = #{seleniumServer,jdbcType=VARCHAR}, + where id = #{id,jdbcType=VARCHAR} diff --git a/backend/src/main/java/io/metersphere/controller/UserController.java b/backend/src/main/java/io/metersphere/controller/UserController.java index f0b5f355ef..a405f551cb 100644 --- a/backend/src/main/java/io/metersphere/controller/UserController.java +++ b/backend/src/main/java/io/metersphere/controller/UserController.java @@ -9,10 +9,7 @@ import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; -import io.metersphere.controller.request.member.AddMemberRequest; -import io.metersphere.controller.request.member.EditPassWordRequest; -import io.metersphere.controller.request.member.QueryMemberRequest; -import io.metersphere.controller.request.member.UserRequest; +import io.metersphere.controller.request.member.*; import io.metersphere.controller.request.resourcepool.UserBatchProcessRequest; import io.metersphere.dto.UserDTO; import io.metersphere.dto.UserGroupPermissionDTO; @@ -269,4 +266,18 @@ public class UserController { public Map getWSAndProjectByUserId(@PathVariable String userId) { return userService.getWSAndProjectByUserId(userId); } + + /** + * 配置 用户的selenium-server 地址 ip:port + */ + @PostMapping("/update/seleniumServer") + @MsAuditLog(module = OperLogModule.SYSTEM_USER, type = OperLogConstants.UPDATE, title = "selenium-server地址") + public int updateSeleniumServer(@RequestBody EditSeleniumServerRequest request) { + return userService.updateUserSeleniumServer(request); + } + + @GetMapping("/verify/seleniumServer") + public String verifySeleniumServer() { + return userService.verifyUserSeleniumServer(); + } } diff --git a/backend/src/main/java/io/metersphere/controller/request/member/EditSeleniumServerRequest.java b/backend/src/main/java/io/metersphere/controller/request/member/EditSeleniumServerRequest.java new file mode 100644 index 0000000000..2509020312 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/request/member/EditSeleniumServerRequest.java @@ -0,0 +1,10 @@ +package io.metersphere.controller.request.member; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class EditSeleniumServerRequest { + private String seleniumServer; +} diff --git a/backend/src/main/java/io/metersphere/dto/ProjectConfig.java b/backend/src/main/java/io/metersphere/dto/ProjectConfig.java index 825274b8f0..9c8377f422 100644 --- a/backend/src/main/java/io/metersphere/dto/ProjectConfig.java +++ b/backend/src/main/java/io/metersphere/dto/ProjectConfig.java @@ -15,6 +15,7 @@ public class ProjectConfig { private Boolean caseCustomNum = false; private Boolean scenarioCustomNum = false; private String apiQuickMenu; + private String uiQuickMenu; private Boolean casePublic = false; private Integer mockTcpPort = 0; private Boolean mockTcpOpen = false; diff --git a/backend/src/main/java/io/metersphere/service/UserService.java b/backend/src/main/java/io/metersphere/service/UserService.java index cb8063a12f..1046cb86ce 100644 --- a/backend/src/main/java/io/metersphere/service/UserService.java +++ b/backend/src/main/java/io/metersphere/service/UserService.java @@ -19,10 +19,7 @@ import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.ResultHolder; import io.metersphere.controller.request.LoginRequest; import io.metersphere.controller.request.WorkspaceRequest; -import io.metersphere.controller.request.member.AddMemberRequest; -import io.metersphere.controller.request.member.EditPassWordRequest; -import io.metersphere.controller.request.member.QueryMemberRequest; -import io.metersphere.controller.request.member.UserRequest; +import io.metersphere.controller.request.member.*; import io.metersphere.controller.request.resourcepool.UserBatchProcessRequest; import io.metersphere.dto.GroupResourceDTO; import io.metersphere.dto.UserDTO; @@ -39,6 +36,7 @@ import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.system.SystemReference; import io.metersphere.notice.domain.UserDetail; import io.metersphere.security.MsUserToken; +import okhttp3.*; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; @@ -59,6 +57,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static io.metersphere.commons.constants.SessionConstants.ATTR_USER; @@ -102,7 +101,7 @@ public class UserService { } public Map queryNameByIds(List userIds) { - if(userIds.isEmpty()){ + if (userIds.isEmpty()) { return new HashMap<>(0); } return extUserMapper.queryNameByIds(userIds); @@ -171,7 +170,7 @@ public class UserService { private void checkQuota(QuotaService quotaService, String type, List sourceIds, int size) { if (quotaService != null) { - Map addMemberMap = sourceIds.stream().collect(Collectors.toMap( id -> id, id -> size)); + Map addMemberMap = sourceIds.stream().collect(Collectors.toMap(id -> id, id -> size)); quotaService.checkMemberCount(addMemberMap, type); } } @@ -1346,4 +1345,64 @@ public class UserService { return false; } + + public int updateUserSeleniumServer(EditSeleniumServerRequest request) { + UserExample userExample = new UserExample(); + userExample.createCriteria().andIdEqualTo(SessionUtils.getUser().getId()); + List users = userMapper.selectByExample(userExample); + if (!CollectionUtils.isEmpty(users)) { + User user = users.get(0); + String seleniumServer = request.getSeleniumServer(); + user.setSeleniumServer(StringUtils.isBlank(seleniumServer) ? "" : seleniumServer.trim()); + user.setUpdateTime(System.currentTimeMillis()); + //更新session seleniumServer 信息 + SessionUser sessionUser = SessionUtils.getUser(); + sessionUser.setSeleniumServer(seleniumServer); + SessionUtils.putUser(sessionUser); + return userMapper.updateByPrimaryKeySelective(user); + } + MSException.throwException("更新selenium-server地址失败!"); + return 0; + } + + public String verifyUserSeleniumServer() { + UserExample userExample = new UserExample(); + userExample.createCriteria().andIdEqualTo(SessionUtils.getUser().getId()); + List users = userMapper.selectByExample(userExample); + if (!CollectionUtils.isEmpty(users)) { + User user = users.get(0); + if (StringUtils.isBlank(user.getSeleniumServer())) { + return "configErr"; + } + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(5, TimeUnit.SECONDS) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, + "{\"operationName\":\"\",\"variables\":{},\"query\":\"query Summary {\\n grid {\\n uri\\n totalSlots\\n nodeCount\\n maxSession\\n sessionCount\\n sessionQueueSize\\n version\\n __typename\\n }\\n}\"}"); + Request req = new Request.Builder() + .url(user.getSeleniumServer() + "/graphql") + .method("POST", body) + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + try { + response = client.newCall(req).execute(); + if (!response.isSuccessful()) { + return "connectionErr"; + } + } catch (Exception e) { + return "connectionErr"; + } finally { + try { + if (response != null) { + response.close(); + } + } catch (Exception e) { + + } + } + } + return "ok"; + } } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 04012284cd..bdab35b7a7 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 04012284cd9cd16dd6270f01e71ec4714d67babf +Subproject commit bdab35b7a74d9a77ca74aa0e41e813d28067afaf diff --git a/backend/src/main/resources/db/migration/V116_add_user_selenium_server.sql b/backend/src/main/resources/db/migration/V116_add_user_selenium_server.sql new file mode 100644 index 0000000000..17693a916b --- /dev/null +++ b/backend/src/main/resources/db/migration/V116_add_user_selenium_server.sql @@ -0,0 +1,2 @@ +alter table user + add selenium_server varchar(255) default ""; \ No newline at end of file diff --git a/backend/src/main/resources/permission.json b/backend/src/main/resources/permission.json index 8fd020115d..1052ac42d3 100644 --- a/backend/src/main/resources/permission.json +++ b/backend/src/main/resources/permission.json @@ -1083,6 +1083,12 @@ "id": "PERSONAL_INFORMATION:READ+THIRD_ACCOUNT", "name": "permission.personal_information.third_account", "resourceId": "PERSONAL_INFORMATION" + }, + { + "id": "PERSONAL_INFORMATION:READ+UI_SETTING", + "name": "permission.personal_information.ui_setting", + "resourceId": "PERSONAL_INFORMATION", + "license": true } ], "resource": [ diff --git a/frontend/package.json b/frontend/package.json index f10fb056a3..90d4833a2a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -74,6 +74,8 @@ "eslint-plugin-vue": "^5.0.0", "file-writer": "^1.0.2", "html-webpack-inline-source-plugin": "0.0.10", + "less": "^3.9.0", + "less-loader": "^7.3.0", "vue-template-compiler": "2.6.14" }, "eslintConfig": { diff --git a/frontend/src/business/components/api/automation/scenario/DebugRun.vue b/frontend/src/business/components/api/automation/scenario/DebugRun.vue index b0c72b87cc..afa343cffe 100644 --- a/frontend/src/business/components/api/automation/scenario/DebugRun.vue +++ b/frontend/src/business/components/api/automation/scenario/DebugRun.vue @@ -17,6 +17,7 @@ export default { debug: Boolean, reportId: String, runData: Object, + runLocal: Boolean, saved: Boolean, environmentType: String, environmentGroupId: String @@ -78,6 +79,7 @@ export default { if (this.runData.variables) { reqObj.variables = this.runData.variables; } + reqObj.runLocal = this.runLocal; this.$emit('runRefresh', {}); let url = '/api/automation/run/debug'; diff --git a/frontend/src/business/components/common/head/HeaderUser.vue b/frontend/src/business/components/common/head/HeaderUser.vue index 46e1d19db0..eea6002131 100644 --- a/frontend/src/business/components/common/head/HeaderUser.vue +++ b/frontend/src/business/components/common/head/HeaderUser.vue @@ -46,6 +46,12 @@ export default { return getCurrentUser(); }, }, + mounted() { + this.$EventBus.$on('showPersonInfo', this.handleCommand) + }, + beforeDestroy(){ + this.$EventBus.$off("showPersonInfo") + }, methods: { logout: function () { logout(); diff --git a/frontend/src/business/components/project/menu/appmanage/AppManage.vue b/frontend/src/business/components/project/menu/appmanage/AppManage.vue index f2ec92a1c3..782961c7b6 100644 --- a/frontend/src/business/components/project/menu/appmanage/AppManage.vue +++ b/frontend/src/business/components/project/menu/appmanage/AppManage.vue @@ -39,6 +39,28 @@ + + + + {{ $t('commons.view_settings') }} + + + + + + + + @@ -178,6 +200,7 @@ export default { caseCustomNum: false, scenarioCustomNum: false, apiQuickMenu: "", + uiQuickMenu: "server", casePublic: false, mockTcpPort: 0, mockTcpOpen: false, @@ -224,6 +247,9 @@ export default { if (res.data) { this.config = res.data; this.config.shareReport = true; + if(!this.config.uiQuickMenu){ + this.config.uiQuickMenu = "server"; + } } }); } diff --git a/frontend/src/business/components/settings/components/PersonRouter.vue b/frontend/src/business/components/settings/components/PersonRouter.vue index a36c135fee..3207f6a922 100644 --- a/frontend/src/business/components/settings/components/PersonRouter.vue +++ b/frontend/src/business/components/settings/components/PersonRouter.vue @@ -5,11 +5,13 @@ + + @@ -32,7 +34,8 @@ import MsApiKeys from "@/business/components/settings/personal/ApiKeys"; import MsMainContainer from "@/business/components/common/components/MsMainContainer"; import PasswordInfo from "@/business/components/settings/personal/PasswordInfo"; - import {getCurrentUser, getCurrentWorkspaceId, hasPermission} from "@/common/js/utils"; + import UiSetting from "@/business/components/settings/personal/UiSetting"; + import {getCurrentUser, getCurrentWorkspaceId, hasPermission, hasLicense} from "@/common/js/utils"; import ZentaoUserInfo from "@/business/components/settings/personal/ZentaoUserInfo"; import TapdUserInfo from "@/business/components/settings/personal/TapdUserInfo"; import JiraUserInfo from "@/business/components/settings/personal/JiraUserInfo"; @@ -42,7 +45,7 @@ export default { name: "MsPersonRouter", - components: {MsMainContainer,MsPersonFromSetting,MsApiKeys,PasswordInfo,ZentaoUserInfo, TapdUserInfo, JiraUserInfo, AzureDevopsUserInfo}, + components: {MsMainContainer,MsPersonFromSetting,MsApiKeys,PasswordInfo,ZentaoUserInfo, TapdUserInfo, JiraUserInfo, AzureDevopsUserInfo, UiSetting}, inject: [ 'reload', ], @@ -69,6 +72,7 @@ hasTapd: false, hasZentao: false, hasAzure: false, + isXpack: false, updatePath: '/user/update/current', form: {platformInfo: {}}, currentPlatformInfo: { @@ -84,6 +88,17 @@ projectList:[] } }, + mounted() { + this.$EventBus.$on('siwtchActive', (item) => { + if(item){ + this.activeIndex = item + } + }) + this.isXpack = hasLicense(); + }, + beforeDestroy(){ + this.$EventBus.$off("siwtchActive") + }, methods:{ hasPermission, currentUser: () => { @@ -201,7 +216,7 @@ this.activeIndex = 'third_account'; return; } - } + }, }, created() { this.getActiveIndex(); diff --git a/frontend/src/business/components/settings/personal/UiSetting.vue b/frontend/src/business/components/settings/personal/UiSetting.vue new file mode 100644 index 0000000000..e3ba46a461 --- /dev/null +++ b/frontend/src/business/components/settings/personal/UiSetting.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index e30c5a16d5..4bfd301399 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit e30c5a16d53a4cc551066b22598e43b2f5d3a6ce +Subproject commit 4bfd301399124b83199c4a767f8c7f42a5f6b20a diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index b994f3dcf3..583cf3d5c2 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -109,6 +109,7 @@ export default { personal_setting: 'Personal Setting', api_keys: 'API Keys', third_account: 'Third Account', + ui_setting: 'UI Setting', quota: 'Quota', test_resource_pool: 'Resource Pool', system_setting: 'Settings', @@ -118,6 +119,7 @@ export default { follow_api: 'Follow API definition', response_time_delay: 'Response delay time', my_workstation: 'MyWorkstation', + ui_test: 'UiTest', performance: 'Performance', enable_settings: 'Enable Settings', view_settings: 'View Settings', @@ -3124,6 +3126,7 @@ export default { api_keys: 'API Keys', edit_password: "EDIT PASSWORD", third_account: 'Third Account', + ui_setting: 'UI Setting', }, other: { track: "Track", @@ -3162,5 +3165,8 @@ export default { ui_automation: "UI Automation", ui_element: "UI Element Library", report: "Test Report", + ui_debug_mode: 'UI debugging mode', + ui_local_debug: 'local', + ui_server_debug: 'server', } }; diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 70c53532da..353d2c7efa 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -102,6 +102,7 @@ export default { personal_info: '个人信息', api_keys: 'API Keys', third_account: '第三方平台账号', + ui_setting: 'UI设置', quota: '配额管理', status: '状态', show_all: '显示全部', @@ -123,6 +124,7 @@ export default { view_settings: '显示设置', functional: '功能测试', my_workstation: '我的工作台', + ui_test: 'UI测试', input_content: '请输入内容', create: '新建', edit: '编辑', @@ -3129,6 +3131,7 @@ export default { api_keys: 'API Keys', edit_password: "修改密码", third_account: '第三方平台账号', + ui_setting: 'UI设置', }, other: { track: "测试跟踪", @@ -3214,6 +3217,9 @@ export default { cmdExtraction: "数据提取", cmdExtractWindow: "提取窗口信息", cmdExtractElement: "提取元素信息", - valiate_fail: "校验失败,请检查必填项" + valiate_fail: "校验失败,请检查必填项", + ui_debug_mode: 'UI自动化调试方式', + ui_local_debug: '本地调试', + ui_server_debug: '后端调试', } }; diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 0d5340746c..ff9913cdd4 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -102,6 +102,7 @@ export default { personal_info: '個人信息', api_keys: 'API Keys', third_account: '第三方平臺賬號', + ui_setting: 'UI 設置', quota: '配額管理', status: '狀態', show_all: '顯示全部', @@ -123,6 +124,7 @@ export default { view_settings: '顯示設置', functional: '功能測試', my_workstation: '我的工作臺', + ui_test: 'UI測試', input_content: '請輸入內容', create: '新建', edit: '編輯', @@ -3128,6 +3130,7 @@ export default { api_keys: 'API Keys', edit_password: "修改密碼", third_account: '第三方平臺賬號', + ui_setting: 'UI 設置', }, other: { track: "測試跟蹤", @@ -3166,5 +3169,8 @@ export default { ui_automation: "UI 自動化", ui_element: "元素庫", report: "測試報告", + ui_debug_mode: 'UI自動化調試管道', + ui_local_debug: '本地調試', + ui_server_debug: '後端調試', } };