[Metadata] Remove invalid metadata manager (#465)

This commit is contained in:
qianmoQ 2023-11-06 13:22:41 +08:00 committed by GitHub
commit 353eca6c27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 324 additions and 1481 deletions

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,219 +0,0 @@
package io.edurt.datacap.server.scheduled;
import com.google.inject.Injector;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.common.enums.Type;
import io.edurt.datacap.common.utils.JsonUtils;
import io.edurt.datacap.schedule.ScheduledRunnable;
import io.edurt.datacap.service.common.PluginUtils;
import io.edurt.datacap.service.entity.SourceEntity;
import io.edurt.datacap.service.entity.TemplateSqlEntity;
import io.edurt.datacap.service.itransient.SqlConfigure;
import io.edurt.datacap.service.repository.SourceRepository;
import io.edurt.datacap.service.repository.TemplateSqlRepository;
import io.edurt.datacap.spi.Plugin;
import io.edurt.datacap.spi.model.Configure;
import io.edurt.datacap.spi.model.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Slf4j
@SuppressFBWarnings(value = "REC_CATCH_EXCEPTION")
public class SourceScheduledRunnable
extends ScheduledRunnable
{
public static final String DATABASE = "database";
public static final String TABLE = "table";
private static final String GET_ALL_DATABASES = "getAllDatabase";
private static final String GET_ALL_TABLES = "getAllTablesFromDatabase";
private static final String GET_ALL_COLUMNS = "getAllColumnsFromDatabaseAndTable";
private final Injector injector;
private final SourceRepository sourceRepository;
private final TemplateSqlRepository templateSqlRepository;
private final RedisTemplate redisTemplate;
private final Environment environment;
private int maxSuggestions;
public SourceScheduledRunnable(String name, Injector injector, SourceRepository sourceRepository, TemplateSqlRepository templateSqlRepository, RedisTemplate redisTemplate, Environment environment)
{
super(name);
this.injector = injector;
this.sourceRepository = sourceRepository;
this.templateSqlRepository = templateSqlRepository;
this.redisTemplate = redisTemplate;
this.environment = environment;
this.maxSuggestions = Integer.parseInt(environment.getProperty("datacap.editor.sugs.maxSize"));
}
@Override
public void run()
{
this.sourceRepository.findAll().forEach(entity -> {
log.info("==================== {} ---> {} started =================", this.getName(), entity.getName());
Optional<Plugin> pluginOptional = PluginUtils.getPluginByNameAndType(this.injector, entity.getType(), entity.getProtocol());
if (!pluginOptional.isPresent()) {
log.warn("The scheduled task <{}> source {} protocol {} is not available", this.getName(), entity.getType(), entity.getProtocol());
}
else {
long startTime = System.currentTimeMillis();
String name = String.format("%s_%s", entity.getName(), entity.getId());
log.info("The scheduled task <{}> execution start - child{} start with {}", this.getName(), name, startTime);
// Get all databases
TemplateSqlEntity getAllDatabaseEntity = this.templateSqlRepository.findByNameAndPluginContaining(GET_ALL_DATABASES, entity.getType());
if (ObjectUtils.isEmpty(getAllDatabaseEntity)) {
log.warn("The scheduled task {} template {} is not available", this.getName(), entity.getName(), GET_ALL_DATABASES);
}
else {
// Clear redis cache
String key = String.join("_", entity.getType(), entity.getId().toString());
long counter = redisTemplate.opsForSet().size(key);
redisTemplate.delete(key);
log.info("The scheduled task {} child {} type {} find keys counter: {} is cleaned", this.getName(), entity.getName(), entity.getType(), counter);
this.processDatabase(entity, getContent(getAllDatabaseEntity, null), pluginOptional.get(), DATABASE, key);
}
long endTime = System.currentTimeMillis();
long times = endTime - startTime;
log.info("The scheduled task <{}> execution end - child{} end with {} consuming{} millisecond", this.getName(), name, endTime, times);
}
log.info("==================== {} ---> {} end =================", this.getName(), entity.getName());
});
}
private Configure getConfigure(SourceEntity entity)
{
Configure configure = new Configure();
configure.setHost(entity.getHost());
configure.setPort(entity.getPort());
configure.setUsername(Optional.ofNullable(entity.getUsername()));
configure.setPassword(Optional.ofNullable(entity.getPassword()));
Optional<String> database = StringUtils.isNotEmpty(entity.getDatabase()) ? Optional.ofNullable(entity.getDatabase()) : Optional.empty();
configure.setDatabase(database);
configure.setSsl(Optional.ofNullable(entity.getSsl()));
configure.setEnv(Optional.ofNullable(entity.getConfigures()));
return configure;
}
private String getContent(TemplateSqlEntity entity, Map<String, String> configure)
{
try {
if (ObjectUtils.isNotEmpty(entity.getConfigure())) {
final String[] content = {entity.getContent()};
List<LinkedHashMap> configures = JsonUtils.objectmapper.readValue(entity.getConfigure(), List.class);
configure.entrySet().forEach(value -> {
Optional<SqlConfigure> sqlConfigure = configures.stream().filter(v -> String.valueOf(v.get("column")).equalsIgnoreCase(value.getKey())).map(v -> {
SqlConfigure configure1 = new SqlConfigure();
configure1.setColumn(v.get("column").toString());
configure1.setType(Type.valueOf(String.valueOf(v.get("type"))));
configure1.setExpression(String.valueOf(v.get("expression")));
return configure1;
}).findFirst();
if (sqlConfigure.isPresent()) {
content[0] = content[0].replace(sqlConfigure.get().getExpression(), String.valueOf(value.getValue()));
}
});
return content[0];
}
}
catch (Exception e) {
log.warn("Failed to analysis");
return entity.getContent();
}
return entity.getContent();
}
/**
* Get all databases of the configuration data source and buffer them to Redis
*/
private void processDatabase(SourceEntity entity, String content, Plugin plugin, String type, String key)
{
plugin.connect(getConfigure(entity));
Response response = plugin.execute(content);
if (response.getIsSuccessful()) {
TemplateSqlEntity getAllTableEntity = templateSqlRepository.findByNameAndPluginContaining(GET_ALL_TABLES, entity.getType());
if (ObjectUtils.isEmpty(getAllTableEntity)) {
log.warn("The scheduled task {} template {} is not available", this.getName(), entity.getName(), GET_ALL_TABLES);
}
else {
response.getColumns()
.stream()
.limit(maxSuggestions)
.forEach(column -> {
String database = ((List<String>) column).get(0);
log.info("The scheduled task {} child {} sync data from source : {}", this.getName(), entity.getName(), database);
Map<String, String> configure = new HashMap<>();
configure.put("database", database);
this.processTable(entity, this.getContent(getAllTableEntity, configure), database, plugin, key);
});
}
}
else {
log.warn("The scheduled task {} child {} type {} sync data from source is failed {}", this.getName(), entity.getName(), type, response.getMessage());
}
plugin.destroy();
}
private void processTable(SourceEntity entity, String content, String database, Plugin plugin, String key)
{
plugin.connect(getConfigure(entity));
Response response = plugin.execute(content);
if (response.getIsSuccessful()) {
TemplateSqlEntity getAllChildEntity = templateSqlRepository.findByNameAndPluginContaining(GET_ALL_COLUMNS, entity.getType());
if (ObjectUtils.isEmpty(getAllChildEntity)) {
log.warn("The scheduled task {} template {} is not available", this.getName(), entity.getName(), GET_ALL_COLUMNS);
}
else {
response.getColumns()
.stream()
.limit(maxSuggestions)
.forEach(column -> {
String table = ((List<String>) column).get(0);
log.info("The scheduled task {} child {} database {} sync data from source is : {}", this.getName(), entity.getName(), database, table);
Map<String, String> configure = new HashMap<>();
configure.put("table", String.join(".", database, table));
this.processColumn(entity, this.getContent(getAllChildEntity, configure), database, table, plugin, key);
});
}
}
else {
log.warn("The scheduled task {} child {} database {} sync data from source is failed {}", this.getName(), entity.getName(), database, response.getMessage());
}
plugin.destroy();
}
private void processColumn(SourceEntity entity, String content, String database, String table, Plugin plugin, String key)
{
plugin.connect(getConfigure(entity));
Response response = plugin.execute(content);
if (response.getIsSuccessful()) {
TemplateSqlEntity getAllChildEntity = templateSqlRepository.findByNameAndPluginContaining(GET_ALL_COLUMNS, entity.getType());
if (ObjectUtils.isEmpty(getAllChildEntity)) {
log.warn("The scheduled task {} template {} is not available", this.getName(), entity.getName(), GET_ALL_COLUMNS);
}
else {
response.getColumns()
.stream()
.limit(maxSuggestions)
.forEach(column -> {
String value = ((List<String>) column).get(0);
log.info("The scheduled task {} child {} database {} table {} sync data from source is : {}", this.getName(), entity.getName(), database, table, value);
redisTemplate.opsForSet().add(key, String.join(".", database, table, value));
});
}
}
else {
log.warn("The scheduled task {} child {} database {} table {} sync data from source is failed {}", this.getName(), entity.getName(), database, table, response.getMessage());
}
plugin.destroy();
}
}

View File

@ -0,0 +1,3 @@
DELETE
FROM `template_sql`
WHERE `name` in ('getAllDatabase', 'getAllDatabaseAndTable', 'getAllTablesFromDatabase', 'getAllColumnsFromDatabaseAndTable');

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,7 +1,7 @@
{
"name": "datacap-console",
"description": "DataCap console",
"version": "1.16.0",
"version": "1.17.0-SNAPSHOT",
"private": true,
"scripts": {
"dev": "vue-cli-service serve",

View File

@ -1,139 +0,0 @@
<template>
<div style="max-height: 500px; max-width: 200px; overflow: auto;">
<SkeletonItem v-if="loading" :animated="true" type="rect" size="large" style="width: 165px;"/>
<Tree v-else :data="dataTreeArray" :load-data="handlerLoadChildData" @on-select-change="handlerSelectNode"/>
</div>
</template>
<script lang="ts">
import {defineComponent, watch} from "vue";
import MangerService from "@/services/source/MangerService";
import useClipboard from "vue-clipboard3";
const {toClipboard} = useClipboard();
export enum DataTreeLevel
{
database,
table,
column
}
export class DataTree
{
title: null;
database: null;
table: null;
level: DataTreeLevel = DataTreeLevel.database;
loading = false;
children: DataTree[] = [];
}
export default defineComponent({
name: "DataLazyTree",
props: {
id: {
type: String,
default: () => ''
},
type: {
type: String,
default: () => ''
}
},
data()
{
return {
loading: false,
dataTreeArray: []
}
},
created()
{
this.handlerInitialize();
watch(() => this.id, () => {
this.handlerInitialize();
}
);
},
methods: {
handlerInitialize()
{
this.dataTreeArray = [];
this.loading = true;
MangerService.getDatabases(this.id)
.then(response => {
if (response.status) {
const header = response.data.headers[0];
response.data.columns.forEach(column => {
const data = new DataTree();
data.title = column[header];
this.dataTreeArray.push(data);
});
}
})
.finally(() => {
this.loading = false;
});
},
handlerLoadChildData(item: DataTree, callback)
{
const dataChildArray = [];
if (item.level === DataTreeLevel.database) {
MangerService.getTables(this.id, item.title)
.then(response => {
if (response.status) {
const header = response.data.headers[0];
response.data.columns.forEach(column => {
const data = new DataTree();
data.title = column[header];
data.database = item.title;
data.level = DataTreeLevel.table;
dataChildArray.push(data);
});
}
})
.finally(() => {
callback(dataChildArray);
});
}
else if (item.level === DataTreeLevel.table) {
MangerService.getColumns(this.id, item.database, item.title)
.then(response => {
if (response.status) {
const header = response.data.headers[0];
response.data.columns.forEach(column => {
const data = {
title: column[header],
database: item.database,
table: item.title,
level: DataTreeLevel.column
};
dataChildArray.push(data);
});
}
})
.finally(() => {
callback(dataChildArray);
});
}
else {
callback(dataChildArray);
}
},
handlerSelectNode(item: DataTree)
{
const target = item[0];
let text: string = target.title;
switch (target.level) {
case DataTreeLevel.table:
text = target.database + '.' + text;
break
case DataTreeLevel.column:
text = target.database + '.' + target.table + '.' + text;
break
}
toClipboard(text).finally(() => this.$Message.success('Copy successful!'));
}
}
});
</script>

View File

@ -1,106 +0,0 @@
<template>
<div style="max-height: 500px; max-width: 200px; overflow: auto;">
<SkeletonItem v-if="loading" :animated="true" type="rect" size="large" style="width: 165px;"/>
<Tree v-else :data="treeData" :render="renderContent"/>
</div>
</template>
<script lang="ts">
import {defineComponent, resolveComponent, watch} from "vue";
import {TreeService} from "@/services/TreeService";
import {TreeData} from "@/model/TreeData";
import useClipboard from 'vue-clipboard3';
import TemplateSqlService from "@/services/template/TemplateSqlService";
import {SqlBody} from "@/model/template/SqlBody";
const {toClipboard} = useClipboard();
export default defineComponent({
name: "DatabaseTree",
props: {
id: {
type: String,
default: () => ''
},
type: {
type: String,
default: () => ''
}
},
data()
{
return {
treeData: [] as TreeData[],
loading: false
}
},
created()
{
this.handlerInitialize();
watch(() => this.id, () => {
this.handlerInitialize();
}
);
},
methods: {
renderContent(h, {data})
{
return h('span',
{
style: {
display: 'inline-block',
width: '100%'
}
},
[
h(resolveComponent('Ellipsis'), {
text: data.title,
length: 15,
tooltip: true,
transfer: true,
onClick: () => {
this.handlerCopy(data.database, data.table, data.value, data.dataType);
}
})
]);
},
handlerInitialize()
{
this.treeData = [];
this.loading = true;
const sqlBody: SqlBody = {
templateName: 'getAllDatabaseAndTable',
sourceId: this.id,
configure: {}
}
TemplateSqlService.execute(sqlBody)
.then((response) => {
if (response.status) {
this.treeData = new TreeService().getTree(response);
}
else {
this.$Message.error(response.message);
}
})
.finally(() => {
this.loading = false;
});
},
handlerCopy(database: string, table: string, value: string, dataType: string)
{
let text: string = value;
switch (dataType) {
case 'database':
text = database;
break;
case 'table':
text = database + '.' + table;
break
case 'column':
text = database + '.' + table + '.' + value;
break
}
toClipboard(text).finally(() => this.$Message.success('Copy successful!'));
}
}
});
</script>

View File

@ -130,12 +130,6 @@ const createDefaultRouter = (router: any) => {
meta: {title: 'common.source'},
layout: LayoutContainer,
component: () => import("../views/admin/source/SourceManager.vue")
},
{
path: "source/:id/managerBeta",
meta: {title: 'common.source'},
layout: LayoutContainer,
component: () => import("../views/admin/source/SourceManagerBeta.vue")
}
]
})

