diff --git a/assembly/bin/supersonic-daemon.bat b/assembly/bin/supersonic-daemon.bat index 64e07244d..0882ad6c9 100644 --- a/assembly/bin/supersonic-daemon.bat +++ b/assembly/bin/supersonic-daemon.bat @@ -55,8 +55,8 @@ if "%command%"=="restart" ( set "webDir=%baseDir%\webapp" set "logDir=%baseDir%\logs" set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%" - set "java-command=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile% -Xms1024m - -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%" + set "property=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile%" + set "java-command=%property% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%" if not exist %logDir% mkdir %logDir% start /B java %java-command% >nul 2>&1 timeout /t 10 >nul diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/AuthenticationInterceptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/AuthenticationInterceptor.java index a395c2aac..24ff43318 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/AuthenticationInterceptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/AuthenticationInterceptor.java @@ -1,7 +1,7 @@ package com.tencent.supersonic.auth.authentication.interceptor; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; -import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; +import com.tencent.supersonic.auth.api.authentication.service.UserService; import com.tencent.supersonic.auth.authentication.utils.TokenService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -16,7 +16,7 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor { protected AuthenticationConfig authenticationConfig; - protected UserServiceImpl userServiceImpl; + protected UserService userService; protected TokenService tokenService; diff --git a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/DefaultAuthenticationInterceptor.java b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/DefaultAuthenticationInterceptor.java index 47886aa94..0942305c5 100644 --- a/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/DefaultAuthenticationInterceptor.java +++ b/auth/authentication/src/main/java/com/tencent/supersonic/auth/authentication/interceptor/DefaultAuthenticationInterceptor.java @@ -3,7 +3,7 @@ package com.tencent.supersonic.auth.authentication.interceptor; import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; -import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; +import com.tencent.supersonic.auth.api.authentication.service.UserService; import com.tencent.supersonic.auth.authentication.utils.TokenService; import com.tencent.supersonic.common.pojo.exception.AccessException; import com.tencent.supersonic.common.util.ContextUtils; @@ -16,12 +16,7 @@ import org.springframework.web.method.HandlerMethod; import java.lang.reflect.Method; import java.util.Optional; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_EMAIL; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME; -import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD; +import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.*; @Slf4j public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor { @@ -30,7 +25,7 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws AccessException { authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class); - userServiceImpl = ContextUtils.getBean(UserServiceImpl.class); + userService = ContextUtils.getBean(UserService.class); tokenService = ContextUtils.getBean(TokenService.class); if (!authenticationConfig.isEnabled()) { return true; diff --git a/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java b/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java index d26ad2c4a..c607f78fb 100644 --- a/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java +++ b/common/src/main/java/com/tencent/supersonic/common/pojo/Order.java @@ -4,10 +4,13 @@ import com.google.common.base.Objects; import jakarta.validation.constraints.NotBlank; import lombok.Data; +import java.io.Serializable; + import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER; @Data -public class Order { +public class Order implements Serializable { + private static final long serialVersionUID = 1L; @NotBlank(message = "Invalid order column") private String column; diff --git a/docker/Dockerfile b/docker/Dockerfile index 72caa801f..e74861da3 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,25 +1,15 @@ -# Use an official OpenJDK runtime as a parent image -FROM openjdk:21-jdk-bullseye +FROM supersonicbi/supersonic:0.9.10-SNAPSHOT # Set the working directory in the container WORKDIR /usr/src/app +# Delete old supersonic installation directory and the symbolic link +RUN rm -rf /usr/src/app/supersonic-standalone-0.9.10-SNAPSHOT +RUN rm -f /usr/src/app/supersonic-standalone-latest + # Argument to pass in the supersonic version at build time ARG SUPERSONIC_VERSION -# Install necessary packages, including Postgres client -RUN apt-get update && apt-get install -y postgresql-client - -# Install the vim editor. -RUN apt-get update && apt-get install -y vim && \ - rm -rf /var/lib/apt/lists/* - -# Update the package list and install iputils-ping. -RUN apt-get update && apt-get install -y iputils-ping - -# 更新包列表并安装 dnsutils 包 -RUN apt-get update && apt-get install -y dnsutils - # Copy the supersonic standalone zip file into the container COPY assembly/build/supersonic-standalone-${SUPERSONIC_VERSION}.zip . diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 6b9ea2da0..174fcff4d 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -12,7 +12,7 @@ services: ports: - "15432:5432" # volumes: -# - postgres_data:/var/lib/postgresql +# - postgres_data:/var/lib/postgresql/data networks: - supersonic_network dns: @@ -21,7 +21,7 @@ services: - 8.8.4.4 healthcheck: test: ["CMD-SHELL", "sh -c 'pg_isready -U supersonic_user -d postgres'"] - interval: 30s + interval: 10s timeout: 10s retries: 5 @@ -62,4 +62,4 @@ services: # supersonic_data: networks: - supersonic_network: \ No newline at end of file + supersonic_network: diff --git a/headless/core/pom.xml b/headless/core/pom.xml index d261b6e2f..d4e829879 100644 --- a/headless/core/pom.xml +++ b/headless/core/pom.xml @@ -133,6 +133,10 @@ io.trino trino-jdbc + + org.jgrapht + jgrapht-core + diff --git a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/DefaultSemanticTranslator.java b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/DefaultSemanticTranslator.java index f61d2f8bb..c6b2c8abe 100644 --- a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/DefaultSemanticTranslator.java +++ b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/DefaultSemanticTranslator.java @@ -1,6 +1,7 @@ package com.tencent.supersonic.headless.core.translator; import com.tencent.supersonic.common.calcite.SqlMergeWithUtils; +import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper; import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.headless.api.pojo.response.QueryState; import com.tencent.supersonic.headless.core.pojo.OntologyQuery; @@ -73,7 +74,7 @@ public class DefaultSemanticTranslator implements SemanticTranslator { String finalSql = null; if (sqlQuery.isSupportWith()) { EngineType engineType = queryStatement.getOntology().getDatabaseType(); - if (!SqlMergeWithUtils.hasWith(engineType, ontologyOuterSql)) { + if (!SqlSelectHelper.hasWith(ontologyOuterSql)) { finalSql = "with " + tables.stream() .map(t -> String.format("%s as (%s)", t.getLeft(), t.getRight())) .collect(Collectors.joining(",")) + "\n" + ontologyOuterSql; diff --git a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/calcite/SqlBuilder.java b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/calcite/SqlBuilder.java index 508d2fa90..3617d6df4 100644 --- a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/calcite/SqlBuilder.java +++ b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/calcite/SqlBuilder.java @@ -1,5 +1,6 @@ package com.tencent.supersonic.headless.core.translator.parser.calcite; +import com.google.common.collect.Sets; import com.tencent.supersonic.common.calcite.Configuration; import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.headless.api.pojo.Dimension; @@ -9,17 +10,26 @@ import com.tencent.supersonic.headless.api.pojo.response.DatabaseResp; import com.tencent.supersonic.headless.api.pojo.response.DimSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.MetricSchemaResp; import com.tencent.supersonic.headless.api.pojo.response.ModelResp; -import com.tencent.supersonic.headless.core.pojo.*; +import com.tencent.supersonic.headless.core.pojo.JoinRelation; +import com.tencent.supersonic.headless.core.pojo.Ontology; +import com.tencent.supersonic.headless.core.pojo.OntologyQuery; +import com.tencent.supersonic.headless.core.pojo.QueryStatement; import com.tencent.supersonic.headless.core.translator.parser.Constants; import lombok.extern.slf4j.Slf4j; import org.apache.calcite.sql.*; import org.apache.calcite.sql.fun.SqlStdOperatorTable; +import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.validate.SqlValidatorScope; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Triple; -import org.springframework.util.CollectionUtils; +import org.jgrapht.Graph; +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.graph.DefaultUndirectedGraph; import java.util.*; import java.util.stream.Collectors; @@ -37,6 +47,8 @@ public class SqlBuilder { public String buildOntologySql(QueryStatement queryStatement) throws Exception { OntologyQuery ontologyQuery = queryStatement.getOntologyQuery(); + Ontology ontology = queryStatement.getOntology(); + if (ontologyQuery.getLimit() == null) { ontologyQuery.setLimit(0L); } @@ -46,7 +58,14 @@ public class SqlBuilder { throw new Exception("data model not found"); } - TableView tableView = render(ontologyQuery, new ArrayList<>(dataModels), scope, schema); + TableView tableView; + if (!CollectionUtils.isEmpty(ontology.getJoinRelations()) && dataModels.size() > 1) { + Set models = probeRelatedModels(dataModels, queryStatement.getOntology()); + tableView = render(ontologyQuery, models, scope, schema); + } else { + tableView = render(ontologyQuery, dataModels, scope, schema); + } + SqlNode parserNode = tableView.build(); DatabaseResp database = queryStatement.getOntology().getDatabase(); EngineType engineType = EngineType.fromString(database.getType()); @@ -54,7 +73,61 @@ public class SqlBuilder { return SemanticNode.getSql(parserNode, engineType); } - private SqlNode optimizeParseNode(SqlNode parserNode, EngineType engineType) { + private Set probeRelatedModels(Set dataModels, Ontology ontology) { + List joinRelations = ontology.getJoinRelations(); + Graph graph = buildGraph(joinRelations); + DijkstraShortestPath dijkstraAlg = new DijkstraShortestPath<>(graph); + Set queryModels = + dataModels.stream().map(ModelResp::getName).collect(Collectors.toSet()); + GraphPath selectedGraphPath = null; + for (String fromModel : queryModels) { + for (String toModel : queryModels) { + if (fromModel != toModel) { + GraphPath path = dijkstraAlg.getPath(fromModel, toModel); + if (isGraphPathContainsAll(path, queryModels)) { + selectedGraphPath = path; + break; + } + } + } + } + if (selectedGraphPath == null) { + return dataModels; + } + Set modelNames = Sets.newHashSet(); + for (DefaultEdge edge : selectedGraphPath.getEdgeList()) { + modelNames.add(selectedGraphPath.getGraph().getEdgeSource(edge)); + modelNames.add(selectedGraphPath.getGraph().getEdgeTarget(edge)); + } + return modelNames.stream().map(m -> ontology.getModelMap().get(m)) + .collect(Collectors.toSet()); + } + + private boolean isGraphPathContainsAll(GraphPath graphPath, + Set vertex) { + Set allVertex = Sets.newHashSet(); + for (DefaultEdge edge : graphPath.getEdgeList()) { + allVertex.add(graphPath.getGraph().getEdgeSource(edge)); + allVertex.add(graphPath.getGraph().getEdgeTarget(edge)); + } + Collection intersect = + org.apache.commons.collections.CollectionUtils.intersection(vertex, allVertex); + + return intersect.size() == vertex.size() ? true : false; + } + + private Graph buildGraph(List joinRelations) { + Graph directedGraph = new DefaultUndirectedGraph<>(DefaultEdge.class); + for (JoinRelation joinRelation : joinRelations) { + directedGraph.addVertex(joinRelation.getLeft()); + directedGraph.addVertex(joinRelation.getRight()); + directedGraph.addEdge(joinRelation.getLeft(), joinRelation.getRight()); + } + return directedGraph; + } + + private SqlNode optimizeParseNode(SqlNode parserNode, EngineType engineType) + throws SqlParseException { if (Objects.isNull(schema.getRuntimeOptions()) || Objects.isNull(schema.getRuntimeOptions().getEnableOptimize()) || !schema.getRuntimeOptions().getEnableOptimize()) { @@ -62,14 +135,10 @@ public class SqlBuilder { } SqlNode optimizeNode = null; - try { - SqlNode sqlNode = SqlParser.create(SemanticNode.getSql(parserNode, engineType), - Configuration.getParserConfig(engineType)).parseStmt(); - if (Objects.nonNull(sqlNode)) { - optimizeNode = SemanticNode.optimize(scope, schema, sqlNode, engineType); - } - } catch (Exception e) { - log.error("optimize error {}", e); + SqlNode sqlNode = SqlParser.create(SemanticNode.getSql(parserNode, engineType), + Configuration.getParserConfig(engineType)).parseStmt(); + if (Objects.nonNull(sqlNode)) { + optimizeNode = SemanticNode.optimize(scope, schema, sqlNode, engineType); } if (Objects.nonNull(optimizeNode)) { @@ -79,7 +148,7 @@ public class SqlBuilder { return parserNode; } - private TableView render(OntologyQuery ontologyQuery, List dataModels, + private TableView render(OntologyQuery ontologyQuery, Set dataModels, SqlValidatorScope scope, S2CalciteSchema schema) throws Exception { SqlNode left = null; TableView leftTable = null; @@ -88,8 +157,7 @@ public class SqlBuilder { Map beforeModels = new HashMap<>(); EngineType engineType = EngineType.fromString(schema.getOntology().getDatabase().getType()); - for (int i = 0; i < dataModels.size(); i++) { - final ModelResp dataModel = dataModels.get(i); + for (ModelResp dataModel : dataModels) { final Set queryDimensions = ontologyQuery.getDimensionsByModel(dataModel.getName()); final Set queryMetrics = @@ -141,7 +209,8 @@ public class SqlBuilder { SqlLiteral sqlLiteral = SemanticNode.getJoinSqlLiteral(""); JoinRelation matchJoinRelation = getMatchJoinRelation(before, rightTable, schema); SqlNode joinRelationCondition; - if (!CollectionUtils.isEmpty(matchJoinRelation.getJoinCondition())) { + if (!org.apache.commons.collections.CollectionUtils + .isEmpty(matchJoinRelation.getJoinCondition())) { sqlLiteral = SemanticNode.getJoinSqlLiteral(matchJoinRelation.getJoinType()); joinRelationCondition = getCondition(matchJoinRelation, scope, engineType); condition = joinRelationCondition; @@ -170,12 +239,19 @@ public class SqlBuilder { } else if (joinRelation.getLeft() .equalsIgnoreCase(tableView.getDataModel().getName()) && before.containsKey(joinRelation.getRight())) { - matchJoinRelation.setJoinCondition(joinRelation.getJoinCondition().stream() + List> candidateJoinCon = joinRelation + .getJoinCondition().stream() .map(r -> Triple.of( before.get(joinRelation.getRight()) + "." + r.getRight(), r.getMiddle(), tableView.getAlias() + "." + r.getLeft())) - .collect(Collectors.toList())); - matchJoinRelation.setJoinType(joinRelation.getJoinType()); + .collect(Collectors.toList()); + // added by jerryjzhang on 20250214 + // use the one with the most conditions to join left and right tables + if (matchJoinRelation.getJoinCondition() == null || candidateJoinCon + .size() > matchJoinRelation.getJoinCondition().size()) { + matchJoinRelation.setJoinCondition(candidateJoinCon); + matchJoinRelation.setJoinType(joinRelation.getJoinType()); + } } } } diff --git a/headless/server/src/main/java/com/tencent/supersonic/headless/server/rest/DataSetController.java b/headless/server/src/main/java/com/tencent/supersonic/headless/server/rest/DataSetController.java index 3d3822da9..796cef2e0 100644 --- a/headless/server/src/main/java/com/tencent/supersonic/headless/server/rest/DataSetController.java +++ b/headless/server/src/main/java/com/tencent/supersonic/headless/server/rest/DataSetController.java @@ -2,6 +2,7 @@ package com.tencent.supersonic.headless.server.rest; import com.tencent.supersonic.auth.api.authentication.utils.UserHolder; import com.tencent.supersonic.common.pojo.User; +import com.tencent.supersonic.common.pojo.enums.StatusEnum; import com.tencent.supersonic.headless.api.pojo.MetaFilter; import com.tencent.supersonic.headless.api.pojo.request.DataSetReq; import com.tencent.supersonic.headless.api.pojo.response.DataSetResp; @@ -51,6 +52,7 @@ public class DataSetController { public List getDataSetList(@RequestParam("domainId") Long domainId) { MetaFilter metaFilter = new MetaFilter(); metaFilter.setDomainId(domainId); + metaFilter.setStatus(StatusEnum.ONLINE.getCode()); return dataSetService.getDataSetList(metaFilter); } diff --git a/headless/server/src/main/java/com/tencent/supersonic/headless/server/service/impl/DataSetServiceImpl.java b/headless/server/src/main/java/com/tencent/supersonic/headless/server/service/impl/DataSetServiceImpl.java index 3df28ce9f..9c1fee36e 100644 --- a/headless/server/src/main/java/com/tencent/supersonic/headless/server/service/impl/DataSetServiceImpl.java +++ b/headless/server/src/main/java/com/tencent/supersonic/headless/server/service/impl/DataSetServiceImpl.java @@ -56,9 +56,9 @@ public class DataSetServiceImpl extends ServiceImpl public DataSetResp save(DataSetReq dataSetReq, User user) { dataSetReq.createdBy(user.getName()); DataSetDO dataSetDO = convert(dataSetReq); - dataSetDO.setStatus(StatusEnum.ONLINE.getCode()); + dataSetDO.setStatus(dataSetReq.getStatus() != null ? dataSetReq.getStatus() + : StatusEnum.ONLINE.getCode()); DataSetResp dataSetResp = convert(dataSetDO); - // conflictCheck(dataSetResp); save(dataSetDO); dataSetResp.setId(dataSetDO.getId()); return dataSetResp; diff --git a/launchers/standalone/src/main/resources/application-docker.yaml b/launchers/standalone/src/main/resources/application-docker.yaml index 8ec7476d5..326af1d99 100644 --- a/launchers/standalone/src/main/resources/application-docker.yaml +++ b/launchers/standalone/src/main/resources/application-docker.yaml @@ -4,9 +4,9 @@ spring: url: jdbc:postgresql://${DB_HOST}:${DB_PORT:5432}/${DB_NAME}?stringtype=unspecified username: ${DB_USERNAME} password: ${DB_PASSWORD} - sql: init: + continue-on-error: true mode: always username: ${DB_USERNAME} password: ${DB_PASSWORD} diff --git a/launchers/standalone/src/main/resources/db/schema-mysql.sql b/launchers/standalone/src/main/resources/db/schema-mysql.sql index 8d18fa8d4..f9d330177 100644 --- a/launchers/standalone/src/main/resources/db/schema-mysql.sql +++ b/launchers/standalone/src/main/resources/db/schema-mysql.sql @@ -5,21 +5,21 @@ CREATE TABLE IF NOT EXISTS `s2_agent` ( `examples` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, `status` tinyint DEFAULT NULL, `model` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, - `tool_config` varchar(6000) COLLATE utf8_unicode_ci DEFAULT NULL, - `llm_config` varchar(2000) COLLATE utf8_unicode_ci DEFAULT NULL, + `tool_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, + `llm_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, `chat_model_config` text COLLATE utf8_unicode_ci DEFAULT NULL, - `visual_config` varchar(2000) COLLATE utf8_unicode_ci DEFAULT NULL, + `visual_config` TEXT COLLATE utf8_unicode_ci DEFAULT NULL, `enable_search` tinyint DEFAULT 1, `enable_feedback` tinyint DEFAULT 1, `created_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `created_at` datetime DEFAULT NULL, `updated_by` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `updated_at` datetime DEFAULT NULL, - `admin` varchar(3000) DEFAULT NULL COMMENT '管理员', - `admin_org` varchar(3000) DEFAULT NULL COMMENT '管理员组织', + `admin` varchar(1000) DEFAULT NULL COMMENT '管理员', + `admin_org` varchar(1000) DEFAULT NULL COMMENT '管理员组织', `is_open` tinyint DEFAULT NULL COMMENT '是否公开', - `viewer` varchar(3000) DEFAULT NULL COMMENT '可用用户', - `view_org` varchar(3000) DEFAULT NULL COMMENT '可用组织', + `viewer` varchar(1000) DEFAULT NULL COMMENT '可用用户', + `view_org` varchar(1000) DEFAULT NULL COMMENT '可用组织', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/pom.xml b/pom.xml index a71d1f501..da1164b3c 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ - 0.9.10-SNAPSHOT + 1.0.0-SNAPSHOT 21 21 21 @@ -82,6 +82,7 @@ false 4.2.1 1.12.780 + 1.5.2 @@ -236,6 +237,11 @@ aws-java-sdk ${aws-java-sdk.version} + + org.jgrapht + jgrapht-core + ${jgrapht.version} + diff --git a/webapp/packages/supersonic-fe/config/config.ts b/webapp/packages/supersonic-fe/config/config.ts index cbb160b86..3390eb348 100644 --- a/webapp/packages/supersonic-fe/config/config.ts +++ b/webapp/packages/supersonic-fe/config/config.ts @@ -155,29 +155,8 @@ export default defineConfig({ //================ pro 插件配置 ================= presets: ['umi-presets-pro'], - /** - * @name openAPI 插件的配置 - * @description 基于 openapi 的规范生成serve 和mock,能减少很多样板代码 - * @doc https://pro.ant.design/zh-cn/docs/openapi/ - */ - // openAPI: [ - // { - // requestLibPath: "import { request } from '@umijs/max'", - // // 或者使用在线的版本 - // // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" - // schemaPath: join(__dirname, 'oneapi.json'), - // mock: false, - // }, - // { - // requestLibPath: "import { request } from '@umijs/max'", - // schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', - // projectName: 'swagger', - // }, - // ], - // 将insights-flow相关包排除出mfsu编译,在pnpm link 模式下保持热更新 mfsu: { strategy: 'normal', - // exclude: ['supersonic-insights-flow-components', 'supersonic-insights-flow-core'], }, requestRecord: {}, exportStatic: {}, diff --git a/webapp/packages/supersonic-fe/public/icons/icon-128x128.png b/webapp/packages/supersonic-fe/public/icons/icon-128x128.png deleted file mode 100644 index 48d0e2339..000000000 Binary files a/webapp/packages/supersonic-fe/public/icons/icon-128x128.png and /dev/null differ diff --git a/webapp/packages/supersonic-fe/public/icons/icon-192x192.png b/webapp/packages/supersonic-fe/public/icons/icon-192x192.png deleted file mode 100644 index 938e9b53f..000000000 Binary files a/webapp/packages/supersonic-fe/public/icons/icon-192x192.png and /dev/null differ diff --git a/webapp/packages/supersonic-fe/public/icons/icon-512x512.png b/webapp/packages/supersonic-fe/public/icons/icon-512x512.png deleted file mode 100644 index 21fc108f0..000000000 Binary files a/webapp/packages/supersonic-fe/public/icons/icon-512x512.png and /dev/null differ diff --git a/webapp/packages/supersonic-fe/src/app.tsx b/webapp/packages/supersonic-fe/src/app.tsx index bcc5d7a69..7ebaf6ea6 100644 --- a/webapp/packages/supersonic-fe/src/app.tsx +++ b/webapp/packages/supersonic-fe/src/app.tsx @@ -147,8 +147,8 @@ export const layout: RunTimeLayoutConfig = (params) => { height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined, }} > - - {/* {dom} */} + {/* */} + {dom} {history.location.pathname !== '/chat' && !isMobile && ( )} diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DomainList.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DomainList.tsx index 59306b816..c62714fe4 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DomainList.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/DomainList.tsx @@ -1,9 +1,9 @@ import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; -import { Input, message, Popconfirm, Tooltip, Row, Col, Button, Menu } from 'antd'; +import { Input, message, Popconfirm, Tooltip, Row, Col, Button, Menu, MenuProps } from 'antd'; import type { DataNode } from 'antd/lib/tree'; import { useEffect, useState } from 'react'; import type { FC } from 'react'; -import { useModel } from '@umijs/max'; +import { useModel, history } from '@umijs/max'; import { createDomain, updateDomain, deleteDomain } from '../service'; import DomainInfoForm from './DomainInfoForm'; import styles from './style.less'; @@ -71,6 +71,7 @@ const DomainListTree: FC = ({ message.success('编辑分类成功'); setProjectInfoModalVisible(false); onTreeDataUpdate?.(); + window.location.reload(); } else { message.error(res.msg); } @@ -78,10 +79,13 @@ const DomainListTree: FC = ({ const domainSubmit = async (values: any) => { if (values.modelType === 'add') { - const { code, data } = await createDomain(values); - // if (code === 200 && values.type === 'top') { - // await createDefaultModelSet(data.id); - // } + const { code, data, msg } = await createDomain(values); + if (code === 200) { + history.push(`/model/domain/${data.id}`); + window.location.reload(); + } else { + message.error(msg); + } } else if (values.modelType === 'edit') { await editProject(values); } @@ -95,6 +99,7 @@ const DomainListTree: FC = ({ message.success('删除成功'); setProjectInfoModalVisible(false); onTreeDataUpdate?.(); + window.location.reload(); } else { message.error(res.msg); } @@ -104,12 +109,7 @@ const DomainListTree: FC = ({ const { id, name, path, hasEditPermission, parentId, hasModel } = node as any; const type = parentId === 0 ? 'top' : 'normal'; return ( -
{ - // handleSelect(id); - // }} - > +
{name} {createDomainBtnVisible && hasEditPermission && ( @@ -175,13 +175,12 @@ const DomainListTree: FC = ({ return { key: domain.id, label: titleRender(domain), - // icon: , }; }); - const getLevelKeys = (items1: LevelKeysProps[]) => { + const getLevelKeys = (items1: any[]) => { const key: Record = {}; - const func = (items2: LevelKeysProps[], level = 1) => { + const func = (items2: any[], level = 1) => { items2.forEach((item) => { if (item.key) { key[item.key] = level; @@ -194,7 +193,7 @@ const DomainListTree: FC = ({ func(items1); return key; }; - const levelKeys = getLevelKeys(items as LevelKeysProps[]); + const levelKeys = getLevelKeys(items as any[]); const [stateOpenKeys, setStateOpenKeys] = useState(['2', '23']); const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => { diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx index 15641e66a..484497f9e 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx @@ -82,6 +82,7 @@ const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelC }); if (code === 200) { onModelChange?.(); + window.location.reload(); return; } message.error(msg); @@ -198,6 +199,7 @@ const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelC const { code, msg } = await deleteModel(record.id); if (code === 200) { onModelChange?.(); + window.location.reload(); } else { message.error(msg); } @@ -292,6 +294,7 @@ const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelC onModelChange?.(); setIsEditing(false); setCreateDataSourceModalOpen(false); + window.location.reload(); }} onCancel={() => { setIsEditing(false); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/index.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/index.tsx index 11dda227f..4926719dd 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/index.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/index.tsx @@ -1,11 +1,8 @@ import { message } from 'antd'; -import React, { useEffect, useState } from 'react'; -import { history, useParams, useModel, Outlet } from '@umijs/max'; -import DomainListTree from './components/DomainList'; -import styles from './components/style.less'; -import { LeftOutlined, RightOutlined } from '@ant-design/icons'; +import React, { useEffect } from 'react'; +import { useParams, useModel, Outlet } from '@umijs/max'; import { ISemantic } from './data'; -import { getDomainList, getDataSetList, getModelDetail } from './service'; +import { getDomainList, getModelDetail } from './service'; import PageBreadcrumb from './PageBreadcrumb'; type Props = {}; @@ -17,20 +14,10 @@ const SemanticModel: React.FC = ({}) => { const domainModel = useModel('SemanticModel.domainData'); const modelModel = useModel('SemanticModel.modelData'); const databaseModel = useModel('SemanticModel.databaseData'); - const metricModel = useModel('SemanticModel.metricData'); - const { setSelectDomain, setDomainList, selectDomainId } = domainModel; - const { selectModel, setSelectModel, setModelTableHistoryParams, MrefreshModelList } = modelModel; + const { setSelectDomain, setDomainList } = domainModel; + const { selectModel, setSelectModel } = modelModel; const { MrefreshDatabaseList } = databaseModel; - const { selectMetric, setSelectMetric } = metricModel; - - // useEffect(() => { - - // return () => { - // setSelectMetric(undefined); - // } - // }, []) - const initSelectedDomain = (domainList: ISemantic.IDomainItem[]) => { const targetNode = domainList.filter((item: any) => { return `${item.id}` === domainId; @@ -40,9 +27,7 @@ const SemanticModel: React.FC = ({}) => { return item.parentId === 0; })[0]; if (firstRootNode) { - const { id } = firstRootNode; setSelectDomain(firstRootNode); - // pushUrlMenu(id, menuKey); } } else { setSelectDomain(targetNode); @@ -87,7 +72,6 @@ const SemanticModel: React.FC = ({}) => {
- {/* */}
); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/models/domainData.ts b/webapp/packages/supersonic-fe/src/pages/SemanticModel/models/domainData.ts index 160bfbc3b..867965a0c 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/models/domainData.ts +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/models/domainData.ts @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import { useModel } from '@umijs/max'; export default function Domain() { - const [selectDomain, setSelectDomain] = useState( + const [selectDomain, setSelectDomain] = useState( {} as ISemantic.IDomainItem, ); const [selectDataSet, setSelectDataSet] = useState();