tachybase_todo/packages/plugins/data-visualization/src/client/utils.ts

103 lines
3.2 KiB
TypeScript
Raw Normal View History

feat: data visualization (#2160) * feat(charts-v2): init * chore(charts-v2): init chart renderer * feat(chart-v2): add chart grid and initializer * feat(chart-v2): improve ui * feat(chart-v2): ui * feat(charts-v2): query sort ui * feat(charts-v2): field select component * feat(charts-v2): improve ui && add query action * feat(charts-v2): imporve ui, work in progress * fix(charts-v2): chart renderer request api twice * feat(charts-v2): add dimension formatter * feat(charts-v2): filter, sort, limit * feat(charts-v2): sql mode ui * feat(charts-v2): support duplicate & sql mode * fix(charts-v2): wrong defaultValue of json config * feat(charts-v2): transformer ui * feat(charts-v2): transformer * chore(charts-v2): rename transfromer to transform * feat(charts-v2): support cache * feat(charts-v2): add acl provider * chore(charts-v2): hide sql mode * refactor(charts-v2): add renderer provider * feat: collection permission check * feat(charts-v2): add antd statistic * test(charts-v2): backend * chore: improve code * test(charts-v2): add test * chore: add Chinese translation * fix(charts-v2): locale switch bug * chore: add dependency * feat(charts-v2): init chart config from query * feat: change layout * test: fix frontend test * feat: improve auto infer * fix: ui issues * chore: translation * fix: sql error * fix: some issues * feat: support table * fix: bug * chore: improve code and fix query * feat: add config reference * chore: add translation * fix: process data due to pg issue * test: fix parseBuilder * chore: upgrade formily to 2.2.25 * fix: some issues and import style * fix: bug when query with sort * feat: parse enum data * fix: yarn.lock * fix: type error * fix: infer bug and frontend test * test: fix frontend * fix: test * feat: improve preview * chore: downgrade formily * feat: support associations, draft, in testing * fix: typo * test: frontend & backend * fix: infer bug * feat: measure selection of statistics * fix: bug of group by alias * fix: some issues * fix: order issues * fix: yarn.lock * chore: fix filter include & 'data-visualization' * style: improve style * docs: add readme * chore: add translation --------- Co-authored-by: chenos <chenlinxh@gmail.com>
2023-06-30 20:49:44 +08:00
import { Schema } from '@formily/react';
import { uid } from '@formily/shared';
import { SelectedField } from './block';
import { FieldOption } from './hooks';
import { QueryProps } from './renderer';
export const createRendererSchema = (decoratorProps: any, componentProps = {}) => {
const { collection } = decoratorProps;
return {
type: 'void',
'x-decorator': 'ChartRendererProvider',
'x-decorator-props': decoratorProps,
'x-acl-action': `${collection}:list`,
'x-designer': 'ChartRenderer.Designer',
'x-component': 'CardItem',
'x-component-props': {
size: 'small',
},
'x-initializer': 'ChartInitializers',
properties: {
[uid()]: {
type: 'void',
'x-component': 'ChartRenderer',
'x-component-props': componentProps,
},
},
};
};
// For AssociationField, the format of field is [targetField, field]
export const parseField = (field: string | string[]) => {
let target: string;
let name: string;
if (!Array.isArray(field)) {
name = field;
} else if (field.length === 1) {
name = field[0];
} else if (field.length > 1) {
[target, name] = field;
}
return { target, name, alias: target ? `${target}.${name}` : name };
};
export const getField = (fields: FieldOption[], field: string | string[]) => {
const { target, name } = parseField(field);
if (!target) {
return fields.find((f) => f.name === name);
}
const targetField = fields.find((f) => f.name === target)?.targetFields?.find((f) => f.name === name);
return targetField;
};
export const getSelectedFields = (fields: FieldOption[], query: QueryProps) => {
// When field alias is set, appends it to the field list
const process = (selectedFields: SelectedField[]) => {
return selectedFields.map((selectedField) => {
const fieldProps = getField(fields, selectedField.field);
return {
...fieldProps,
key: selectedField.alias || fieldProps?.key,
label: selectedField.alias || fieldProps?.label,
value: selectedField.alias || fieldProps?.value,
};
});
};
const measures = query.measures || [];
const dimensions = query.dimensions || [];
// unique
const map = new Map([...process(measures), ...process(dimensions)].map((item) => [item.value, item]));
const selectedFields = [...map.values()];
return selectedFields;
};
export const processData = (fields: FieldOption[], data: any[], scope: any) => {
const parseEnum = (field: FieldOption, value: any) => {
const options = field.uiSchema?.enum as { value: string; label: string }[];
if (!options || !Array.isArray(options)) {
return value;
}
const option = options.find((option) => option.value === value);
return Schema.compile(option?.label || value, scope);
};
return data.map((record) => {
const processed = {};
Object.entries(record).forEach(([key, value]) => {
const field = getField(fields, key.split('.'));
if (!field) {
processed[key] = value;
return;
}
switch (field.interface) {
case 'select':
case 'radioGroup':
processed[key] = parseEnum(field, value);
break;
default:
processed[key] = value;
}
});
return processed;
});
};