View File

@ -1,174 +0,0 @@
import {ResponseModel} from "@/model/ResponseModel";
import TemplateSqlService from "@/services/template/TemplateSqlService";
import {SqlBody} from "@/model/template/SqlBody";
import {ExecuteService} from "@/services/ExecuteService";
import {Sql} from "@/model/sql/Sql";
import {ExecuteDslBodyBuilder} from "@/model/ExecuteDslBody";
import {SqlBodyBuilder} from "@/model/builder/SqlBody";
import {SqlType} from "@/model/builder/SqlType";
import {SqlColumn, SqlColumnBuilder} from "@/model/builder/SqlColumn";
import {SqlOrder} from "@/model/builder/SqlOrder";
class ManagerService
{
getDatabases(id: number): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: undefined,
sourceId: id,
templateName: 'getAllDatabase'
};
return TemplateSqlService.execute(configure);
}
/**
* Finds all table types under the database according to the database
* Template: FindTableTypeByDatabase
* @param id The selected data source tag, which is stored in the database
* @param database The query database name
*/
findTableTypeByDatabase(id: number, database: string): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
database: database
},
sourceId: id,
templateName: 'FindTableTypeByDatabase'
};
return TemplateSqlService.execute(configure);
}
/**
* Gets a collection of related data based on the specified database and data type
* Template: FindTableByDatabaseAndType
* @param id The selected data source tag, which is stored in the database
* @param database The query database name
* @param type The query table type
*/
getTableDataByDatabaseAndType(id: number, database: string, type: string): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
database: database,
type: type
},
sourceId: id,
templateName: 'FindTableByDatabaseAndType'
};
return TemplateSqlService.execute(configure);
}
/**
* Gets the data column classification collection based on the provided database and data table
* Template: FindColumnTypeByDatabaseAndTable
* @param id The selected data source tag, which is stored in the database
* @param database The query database name
* @param table The query table name
*/
findColumnTypeByDatabaseAndTable(id: number, database: string, table: string): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
database: database,
table: table
},
sourceId: id,
templateName: 'FindColumnTypeByDatabaseAndTable'
};
return TemplateSqlService.execute(configure);
}
/**
* Gets a collection of related data based on the specified database, table, and data type
* Template: FindColumnByDatabaseAndTableAndType
* @param id The selected data source tag, which is stored in the database
* @param database The query database name
* @param table The query table name
* @param type The query table type
*/
getColumnDataByDatabaseAndTableAndType(id: number, database: string, table: string, type: string): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
database: database,
table: table,
type: type
},
sourceId: id,
templateName: 'FindColumnByDatabaseAndTableAndType'
};
return TemplateSqlService.execute(configure);
}
getTables(id: number, database: string): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
database: database
},
sourceId: id,
templateName: 'getAllTablesFromDatabase'
};
return TemplateSqlService.execute(configure);
}
getColumns(id: number, database: string, table): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
table: database + '.' + table
},
sourceId: id,
templateName: 'getAllColumnsFromDatabaseAndTable'
};
return TemplateSqlService.execute(configure);
}
getData(id: number, database: string, table: string, page: number, size: number): Promise<ResponseModel>
{
const configure: SqlBody = {
configure: {
table: database + '.' + table,
page: page,
size: size
},
sourceId: id,
templateName: 'getDataFromDatabaseAndTableLimited'
};
return TemplateSqlService.execute(configure);
}
getDataByConfigure(id: string, sql: Sql): Promise<ResponseModel>
{
const columns: SqlColumn[] = new Array<SqlColumn>();
if (sql.columns.length > 0) {
sql.columns.forEach(column => columns.push(new SqlColumnBuilder(column).build()));
}
else {
columns.push(new SqlColumnBuilder('*').build());
}
// The default offset is 1, and the database index defaults to 0, which needs to be subtracted by 1
const orders: SqlColumn[] = new Array();
if (sql.sort) {
sql.sort.forEach(order => {
orders.push(new SqlColumnBuilder(order.column).setOrder(SqlOrder[order.sort.toUpperCase()]).build());
});
}
const sqlBody = new SqlBodyBuilder(sql.database, sql.table)
.setColumns(columns)
.setOrders(orders)
.setType(SqlType.SELECT)
.setLimit(sql.limit)
.setOffset(sql.offset - 1)
.setWhere(sql.where)
.build();
const configure = new ExecuteDslBodyBuilder(id, 'JSON')
.setConfigure(sqlBody)
.build();
return new ExecuteService().executeDsl(configure);
}
}
export default new ManagerService();

