Skip to content

Commit

Permalink
Merge pull request #1451 from merico-dev/1450-apply-visualmap-to-cale…
Browse files Browse the repository at this point in the history
…ndar-heatmap-merico-heatmap

1450 apply visualmap to calendar heatmap merico heatmap
  • Loading branch information
GerilLeto authored Jun 25, 2024
2 parents 0e25fdc + 89de81a commit 72c1ed1
Show file tree
Hide file tree
Showing 31 changed files with 301 additions and 270 deletions.
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/api",
"version": "13.18.0",
"version": "13.19.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtable/dashboard",
"version": "13.18.0",
"version": "13.19.0",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ export function getNumberOrDynamicValue(

if (conf.type === 'static') {
const { value } = conf as TNumberOrDynamic_Static;
return value;
return Number(value);
}

const { value } = conf as TNumberOrDynamic_Dynamic;
try {
return new Function(`return ${value}`)()({ variables: variableValueMap }, { lodash, interpolate });
const ret = new Function(`return ${value}`)()({ variables: variableValueMap }, { lodash, interpolate });
return Number(ret);
} catch (error) {
// @ts-expect-error Object is of type 'unknown'.
console.error(`[getNumberOrDynamicValue] failed parsing custom function, error: ${error.message}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ export function getVisualMap(visualMap: VisualMap, variableValueMap: Record<stri
const { piecewise_mode, pieces, categories, ...rest } = visualMap;
const ret: AnyObject = {
...rest,
min: minValue,
max: maxValue,
};
delete ret.min;
delete ret.max;

if (piecewise_mode === 'pieces') {
ret.pieces = pieces.map((p) => {
const item: AnyObject = {};
Expand All @@ -106,11 +107,16 @@ export function getVisualMap(visualMap: VisualMap, variableValueMap: Record<stri
item.color = p.color;
}
const lowerValue = Number(p.lower.value);
if (p.lower.value !== '' && Number.isFinite(lowerValue)) {
if (p.lower.value === '') {
item[p.lower.symbol] = minValue;
} else if (Number.isFinite(lowerValue)) {
item[p.lower.symbol] = lowerValue;
}

const upperValue = Number(p.upper.value);
if (p.upper.value !== '' && Number.isFinite(upperValue)) {
if (p.upper.value === '') {
item[p.upper.symbol] = maxValue;
} else if (Number.isFinite(upperValue)) {
item[p.upper.symbol] = upperValue;
}
return item;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export const VisualMapEditor = ({ form }: Props) => {
const { t, i18n } = useTranslation();
const control = form.control;
const visualMap = form.watch('visualMap');
const { type, orient } = visualMap;

const visualMapTypeOptions = useMemo(() => {
return [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Button, Group, Popover, Select, Text, TextInput } from '@mantine/core';
import { Control, Controller, UseFormReturn } from 'react-hook-form';
import { VisualMapPartialForm } from '../types';
import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

const symbols = {
lower: [
Expand All @@ -20,27 +21,32 @@ const symbolToBracket = {
lt: ')',
lte: ']',
};
const toIntervalValue = (v: string, sign: '' | '-') => {
if (v === '' || Number.isNaN(Number(v))) {
return sign + '∞';
const toIntervalValue = (v: string, extremum: '') => {
if (v === '') {
return extremum;
}
return sign + v;
if (Number.isNaN(Number(v))) {
return 'INVALID VALUE';
}
return v;
};

type Props = {
form: UseFormReturn<VisualMapPartialForm>;
index: number;
};
export const IntervalEditor = ({ form, index }: Props) => {
const { t } = useTranslation();

const { control, watch } = form;
const piece = watch(`visualMap.pieces.${index}`);
const { lower, upper } = piece;

const intervalPreview = [
symbolToBracket[lower.symbol],
toIntervalValue(lower.value, '-'),
toIntervalValue(lower.value, t('chart.visual_map.min_value')),
',',
toIntervalValue(upper.value, ''),
toIntervalValue(upper.value, t('chart.visual_map.max_value')),
symbolToBracket[upper.symbol],
].join('');

Expand Down Expand Up @@ -77,11 +83,10 @@ export const IntervalEditor = ({ form, index }: Props) => {
render={({ field }) => (
<TextInput
{...field}
placeholder="∞"
placeholder={t('chart.visual_map.min_value')}
size="xs"
onChange={(e) => field.onChange(e.currentTarget.value)}
error={field.value !== '' && Number.isNaN(Number(field.value))}
styles={{ input: { '&::placeholder': { fontSize: '16px' } } }}
/>
)}
/>
Expand All @@ -93,7 +98,7 @@ export const IntervalEditor = ({ form, index }: Props) => {
)}
/>
<Text color="dimmed" size="sm" sx={{ userSelect: 'none', cursor: 'default' }}>
value
{t('common.value').toLowerCase()}
</Text>
<Controller
name={`visualMap.pieces.${index}.upper.symbol`}
Expand All @@ -109,10 +114,9 @@ export const IntervalEditor = ({ form, index }: Props) => {
<TextInput
{...field}
size="xs"
placeholder="∞"
placeholder={t('chart.visual_map.max_value')}
onChange={(e) => field.onChange(e.currentTarget.value)}
error={field.value !== '' && Number.isNaN(Number(field.value))}
styles={{ input: { '&::placeholder': { fontSize: '16px' } } }}
/>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const PieceEditor = ({ form, index, remove }: Props) => {
const { t } = useTranslation();
return (
<tr>
<td>{index.toString()}</td>
<td>{(index + 1).toString()}</td>
<td>
<IntervalEditor form={form} index={index} />
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export const PiecesEditor = ({ form }: Props) => {
<thead>
<tr>
<th style={{ width: '40px' }} />
<th>Interval</th>
<th>Label</th>
<th>Color</th>
<th>{t('chart.visual_map.piecewise.interval')}</th>
<th>{t('chart.visual_map.piecewise.piece_label')}</th>
<th>{t('chart.color.label')}</th>
<th style={{ width: '40px' }} />
</tr>
</thead>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Divider, Group, Stack, TextInput } from '@mantine/core';
import { Control, Controller, UseFormWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { DataFieldSelector } from '~/components/panel/settings/common/data-field-selector';
import { NumbroFormatSelector } from '~/components/panel/settings/common/numbro-format-selector';
import { NumberOrDynamicValue } from '~/components/plugins/common-echarts-fields/number-or-dynamic-value';
import { ICalendarHeatmapConf } from '../../type';
import { useTranslation } from 'react-i18next';

interface IHeatBlockField {
control: Control<ICalendarHeatmapConf, $TSFixMe>;
Expand All @@ -27,18 +26,7 @@ export function HeatBlockField({ control, watch }: IHeatBlockField) {
render={({ field }) => <TextInput label={t('common.name')} sx={{ flex: 1 }} {...field} />}
/>
</Group>
<Group grow noWrap>
<Controller
name="heat_block.min"
control={control}
render={({ field }) => <NumberOrDynamicValue label={t('chart.heatmap.heatblock.min_value')} {...field} />}
/>
<Controller
name="heat_block.max"
control={control}
render={({ field }) => <NumberOrDynamicValue label={t('chart.heatmap.heatblock.max_value')} {...field} />}
/>
</Group>

<Divider mb={-15} variant="dashed" label={t('numbro.format.label')} labelPosition="center" />
<Controller
name={`heat_block.value_formatter`}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,72 +1,14 @@
import { AnyObject } from '~/types';
import { VizComponent } from '~/types/plugin';
import { IMigrationEnv, VersionBasedMigrator } from '../../plugin-data-migrator';
import { VersionBasedMigrator } from '../../plugin-data-migrator';
import * as Migrators from './migrators';
import { translation } from './translation';
import { ClickCalendarDate } from './triggers';
import { DEFAULT_CONFIG, ICalendarHeatmapConf } from './type';
import { VizCalendarHeatmap } from './viz-calendar-heatmap';
import { VizCalendarHeatmapEditor } from './viz-calendar-heatmap-editor';
import { DEFAULT_CONFIG, ICalendarHeatmapConf } from './type';
import { ClickCalendarDate } from './triggers';
import { translation } from './translation';

function v2(legacyConf: any, { panelModel }: IMigrationEnv): ICalendarHeatmapConf {
try {
const queryID = panelModel.queryIDs[0];
if (!queryID) {
throw new Error('cannot migrate when queryID is empty');
}
const changeKey = (key: string) => (key ? `${queryID}.${key}` : key);
const { calendar, heat_block, tooltip, ...rest } = legacyConf;
return {
...rest,
calendar: {
...calendar,
data_key: changeKey(calendar.data_key),
},
heat_block: {
...heat_block,
data_key: changeKey(heat_block.data_key),
},
tooltip: {
...tooltip,
metrics: tooltip.metrics.map((m: any) => ({
...m,
data_key: changeKey(m.data_key),
})),
},
};
} catch (error) {
console.error('[Migration failed]', error);
throw error;
}
}

function v3(legacyConf: any): ICalendarHeatmapConf {
const { heat_block } = legacyConf;
let { min, max } = heat_block;
if (typeof min !== 'number') {
min = 0;
}
if (typeof max !== 'number') {
max = 100;
}

return {
...legacyConf,
heat_block: {
...heat_block,
min: {
type: 'static',
value: min,
},
max: {
type: 'static',
value: max,
},
},
};
}

class VizCalendarHeatmapMigrator extends VersionBasedMigrator {
readonly VERSION = 3;
readonly VERSION = 4;

configVersions(): void {
this.version(1, (data: any) => {
Expand All @@ -79,14 +21,21 @@ class VizCalendarHeatmapMigrator extends VersionBasedMigrator {
return {
...data,
version: 2,
config: v2(data.config, env),
config: Migrators.v2(data.config, env),
};
});
this.version(3, (data) => {
return {
...data,
version: 3,
config: v3(data.config),
config: Migrators.v3(data.config),
};
});
this.version(4, (data) => {
return {
...data,
version: 4,
config: Migrators.v4(data.config),
};
});
}
Expand All @@ -104,7 +53,7 @@ export const CalendarHeatmapVizComponent: VizComponent = {
name: 'calendarHeatmap',
viewRender: VizCalendarHeatmap,
configRender: VizCalendarHeatmapEditor,
createConfig: (): ConfigType => ({ version: 3, config: DEFAULT_CONFIG }),
createConfig: (): ConfigType => ({ version: 4, config: DEFAULT_CONFIG }),
triggers: [ClickCalendarDate],
translation,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { getDefaultVisualMap } from '~/components/plugins/common-echarts-fields/visual-map';
import { ICalendarHeatmapConf } from '../type';
import { IMigrationEnv } from '~/components/plugins/plugin-data-migrator';

export function v2(legacyConf: any, { panelModel }: IMigrationEnv): ICalendarHeatmapConf {
try {
const queryID = panelModel.queryIDs[0];
if (!queryID) {
throw new Error('cannot migrate when queryID is empty');
}
const changeKey = (key: string) => (key ? `${queryID}.${key}` : key);
const { calendar, heat_block, tooltip, ...rest } = legacyConf;
return {
...rest,
calendar: {
...calendar,
data_key: changeKey(calendar.data_key),
},
heat_block: {
...heat_block,
data_key: changeKey(heat_block.data_key),
},
tooltip: {
...tooltip,
metrics: tooltip.metrics.map((m: any) => ({
...m,
data_key: changeKey(m.data_key),
})),
},
};
} catch (error) {
console.error('[Migration failed]', error);
throw error;
}
}

export function v3(legacyConf: any): ICalendarHeatmapConf {
const { heat_block } = legacyConf;
let { min, max } = heat_block;
if (typeof min !== 'number') {
min = 0;
}
if (typeof max !== 'number') {
max = 100;
}

return {
...legacyConf,
heat_block: {
...heat_block,
min: {
type: 'static',
value: min,
},
max: {
type: 'static',
value: max,
},
},
};
}

export function v4(legacyConf: any): ICalendarHeatmapConf {
const {
visualMap = getDefaultVisualMap(),
heat_block: { min, max, ...restHeatBlock },
...rest
} = legacyConf;
return {
...rest,
heat_block: restHeatBlock,
visualMap: {
...getDefaultVisualMap(),
min,
max,
},
};
}
Loading

0 comments on commit 72c1ed1

Please sign in to comment.