[improvement][semantic-fe] Added an editing component to set filtering rules for Q&A. Now, the SQL editor will be accompanied by a list for display and control, to resolve ambiguity when using comma-separated values.

[improvement][semantic-fe] Improved validation logic and prompt copywriting for data source/dimension/metric editing and creation.
[improvement][semantic-fe] Improved user experience for visual modeling. Now, when using the legend to control the display/hide of data sources and their associated metric dimensions, the canvas will be re-layout based on the activated data source in the legend.

Co-authored-by: tristanliu <tristanliu@tencent.com>
This commit is contained in:
tristanliu
2023-07-21 15:30:38 +08:00
committed by GitHub
parent 6492316e23
commit 078a81038f
39 changed files with 1541 additions and 1161 deletions

View File

@@ -1,80 +1,139 @@
import { ISemantic, IDataSource } from '../data';
import { SemanticNodeType } from '../enum';
export const typeConfigs = {
datasource: {
type: 'circle',
size: 5,
style: {
fill: '#5B8FF9',
},
size: 10,
},
dimension: {
type: 'circle',
size: 20,
style: {
fill: '#5AD8A6',
},
},
metric: {
type: 'rect',
size: [10, 10],
style: {
fill: '#5D7092',
},
},
// eType1: {
// type: 'line',
// style: {
// width: 20,
// stroke: '#F6BD16',
// },
// },
// eType2: {
// type: 'cubic',
// },
// eType3: {
// type: 'quadratic',
// style: {
// width: 25,
// stroke: '#6F5EF9',
// },
// },
};
export const legendData = {
nodes: [
{
id: 'type1',
label: 'node-type1',
order: 4,
...typeConfigs.datasource,
export const getDimensionChildren = (
dimensions: ISemantic.IDimensionItem[],
dataSourceNodeId: string,
) => {
const dimensionChildrenList = dimensions.reduce(
(dimensionChildren: any[], dimension: ISemantic.IDimensionItem) => {
const { id } = dimension;
dimensionChildren.push({
...dimension,
nodeType: SemanticNodeType.DIMENSION,
legendType: dataSourceNodeId,
id: `${SemanticNodeType.DIMENSION}-${id}`,
uid: id,
style: {
lineWidth: 2,
fill: '#f0f7ff',
stroke: '#a6ccff',
},
});
return dimensionChildren;
},
{
id: 'type2',
label: 'node-type2',
order: 0,
...typeConfigs.dimension,
},
{
id: 'type3',
label: 'node-type3',
order: 2,
...typeConfigs.metric,
},
],
// edges: [
// {
// id: 'eType1',
// label: 'edge-type1',
// order: 2,
// ...typeConfigs.eType1,
// },
// {
// id: 'eType2',
// label: 'edge-type2',
// ...typeConfigs.eType2,
// },
// {
// id: 'eType3',
// label: 'edge-type3',
// ...typeConfigs.eType3,
// },
// ],
[],
);
return dimensionChildrenList;
};
export const getMetricChildren = (metrics: ISemantic.IMetricItem[], dataSourceNodeId: string) => {
const metricsChildrenList = metrics.reduce(
(metricsChildren: any[], metric: ISemantic.IMetricItem) => {
const { id } = metric;
metricsChildren.push({
...metric,
nodeType: SemanticNodeType.METRIC,
legendType: dataSourceNodeId,
id: `${SemanticNodeType.METRIC}-${id}`,
uid: id,
style: {
lineWidth: 2,
fill: '#f0f7ff',
stroke: '#a6ccff',
},
});
return metricsChildren;
},
[],
);
return metricsChildrenList;
};
export const formatterRelationData = (
dataSourceList: IDataSource.IDataSourceItem[],
type: SemanticNodeType = SemanticNodeType.DIMENSION,
) => {
const relationData = dataSourceList.reduce((relationList: any[], item: any) => {
const { datasource, dimensions, metrics } = item;
const { id } = datasource;
const dataSourceNodeId = `${SemanticNodeType.DATASOURCE}-${id}`;
let childrenList = [];
if (type === SemanticNodeType.METRIC) {
childrenList = getMetricChildren(metrics, dataSourceNodeId);
}
if (type === SemanticNodeType.DIMENSION) {
childrenList = getDimensionChildren(dimensions, dataSourceNodeId);
}
relationList.push({
...datasource,
legendType: dataSourceNodeId,
id: dataSourceNodeId,
uid: id,
nodeType: SemanticNodeType.DATASOURCE,
size: 40,
children: [...childrenList],
style: {
lineWidth: 2,
fill: '#BDEFDB',
stroke: '#5AD8A6',
},
});
return relationList;
}, []);
return relationData;
};
export const loopNodeFindDataSource: any = (node: any) => {
const { model, parent } = node;
if (model?.nodeType === SemanticNodeType.DATASOURCE) {
return model;
}
const parentNode = parent?._cfg;
if (parentNode) {
return loopNodeFindDataSource(parentNode);
}
return false;
};
export const getNodeConfigByType = (nodeData: any, defaultConfig = {}) => {
const { nodeType } = nodeData;
const labelCfg = { style: { fill: '#3c3c3c' } };
switch (nodeType) {
case SemanticNodeType.DATASOURCE: {
return {
...defaultConfig,
labelCfg: { position: 'bottom', ...labelCfg },
};
}
case SemanticNodeType.DIMENSION:
return {
...defaultConfig,
labelCfg: { position: 'right', ...labelCfg },
};
case SemanticNodeType.METRIC:
return {
...defaultConfig,
labelCfg: { position: 'right', ...labelCfg },
};
default:
return defaultConfig;
}
};
export const flatGraphDataNode = (graphData: any[]) => {
return graphData.reduce((nodeList: any[], item: any) => {
const { children } = item;
if (Array.isArray(children)) {
nodeList.push(...children);
}
return nodeList;
}, []);
};