From 6477fd2277229df41370d15d51ebe5a5fb4fda06 Mon Sep 17 00:00:00 2001 From: zhu-mingye <934230207@qq.com> Date: Wed, 6 Sep 2023 14:09:13 +0800 Subject: [PATCH] [Feature]support-token-manager (#2292) * support-token-manager * support-token-manager * fix some bug * add i18n --- .../dinky/controller/SysConfigController.java | 14 ++ .../dinky/controller/TenantController.java | 6 + .../org/dinky/controller/TokenController.java | 113 +++++++++++ .../java/org/dinky/data/model/SysToken.java | 86 ++++++++ .../java/org/dinky/mapper/TokenMapper.java | 29 +++ .../java/org/dinky/service/TenantService.java | 9 + .../java/org/dinky/service/TokenService.java | 42 ++++ .../dinky/service/impl/TenantServiceImpl.java | 17 ++ .../dinky/service/impl/TokenServiceImpl.java | 56 ++++++ dinky-admin/src/main/resources/db/db-h2.sql | 29 +-- .../src/main/resources/mapper/TokenMapper.xml | 44 ++++ dinky-web/config/routes.ts | 6 + dinky-web/package.json | 5 +- dinky-web/src/locales/en-US/menu.ts | 1 + dinky-web/src/locales/en-US/pages.ts | 23 +++ dinky-web/src/locales/zh-CN/menu.ts | 1 + dinky-web/src/locales/zh-CN/pages.ts | 24 +++ .../Menu/components/MenuList/index.tsx | 1 + .../Token/component/TokenList/index.tsx | 188 ++++++++++++++++++ .../TokenModalForm/TokenForm/index.tsx | 142 +++++++++++++ .../Token/component/TokenModalForm/index.tsx | 177 +++++++++++++++++ .../AuthCenter/Token/component/constants.ts | 38 ++++ .../AuthCenter/Token/component/function.ts | 57 ++++++ .../pages/AuthCenter/Token/component/model.ts | 123 ++++++++++++ .../AuthCenter/Token/component/service.ts | 39 ++++ .../src/pages/AuthCenter/Token/index.tsx | 34 ++++ .../DataStudio/HeaderContainer/index.tsx | 50 +++-- .../LeftContainer/Project/function.tsx | 2 +- .../RightContainer/JobConfig/index.tsx | 2 +- dinky-web/src/pages/DataStudio/function.ts | 6 + .../RegCenter/Alert/AlertGroup/index.tsx | 6 +- .../RegCenter/Alert/AlertInstance/index.tsx | 6 +- .../components/ConfigurationList/index.tsx | 8 +- .../components/DataSourceList/index.tsx | 8 +- .../SettingOverView/constants.ts | 3 +- .../SettingCenter/GlobalSetting/model.ts | 69 +++++++ .../SettingCenter/GlobalSetting/service.ts | 25 +++ dinky-web/src/services/BusinessCrud.ts | 4 +- dinky-web/src/services/constants.tsx | 3 + dinky-web/src/services/endpoints.tsx | 12 ++ dinky-web/src/types/AuthCenter/data.d.ts | 17 ++ dinky-web/src/types/AuthCenter/init.d.ts | 8 + dinky-web/src/types/AuthCenter/state.d.ts | 6 +- dinky-web/src/utils/function.tsx | 17 +- script/sql/dinky-mysql.sql | 51 +++-- script/sql/dinky-pg.sql | 66 ++++-- .../1.0.0-SNAPSHOT_schema/mysql/dinky_ddl.sql | 22 +- .../1.0.0-SNAPSHOT_schema/mysql/dinky_dml.sql | 30 +-- 48 files changed, 1636 insertions(+), 89 deletions(-) create mode 100644 dinky-admin/src/main/java/org/dinky/controller/TokenController.java create mode 100644 dinky-admin/src/main/java/org/dinky/data/model/SysToken.java create mode 100644 dinky-admin/src/main/java/org/dinky/mapper/TokenMapper.java create mode 100644 dinky-admin/src/main/java/org/dinky/service/TokenService.java create mode 100644 dinky-admin/src/main/java/org/dinky/service/impl/TokenServiceImpl.java create mode 100644 dinky-admin/src/main/resources/mapper/TokenMapper.xml create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/TokenList/index.tsx create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/TokenForm/index.tsx create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/index.tsx create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/constants.ts create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/function.ts create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/model.ts create mode 100644 dinky-web/src/pages/AuthCenter/Token/component/service.ts create mode 100644 dinky-web/src/pages/AuthCenter/Token/index.tsx create mode 100644 dinky-web/src/pages/SettingCenter/GlobalSetting/model.ts create mode 100644 dinky-web/src/pages/SettingCenter/GlobalSetting/service.ts diff --git a/dinky-admin/src/main/java/org/dinky/controller/SysConfigController.java b/dinky-admin/src/main/java/org/dinky/controller/SysConfigController.java index 49e53fbe1f..3886c80606 100644 --- a/dinky-admin/src/main/java/org/dinky/controller/SysConfigController.java +++ b/dinky-admin/src/main/java/org/dinky/controller/SysConfigController.java @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.hutool.core.lang.Dict; @@ -84,4 +85,17 @@ public Result>>> getAll() { MapUtil.map(all, (k, v) -> v.stream().map(Configuration::show).collect(Collectors.toList())); return Result.succeed(map); } + + @GetMapping("/getConfigByType") + @ApiOperation("Query One Type System Config List By Key") + public Result>> getOneTypeByKey(@RequestParam("type") String type) { + Map>> all = sysConfigService.getAll(); + // 过滤出 以 type 开头的配置 返回 list + List> configList = all.entrySet().stream() + .filter(entry -> entry.getKey().startsWith(type)) + .map(Map.Entry::getValue) + .flatMap(List::stream) + .collect(Collectors.toList()); + return Result.succeed(configList); + } } diff --git a/dinky-admin/src/main/java/org/dinky/controller/TenantController.java b/dinky-admin/src/main/java/org/dinky/controller/TenantController.java index e1d5e47efa..53a9dc46d3 100644 --- a/dinky-admin/src/main/java/org/dinky/controller/TenantController.java +++ b/dinky-admin/src/main/java/org/dinky/controller/TenantController.java @@ -122,4 +122,10 @@ public Result assignUserToTenant(@RequestBody AssignUserToTenantParams ass public Result> getUserListByTenantId(@RequestParam("id") Integer id) { return Result.succeed(userService.getUserListByTenantId(id)); } + + @GetMapping("/getTenantListByUserId") + @ApiOperation("Get Tenant List By User Id") + public Result> getTenantListByUserId(@RequestParam("id") Integer userId) { + return Result.succeed(tenantService.getTenantListByUserId(userId)); + } } diff --git a/dinky-admin/src/main/java/org/dinky/controller/TokenController.java b/dinky-admin/src/main/java/org/dinky/controller/TokenController.java new file mode 100644 index 0000000000..63a599ce4b --- /dev/null +++ b/dinky-admin/src/main/java/org/dinky/controller/TokenController.java @@ -0,0 +1,113 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.dinky.controller; + +import org.dinky.data.annotation.Log; +import org.dinky.data.enums.BusinessType; +import org.dinky.data.enums.Status; +import org.dinky.data.model.SysToken; +import org.dinky.data.model.UDFTemplate; +import org.dinky.data.result.ProTableResult; +import org.dinky.data.result.Result; +import org.dinky.service.TokenService; + +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.fasterxml.jackson.databind.JsonNode; + +import cn.hutool.core.lang.UUID; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** TokenController */ +@Slf4j +@Api(tags = "Token Controller") +@RestController +@RequestMapping("/api/token") +@RequiredArgsConstructor +public class TokenController { + + private final TokenService tokenService; + + /** + * get udf template list + * + * @param params {@link JsonNode} + * @return {@link ProTableResult} <{@link UDFTemplate}> + */ + @PostMapping("/list") + @ApiOperation("Get Token List") + public ProTableResult listToken(@RequestBody JsonNode params) { + return tokenService.selectForProTable(params); + } + + /** + * save or update udf template + * + * @param sysToken {@link SysToken} + * @return {@link Result} <{@link String}> + */ + @PutMapping("/saveOrUpdateToken") + @ApiOperation("Insert or Update Token") + @Log(title = "Insert or Update Token", businessType = BusinessType.INSERT_OR_UPDATE) + public Result saveOrUpdateToken(@RequestBody SysToken sysToken) { + return tokenService.saveOrUpdate(sysToken) + ? Result.succeed(Status.SAVE_SUCCESS) + : Result.failed(Status.SAVE_FAILED); + } + + /** + * delete Token by id + * + * @param id {@link Integer} + * @return {@link Result} <{@link Void}> + */ + @DeleteMapping("/delete") + @Log(title = "Delete Token By Id", businessType = BusinessType.DELETE) + @ApiOperation("Delete Token By Id") + @Transactional(rollbackFor = Exception.class) + public Result deleteToken(@RequestParam Integer id) { + if (tokenService.removeTokenById(id)) { + return Result.succeed(Status.DELETE_SUCCESS); + } else { + return Result.failed(Status.DELETE_FAILED); + } + } + + /** + * delete Token by id + * @return {@link Result} <{@link Void}> + */ + @PostMapping("/buildToken") + @Log(title = "Build Token", businessType = BusinessType.OTHER) + @ApiOperation("Build Token") + public Result buildToken() { + return Result.succeed(UUID.fastUUID().toString(true), Status.SUCCESS); + } +} diff --git a/dinky-admin/src/main/java/org/dinky/data/model/SysToken.java b/dinky-admin/src/main/java/org/dinky/data/model/SysToken.java new file mode 100644 index 0000000000..b6bcc7399c --- /dev/null +++ b/dinky-admin/src/main/java/org/dinky/data/model/SysToken.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.dinky.data.model; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("dinky_sys_token") +public class SysToken implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private String tokenValue; + private Integer userId; + private Integer roleId; + private Integer tenantId; + + private Integer expireType; + + private Date expireStartTime; + private Date expireEndTime; + + @TableField(fill = FieldFill.INSERT) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime createTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime updateTime; + + private Integer creator; + private Integer updator; + + @TableField(exist = false) + private String userName; + + @TableField(exist = false) + private String roleName; + + @TableField(exist = false) + private String tenantCode; + + @TableField(exist = false) + private List expireTimeRange = new ArrayList<>(); +} diff --git a/dinky-admin/src/main/java/org/dinky/mapper/TokenMapper.java b/dinky-admin/src/main/java/org/dinky/mapper/TokenMapper.java new file mode 100644 index 0000000000..842ae391a2 --- /dev/null +++ b/dinky-admin/src/main/java/org/dinky/mapper/TokenMapper.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.dinky.mapper; + +import org.dinky.data.model.SysToken; +import org.dinky.mybatis.mapper.SuperMapper; + +import org.apache.ibatis.annotations.Mapper; + +/** TokenMapper */ +@Mapper +public interface TokenMapper extends SuperMapper {} diff --git a/dinky-admin/src/main/java/org/dinky/service/TenantService.java b/dinky-admin/src/main/java/org/dinky/service/TenantService.java index 98814833b6..6a6bcdba63 100644 --- a/dinky-admin/src/main/java/org/dinky/service/TenantService.java +++ b/dinky-admin/src/main/java/org/dinky/service/TenantService.java @@ -24,6 +24,8 @@ import org.dinky.data.result.Result; import org.dinky.mybatis.service.ISuperService; +import java.util.List; + import com.fasterxml.jackson.databind.JsonNode; public interface TenantService extends ISuperService { @@ -60,6 +62,13 @@ public interface TenantService extends ISuperService { */ Tenant getTenantByTenantCode(String tenantCode); + /** + * query tenant list by user id + * @param userId user id + * @return tenant list + */ + List getTenantListByUserId(Integer userId); + /** * @param tenant tenant info * @return modify code diff --git a/dinky-admin/src/main/java/org/dinky/service/TokenService.java b/dinky-admin/src/main/java/org/dinky/service/TokenService.java new file mode 100644 index 0000000000..a1c3a5d2b3 --- /dev/null +++ b/dinky-admin/src/main/java/org/dinky/service/TokenService.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.dinky.service; + +import org.dinky.data.model.SysToken; +import org.dinky.mybatis.service.ISuperService; + +public interface TokenService extends ISuperService { + + /** + * remove token by id + * + * @param tokenId token id + * @return delete result code + */ + boolean removeTokenById(Integer tokenId); + + /** + * add or update token + * + * @param token token + * @return add or update code + */ + boolean saveOrUpdateSysToken(SysToken token); +} diff --git a/dinky-admin/src/main/java/org/dinky/service/impl/TenantServiceImpl.java b/dinky-admin/src/main/java/org/dinky/service/impl/TenantServiceImpl.java index 6a32ffc635..15ca8a5c07 100644 --- a/dinky-admin/src/main/java/org/dinky/service/impl/TenantServiceImpl.java +++ b/dinky-admin/src/main/java/org/dinky/service/impl/TenantServiceImpl.java @@ -90,6 +90,23 @@ public Tenant getTenantByTenantCode(String tenantCode) { .eq(Tenant::getIsDelete, 0)); } + /** + * @param userId + * @return + */ + @Override + public List getTenantListByUserId(Integer userId) { + List userTenants = userTenantService + .getBaseMapper() + .selectList(new LambdaQueryWrapper().eq(UserTenant::getUserId, userId)); + if (CollectionUtil.isNotEmpty(userTenants)) { + List tenantIds = new ArrayList<>(); + userTenants.forEach(userTenant -> tenantIds.add(userTenant.getTenantId())); + return getBaseMapper().selectList(new LambdaQueryWrapper().in(Tenant::getId, tenantIds)); + } + return null; + } + @Override public boolean modifyTenant(Tenant tenant) { if (Asserts.isNull(tenant.getId())) { diff --git a/dinky-admin/src/main/java/org/dinky/service/impl/TokenServiceImpl.java b/dinky-admin/src/main/java/org/dinky/service/impl/TokenServiceImpl.java new file mode 100644 index 0000000000..623f1bcac9 --- /dev/null +++ b/dinky-admin/src/main/java/org/dinky/service/impl/TokenServiceImpl.java @@ -0,0 +1,56 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.dinky.service.impl; + +import org.dinky.data.model.SysToken; +import org.dinky.mapper.TokenMapper; +import org.dinky.mybatis.service.impl.SuperServiceImpl; +import org.dinky.service.TokenService; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class TokenServiceImpl extends SuperServiceImpl implements TokenService { + + /** + * remove token by id + * + * @param tokenId token id + * @return delete result code + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeTokenById(Integer tokenId) { + return removeById(tokenId); + } + + /** + * add or update token + * + * @param token token + * @return add or update code + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean saveOrUpdateSysToken(SysToken token) { + return this.saveOrUpdate(token); + } +} diff --git a/dinky-admin/src/main/resources/db/db-h2.sql b/dinky-admin/src/main/resources/db/db-h2.sql index 2745853ce8..0181fcf242 100644 --- a/dinky-admin/src/main/resources/db/db-h2.sql +++ b/dinky-admin/src/main/resources/db/db-h2.sql @@ -1768,20 +1768,20 @@ INSERT INTO `dinky_sys_menu` VALUES (30, 9, 'cluster-config', '/registration/clu INSERT INTO `dinky_sys_menu` VALUES (31, 12, 'instance', '/registration/alert/instance', './RegCenter/Alert/AlertInstance', null, null, 'C', 0, 15, '2023-08-11 14:06:55', '2023-08-18 17:09:39', null); INSERT INTO `dinky_sys_menu` VALUES (32, 1, '作业监控', '/home/jobOverView', 'JobOverView', 'show', 'AntCloudOutlined', 'F', 0, 2, '2023-08-15 16:52:59', '2023-08-18 17:09:39', null); INSERT INTO `dinky_sys_menu` VALUES (33, 1, '数据开发', '/home/devOverView', 'DevOverView', 'show', 'AimOutlined', 'F', 0, 3, '2023-08-15 16:54:47', '2023-08-18 17:09:39', null); -INSERT INTO `dinky_sys_menu` VALUES (34, 5, '项目列表', '/datastudio/left/project', null, null, null, 'F', 0, 1, '2023-09-01 18:00:39', '2023-09-02 00:51:06', null); -INSERT INTO `dinky_sys_menu` VALUES (35, 5, '元数据', '/datastudio/left/metadata', null, null, null, 'F', 0, 2, '2023-09-01 18:01:09', '2023-09-02 00:51:12', null); -INSERT INTO `dinky_sys_menu` VALUES (36, 5, '结构', '/datastudio/left/structure', null, null, null, 'F', 0, 3, '2023-09-01 18:01:30', '2023-09-02 00:51:26', null); -INSERT INTO `dinky_sys_menu` VALUES (37, 5, '作业配置', '/datastudio/right/jobConfig', null, null, null, 'F', 0, 4, '2023-09-01 18:02:15', '2023-09-02 00:51:32', null); -INSERT INTO `dinky_sys_menu` VALUES (38, 5, '执行配置', '/datastudio/right/executeConfig', null, null, null, 'F', 0, 5, '2023-09-01 18:03:08', '2023-09-02 00:51:38', null); -INSERT INTO `dinky_sys_menu` VALUES (39, 5, '版本历史', '/datastudio/right/historyVision', null, null, null, 'F', 0, 6, '2023-09-01 18:03:29', '2023-09-02 00:51:56', null); -INSERT INTO `dinky_sys_menu` VALUES (40, 5, '保存点', '/datastudio/right/savePoint', null, null, null, 'F', 0, 7, '2023-09-01 18:03:58', '2023-09-02 00:51:47', null); -INSERT INTO `dinky_sys_menu` VALUES (41, 5, '作业信息', '/datastudio/right/jobInfo', null, null, null, 'F', 0, 8, '2023-09-01 18:04:31', '2023-09-02 00:52:06', null); -INSERT INTO `dinky_sys_menu` VALUES (42, 5, '控制台', '/datastudio/bottom/console', null, null, null, 'F', 0, 9, '2023-09-01 18:04:56', '2023-09-01 18:04:56', null); -INSERT INTO `dinky_sys_menu` VALUES (43, 5, '结果', '/datastudio/bottom/result', null, null, null, 'F', 0, 10, '2023-09-01 18:05:16', '2023-09-01 18:05:16', null); -INSERT INTO `dinky_sys_menu` VALUES (44, 5, 'BI', '/datastudio/bottom/bi', null, null, null, 'F', 0, 11, '2023-09-01 18:05:43', '2023-09-01 18:05:43', null); -INSERT INTO `dinky_sys_menu` VALUES (45, 5, '血缘', '/datastudio/bottom/lineage', null, null, null, 'F', 0, 12, '2023-09-01 18:07:15', '2023-09-02 00:52:12', null); -INSERT INTO `dinky_sys_menu` VALUES (46, 5, '表数据监控', '/datastudio/bottom/process', null, null, null, 'F', 0, 13, '2023-09-01 18:07:55', '2023-09-02 00:52:21', null); -INSERT INTO `dinky_sys_menu` VALUES (47, 5, '小工具', '/datastudio/bottom/tool', null, null, null, 'F', 0, 14, '2023-09-01 18:08:18', '2023-09-01 18:08:18', null); +INSERT INTO `dinky_sys_menu` VALUES (34, 5, '项目列表', '/datastudio/left/project', null, null, 'ConsoleSqlOutlined', 'F', 0, 1, '2023-09-01 18:00:39', '2023-09-02 00:51:06', null); +INSERT INTO `dinky_sys_menu` VALUES (35, 5, '元数据', '/datastudio/left/metadata', null, null, 'TableOutlined', 'F', 0, 2, '2023-09-01 18:01:09', '2023-09-02 00:51:12', null); +INSERT INTO `dinky_sys_menu` VALUES (36, 5, '结构', '/datastudio/left/structure', null, null, 'DatabaseOutlined', 'F', 0, 3, '2023-09-01 18:01:30', '2023-09-02 00:51:26', null); +INSERT INTO `dinky_sys_menu` VALUES (37, 5, '作业配置', '/datastudio/right/jobConfig', null, null, 'SettingOutlined', 'F', 0, 4, '2023-09-01 18:02:15', '2023-09-02 00:51:32', null); +INSERT INTO `dinky_sys_menu` VALUES (38, 5, '执行配置', '/datastudio/right/executeConfig', null, null, 'ExperimentOutlined', 'F', 0, 5, '2023-09-01 18:03:08', '2023-09-02 00:51:38', null); +INSERT INTO `dinky_sys_menu` VALUES (39, 5, '版本历史', '/datastudio/right/historyVision', null, null, 'HistoryOutlined', 'F', 0, 6, '2023-09-01 18:03:29', '2023-09-02 00:51:56', null); +INSERT INTO `dinky_sys_menu` VALUES (40, 5, '保存点', '/datastudio/right/savePoint', null, null, 'FolderOutlined', 'F', 0, 7, '2023-09-01 18:03:58', '2023-09-02 00:51:47', null); +INSERT INTO `dinky_sys_menu` VALUES (41, 5, '作业信息', '/datastudio/right/jobInfo', null, null, 'InfoCircleOutlined', 'F', 0, 8, '2023-09-01 18:04:31', '2023-09-02 00:52:06', null); +INSERT INTO `dinky_sys_menu` VALUES (42, 5, '控制台', '/datastudio/bottom/console', null, null, 'ConsoleSqlOutlined', 'F', 0, 9, '2023-09-01 18:04:56', '2023-09-01 18:04:56', null); +INSERT INTO `dinky_sys_menu` VALUES (43, 5, '结果', '/datastudio/bottom/result', null, null, 'SearchOutlined', 'F', 0, 10, '2023-09-01 18:05:16', '2023-09-01 18:05:16', null); +INSERT INTO `dinky_sys_menu` VALUES (44, 5, 'BI', '/datastudio/bottom/bi', null, null, 'DashboardOutlined', 'F', 0, 11, '2023-09-01 18:05:43', '2023-09-01 18:05:43', null); +INSERT INTO `dinky_sys_menu` VALUES (45, 5, '血缘', '/datastudio/bottom/lineage', null, null, 'PushpinOutlined', 'F', 0, 12, '2023-09-01 18:07:15', '2023-09-02 00:52:12', null); +INSERT INTO `dinky_sys_menu` VALUES (46, 5, '表数据监控', '/datastudio/bottom/process', null, null, 'TableOutlined', 'F', 0, 13, '2023-09-01 18:07:55', '2023-09-02 00:52:21', null); +INSERT INTO `dinky_sys_menu` VALUES (47, 5, '小工具', '/datastudio/bottom/tool', null, null, 'ToolOutlined', 'F', 0, 14, '2023-09-01 18:08:18', '2023-09-01 18:08:18', null); INSERT INTO `dinky_sys_menu` VALUES (48, 28, '新建', '/registration/cluster/instance/new', null, null, 'PlusOutlined', 'F', 0, 15, '2023-09-06 08:56:45', '2023-09-06 08:56:45', null); INSERT INTO `dinky_sys_menu` VALUES (49, 28, '回收', '/registration/cluster/instance/recovery', null, null, 'PlusOutlined', 'F', 0, 16, '2023-09-06 08:57:30', '2023-09-06 08:57:30', null); INSERT INTO `dinky_sys_menu` VALUES (50, 28, '编辑', '/registration/cluster/instance/edit', null, null, 'PlusOutlined', 'F', 0, 17, '2023-09-06 08:56:45', '2023-09-06 08:56:45', null); @@ -1820,6 +1820,7 @@ INSERT INTO `dinky_sys_menu` VALUES (82, 19, '上传', '/registration/resource/u INSERT INTO `dinky_sys_menu` VALUES (83, 19, '重命名', '/registration/resource/rename', null, null, 'PlusOutlined', 'F', 0, 17, '2023-09-06 08:56:45', '2023-09-06 08:56:45', null); INSERT INTO `dinky_sys_menu` VALUES (84, 19, '删除', '/registration/resource/delete', null, null, 'PlusOutlined', 'F', 0, 18, '2023-09-06 08:57:30', '2023-09-06 08:57:30', null); INSERT INTO `dinky_sys_menu` VALUES (85, 19, '创建文件夹', '/registration/resource/folder', null, null, 'PlusOutlined', 'F', 0, 18, '2023-09-06 08:57:30', '2023-09-06 08:57:30', null); +INSERT INTO `dinky_sys_menu` VALUES (86, 4, 'Token', '/auth/token', './AuthCenter/Token', null, 'SecurityScanFilled', 'C', 0, 35, '2023-09-05 23:14:23', '2023-09-05 23:14:23', null); -- ---------------------------- diff --git a/dinky-admin/src/main/resources/mapper/TokenMapper.xml b/dinky-admin/src/main/resources/mapper/TokenMapper.xml new file mode 100644 index 0000000000..0b9ee212a6 --- /dev/null +++ b/dinky-admin/src/main/resources/mapper/TokenMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + \ No newline at end of file diff --git a/dinky-web/config/routes.ts b/dinky-web/config/routes.ts index 1da897458e..b4d3bf9c4f 100644 --- a/dinky-web/config/routes.ts +++ b/dinky-web/config/routes.ts @@ -209,6 +209,12 @@ export default [ name: 'tenant', icon: 'SecurityScanOutlined', component: './AuthCenter/Tenant' + }, + { + path: '/auth/token', + name: 'token', + icon: 'SecurityScanOutlined', + component: './AuthCenter/Token' } ] }, diff --git a/dinky-web/package.json b/dinky-web/package.json index d65109c94b..214e6d1caa 100644 --- a/dinky-web/package.json +++ b/dinky-web/package.json @@ -5,9 +5,9 @@ "license": "Apache License 2.0", "scripts": { "analyze": "cross-env ANALYZE=1 max build", - "build": "max build", + "build": "concurrently max build && npm run build-to-admin --prefix ../dinky-web-flink", "deploy": "npm run build && npm run gh-pages", - "dev": "npm run start:dev", + "dev": "npm run build-to-admin --prefix ../dinky-web-flink && npm run start:dev ", "postinstall": "max setup", "lint": "npm run lint:js && npm run lint:prettier && npm run tsc", "lint-staged": "lint-staged", @@ -47,6 +47,7 @@ "@umijs/route-utils": "^4.0.1", "antd": "^5.6.1", "classnames": "^2.3.2", + "dayjs": "^1.11.9", "js-cookie": "^3.0.5", "lodash": "^4.17.21", "million": "^2.5.1-beta.3", diff --git a/dinky-web/src/locales/en-US/menu.ts b/dinky-web/src/locales/en-US/menu.ts index 563b41825d..2815667496 100644 --- a/dinky-web/src/locales/en-US/menu.ts +++ b/dinky-web/src/locales/en-US/menu.ts @@ -64,6 +64,7 @@ export default { 'menu.auth.rowpermissions': 'Row Permissions', 'menu.auth.namespace': 'NameSpace', 'menu.auth.tenant': 'Tenant', + 'menu.auth.token': 'Token', 'menu.settings': 'Setting Center', 'menu.settings.globalsetting': 'Global Settings', 'menu.settings.systemlog': 'System Log', diff --git a/dinky-web/src/locales/en-US/pages.ts b/dinky-web/src/locales/en-US/pages.ts index cb01c0d594..9f6832e675 100644 --- a/dinky-web/src/locales/en-US/pages.ts +++ b/dinky-web/src/locales/en-US/pages.ts @@ -247,6 +247,29 @@ export default { 'tenant.cancel.admin': 'Cancel Tenant Admin', 'tenant.user.list': 'User List', + 'token.manager': 'Token Management', + 'token.value': 'Token', + 'token.generate.placeholder': 'Please generate token', + 'token.generate': 'Generate Token', + 'token.username': 'User', + 'token.user.choose': 'Please choose user', + 'token.role': 'Role', + 'token.role.choose': 'Please choose role', + 'token.tenant': 'Tenant', + 'token.tenant.choose': 'Please choose tenant', + 'token.expireType': 'Expire Type', + 'token.choose.expireType': 'Please choose expire type', + 'token.expireType.1': 'Never Expire', + 'token.expireType.2': 'Expire Time', + 'token.expireType.3': 'Expire Range Time', + 'token.expireTime': 'Expire Time', + 'token.expireTime.placeholder': 'Please choose expire time', + 'token.expireEndTime': 'Expire End Time', + 'token.expireStartTime': 'Expire Start Time', + 'token.deleteConfirm': 'Are you sure you want to delete this Token?', + 'token.create': 'Create Token', + 'token.update': 'Update Token', + // role 'role.roleManagement': 'Role Management', 'role.roleCode': 'Role Code', diff --git a/dinky-web/src/locales/zh-CN/menu.ts b/dinky-web/src/locales/zh-CN/menu.ts index c8086f0faa..d5d917ac31 100644 --- a/dinky-web/src/locales/zh-CN/menu.ts +++ b/dinky-web/src/locales/zh-CN/menu.ts @@ -64,6 +64,7 @@ export default { 'menu.auth.rowpermissions': '行权限', 'menu.auth.namespace': '命名空间', 'menu.auth.tenant': '租户', + 'menu.auth.token': '令牌', 'menu.settings': '配置中心', 'menu.settings.globalsetting': '全局配置', 'menu.settings.systemlog': '系统日志', diff --git a/dinky-web/src/locales/zh-CN/pages.ts b/dinky-web/src/locales/zh-CN/pages.ts index 4566b8201e..5824c1c497 100644 --- a/dinky-web/src/locales/zh-CN/pages.ts +++ b/dinky-web/src/locales/zh-CN/pages.ts @@ -244,6 +244,30 @@ export default { 'tenant.cancel.admin': '取消租户管理员', 'tenant.user.list': '租户用户列表', + // token + 'token.manager': 'Token管理', + 'token.value': 'Token', + 'token.generate.placeholder': '请生成 Token', + 'token.generate': '生成 Token', + 'token.username': '用户', + 'token.user.choose': '请选择用户', + 'token.role': '角色', + 'token.role.choose': '请选择角色', + 'token.tenant': '租户', + 'token.tenant.choose': '请选择租户', + 'token.expireType': '过期类型', + 'token.choose.expireType': '请选择过期类型', + 'token.expireType.1': '永不过期', + 'token.expireType.2': '指定结束时间', + 'token.expireType.3': '过期时间范围', + 'token.expireEndTime': '结束时间', + 'token.expireStartTime': '开始时间', + 'token.expireTime': '过期时间', + 'token.expireTime.placeholder': '请选择过期时间', + 'token.deleteConfirm': '您确定要删除此 Token 吗?', + 'token.create': '创建 Token', + 'token.update': '修改 Token', + // role 'role.roleManagement': '角色管理', 'role.roleCode': '角色编码', diff --git a/dinky-web/src/pages/AuthCenter/Menu/components/MenuList/index.tsx b/dinky-web/src/pages/AuthCenter/Menu/components/MenuList/index.tsx index d696e6768e..3cad0b7912 100644 --- a/dinky-web/src/pages/AuthCenter/Menu/components/MenuList/index.tsx +++ b/dinky-web/src/pages/AuthCenter/Menu/components/MenuList/index.tsx @@ -70,6 +70,7 @@ const MenuList: React.FC = () => { ) ); setMenuState((prevState) => ({ ...prevState, contextMenuOpen: false })); + queryMenuData(); }; /** diff --git a/dinky-web/src/pages/AuthCenter/Token/component/TokenList/index.tsx b/dinky-web/src/pages/AuthCenter/Token/component/TokenList/index.tsx new file mode 100644 index 0000000000..e77714d0dc --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/TokenList/index.tsx @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CreateBtn } from '@/components/CallBackButton/CreateBtn'; +import { EditBtn } from '@/components/CallBackButton/EditBtn'; +import { PopconfirmDeleteBtn } from '@/components/CallBackButton/PopconfirmDeleteBtn'; +import { mapDispatchToProps } from '@/pages/AuthCenter/Token/component/model'; +import TokenModalForm from '@/pages/AuthCenter/Token/component/TokenModalForm'; +import { queryList } from '@/services/api'; +import { handleAddOrUpdate, handleRemoveById } from '@/services/BusinessCrud'; +import { PROTABLE_OPTIONS_PUBLIC } from '@/services/constants'; +import { API_CONSTANTS } from '@/services/endpoints'; +import { SysToken } from '@/types/AuthCenter/data'; +import { InitTokenListState } from '@/types/AuthCenter/init.d'; +import { TokenListState } from '@/types/AuthCenter/state.d'; +import { l } from '@/utils/intl'; +import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table'; +import { connect } from '@umijs/max'; +import { useRef, useState } from 'react'; + +const TokenList = (props: any) => { + const actionRef = useRef(); // table action + const [tokenState, setTokenState] = useState(InitTokenListState); // token state + + const executeAndCallbackRefresh = async (callback: () => void) => { + setTokenState((prevState) => ({ ...prevState, loading: true })); + await callback(); + setTokenState((prevState) => ({ ...prevState, loading: false })); + actionRef.current?.reload?.(); + }; + + function handleEditVisible(record: Partial) { + setTokenState((prevState) => ({ ...prevState, editOpen: true, value: record })); + } + + const handleDeleteToken = async (id: number) => { + await executeAndCallbackRefresh( + async () => await handleRemoveById(API_CONSTANTS.TOKEN_DELETE, id) + ); + }; + + /** + * table columns + */ + const columns: ProColumns[] = [ + { + title: l('token.value'), + dataIndex: 'tokenValue', + copyable: true, + ellipsis: true + }, + { + title: l('token.username'), + dataIndex: 'userName' + }, + { + title: l('token.role'), + dataIndex: 'roleName' + }, + { + title: l('token.tenant'), + dataIndex: 'tenantCode' + }, + { + title: l('token.expireType'), + dataIndex: 'expireType', + valueEnum: { + 1: { text: l('token.expireType.1') }, + 2: { text: l('token.expireType.2') }, + 3: { text: l('token.expireType.3') } + } + }, + { + title: l('token.expireStartTime'), + dataIndex: 'expireStartTime', + valueType: 'dateTime', + hideInSearch: true + }, + { + title: l('token.expireEndTime'), + dataIndex: 'expireEndTime', + valueType: 'dateTime', + hideInSearch: true + }, + { + title: l('global.table.createTime'), + dataIndex: 'createTime', + sorter: true, + valueType: 'dateTime', + hideInTable: true, + hideInSearch: true + }, + { + title: l('global.table.operate'), + valueType: 'option', + width: '5vw', + fixed: 'right', + render: (_, record: SysToken) => [ + handleEditVisible(record)} />, + handleDeleteToken(record?.id)} + description={l('token.deleteConfirm')} + /> + ] + } + ]; + + const handleSubmitToken = async (value: SysToken) => { + await executeAndCallbackRefresh(async () => + handleAddOrUpdate( + API_CONSTANTS.TOKEN_SAVE_OR_UPDATE, + value, + () => {}, + () => setTokenState((prevState) => ({ ...prevState, ...InitTokenListState })) + ) + ); + }; + + /** + * render + */ + return ( + <> + + {...PROTABLE_OPTIONS_PUBLIC} + headerTitle={l('token.manager')} + actionRef={actionRef} + loading={tokenState.loading} + toolBarRender={() => [ + setTokenState((prevState) => ({ ...prevState, addedOpen: true }))} + /> + ]} + request={(params, sorter, filter: any) => + queryList(API_CONSTANTS.TOKEN, { + ...params, + sorter, + filter + }) + } + columns={columns} + /> + + setTokenState((prevState) => ({ ...prevState, addedOpen: false }))} + visible={tokenState.addedOpen} + value={{}} + loading={tokenState.loading} + /> + {Object.keys(tokenState.value).length > 0 && ( + <> + + setTokenState((prevState) => ({ ...prevState, editOpen: false, value: {} })) + } + visible={tokenState.editOpen} + value={tokenState.value} + loading={tokenState.loading} + /> + + )} + + ); +}; + +export default connect(() => ({}), mapDispatchToProps)(TokenList); diff --git a/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/TokenForm/index.tsx b/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/TokenForm/index.tsx new file mode 100644 index 0000000000..762cb34121 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/TokenForm/index.tsx @@ -0,0 +1,142 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { TOKEN_EXPIRE_TYPE } from '@/pages/AuthCenter/Token/component/constants'; +import { + buildRoleOptions, + buildTenantOptions, + buildUserOptions +} from '@/pages/AuthCenter/Token/component/function'; +import { TokenStateType } from '@/pages/AuthCenter/Token/component/model'; +import { UserBaseInfo } from '@/types/AuthCenter/data'; +import { + ProFormDateTimePicker, + ProFormDateTimeRangePicker, + ProFormGroup, + ProFormRadio, + ProFormSelect, + ProFormText +} from '@ant-design/pro-components'; +import { connect } from '@umijs/max'; +import React from 'react'; +import {l} from "@/utils/intl"; + +type TokenFormProps = { + users: UserBaseInfo.User[]; + roles: UserBaseInfo.Role[]; + tenants: UserBaseInfo.Tenant[]; + expireType: number; + tokenValue: string; + buildToken: () => void; +}; +const TokenForm: React.FC = (props) => { + const { users, roles, tenants, expireType, buildToken } = props; + + return ( + <> + + buildToken()}>{l('token.generate')} + }} + /> + + + + + + + + + + + {expireType === 2 && ( + <> + + + )} + {expireType === 3 && ( + <> + + + )} + + + ); +}; + +export default connect(({ Token }: { Token: TokenStateType }) => ({ + users: Token.users, + roles: Token.roles, + tenants: Token.tenants, + tokenValue: Token.token +}))(TokenForm); diff --git a/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/index.tsx b/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/index.tsx new file mode 100644 index 0000000000..b281b70cc2 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/TokenModalForm/index.tsx @@ -0,0 +1,177 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {FormContextValue} from '@/components/Context/FormContext'; +import {mapDispatchToProps, TokenStateType} from '@/pages/AuthCenter/Token/component/model'; +import TokenForm from '@/pages/AuthCenter/Token/component/TokenModalForm/TokenForm'; +import {DATETIME_FORMAT, MODAL_FORM_STYLE} from '@/services/constants'; +import {SysToken} from '@/types/AuthCenter/data.d'; +import {formatDateToYYYYMMDDHHMMSS, parseDateStringToDate} from '@/utils/function'; +import {l} from '@/utils/intl'; +import {ModalForm} from '@ant-design/pro-components'; +import {ProFormInstance} from '@ant-design/pro-form/lib'; +import {connect} from '@umijs/max'; +import {Button, Form} from 'antd'; +import React, {useEffect, useRef} from 'react'; +import dayjs from "dayjs"; + +const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'; + +type TokenModalFormProps = { + visible: boolean; + onCancel: () => void; + onSubmit: (value: SysToken) => void; + value: Partial; + loading: boolean; + buildToken: () => void; + tokenValue: string; +}; +const TokenModalForm: React.FC = (props) => { + /** + * init props + */ + const { + onSubmit: handleSubmit, + onCancel: handleModalVisible, + visible, + value, + loading, + buildToken, + tokenValue + } = props; + + const [expireType, setExpireType] = React.useState(value.expireType ?? 1); + const [selectUserId, setSelectUserId] = React.useState(value.userId ?? 0); + const formRef = useRef(); + + /** + * init form + */ + const [form] = Form.useForm(); + /** + * init form context + */ + const formContext = React.useMemo( + () => ({ + resetForm: () => form.resetFields() // 定义 resetForm 方法 + }), + [form] + ); + + /** + * when modalVisible or values changed, set form values + */ + useEffect(() => { + if (!visible) return; + props.queryUsers(); + selectUserId && props.queryRoles(selectUserId); + selectUserId && props.queryTenants(selectUserId); + form.setFieldsValue({ + ...value, + expireTime: + value.expireType === 2 + ? parseDateStringToDate(value.expireEndTime) + : value.expireType === 3 + ? [ + parseDateStringToDate(value.expireStartTime), + parseDateStringToDate(value.expireEndTime) + ] + : undefined + }); + }, [visible, value, form, selectUserId]); + + /** + * handle cancel + */ + const handleCancel = () => { + handleModalVisible(); + formContext.resetForm(); + }; + + /** + * submit form + */ + const submitForm = async () => { + const fieldsValue = await form.validateFields(); + let result = {...value, ...fieldsValue}; + // 转化时间 + if (fieldsValue.expireType === 2) { + // 只有一个时间 设置为结束时间 + result = { + ...result, + expireEndTime: formatDateToYYYYMMDDHHMMSS(fieldsValue.expireTime), + } + } else if (fieldsValue.expireType === 3) { + // 两个时间都有 设置开始时间和结束时间 + result = { + ...result, + expireEndTime: formatDateToYYYYMMDDHHMMSS(fieldsValue.expireTime[0]), + expireStartTime: formatDateToYYYYMMDDHHMMSS(fieldsValue.expireTime[1]), + }; + } + + await handleSubmit({...result}); + await handleCancel(); + }; + + const renderFooter = () => { + return [ + , + + ]; + }; + + const handleValuesChange = (changedValues: any, allValues: any) => { + if (allValues.expireType) setExpireType(allValues.expireType); + if (allValues.userId) setSelectUserId(allValues.userId); + }; + + const handleBuildToken = () => { + buildToken(); + form.setFieldValue('tokenValue', tokenValue); + }; + + return ( + <> + + {...MODAL_FORM_STYLE} + width={'25%'} + title={value.id ? l('token.update') : l('token.create')} + open={visible} + form={form} + formRef={formRef} + onValuesChange={handleValuesChange} + submitter={{render: () => [...renderFooter()]}} + initialValues={{...value}} + > + + + + ); +}; +export default connect( + ({Token}: { Token: TokenStateType }) => ({ + tokenValue: Token.token + }), + mapDispatchToProps +)(TokenModalForm); diff --git a/dinky-web/src/pages/AuthCenter/Token/component/constants.ts b/dinky-web/src/pages/AuthCenter/Token/component/constants.ts new file mode 100644 index 0000000000..ec90aaac58 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/constants.ts @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CheckboxOptionType } from 'antd/es/checkbox/Group'; + +export const TOKEN_EXPIRE_TYPE: CheckboxOptionType[] = [ + { + label: '永不过期', + value: 1, + title: '永不过期' + }, + { + label: '指定过期时间', + value: 2, + title: '指定过期时间' + }, + { + label: '指定过期时间区间', + value: 3, + title: '指定过期时间区间' + } +]; diff --git a/dinky-web/src/pages/AuthCenter/Token/component/function.ts b/dinky-web/src/pages/AuthCenter/Token/component/function.ts new file mode 100644 index 0000000000..152b298171 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/function.ts @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { UserBaseInfo } from '@/types/AuthCenter/data.d'; +import { DefaultOptionType } from 'antd/es/select'; + +export const buildUserOptions = (userList: UserBaseInfo.User[]): DefaultOptionType[] => { + return userList + ? userList.map((user) => { + return { + label: user.username, + value: user.id, + disabled: user.isDelete || !user.enabled + }; + }) + : []; +}; + +export const buildRoleOptions = (roleList: UserBaseInfo.Role[]): DefaultOptionType[] => { + return roleList + ? roleList.map((role) => { + return { + label: role.roleName, + value: role.id, + disabled: role.isDelete + }; + }) + : []; +}; + +export const buildTenantOptions = (tenantList: UserBaseInfo.Tenant[]): DefaultOptionType[] => { + return tenantList + ? tenantList.map((tenant) => { + return { + label: tenant.tenantCode, + value: tenant.id, + disabled: tenant.isDelete + }; + }) + : []; +}; diff --git a/dinky-web/src/pages/AuthCenter/Token/component/model.ts b/dinky-web/src/pages/AuthCenter/Token/component/model.ts new file mode 100644 index 0000000000..7f0b70f549 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/model.ts @@ -0,0 +1,123 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + buildToken, + showRoleList, + showTenantList, + showUserList +} from '@/pages/AuthCenter/Token/component/service'; +import { UserBaseInfo } from '@/types/AuthCenter/data.d'; +import { createModelTypes } from '@/utils/modelUtils'; +import { Effect } from '@@/plugin-dva/types'; +import { Dispatch } from '@umijs/max'; +import { Reducer } from 'umi'; + +export type TokenStateType = { + users: UserBaseInfo.User[]; + roles: UserBaseInfo.Role[]; + tenants: UserBaseInfo.Tenant[]; + token: string; +}; + +export type TokenModelType = { + namespace: string; + state: TokenStateType; + effects: { + queryUsers: Effect; + queryRoles: Effect; + queryTenants: Effect; + tokenValue: Effect; + }; + reducers: { + saveUsers: Reducer; + saveRoles: Reducer; + saveTenants: Reducer; + saveBuildToken: Reducer; + }; +}; + +const TokenModel: TokenModelType = { + namespace: 'Token', + state: { + users: [], + roles: [], + tenants: [], + token: '' + }, + + effects: { + *queryUsers({}, { call, put }) { + const data: UserBaseInfo.User = yield call(showUserList); + yield put({ type: 'saveUsers', payload: data }); + }, + *queryRoles({ payload }, { call, put }) { + const data: UserBaseInfo.Role = yield call(showRoleList, payload); + yield put({ type: 'saveRoles', payload: data }); + }, + *queryTenants({ payload }, { call, put }) { + const data: UserBaseInfo.Tenant = yield call(showTenantList, payload); + + yield put({ type: 'saveTenants', payload: data }); + }, + *tokenValue({ payload }, { call, put }) { + const data: string = yield call(buildToken); + yield put({ type: 'saveBuildToken', payload: data }); + } + }, + + reducers: { + saveUsers(state, { payload }) { + return { + ...state, + users: payload + }; + }, + saveRoles(state, { payload }) { + return { + ...state, + roles: payload + }; + }, + saveTenants(state, { payload }) { + return { + ...state, + tenants: payload + }; + }, + saveBuildToken(state, { payload }) { + return { + ...state, + token: payload + }; + } + } +}; + +export const [TOKEN_MODEL, TOKEN_MODEL_ASYNC] = createModelTypes(TokenModel); + +export default TokenModel; + +export const mapDispatchToProps = (dispatch: Dispatch) => ({ + queryUsers: () => dispatch({ type: TOKEN_MODEL_ASYNC.queryUsers }), + queryRoles: (userId: number) => dispatch({ type: TOKEN_MODEL_ASYNC.queryRoles, payload: userId }), + queryTenants: (userId: number) => + dispatch({ type: TOKEN_MODEL_ASYNC.queryTenants, payload: userId }), + buildToken: () => dispatch({ type: TOKEN_MODEL_ASYNC.tokenValue }) +}); diff --git a/dinky-web/src/pages/AuthCenter/Token/component/service.ts b/dinky-web/src/pages/AuthCenter/Token/component/service.ts new file mode 100644 index 0000000000..d4ecdb8fe1 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/component/service.ts @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { getDataByParams, queryDataByParams } from '@/services/BusinessCrud'; +import { API_CONSTANTS } from '@/services/endpoints'; + +export async function showUserList() { + return await getDataByParams(API_CONSTANTS.USER); +} + +export async function showRoleList(userId: number) { + return queryDataByParams(API_CONSTANTS.GET_ROLES_BY_USERID, { id: userId }).then( + (res) => res.roles + ); +} + +export async function showTenantList(userId: number) { + return await queryDataByParams(API_CONSTANTS.TENANT_USER_LIST, { id: userId }); +} + +export async function buildToken() { + return await getDataByParams(API_CONSTANTS.TOKEN_BUILD); +} diff --git a/dinky-web/src/pages/AuthCenter/Token/index.tsx b/dinky-web/src/pages/AuthCenter/Token/index.tsx new file mode 100644 index 0000000000..8732676a97 --- /dev/null +++ b/dinky-web/src/pages/AuthCenter/Token/index.tsx @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import SlowlyAppear from '@/components/Animation/SlowlyAppear'; +import TokenList from '@/pages/AuthCenter/Token/component/TokenList'; +import { PageContainer } from '@ant-design/pro-components'; + +export default () => { + return ( + <> + + + + + + + ); +}; diff --git a/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx b/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx index 5170471eea..d690a5a187 100644 --- a/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx +++ b/dinky-web/src/pages/DataStudio/HeaderContainer/index.tsx @@ -40,7 +40,10 @@ import { TaskDataType, VIEW } from '@/pages/DataStudio/model'; +import { ConfigStateType } from '@/pages/SettingCenter/GlobalSetting/model'; +import { SettingConfigKeyEnum } from '@/pages/SettingCenter/GlobalSetting/SettingOverView/constants'; import { handlePutDataJson } from '@/services/BusinessCrud'; +import { BaseConfigProperties } from '@/types/SettingCenter/data'; import { l } from '@/utils/intl'; import { ErrorNotification } from '@/utils/messages'; import { connect } from '@@/exports'; @@ -52,10 +55,11 @@ import { PlayCircleTwoTone, SafetyCertificateTwoTone, SaveTwoTone, + SendOutlined, SmileOutlined } from '@ant-design/icons'; import { Breadcrumb, Button, Descriptions, message, Modal, notification, Space } from 'antd'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; const headerStyle: React.CSSProperties = { display: 'inline-flex', @@ -82,12 +86,31 @@ const HeaderContainer = (props: any) => { activeBreadcrumbTitle, tabs: { panes, activeKey }, saveTabs, - updateJobRunningMsg + updateJobRunningMsg, + queryDsConfig, + dsConfig } = props; const [modal, contextHolder] = Modal.useModal(); const [notificationApi, notificationContextHolder] = notification.useNotification(); const [messageApi, messageContextHolder] = message.useMessage(); + const [enableDs, setEnableDs] = useState(false); + + useEffect(() => { + queryDsConfig(SettingConfigKeyEnum.DOLPHIN_SCHEDULER.toLowerCase()); + }, []); + + useEffect(() => { + // 检查是否开启 ds 配置 & 如果 + if (!dsConfig) { + dsConfig.map((item: BaseConfigProperties) => { + if (item.key === 'dolphinscheduler.settings.enable') { + setEnableDs(item.value === 'true'); + } + }); + } + }, [dsConfig]); + const handlerStop = () => { const current = getCurrentData(panes, activeKey); if (!current) { @@ -259,14 +282,16 @@ const HeaderContainer = (props: any) => { // console.log("ctrl+s") // }, // // hotKey: (e: KeyboardEvent) => e.ctrlKey && e.key === 's' - // }, { - // // 推送海豚, 此处需要将系统设置中的 ds 的配置拿出来做判断 启用才展示 - // icon: , - // title: l('button.push'), - // click: () => { - // }, - // // hotKey: (e: KeyboardEvent) => e.ctrlKey && e.key === 's' - // }, { + // }, + { + // 推送海豚, 此处需要将系统设置中的 ds 的配置拿出来做判断 启用才展示 + icon: , + title: l('button.push'), + click: () => {}, + hotKey: (e: KeyboardEvent) => e.ctrlKey && e.key === 's', + isShow: () => enableDs + }, + // { // // 发布按钮 // icon: , // title: l('button.publish'), @@ -384,8 +409,9 @@ const HeaderContainer = (props: any) => { }; export default connect( - ({ Studio }: { Studio: StateType }) => ({ - tabs: Studio.tabs + ({ Studio, Config }: { Studio: StateType; Config: ConfigStateType }) => ({ + tabs: Studio.tabs, + dsConfig: Config.dsConfig }), mapDispatchToProps )(HeaderContainer); diff --git a/dinky-web/src/pages/DataStudio/LeftContainer/Project/function.tsx b/dinky-web/src/pages/DataStudio/LeftContainer/Project/function.tsx index ef5d7700dc..c9511714e3 100644 --- a/dinky-web/src/pages/DataStudio/LeftContainer/Project/function.tsx +++ b/dinky-web/src/pages/DataStudio/LeftContainer/Project/function.tsx @@ -39,7 +39,7 @@ export const getParentKey = (key: number | string, tree: any): any => { export const buildProjectTree = ( data: Catalogue[], searchValue: string = '', - path?: string[] + path: string[] = [] ): any => data ? data.map((item: Catalogue) => { diff --git a/dinky-web/src/pages/DataStudio/RightContainer/JobConfig/index.tsx b/dinky-web/src/pages/DataStudio/RightContainer/JobConfig/index.tsx index bd6275ff0e..5cce629afa 100644 --- a/dinky-web/src/pages/DataStudio/RightContainer/JobConfig/index.tsx +++ b/dinky-web/src/pages/DataStudio/RightContainer/JobConfig/index.tsx @@ -297,7 +297,7 @@ const JobConfig = (props: any) => { options={flinkConfigOptions} /> diff --git a/dinky-web/src/pages/DataStudio/function.ts b/dinky-web/src/pages/DataStudio/function.ts index 24bc6ce567..a33c8e132b 100644 --- a/dinky-web/src/pages/DataStudio/function.ts +++ b/dinky-web/src/pages/DataStudio/function.ts @@ -28,6 +28,7 @@ import { TabsPageType, TaskDataType } from '@/pages/DataStudio/model'; +import { CONFIG_MODEL_ASYNC } from '@/pages/SettingCenter/GlobalSetting/model'; import { Cluster, DataSources } from '@/types/RegCenter/data'; import { Dispatch } from '@@/plugin-dva/types'; @@ -116,6 +117,11 @@ export const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch({ type: STUDIO_MODEL.updateJobRunningMsg, payload: data + }), + queryDsConfig: (data: string) => + dispatch({ + type: CONFIG_MODEL_ASYNC.queryDsConfig, + payload: data }) }); diff --git a/dinky-web/src/pages/RegCenter/Alert/AlertGroup/index.tsx b/dinky-web/src/pages/RegCenter/Alert/AlertGroup/index.tsx index 182223c397..17c9becde2 100644 --- a/dinky-web/src/pages/RegCenter/Alert/AlertGroup/index.tsx +++ b/dinky-web/src/pages/RegCenter/Alert/AlertGroup/index.tsx @@ -17,7 +17,7 @@ * */ -import Pop from '@/components/Animation/Pop'; +import SlowlyAppear from '@/components/Animation/SlowlyAppear'; import { DangerDeleteIcon } from '@/components/Icons/CustomIcons'; import { Authorized } from '@/hooks/useAccess'; import AlertGroupForm from '@/pages/RegCenter/Alert/AlertGroup/components/AlertGroupForm'; @@ -237,7 +237,7 @@ const AlertGroupTableList: React.FC = (props: any) => { })); return ( - + {/* alert group list */} @@ -265,7 +265,7 @@ const AlertGroupTableList: React.FC = (props: any) => { /> )} - + ); }; diff --git a/dinky-web/src/pages/RegCenter/Alert/AlertInstance/index.tsx b/dinky-web/src/pages/RegCenter/Alert/AlertInstance/index.tsx index 74d8f2a913..d874ab4950 100644 --- a/dinky-web/src/pages/RegCenter/Alert/AlertInstance/index.tsx +++ b/dinky-web/src/pages/RegCenter/Alert/AlertInstance/index.tsx @@ -15,17 +15,17 @@ * limitations under the License. */ -import Scale from '@/components/Animation/Scale'; +import SlowlyAppear from '@/components/Animation/SlowlyAppear'; import AlertInstanceList from '@/pages/RegCenter/Alert/AlertInstance/components/AlertInstanceList'; import { PageContainer } from '@ant-design/pro-components'; export { ALERT_MODEL, ALERT_MODEL_ASYNC } from '@/pages/RegCenter/Alert/AlertInstance/model'; export default () => { return ( - + - + ); }; diff --git a/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationList/index.tsx b/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationList/index.tsx index 774071ecb7..615b936ca6 100644 --- a/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationList/index.tsx +++ b/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationList/index.tsx @@ -195,8 +195,12 @@ export default () => { */ const renderDataActionButton = (item: Cluster.Config) => { return [ - editClick(item)} />, - handleDeleteSubmit(item.id)} />, + + editClick(item)} /> + , + + handleDeleteSubmit(item.id)} /> + , = (props) => { */ const renderDataSourceActionButton = (item: DataSources.DataSource) => { return [ - editClick(item)} />, - handleDeleteSubmit(item.id)} />, + + editClick(item)} /> + , + + handleDeleteSubmit(item.id)} /> + ,