mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-19 13:04:21 +08:00
Merge remote-tracking branch 'origin/master' into jsqlparser-fix
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 .
|
||||
|
||||
|
||||
@@ -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:
|
||||
supersonic_network:
|
||||
|
||||
@@ -133,6 +133,10 @@
|
||||
<groupId>io.trino</groupId>
|
||||
<artifactId>trino-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ModelResp> 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<ModelResp> probeRelatedModels(Set<ModelResp> dataModels, Ontology ontology) {
|
||||
List<JoinRelation> joinRelations = ontology.getJoinRelations();
|
||||
Graph<String, DefaultEdge> graph = buildGraph(joinRelations);
|
||||
DijkstraShortestPath<String, DefaultEdge> dijkstraAlg = new DijkstraShortestPath<>(graph);
|
||||
Set<String> queryModels =
|
||||
dataModels.stream().map(ModelResp::getName).collect(Collectors.toSet());
|
||||
GraphPath<String, DefaultEdge> selectedGraphPath = null;
|
||||
for (String fromModel : queryModels) {
|
||||
for (String toModel : queryModels) {
|
||||
if (fromModel != toModel) {
|
||||
GraphPath<String, DefaultEdge> path = dijkstraAlg.getPath(fromModel, toModel);
|
||||
if (isGraphPathContainsAll(path, queryModels)) {
|
||||
selectedGraphPath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedGraphPath == null) {
|
||||
return dataModels;
|
||||
}
|
||||
Set<String> 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<String, DefaultEdge> graphPath,
|
||||
Set<String> vertex) {
|
||||
Set<String> allVertex = Sets.newHashSet();
|
||||
for (DefaultEdge edge : graphPath.getEdgeList()) {
|
||||
allVertex.add(graphPath.getGraph().getEdgeSource(edge));
|
||||
allVertex.add(graphPath.getGraph().getEdgeTarget(edge));
|
||||
}
|
||||
Collection<String> intersect =
|
||||
org.apache.commons.collections.CollectionUtils.intersection(vertex, allVertex);
|
||||
|
||||
return intersect.size() == vertex.size() ? true : false;
|
||||
}
|
||||
|
||||
private Graph<String, DefaultEdge> buildGraph(List<JoinRelation> joinRelations) {
|
||||
Graph<String, DefaultEdge> 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<ModelResp> dataModels,
|
||||
private TableView render(OntologyQuery ontologyQuery, Set<ModelResp> dataModels,
|
||||
SqlValidatorScope scope, S2CalciteSchema schema) throws Exception {
|
||||
SqlNode left = null;
|
||||
TableView leftTable = null;
|
||||
@@ -88,8 +157,7 @@ public class SqlBuilder {
|
||||
Map<String, String> 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<DimSchemaResp> queryDimensions =
|
||||
ontologyQuery.getDimensionsByModel(dataModel.getName());
|
||||
final Set<MetricSchemaResp> 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<Triple<String, String, String>> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<DataSetResp> getDataSetList(@RequestParam("domainId") Long domainId) {
|
||||
MetaFilter metaFilter = new MetaFilter();
|
||||
metaFilter.setDomainId(domainId);
|
||||
metaFilter.setStatus(StatusEnum.ONLINE.getCode());
|
||||
return dataSetService.getDataSetList(metaFilter);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,9 @@ public class DataSetServiceImpl extends ServiceImpl<DataSetDOMapper, DataSetDO>
|
||||
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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
8
pom.xml
8
pom.xml
@@ -26,7 +26,7 @@
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<revision>0.9.10-SNAPSHOT</revision>
|
||||
<revision>1.0.0-SNAPSHOT</revision>
|
||||
<java.source.version>21</java.source.version>
|
||||
<java.target.version>21</java.target.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
@@ -82,6 +82,7 @@
|
||||
<spotless.skip>false</spotless.skip>
|
||||
<stax2.version>4.2.1</stax2.version>
|
||||
<aws-java-sdk.version>1.12.780</aws-java-sdk.version>
|
||||
<jgrapht.version>1.5.2</jgrapht.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -236,6 +237,11 @@
|
||||
<artifactId>aws-java-sdk</artifactId>
|
||||
<version>${aws-java-sdk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-core</artifactId>
|
||||
<version>${jgrapht.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -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: {},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -147,8 +147,8 @@ export const layout: RunTimeLayoutConfig = (params) => {
|
||||
height: location.pathname.includes('chat') ? 'calc(100vh - 56px)' : undefined,
|
||||
}}
|
||||
>
|
||||
<AppPage dom={dom} />
|
||||
{/* {dom} */}
|
||||
{/* <AppPage dom={dom} /> */}
|
||||
{dom}
|
||||
{history.location.pathname !== '/chat' && !isMobile && (
|
||||
<Copilot token={getToken() || ''} isDeveloper />
|
||||
)}
|
||||
|
||||
@@ -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<DomainListProps> = ({
|
||||
message.success('编辑分类成功');
|
||||
setProjectInfoModalVisible(false);
|
||||
onTreeDataUpdate?.();
|
||||
window.location.reload();
|
||||
} else {
|
||||
message.error(res.msg);
|
||||
}
|
||||
@@ -78,10 +79,13 @@ const DomainListTree: FC<DomainListProps> = ({
|
||||
|
||||
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<DomainListProps> = ({
|
||||
message.success('删除成功');
|
||||
setProjectInfoModalVisible(false);
|
||||
onTreeDataUpdate?.();
|
||||
window.location.reload();
|
||||
} else {
|
||||
message.error(res.msg);
|
||||
}
|
||||
@@ -104,12 +109,7 @@ const DomainListTree: FC<DomainListProps> = ({
|
||||
const { id, name, path, hasEditPermission, parentId, hasModel } = node as any;
|
||||
const type = parentId === 0 ? 'top' : 'normal';
|
||||
return (
|
||||
<div
|
||||
className={styles.projectItem}
|
||||
// onClick={() => {
|
||||
// handleSelect(id);
|
||||
// }}
|
||||
>
|
||||
<div className={styles.projectItem}>
|
||||
<span className={styles.projectItemTitle}>{name}</span>
|
||||
{createDomainBtnVisible && hasEditPermission && (
|
||||
<span className={`${styles.operation} ${styles.rowHover} `}>
|
||||
@@ -175,13 +175,12 @@ const DomainListTree: FC<DomainListProps> = ({
|
||||
return {
|
||||
key: domain.id,
|
||||
label: titleRender(domain),
|
||||
// icon: <AppstoreOutlined />,
|
||||
};
|
||||
});
|
||||
|
||||
const getLevelKeys = (items1: LevelKeysProps[]) => {
|
||||
const getLevelKeys = (items1: any[]) => {
|
||||
const key: Record<string, number> = {};
|
||||
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<DomainListProps> = ({
|
||||
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) => {
|
||||
|
||||
@@ -82,6 +82,7 @@ const ModelTable: React.FC<Props> = ({ modelList, disabledEdit = false, onModelC
|
||||
});
|
||||
if (code === 200) {
|
||||
onModelChange?.();
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
message.error(msg);
|
||||
@@ -198,6 +199,7 @@ const ModelTable: React.FC<Props> = ({ 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<Props> = ({ modelList, disabledEdit = false, onModelC
|
||||
onModelChange?.();
|
||||
setIsEditing(false);
|
||||
setCreateDataSourceModalOpen(false);
|
||||
window.location.reload();
|
||||
}}
|
||||
onCancel={() => {
|
||||
setIsEditing(false);
|
||||
|
||||
@@ -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<Props> = ({}) => {
|
||||
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<Props> = ({}) => {
|
||||
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<Props> = ({}) => {
|
||||
</div>
|
||||
<div>
|
||||
<Outlet />
|
||||
{/* <OverviewContainer /> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useState, useEffect } from 'react';
|
||||
import { useModel } from '@umijs/max';
|
||||
|
||||
export default function Domain() {
|
||||
const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem>(
|
||||
const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem | undefined>(
|
||||
{} as ISemantic.IDomainItem,
|
||||
);
|
||||
const [selectDataSet, setSelectDataSet] = useState<ISemantic.IDatasetItem>();
|
||||
|
||||
Reference in New Issue
Block a user