Skip to content

Feature 表格和透视表支持自定义排序 #2287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
public class OrderOperator extends ColumnOperator {
@@ -29,9 +31,12 @@ public class OrderOperator extends ColumnOperator {

private SqlOperator operator;

private List<String> value;

public enum SqlOperator {
ASC,
DESC
DESC,
CUSTOMIZE
}

@Override
Original file line number Diff line number Diff line change
@@ -25,11 +25,16 @@
import datart.core.data.provider.SingleTypedValue;
import datart.core.data.provider.sql.*;
import datart.data.provider.calcite.custom.CustomSqlBetweenOperator;
import org.apache.calcite.avatica.util.Casing;
import org.apache.calcite.avatica.util.Quoting;
import org.apache.calcite.sql.*;
import org.apache.calcite.sql.fun.SqlBetweenOperator;
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.parser.impl.SqlParserImpl;
import org.apache.calcite.sql.validate.SqlConformanceEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

@@ -268,6 +273,30 @@ private SqlNode createOrderNode(OrderOperator operator) {
if (operator.getOperator() == OrderOperator.SqlOperator.DESC) {
return new SqlBasicCall(SqlStdOperatorTable.DESC,
new SqlNode[]{sqlNode}, SqlParserPos.ZERO);
} else if (operator.getOperator() == OrderOperator.SqlOperator.CUSTOMIZE) {
// implements customize sort of single none-num field by 'case + when'
List<String> values = operator.getValue();
StringBuffer sortExpr = new StringBuffer();
sortExpr.append("case ");
for (int i = 0; i < values.size(); i++) {
String v = values.get(i);
sortExpr.append("when " + operator.getColumnKey() + " = '" + v + "' then " + i);
}
sortExpr.append(" end");

SqlParser.Config config = SqlParser.config()
.withParserFactory(SqlParserImpl.FACTORY)
.withQuotedCasing(Casing.UNCHANGED)
.withUnquotedCasing(Casing.UNCHANGED)
.withConformance(SqlConformanceEnum.LENIENT)
.withCaseSensitive(true)
.withQuoting(Quoting.BRACKET);
try {
SqlParser parser = SqlParser.create(sortExpr.toString(), config);
return parser.parseExpression();
} catch (SqlParseException e) {
throw new RuntimeException(e);
}
} else {
return sqlNode;
}
9 changes: 6 additions & 3 deletions frontend/src/app/components/ChartEditor.tsx
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@ import {
} from 'app/utils/ChartEventListenerHelper';
import {
clearRuntimeDateLevelFieldsInChartConfig,
clearUnsupportedChartConfig,
filterCurrentUsedComputedFields,
getValue,
} from 'app/utils/chartHelper';
@@ -315,8 +316,10 @@ export const ChartEditor: FC<ChartEditorProps> = ({
setChart(c);

const targetChartConfig = CloneValueDeep(c.config);
const finalChartConfig = clearRuntimeDateLevelFieldsInChartConfig(
transferChartConfigs(targetChartConfig, shadowChartConfig || chartConfig),
const finalChartConfig = clearUnsupportedChartConfig(
clearRuntimeDateLevelFieldsInChartConfig(
transferChartConfigs(targetChartConfig, shadowChartConfig || chartConfig)
)
);

const computedFields = updateBy(dataview?.computedFields || [], draft => {
@@ -591,7 +594,7 @@ export const ChartEditor: FC<ChartEditorProps> = ({
{
...builder.build(),
...{
analytics: dataChartId ? false : true,
analytics: !dataChartId,
vizName: backendChart?.name || 'chart',
vizId: isWidget ? widgetId : dataChartId,
vizType: isWidget ? 'widget' : 'dataChart',
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ const config: ChartConfig = {
key: 'mixed',
required: true,
type: 'mixed',
allowFieldCustomizeSort: true,
},
{
label: 'filter',
Original file line number Diff line number Diff line change
@@ -588,16 +588,16 @@ class PivotSheetChart extends ReactChart {
): Array<SortParam> {
return sectionConfigRows
.map(config => {
if (!config?.sort?.type || config?.sort?.type === SortActionType.None) {
const type = config?.sort?.type;
if (!type || type === SortActionType.None || type === SortActionType.Customize) {
return null;
}
const isASC = config.sort.type === SortActionType.ASC;
return {
sortFieldId: chartDataSet.getFieldKey(config),
sortFunc: params => {
const { data } = params;
return data?.sort((a, b) =>
isASC ? a?.localeCompare(b) : b?.localeCompare(a),
type === SortActionType.ASC ? a?.localeCompare(b) : b?.localeCompare(a),
);
},
};
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ const config: ChartConfig = {
options: {
sortable: { backendSort: false },
},
allowFieldCustomizeSort: true,
},
{
label: 'row',
@@ -37,6 +38,7 @@ const config: ChartConfig = {
},
drillable: false,
drillContextMenuVisible: true,
allowFieldCustomizeSort: true,
},
{
label: 'metrics',
1 change: 1 addition & 0 deletions frontend/src/app/constants.ts
Original file line number Diff line number Diff line change
@@ -167,6 +167,7 @@ export const ChartDataSectionFieldActionType = {
ColorizeSingle: 'colorSingle',
Size: 'size',
DateLevel: 'dateLevel',
CustomizeSort: 'customizeSort',
};

export const FilterRelationType = {
19 changes: 14 additions & 5 deletions frontend/src/app/hooks/useFieldActionModal.tsx
Original file line number Diff line number Diff line change
@@ -56,6 +56,8 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) {
};

switch (actionType) {
case ChartDataSectionFieldActionType.CustomizeSort:
return <FieldActions.CustomizeSortAction {...props} />;
case ChartDataSectionFieldActionType.Sortable:
return <FieldActions.SortAction {...props} />;
case ChartDataSectionFieldActionType.Alias:
@@ -97,11 +99,18 @@ function useFieldActionModal({ i18nPrefix }: I18NComponentProps) {
aggregation?: boolean,
) => {
const currentConfig = dataConfig.rows?.find(c => c.uid === columnUid);
let _modalSize = StateModalSize.MIDDLE;
if (actionType === ChartDataSectionFieldActionType.Colorize) {
_modalSize = StateModalSize.XSMALL;
} else if (actionType === ChartDataSectionFieldActionType.ColorizeSingle) {
_modalSize = StateModalSize.XSMALL;
let _modalSize: StateModalSize;
switch (actionType) {
case ChartDataSectionFieldActionType.Colorize:
case ChartDataSectionFieldActionType.ColorizeSingle:
case ChartDataSectionFieldActionType.Sortable:
_modalSize = StateModalSize.XSMALL;
break;
case ChartDataSectionFieldActionType.CustomizeSort:
_modalSize = StateModalSize.SMALL;
break;
default:
_modalSize = StateModalSize.MIDDLE;
}
return (show as Function)({
title: t(actionType),
15 changes: 12 additions & 3 deletions frontend/src/app/models/ChartDataRequestBuilder.ts
Original file line number Diff line number Diff line change
@@ -442,15 +442,24 @@ export class ChartDataRequestBuilder {
return acc;
}, [])
.filter(
col =>
col?.sort?.type &&
[SortActionType.ASC, SortActionType.DESC].includes(col?.sort?.type),
col => {
const type = col?.sort?.type;
if (!type) {
return false;
} else if (type === SortActionType.Customize) {
const value = col.sort!.value;
return Array.isArray(value) && value.length > 0;
} else {
return [SortActionType.ASC, SortActionType.DESC].includes(type);
}
}
);

const originalSorters = sortColumns.map(aggCol => ({
column: this.buildColumnName(aggCol),
operator: aggCol.sort?.type!,
aggOperator: aggCol.aggregate,
value: aggCol.sort?.type === SortActionType.Customize ? aggCol.sort.value! : undefined,
}));

const _extraSorters = this.extraSorters
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ import SubMenu from 'antd/lib/menu/SubMenu';
import {
ChartDataSectionFieldActionType,
ChartDataViewFieldCategory,
DataViewFieldType,
SortActionType,
} from 'app/constants';
import useI18NPrefix from 'app/hooks/useI18NPrefix';
import { ChartDataSectionField } from 'app/types/ChartConfig';
@@ -30,7 +32,7 @@ import { FC } from 'react';
import AggregationAction from '../ChartFieldAction/AggregationAction';
import AggregationLimitAction from '../ChartFieldAction/AggregationLimitAction';
import DateLevelAction from '../ChartFieldAction/DateLevelAction/DateLevelAction';
import SortAction from '../ChartFieldAction/SortAction';
import { SortAction } from '../ChartFieldAction/SortAction';
import { updateDataConfigByField } from './utils';

const ChartDataConfigSectionActionMenu: FC<
@@ -53,12 +55,7 @@ const ChartDataConfigSectionActionMenu: FC<
onConfigChanged,
}) => {
const t = useI18NPrefix(`viz.palette.data.enum.actionType`);
const subMenuAction = [
ChartDataSectionFieldActionType.Sortable,
ChartDataSectionFieldActionType.Aggregate,
ChartDataSectionFieldActionType.AggregateLimit,
ChartDataSectionFieldActionType.DateLevel,
];


const handleFieldConfigChanged = (
columnUid: string,
@@ -131,14 +128,20 @@ const ChartDataConfigSectionActionMenu: FC<
}
const options = config?.options?.[actionName];
if (actionName === ChartDataSectionFieldActionType.Sortable) {
const allowCustomSort = config?.allowFieldCustomizeSort && type !== DataViewFieldType.NUMERIC;
return (
<SortAction
config={fieldConfig}
onConfigChange={(config, needRefresh) => {
handleFieldConfigChanged(uid, config, needRefresh);
if (config.sort?.type === SortActionType.Customize) {
onOpenModal(uid)(ChartDataSectionFieldActionType.CustomizeSort);
} else {
handleFieldConfigChanged(uid, config, needRefresh);
}
}}
options={options}
mode="menu"
allowCustomSort={allowCustomSort}
/>
);
}
@@ -198,4 +201,10 @@ const ChartDataConfigSectionActionMenu: FC<
);
};

const subMenuAction = [
ChartDataSectionFieldActionType.Sortable,
ChartDataSectionFieldActionType.Aggregate,
ChartDataSectionFieldActionType.AggregateLimit,
ChartDataSectionFieldActionType.DateLevel,
];
export default ChartDataConfigSectionActionMenu;
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import {
GroupOutlined,
SortAscendingOutlined,
SortDescendingOutlined,
DragOutlined,
} from '@ant-design/icons';
import Dropdown from 'antd/lib/dropdown';
import { SortActionType } from 'app/constants';
@@ -137,6 +138,9 @@ const ChartDraggableElementField: FC<{
if (col.sort.type === SortActionType.DESC) {
icons.push(<SortDescendingOutlined key="sort" />);
}
if (col.sort.type === SortActionType.Customize) {
icons.push(<DragOutlined key="sort" />);
}
}
if (col.format) {
icons.push(<FormatPainterOutlined key="format" />);
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ import {
ChartDataSectionType,
ChartDataViewFieldCategory,
DataViewFieldType,
SortActionType,
} from 'app/constants';
import ChartDrillContext from 'app/contexts/ChartDrillContext';
import useFieldActionModal from 'app/hooks/useFieldActionModal';
@@ -29,7 +30,7 @@ import ChartDatasetContext from 'app/pages/ChartWorkbenchPage/contexts/ChartData
import VizDataViewContext from 'app/pages/ChartWorkbenchPage/contexts/ChartDataViewContext';
import { ChartDataSectionField } from 'app/types/ChartConfig';
import { ChartDataConfigSectionProps } from 'app/types/ChartDataConfigSection';
import { getColumnRenderName } from 'app/utils/chartHelper';
import { getColumnRenderName, removeCustomizeSortConfig } from 'app/utils/chartHelper';
import { reachLowerBoundCount } from 'app/utils/internalChartHelper';
import { updateBy, updateByKey } from 'app/utils/mutation';
import { CHART_DRAG_ELEMENT_TYPE } from 'globalConstants';
@@ -51,7 +52,9 @@ import { uuidv4 } from 'utils/utils';
import ChartDraggableElement from './ChartDraggableElement';
import ChartDraggableElementField from './ChartDraggableElementField';
import ChartDraggableElementHierarchy from './ChartDraggableElementHierarchy';
import { getDefaultAggregate, updateDataConfigByField } from './utils';
import {getDefaultAggregate, isUpdate2CustomizeSort, updateDataConfigByField} from './utils';
import { useSelector } from 'react-redux';
import { chartConfigSelector } from 'app/pages/ChartWorkbenchPage/slice/selectors';

type DragItem = {
index?: number;
@@ -65,6 +68,7 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> =
translate: t = (...args) => args?.[0],
onConfigChanged,
}) {
const chartConfig = useSelector(chartConfigSelector);
const { dataset } = useContext(ChartDatasetContext);
const { drillOption } = useContext(ChartDrillContext);
const { dataView, availableSourceFunctions } =
@@ -357,12 +361,32 @@ export const ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> =
if (!fieldConfig) {
return;
}
const newConfig = updateDataConfigByField(
let _currentConfig = currentConfig;
// Check whether the sort configuration of field has been changed to custom sort
const _isUpdate2CustomizeSort = isUpdate2CustomizeSort(columnUid, _currentConfig, fieldConfig);
if (_isUpdate2CustomizeSort) {
// Only allows custom sorting on a single field
// case 1: Custom sort field already exists in the different config section
chartConfig?.datas?.forEach((item, index) => {
if (item.key !== _currentConfig.key
&& item.allowFieldCustomizeSort
&& item.rows?.some(r => r?.sort?.type === SortActionType.Customize)
) {
// remove the custom sort configuration of field
onConfigChanged?.([index], removeCustomizeSortConfig(item), false);
}
});
// case 2: Custom sort field already exists in the same config section
if (_currentConfig.rows?.some(r => r?.sort?.type === SortActionType.Customize)) {
_currentConfig = removeCustomizeSortConfig(_currentConfig);
}
}
_currentConfig = updateDataConfigByField(
columnUid,
currentConfig,
fieldConfig,
);
onConfigChanged?.(ancestors, newConfig, needRefresh);
onConfigChanged?.(ancestors, _currentConfig, _isUpdate2CustomizeSort || needRefresh);
};

const handleOpenActionModal =
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ import {
AggregateFieldSubAggregateType,
ChartDataSectionFieldActionType,
ChartDataSectionType,
ChartDataViewFieldCategory,
ChartDataViewFieldCategory, SortActionType,
} from 'app/constants';
import { ChartDataConfig, ChartDataSectionField } from 'app/types/ChartConfig';
import { updateBy } from 'app/utils/mutation';
@@ -83,3 +83,13 @@ export const getDefaultAggregate = (
}
}
};

export const isUpdate2CustomizeSort = (
uid: string,
config: ChartDataConfig,
field: ChartDataSectionField,
) => {
const originField = config?.rows?.find(r => r.uid === uid);
const type = field?.sort?.type;
return type === SortActionType.Customize && originField?.sort?.type !== type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { FC, useRef, } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import styled from 'styled-components/macro';

interface DraggableBodyRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
index: number;
moveRow: (dragIndex: number, hoverIndex: number) => void;
canDrag: boolean;
}

const DraggableItem: FC<
DraggableBodyRowProps
> = ({
index,
moveRow,
canDrag,
...restProps
}) => {
const ref = useRef<HTMLTableRowElement>(null);
const [, drop] = useDrop({
accept: type,
drop: (item: { index: number }) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
type,
item: { index },
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
canDrag,
});
drop(drag(ref));

return (
<Tr
ref={ref}
canDrag={canDrag}
{...restProps}
/>
);
};

const type = 'DraggableBodyRow';
export default DraggableItem;

const Tr = styled.tr<{
canDrag: boolean;
}>`
cursor: ${p => (p.canDrag ? 'move' : 'no-drop')};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
import { updateBy } from 'app/utils/mutation';
import { Table } from "antd";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { getDistinctFields } from "app/utils/fetch";
import ChartDataView from "app/types/ChartDataView";
import DraggableItem from "./DraggableItem";
import { ChartDataSectionField } from "app/types/ChartConfig";
import { ColumnsType } from "antd/lib/table";
import { SortActionType } from "app/constants";

type SortableField = {
name: string;
}
const COLUMNS: ColumnsType<SortableField> = [
{
dataIndex: "name",
key: "name",
ellipsis: true,
}
];

const CustomizeSortAction: FC<{
config: ChartDataSectionField;
dataView: ChartDataView | undefined;
onConfigChange: (
config: ChartDataSectionField,
needRefresh?: boolean,
) => void;
}> = ({ config, dataView, onConfigChange }) => {
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState<SortableField[]>([]);

const getViewData = useCallback(async (viewId: string, columns: string[], dataView: ChartDataView) => {
setLoading(true);
try {
const dataSet = await getDistinctFields(
viewId,
columns,
dataView,
undefined,
);
const dataList = dataSet?.rows
.filter((row: any) => row?.[0] && (row[0] as string).trim())
.map((item: string) => ({
name: item[0]
}));
setDataSource(dataList || []);
} finally {
setLoading(false);
}
}, []);


const moveRow = useCallback((dragIndex: number, hoverIndex: number) => {
const newDataSource = updateBy(dataSource, draft => {
const dragCard = draft[dragIndex];
draft.splice(dragIndex, 1);
draft.splice(hoverIndex, 0, dragCard);
return draft;
});
const newConfig = updateBy(config, draft => {
draft.sort = {
type: SortActionType.Customize,
value: newDataSource.map(item => item.name),
}
});
setDataSource(newDataSource);
onConfigChange?.(newConfig, true);
}, [dataSource]);

useEffect(() => {
if (!dataView || !config) {
return;
}
const { type, value } = config.sort || {};
if (type === SortActionType.Customize && value?.length) {
setDataSource(Array.from(value, item => ({ name: item } as SortableField)));
} else {
getViewData(dataView.id, [config.colName], dataView);
}
}, [dataView, config]);
const canDrag = useMemo(() => dataSource.length >= 1, [dataSource]);
return (
<DndProvider backend={HTML5Backend}>
<Table
columns={COLUMNS}
dataSource={dataSource}
components={{
body: {
row: DraggableItem
}
}}
onRow={(_, index) => {
const attr = {
index,
moveRow,
canDrag,
};
return attr as React.HTMLAttributes<any>;
}}
pagination={false}
loading={loading}
scroll={{
y: 480
}}
bordered
showHeader={false}
/>
</DndProvider>
);
}

export default CustomizeSortAction;

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@
* limitations under the License.
*/

import { CheckOutlined } from '@ant-design/icons';
import { Col, Menu, Radio, Row, Space } from 'antd';
import { CheckOutlined, InfoCircleOutlined } from '@ant-design/icons';
import { Col, Menu, Radio, Row, Space, Tooltip } from 'antd';
import { SortActionType } from 'app/constants';
import useI18NPrefix from 'app/hooks/useI18NPrefix';
import { ChartDataSectionField } from 'app/types/ChartConfig';
@@ -36,7 +36,8 @@ const SortAction: FC<{
) => void;
mode?: 'menu';
options?;
}> = ({ config, dataset, mode, options, onConfigChange }) => {
allowCustomSort?: boolean;
}> = ({ config, dataset, mode, options, onConfigChange, allowCustomSort }) => {
const actionNeedNewRequest = isEmpty(options?.backendSort)
? true
: Boolean(options?.backendSort);
@@ -47,23 +48,26 @@ const SortAction: FC<{

const handleSortTypeChange = direction => {
setDirection(direction);

if (SortActionType.Customize !== direction) {
onConfigChange &&
onConfigChange(
updateBy(config, draft => {
draft.sort = { type: direction };
}),
actionNeedNewRequest,
);
}
onConfigChange?.(
updateBy(config, draft => {
draft.sort = { type: direction };
}),
actionNeedNewRequest,
);
};

const renderOptions = mode => {
if (mode === 'menu') {
let sortTypeOptions = BASE_SORT_OPTIONS;
if (allowCustomSort) {
sortTypeOptions = [
...sortTypeOptions,
SortActionType.Customize
];
}
return (
<>
{[SortActionType.None, SortActionType.ASC, SortActionType.DESC].map(
{sortTypeOptions.map(
sort => {
return (
<Menu.Item
@@ -72,7 +76,16 @@ const SortAction: FC<{
icon={direction === sort ? <CheckOutlined /> : ''}
onClick={() => handleSortTypeChange(sort)}
>
{t(`sort.${sort?.toLowerCase()}`)}
{
sort === SortActionType.Customize ?
(
<Tooltip title={t(`sort.customizeTip`)} placement='bottom'>
{t(`sort.${sort?.toLowerCase()}`)} <InfoCircleOutlined />
</Tooltip>
)
:
t(`sort.${sort?.toLowerCase()}`)
}
</Menu.Item>
);
},
@@ -111,6 +124,7 @@ const SortAction: FC<{
return renderOptions(mode);
};

const BASE_SORT_OPTIONS = [SortActionType.None, SortActionType.ASC, SortActionType.DESC];
export default SortAction;

const StyledRow = styled(Row)`
Original file line number Diff line number Diff line change
@@ -16,6 +16,6 @@
* limitations under the License.
*/

import SortAction from './SortAction';
export { default as SortAction } from './SortAction';
export { default as CustomizeSortAction } from './CustomizeSortAction';

export default SortAction;
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ import ColorizeSingleAction from './ColorizeSingleAction';
import FilterActions from './FilterAction';
import NumberFormatAction from './NumberFormatAction';
import SizeOptionsAction from './SizeAction';
import SortAction from './SortAction/SortAction';
import { SortAction, CustomizeSortAction } from './SortAction';

const { FilterAction } = FilterActions;

@@ -34,6 +34,7 @@ const actions = {
AliasAction,
NumberFormatAction,
SortAction,
CustomizeSortAction,
AggregationLimitAction,
FilterAction,
AggregationColorizeAction,
1 change: 1 addition & 0 deletions frontend/src/app/types/ChartConfig.ts
Original file line number Diff line number Diff line change
@@ -194,6 +194,7 @@ export type ChartDataConfig = ChartConfigBase & {
fieldRelation?: FilterCondition;
// Runtime filters
[RUNTIME_FILTER_KEY]?: PendingChartDataRequestFilter[];
allowFieldCustomizeSort?: boolean;
};

export type ChartStyleSectionTemplate = {
23 changes: 23 additions & 0 deletions frontend/src/app/utils/chartHelper.ts
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ import {
DataViewFieldType,
FieldFormatType,
RUNTIME_DATE_LEVEL_KEY,
SortActionType,
} from 'app/constants';
import { ChartDataSet, ChartDataSetRow } from 'app/models/ChartDataSet';
import { DrillMode } from 'app/models/ChartDrillOption';
@@ -1882,3 +1883,25 @@ export function hasAggregationFunction(exp?: string) {
AggregateFieldActionType.Sum,
].some(agg => new RegExp(`${agg}\\(`, 'i').test(exp || ''));
}

export function removeCustomizeSortConfig(config: ChartDataConfig): ChartDataConfig {
return updateBy(config, draft => {
draft.rows?.forEach(r => {
if (r?.sort?.type === SortActionType.Customize) {
delete r.sort;
}
});
});
}

export function clearUnsupportedChartConfig(chartConfig: ChartConfig): ChartConfig {
return updateBy(chartConfig, draft => {
draft.datas = (draft?.datas || []).map(item => {
if (!item.allowFieldCustomizeSort) {
return removeCustomizeSortConfig(item);
}
return item;
});
});
};

3 changes: 2 additions & 1 deletion frontend/src/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -637,7 +637,8 @@
"none": "Default",
"asc": "Ascending",
"desc": "Descending",
"customize": "Customized"
"customize": "Customized",
"customizeTip": "Only allows custom sorting on a single non-numeric field"
},
"format": {
"title": "Format Setting",
3 changes: 2 additions & 1 deletion frontend/src/locales/zh/translation.json
Original file line number Diff line number Diff line change
@@ -635,7 +635,8 @@
"none": "默认排序",
"asc": "升序排列",
"desc": "降序排列",
"customize": "自定义"
"customize": "自定义",
"customizeTip": "只允许对单个非数值型字段自定义排序"
},
"format": {
"title": "格式设置",