View File

@ -67,14 +67,6 @@
<Button :disabled="currentUserId !== row.user.id" shape="circle" type="error" size="small" icon="md-trash"/>
</Poptip>
</Tooltip>
<Tooltip :content="$t('common.admin')" transfer>
<Button :disabled="currentUserId !== row.user.id || !row.available"
shape="circle" type="info"
size="small"
icon="md-construct"
:to="'/admin/source/' + row.id + '/manager'">
</Button>
</Tooltip>
<Tooltip :content="$t('common.admin') + $t('common.beta')"
transfer>
<Button :disabled="currentUserId !== row.user.id || !row.available"
@ -82,7 +74,7 @@
type="info"
size="small"
icon="md-construct"
:to="'/admin/source/' + row.id + '/managerBeta'">
:to="'/admin/source/' + row.id + '/manager'">
</Button>
</Tooltip>
</Space>

View File

@ -1,177 +1,145 @@
<template>
<div style="padding: 0">
<SourceNotSupported v-if="!isSupported" :templateName="templateArray" style="margin-top: 50px;"></SourceNotSupported>
<div v-else ref="splitContainer" class="split-container">
<Split v-model="splitModel" :min="0.15">
<CircularLoading v-if="loading"
:show="loading">
</CircularLoading>
<div v-else
ref="splitContainer"
class="split-container">
<Split v-model="splitValue"
:min="0.15">
<template #left>
<div ref="splitContainerLeftPane" class="split-container-pane">
<Card style="width:100%;" :padding="0" :bordered="false" dis-hover>
<div ref="splitContainerLeftPane"
class="split-container-pane">
<Card style="width:100%;"
:padding="0"
:bordered="false"
dis-hover>
<template #title>
<Row>
<Col span="4" style="margin-top: 3px;">
<Tooltip v-if="data" transfer :content="data.name" placement="bottom-start">
<Avatar :src="'/static/images/plugin/' + data.type + '.png'" size="small"/>
</Tooltip>
</Col>
<Col span="20">
<Select v-model="currentDatabase" @on-change="handlerChangeDatabase">
<Option v-for="database in databaseArray" :value="database" :key="database">
{{ database }}
</Option>
</Select>
</Col>
</Row>
<Select v-model="applyValue.database"
@on-change="handlerChangeDatabase">
<Option v-for="item in databaseArray"
:value="item.applyId"
:key="item.title">
<FontAwesomeIcon icon="database"
style="margin-right: 6px;">
</FontAwesomeIcon>
{{ item.title }}
</Option>
</Select>
</template>
<div style="height: 470px; overflow: auto;">
<Tree :data="dataTreeArray" :load-data="handlerLoadChild" @on-select-change="handlerSelectNode"></Tree>
<Spin size="large" fix :show="tableLoading"></Spin>
<Tree :data="dataTreeArray"
style="margin-left: 6px;"
:load-data="handlerLoadChildData"
@on-select-change="handlerSelectNode">
</Tree>
<CircularLoading v-if="dataTreeLoading"
:show="dataTreeLoading">
</CircularLoading>
</div>
<Spin size="large" fix :show="loading"></Spin>
</Card>
</div>
</template>
<template #right>
<div ref="splitContainerRightPane" class="split-container-pane">
<Card v-if="!isShowData" dis-hover :bordered="false">
<Result type="warning" style="margin-top: 10px;">
<template #desc>
{{ $t('alert.managerRequiredTreeData') }}
</template>
</Result>
</Card>
<div v-if="isShowData && !dataLoading && tableConfigure">
<!-- Paging related components -->
<div style="margin: 3px 0px 3px 10px;">
<Space>
<Button :disabled="currentPageNumber === 1" shape="circle" type="text"
size="small" icon="md-arrow-back" @click="handlerChangePage(false)"/>
<Select v-model="configure.limit" size="small" style="width: 60px" @on-change="handlerExecute">
<Option v-for="item in limitOptions" :value="item" :key="item">{{ item }}</Option>
</Select>
<Input v-model="currentPageNumber" size="small" style="max-width: 50px;"/>
<Button :disabled="tableConfigure?.columns.length < configure.limit" shape="circle" type="text"
size="small" icon="md-arrow-forward" @click="handlerChangePage(true)"/>
<Tooltip :content="$t('common.elapsed')">
<Button size="small" icon="md-clock" type="default">{{ tableConfigure.elapsed }} ms</Button>
</Tooltip>
<Tooltip content="DDL">
<Button size="small" icon="md-eye" type="text" shape="circle" @click="handlerControlModal(false)"></Button>
</Tooltip>
<Dropdown v-if="selectedRows.length > 0" placement="bottom-start">
<Button style="margin-top: -8px;" size="small" type="text" icon="ios-download">
[<span style="font-size: 12px; color: #19BE6B; font-weight: bold;">{{ selectedRows.length }}</span>]
</Button>
<template #list>
<DropdownMenu>
<DropdownItem @click="handlerCopyWith(true)">
<Icon type="md-copy"/>
{{ $t('copy.copyWithHeadersRow') }}
</DropdownItem>
<DropdownItem @click="handlerCopyWith(false)">
<Icon type="md-copy"/>
{{ $t('copy.copyDataOnlyRow') }}
</DropdownItem>
</DropdownMenu>
</template>
</Dropdown>
</Space>
</div>
<!-- Filter component -->
<div style="margin: 3px 0px -4px 10px;">
<Space>
<Input v-model="currentOrder.inputValue" size="small" clearable style="width: auto;" @on-enter="handlerGetValue">
<template #prepend>
<Icon type="md-list"/>
ORDER BY
</template>
</Input>
<Input v-model="currentWhere" size="small" clearable style="width: auto;" @on-enter="handlerGetValue">
<template #prepend>
<FontAwesomeIcon icon="filter" />
WHERE
</template>
</Input>
</Space>
</div>
</div>
<TablePreview v-if="tableConfigure"
:configure="tableConfigure"
:sortColumns="tableSortColumns"
@on-sorted="handlerOnSorted"
@on-selected="handlerOnSelected">
</TablePreview>
<Spin size="large" fix :show="dataLoading"></Spin>
</div>
<Card v-if="!applyValue.node"
padding="0 10"
:bordered="false"
dis-hover>
<Result type="warning"
:title="$t('tooltip.notSelectedNodeTitle')">
<template #desc>
<span>{{ $t('tooltip.notSelectedNodeDesc') }}</span>
</template>
</Result>
</Card>
<Card v-else
style="width:100%;"
padding="0 10"
:bordered="false"
:title="null"
dis-hover>
<Tabs v-model="applyValue.tabType"
:animated="false">
<TabPane :label="tabPane.info"
name="info">
<TableInfo v-if="applyValue.tabType === 'info'"
:id="applyValue.node.applyId">
</TableInfo>
</TabPane>
<TabPane :label="tabPane.data"
name="data">
<TableData v-if="applyValue.tabType === 'data'"
:id="applyValue.node.applyId">
</TableData>
</TabPane>
</Tabs>
</Card>
</template>
</Split>
</div>
<SqlDetail v-if="modalVisible"
:isVisible="modalVisible"
:content="tableConfigure.context"
@close="handlerControlModal(true)">
</SqlDetail>
</div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import {defineComponent, resolveComponent} from "vue";
import {useRouter} from "vue-router";
import {SourceService} from "@/services/SourceService";
import {join, toNumber} from "lodash";
import {SourceModel} from "@/model/SourceModel";
import MangerService from "@/services/source/MangerService";
import {Sql} from "@/model/sql/Sql";
import {toNumber} from "lodash";
import {useI18n} from "vue-i18n";
import SourceNotSupported from "@/components/common/SourceNotSupported.vue";
import {TableConfigure} from "@/components/table/TableConfigure";
import TablePreview from "@/views/admin/source/components/TablePreview.vue";
import {Sort} from "@/model/sql/Sort";
import SqlDetail from "@/components/sql/SqlDetail.vue";
import useClipboard from "vue-clipboard3";
import DatabaseService from "@/services/Database";
import TableService from "@/services/Table";
import ColumnService from "@/services/Column";
import CircularLoading from "@/components/loading/CircularLoading.vue";
import {DataStructureModel} from "@/model/DataStructure";
import {DataStructureEnum} from "@/enum/DataStructure";
import TableInfo from "@/views/admin/source/components/TableInfo.vue";
import TableData from "@/views/admin/source/components/TableData.vue";
export default defineComponent({
name: "SourceManager",
components: {SqlDetail, TablePreview, SourceNotSupported},
name: "SourceManagerBeta",
components: {TableData, TableInfo, CircularLoading},
setup()
{
const i18n = useI18n();
const resolveTabPaneComponent = (h, icon: string, key: string) => {
return h('div', [
h(resolveComponent('FontAwesomeIcon'), {
icon: icon,
style: {fontSize: '25px'}
}),
h('p', {
style: {
fontSize: '12px',
}
},
i18n.t(key))
])
}
return {
i18n
i18n,
resolveTabPaneComponent
}
},
data()
{
return {
templateArray: ['getAllDatabase', 'getAllTablesFromDatabase', 'getAllColumnsFromDatabaseAndTable'],
sourceId: 0,
loading: false,
tableLoading: false,
dataLoading: false,
isSupported: false,
isShowData: false,
data: null as SourceModel,
currentDatabase: null,
currentTable: null,
currentItem: null,
currentPageNumber: 1,
currentOrder: {
inputValue: null
dataTreeLoading: false,
splitValue: 0.15,
databaseArray: Array<DataStructureModel>(),
dataTreeArray: Array<DataStructureModel>(),
applyValue: {
database: null,
node: null as DataStructureModel,
tabType: 'info'
},
currentWhere: null,
databaseArray: [],
dataTreeArray: [],
configure: null as Sql,
splitModel: 0.15,
tableConfigure: null as TableConfigure,
tableSortColumns: [],
modalVisible: false,
limitOptions: [5, 10, 15, 20, 50, 100],
selectedRows: []
tabPane: {
info: (h) => this.resolveTabPaneComponent(h, 'circle-info', 'common.info'),
data: (h) => this.resolveTabPaneComponent(h, 'table', 'common.data'),
}
}
},
created()
{
this.configure = new Sql();
this.handlerInitialize();
},
methods: {
@ -180,306 +148,190 @@ export default defineComponent({
this.loading = true;
const router = useRouter();
const id = router.currentRoute?.value?.params['id'];
this.sourceId = toNumber(id);
new SourceService().getById(this.sourceId)
DatabaseService.getAllBySource(toNumber(id))
.then(response => {
if (response.status) {
if (response.data) {
this.data = response.data;
this.isSupported = true;
}
response.data.forEach((item: { name: null; catalog: null; id: null }) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
this.databaseArray.push(structure);
});
}
})
.finally(() => {
this.loading = false;
});
MangerService.getDatabases(this.sourceId)
.then(response => {
if (response.status) {
const header = response.data.headers[0];
response.data.columns.forEach(column => {
this.databaseArray.push(column[header]);
});
}
else {
this.isSupported = false;
}
});
},
handlerChangeDatabase()
{
this.tableLoading = true;
MangerService.findTableTypeByDatabase(this.sourceId, this.currentDatabase)
this.dataTreeLoading = true;
this.dataTreeArray = [];
TableService.getAllByDatabase(this.applyValue.database)
.then(response => {
if (response.status) {
const header = response.data.headers[0];
this.dataTreeArray = [];
response.data.columns.forEach(column => {
this.dataTreeArray.push({
title: this.i18n.t('common.' + column[header]),
level: 'GetDataForTableType',
action: column[header],
loading: false,
type: 'action',
children: []
});
response.data.forEach((item: {
name: null;
title: null;
catalog: null;
id: null;
type: null;
engine: null;
comment: null;
database: { name: null };
}) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.database = item.database.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
structure.type = item.type;
structure.level = DataStructureEnum.TABLE;
structure.engine = item.engine;
structure.comment = item.comment;
structure.origin = item;
structure.render = (h, {data}) => {
return h('div', [
h('span', [
h(resolveComponent('FontAwesomeIcon'), {
icon: "table",
style: {marginRight: '6px'}
}),
this.resolveTableComponent(h, data)
])
]);
}
this.dataTreeArray.push(structure);
});
}
})
.finally(() => {
this.tableLoading = false;
this.dataTreeLoading = false;
});
},
handlerLoadChild(item, callback)
handlerLoadChildData(item: DataStructureModel, callback)
{
this.currentTable = item.title;
// Load all tables under the database according to type
if (item.level === 'GetDataForTableType') {
MangerService.getTableDataByDatabaseAndType(this.sourceId, this.currentDatabase, item.action)
.then(response => {
if (response.status) {
const dataTreeColumnArray = [];
// Add the total amount of data to the parent class header
item.title = item.title + ' [' + response.data.columns.length + ']';
response.data.columns.forEach(column => {
dataTreeColumnArray.push({
title: column['TABLE_NAME'],
level: 'FindColumnType',
database: this.currentDatabase,
catalog: column['TABLE_CATALOG'],
loading: false,
type: 'data',
children: []
});
});
callback(dataTreeColumnArray);
}
else {
this.$Message.error(response.message);
}
})
.finally(() => {
this.tableLoading = false;
});
}
// Gets a collection of related data based on the specified database and data type
else if (item.level === 'FindColumnType') {
MangerService.findColumnTypeByDatabaseAndTable(this.sourceId, item.catalog, this.currentTable)
.then(response => {
if (response.status) {
const dataTreeColumnArray = [];
const types = [];
response.data.columns.forEach(column => {
column['COLUMN_TYPE'].split(',').forEach(type => {
if (types.indexOf(type) === -1) {
dataTreeColumnArray.push({
title: this.i18n.t('common.' + type),
level: 'GetColumnDataForTableType',
action: type,
catalog: column['TABLE_CATALOG'],
database: this.currentDatabase,
table: this.currentTable,
loading: false,
type: 'action',
children: []
});
}
types.push(type);
})
});
callback(dataTreeColumnArray);
}
else {
this.$Message.error(response.message);
}
})
.finally(() => {
this.tableLoading = false;
});
}
// Gets a collection of related data based on the specified database, table, and data type
else if (item.level === 'GetColumnDataForTableType') {
MangerService.getColumnDataByDatabaseAndTableAndType(this.sourceId, item.catalog, item.table, item.action)
.then(response => {
if (response.status) {
const dataTreeColumnArray = [];
item.title = item.title + ' [' + response.data.columns.length + ']';
response.data.columns.forEach(column => {
dataTreeColumnArray.push({
catalog: column['TABLE_CATALOG'],
database: this.currentDatabase,
table: column['TABLE_NAME'],
column: column['COLUMN_NAME'],
title: column['COLUMN_NAME'] + ' [' + column['DATA_TYPE'] + ']',
level: 'GetColumnDataForTable',
type: 'data',
dataType: column['DATA_TYPE'],
children: []
});
})
callback(dataTreeColumnArray);
}
else {
this.$Message.error(response.message);
}
})
.finally(() => {
this.tableLoading = false;
});
const dataChildArray = [];
if (item.level === DataStructureEnum.COLUMN) {
callback(dataChildArray);
return;
}
ColumnService.getAllByTable(item.applyId)
.then(response => {
if (response.status) {
response.data.forEach((item: {
name: null;
title: null;
catalog: null;
id: null;
type: null;
dataType: null;
extra: null;
engine: null;
isKey: null;
defaultValue: null;
table: { name: null, database: { name: null } };
}) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.database = item.table.database.name;
structure.table = item.table.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
structure.level = DataStructureEnum.COLUMN;
structure.type = item.type;
structure.extra = item.extra;
structure.dataType = item.dataType;
structure.engine = item.engine;
structure.isKey = item.isKey;
structure.defaultValue = item.defaultValue;
structure.render = (h, {data}) => {
return h('div', [
h('span', [
h(resolveComponent('FontAwesomeIcon'), {
icon: this.getColumnIcon(data.isKey),
style: {marginRight: '6px'}
}),
h('span', data.title),
h('span', {
style: {
marginLeft: '6px',
color: '#c5c8ce'
},
},
this.getColumnTitle(data.type, data.extra, data.isKey, data.defaultValue)),
])
]);
}
dataChildArray.push(structure);
});
}
})
.finally(() => {
callback(dataChildArray);
});
},
handlerSelectNode(item)
handlerSelectNode(node: Array<DataStructureModel>)
{
if (item.length > 0) {
const data = item[0];
if (data.type === 'action') {
return
}
this.currentItem = item;
this.headers = [];
this.columns = [];
this.isShowData = true;
this.dataLoading = true;
this.selectedRows = [];
// Reinitialize when switching to a new table
if (this.currentTable !== data.title) {
this.configure = new Sql();
this.currentPageNumber = 1;
this.currentOrder.inputValue = null;
this.currentWhere = null;
this.configure.offset = this.currentPageNumber;
this.tableSortColumns = null;
}
this.currentTable = data.title;
this.configure.database = data.catalog;
this.configure.table = this.currentTable;
if (data.level === 'GetColumnDataForTable') {
this.configure.table = data.table;
this.configure.columns = [data.column];
}
this.handlerExecute();
if (node.length === 0) {
// Prevent selection clearing after repeated clicks
this.applyValue.node.selected = true;
return;
}
const currentNode = node[0];
if (currentNode.level === DataStructureEnum.COLUMN) {
this.applyValue.node.selected = true;
currentNode.selected = false;
return;
}
this.applyValue.node = currentNode;
},
handlerChangePage(nexted: boolean)
getColumnIcon(type: string)
{
if (nexted) {
this.configure.offset = this.currentPageNumber * this.configure.limit + 1;
this.currentPageNumber += 1;
if (type === 'PRI') {
return 'key';
}
else if (type === 'MUL') {
return 'repeat';
}
else if (type === 'UNI') {
return 'circle';
}
else {
this.currentPageNumber -= 1;
this.configure.offset = (this.currentPageNumber - 1) * this.configure.limit + 1;
return 'columns';
}
this.handlerSelectNode(this.currentItem);
},
handlerExecute()
getColumnTitle(dataType: string, extra: string, isKey: string, defaultValue: string)
{
this.tableConfigure = null;
this.dataLoading = true;
const splitContainerLeftPane: HTMLElement = this.$refs.splitContainerLeftPane as HTMLElement;
const splitContainer: HTMLElement = this.$refs.splitContainer as HTMLElement;
MangerService.getDataByConfigure(this.sourceId, this.configure)
.then(response => {
if (response.status) {
response.data.headers.forEach(header => {
this.headers.push(
{
title: header,
key: header,
'minWidth': 200,
ellipsis: true,
tooltip: true
}
);
});
const tConfigure: TableConfigure = {
headers: response.data.headers,
columns: response.data.columns,
types: response.data.types,
height: splitContainerLeftPane.offsetHeight - 57,
width: splitContainer.offsetWidth - splitContainerLeftPane.offsetWidth,
showSeriesNumber: false,
elapsed: response?.data?.processor?.elapsed,
context: response?.data?.content
};
this.tableConfigure = tConfigure;
}
else {
this.$Message.error(response.message);
}
})
.finally(() => {
this.tableLoading = false;
this.dataLoading = false;
});
},
handlerGetValue()
{
if (this.currentOrder.inputValue) {
const value = this.currentOrder.inputValue;
if (value) {
const sort: Array<Sort> = new Array<Sort>();
value.split(',').forEach(item => {
const array = item.trim().split(' ')
sort.push({
column: array[0],
sort: array[1]
})
})
this.configure.sort = sort;
let title = dataType;
if (isKey === 'PRI') {
if (extra) {
title = `${title} (${extra.replace('_', ' ')})`;
}
else {
const sort: Array<Sort> = new Array<Sort>();
const array = value.trim().split(' ')
sort.push({
column: array[0],
sort: array[1]
})
this.configure.sort = sort;
title = `${title}`;
}
this.tableSortColumns = this.configure.sort;
}
if (this.currentWhere) {
this.configure.where = this.currentWhere;
if (defaultValue && defaultValue !== 'null') {
title = `${title} = ${defaultValue}`
}
this.handlerExecute();
return title;
},
handlerOnSorted(sort: Array<Sort>)
resolveTableComponent(h, data: { comment: undefined; title: undefined })
{
this.configure.sort = sort;
this.tableSortColumns = sort;
this.currentOrder.inputValue = join(sort.map(item => item.column + ' ' + item.sort));
this.handlerExecute();
},
handlerControlModal(value: boolean)
{
this.modalVisible = !value;
},
handlerOnSelected(nodes: Array<any>)
{
this.selectedRows = nodes;
},
handlerCopyWith(withHeaders: boolean)
{
const headers = [];
const copyRows = [];
this.selectedRows.forEach(row => {
const values = [];
Object.keys(row)
.forEach(key => {
headers.push(key);
values.push(row[key]);
});
copyRows.push(join(values, ','));
});
if (withHeaders) {
copyRows.unshift(join(headers, ','));
if (data.comment) {
return h(resolveComponent('Tooltip'), {
content: data.comment,
placement: 'bottom-start',
transfer: true,
delay: 1000
},
h('span', data.title));
}
else {
return h('span', data.title);
}
useClipboard()
.toClipboard(join(copyRows, '\n'))
.then(() => this.$Message.info('Copy Successfully'));
}
}
});

View File

@ -1,347 +0,0 @@
<template>
<div style="padding: 0">
<CircularLoading v-if="loading"
:show="loading">
</CircularLoading>
<div v-else
ref="splitContainer"
class="split-container">
<Split v-model="splitValue"
:min="0.15">
<template #left>
<div ref="splitContainerLeftPane"
class="split-container-pane">
<Card style="width:100%;"
:padding="0"
:bordered="false"
dis-hover>
<template #title>
<Select v-model="applyValue.database"
@on-change="handlerChangeDatabase">
<Option v-for="item in databaseArray"
:value="item.applyId"
:key="item.title">
<FontAwesomeIcon icon="database"
style="margin-right: 6px;">
</FontAwesomeIcon>
{{ item.title }}
</Option>
</Select>
</template>
<div style="height: 470px; overflow: auto;">
<Tree :data="dataTreeArray"
style="margin-left: 6px;"
:load-data="handlerLoadChildData"
@on-select-change="handlerSelectNode">
</Tree>
<CircularLoading v-if="dataTreeLoading"
:show="dataTreeLoading">
</CircularLoading>
</div>
</Card>
</div>
</template>
<template #right>
<Card v-if="!applyValue.node"
padding="0 10"
:bordered="false"
dis-hover>
<Result type="warning"
:title="$t('tooltip.notSelectedNodeTitle')">
<template #desc>
<span>{{ $t('tooltip.notSelectedNodeDesc') }}</span>
</template>
</Result>
</Card>
<Card v-else
style="width:100%;"
padding="0 10"
:bordered="false"
:title="null"
dis-hover>
<Tabs v-model="applyValue.tabType"
:animated="false">
<TabPane :label="tabPane.info"
name="info">
<TableInfo v-if="applyValue.tabType === 'info'"
:id="applyValue.node.applyId">
</TableInfo>
</TabPane>
<TabPane :label="tabPane.data"
name="data">
<TableData v-if="applyValue.tabType === 'data'"
:id="applyValue.node.applyId">
</TableData>
</TabPane>
</Tabs>
</Card>
</template>
</Split>
</div>
</div>
</template>
<script lang="ts">
import {defineComponent, resolveComponent} from "vue";
import {useRouter} from "vue-router";
import {toNumber} from "lodash";
import {useI18n} from "vue-i18n";
import DatabaseService from "@/services/Database";
import TableService from "@/services/Table";
import ColumnService from "@/services/Column";
import CircularLoading from "@/components/loading/CircularLoading.vue";
import {DataStructureModel} from "@/model/DataStructure";
import {DataStructureEnum} from "@/enum/DataStructure";
import TableInfo from "@/views/admin/source/components/TableInfo.vue";
import TableData from "@/views/admin/source/components/TableData.vue";
export default defineComponent({
name: "SourceManagerBeta",
components: {TableData, TableInfo, CircularLoading},
setup()
{
const i18n = useI18n();
const resolveTabPaneComponent = (h, icon: string, key: string) => {
return h('div', [
h(resolveComponent('FontAwesomeIcon'), {
icon: icon,
style: {fontSize: '25px'}
}),
h('p', {
style: {
fontSize: '12px',
}
},
i18n.t(key))
])
}
return {
i18n,
resolveTabPaneComponent
}
},
data()
{
return {
loading: false,
dataTreeLoading: false,
splitValue: 0.15,
databaseArray: Array<DataStructureModel>(),
dataTreeArray: Array<DataStructureModel>(),
applyValue: {
database: null,
node: null as DataStructureModel,
tabType: 'info'
},
tabPane: {
info: (h) => this.resolveTabPaneComponent(h, 'circle-info', 'common.info'),
data: (h) => this.resolveTabPaneComponent(h, 'table', 'common.data'),
}
}
},
created()
{
this.handlerInitialize();
},
methods: {
handlerInitialize()
{
this.loading = true;
const router = useRouter();
const id = router.currentRoute?.value?.params['id'];
DatabaseService.getAllBySource(toNumber(id))
.then(response => {
if (response.status) {
response.data.forEach((item: { name: null; catalog: null; id: null }) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
this.databaseArray.push(structure);
});
}
})
.finally(() => {
this.loading = false;
});
},
handlerChangeDatabase()
{
this.dataTreeLoading = true;
this.dataTreeArray = [];
TableService.getAllByDatabase(this.applyValue.database)
.then(response => {
if (response.status) {
response.data.forEach((item: {
name: null;
title: null;
catalog: null;
id: null;
type: null;
engine: null;
comment: null;
database: { name: null };
}) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.database = item.database.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
structure.type = item.type;
structure.level = DataStructureEnum.TABLE;
structure.engine = item.engine;
structure.comment = item.comment;
structure.origin = item;
structure.render = (h, {data}) => {
return h('div', [
h('span', [
h(resolveComponent('FontAwesomeIcon'), {
icon: "table",
style: {marginRight: '6px'}
}),
this.resolveTableComponent(h, data)
])
]);
}
this.dataTreeArray.push(structure);
});
}
})
.finally(() => {
this.dataTreeLoading = false;
});
},
handlerLoadChildData(item: DataStructureModel, callback)
{
const dataChildArray = [];
if (item.level === DataStructureEnum.COLUMN) {
callback(dataChildArray);
return;
}
ColumnService.getAllByTable(item.applyId)
.then(response => {
if (response.status) {
response.data.forEach((item: {
name: null;
title: null;
catalog: null;
id: null;
type: null;
dataType: null;
extra: null;
engine: null;
isKey: null;
defaultValue: null;
table: { name: null, database: { name: null } };
}) => {
const structure = new DataStructureModel();
structure.title = item.name;
structure.database = item.table.database.name;
structure.table = item.table.name;
structure.catalog = item.catalog;
structure.applyId = item.id;
structure.level = DataStructureEnum.COLUMN;
structure.type = item.type;
structure.extra = item.extra;
structure.dataType = item.dataType;
structure.engine = item.engine;
structure.isKey = item.isKey;
structure.defaultValue = item.defaultValue;
structure.render = (h, {data}) => {
return h('div', [
h('span', [
h(resolveComponent('FontAwesomeIcon'), {
icon: this.getColumnIcon(data.isKey),
style: {marginRight: '6px'}
}),
h('span', data.title),
h('span', {
style: {
marginLeft: '6px',
color: '#c5c8ce'
},
},
this.getColumnTitle(data.type, data.extra, data.isKey, data.defaultValue)),
])
]);
}
dataChildArray.push(structure);
});
}
})
.finally(() => {
callback(dataChildArray);
});
},
handlerSelectNode(node: Array<DataStructureModel>)
{
if (node.length === 0) {
// Prevent selection clearing after repeated clicks
this.applyValue.node.selected = true;
return;
}
const currentNode = node[0];
if (currentNode.level === DataStructureEnum.COLUMN) {
this.applyValue.node.selected = true;
currentNode.selected = false;
return;
}
this.applyValue.node = currentNode;
},
getColumnIcon(type: string)
{
if (type === 'PRI') {
return 'key';
}
else if (type === 'MUL') {
return 'repeat';
}
else if (type === 'UNI') {
return 'circle';
}
else {
return 'columns';
}
},
getColumnTitle(dataType: string, extra: string, isKey: string, defaultValue: string)
{
let title = dataType;
if (isKey === 'PRI') {
if (extra) {
title = `${title} (${extra.replace('_', ' ')})`;
}
else {
title = `${title}`;
}
}
if (defaultValue && defaultValue !== 'null') {
title = `${title} = ${defaultValue}`
}
return title;
},
resolveTableComponent(h, data: { comment: undefined; title: undefined })
{
if (data.comment) {
return h(resolveComponent('Tooltip'), {
content: data.comment,
placement: 'bottom-start',
transfer: true,
delay: 1000
},
h('span', data.title));
}
else {
return h('span', data.title);
}
}
}
});
</script>
<style scoped>
.split-container {
height: 510px;
}
.split-container-pane {
padding: 0;
}
</style>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@ -20,17 +20,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>${plugin.maven.nexus.version}</version>
<extensions>true</extensions>
<configuration>
<skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<packaging>pom</packaging>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<modules>
<module>client/datacap-cli</module>
@ -152,7 +152,7 @@
<plugin.maven.javadoc.version>3.6.0</plugin.maven.javadoc.version>
<plugin.maven.gpg.version>1.6</plugin.maven.gpg.version>
<plugin.maven.nexus.version>1.6.13</plugin.maven.nexus.version>
<plugin.maven.dokka.version>1.8.10</plugin.maven.dokka.version>
<plugin.maven.dokka.version>1.9.10</plugin.maven.dokka.version>
<environment.compile.java.version>1.8</environment.compile.java.version>
</properties>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap</artifactId>
<version>1.16.0</version>
<version>1.17.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>