Skip to content

Commit ec98f9d

Browse files
authored
Merge pull request #1137 from merico-dev/1132-add-merico-heatmap
1132 add merico heatmap
2 parents 3669eeb + 169a94f commit ec98f9d

File tree

33 files changed

+1314
-14
lines changed

33 files changed

+1314
-14
lines changed

api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/api",
3-
"version": "10.20.2",
3+
"version": "10.21.0",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/dashboard",
3-
"version": "10.20.2",
3+
"version": "10.21.0",
44
"license": "Apache-2.0",
55
"publishConfig": {
66
"access": "public",

dashboard/src/components/plugins/common-echarts-fields/number-or-dynamic-value/get-number-or-dynamic-value.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export function getNumberOrDynamicValue(
1818

1919
const { value } = conf as TNumberOrDynamic_Dynamic;
2020
try {
21-
console.log('returning here');
2221
return new Function(`return ${value}`)()({ variables: variableValueMap }, { lodash, interpolate });
2322
} catch (error) {
2423
// @ts-expect-error Object is of type 'unknown'.

dashboard/src/components/plugins/plugin-context.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { CalendarHeatmapVizComponent } from './viz-components/calendar-heatmap';
3838
import { HorizontalBarChartVizComponent } from './viz-components/horizontal-bar-chart';
3939
import { MericoEstimationChartVizComponent } from './viz-components/merico-estimation-chart';
4040
import { MericoStatsVizComponent } from './viz-components/merico-stats';
41+
import { MericoHeatmapVizComponent } from './viz-components/merico-heatmap';
4142

4243
export interface IPluginContextProps {
4344
pluginManager: IPluginManager;
@@ -137,6 +138,7 @@ const BuiltInPlugin: () => IDashboardPlugin = () => ({
137138
RegressionChartVizComponent,
138139
MericoGQMVizComponent,
139140
MericoEstimationChartVizComponent,
141+
MericoHeatmapVizComponent,
140142
MericoStatsVizComponent,
141143
ButtonVizComponent,
142144
],

dashboard/src/components/plugins/viz-components/heatmap/option/x-axis.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import _ from 'lodash';
2-
import { AnyObject } from '~/types';
2+
import { parseDataKey } from '~/utils/data';
3+
import { getLabelOverflowOptionOnAxis } from '../../../common-echarts-fields/axis-label-overflow';
34
import { FormatterFuncType } from '../editors/x-axis/x-axis-label-formatter/get-echarts-x-axis-tick-label';
45
import { IHeatmapConf } from '../type';
5-
import { getLabelOverflowOptionOnAxis } from '../../../common-echarts-fields/axis-label-overflow';
6-
import { parseDataKey } from '~/utils/data';
76

87
export function getXAxis(conf: IHeatmapConf, data: TPanelData, formatterFunc: FormatterFuncType) {
98
const x = parseDataKey(conf.x_axis.data_key);
@@ -35,6 +34,6 @@ export function getXAxis(conf: IHeatmapConf, data: TPanelData, formatterFunc: Fo
3534
fontWeight: 'bold',
3635
align: 'center',
3736
},
38-
z: 1,
37+
z: 2,
3938
};
4039
}

dashboard/src/components/plugins/viz-components/heatmap/option/y-axis.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import _ from 'lodash';
2-
import { AnyObject } from '~/types';
2+
import { parseDataKey } from '~/utils/data';
3+
import { getLabelOverflowOptionOnAxis } from '../../../common-echarts-fields/axis-label-overflow';
34
import { FormatterFuncType } from '../editors/x-axis/x-axis-label-formatter/get-echarts-x-axis-tick-label';
45
import { IHeatmapConf } from '../type';
5-
import { getLabelOverflowOptionOnAxis } from '../../../common-echarts-fields/axis-label-overflow';
6-
import { parseDataKey } from '~/utils/data';
76

87
export function getYAxis(conf: IHeatmapConf, data: TPanelData, formatterFunc: FormatterFuncType) {
98
const x = parseDataKey(conf.x_axis.data_key);
@@ -40,6 +39,6 @@ export function getYAxis(conf: IHeatmapConf, data: TPanelData, formatterFunc: Fo
4039
},
4140
nameLocation: 'end',
4241
nameGap: 15,
43-
z: 1,
42+
z: 2,
4443
};
4544
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Divider, Group, NumberInput, Stack, Switch, TextInput } from '@mantine/core';
2+
import { IconTextSize } from '@tabler/icons-react';
3+
import { Control, Controller, UseFormWatch } from 'react-hook-form';
4+
import { DataFieldSelector } from '~/components/panel/settings/common/data-field-selector';
5+
import { NumbroFormatSelector } from '~/components/panel/settings/common/numbro-format-selector';
6+
import { NumberOrDynamicValue } from '~/components/plugins/common-echarts-fields/number-or-dynamic-value';
7+
import { TMericoHeatmapConf } from '../../type';
8+
9+
interface IHeatBlockField {
10+
control: Control<TMericoHeatmapConf, $TSFixMe>;
11+
watch: UseFormWatch<TMericoHeatmapConf>;
12+
}
13+
export function HeatBlockField({ control, watch }: IHeatBlockField) {
14+
watch(['heat_block']);
15+
const showLabel = watch('heat_block.label.show');
16+
return (
17+
<Stack>
18+
<Group grow noWrap>
19+
<Controller
20+
name="heat_block.data_key"
21+
control={control}
22+
render={({ field }) => <DataFieldSelector label="Data Field" required sx={{ flex: 1 }} {...field} />}
23+
/>
24+
<Controller
25+
name="heat_block.name"
26+
control={control}
27+
render={({ field }) => <TextInput label="Name" sx={{ flex: 1 }} {...field} />}
28+
/>
29+
</Group>
30+
<Group grow noWrap>
31+
<Controller
32+
name="heat_block.min"
33+
control={control}
34+
render={({ field }) => <NumberOrDynamicValue label="Min Value" {...field} />}
35+
/>
36+
<Controller
37+
name="heat_block.max"
38+
control={control}
39+
render={({ field }) => <NumberOrDynamicValue label="Max Value" {...field} />}
40+
/>
41+
</Group>
42+
43+
<Divider mb={-15} variant="dashed" label="Value Format" labelPosition="center" />
44+
<Controller
45+
name={`heat_block.value_formatter`}
46+
control={control}
47+
render={({ field }) => <NumbroFormatSelector {...field} />}
48+
/>
49+
50+
<Divider mb={-5} variant="dashed" label="Label" labelPosition="center" />
51+
<Group grow noWrap>
52+
<Controller
53+
name="heat_block.label.show"
54+
control={control}
55+
render={({ field }) => (
56+
<Switch
57+
label="Show label"
58+
checked={field.value}
59+
onChange={(e) => field.onChange(e.currentTarget.checked)}
60+
sx={{ flexGrow: 1 }}
61+
/>
62+
)}
63+
/>
64+
<Controller
65+
name="heat_block.label.fontSize"
66+
control={control}
67+
render={({ field }) => (
68+
// @ts-expect-error type of onChange
69+
<NumberInput size="xs" icon={<IconTextSize size={16} />} disabled={!showLabel} {...field} />
70+
)}
71+
/>
72+
</Group>
73+
</Stack>
74+
);
75+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { ActionIcon, Group, Stack, Tabs, Text } from '@mantine/core';
2+
import _, { defaultsDeep, isEqual } from 'lodash';
3+
import { useEffect, useMemo } from 'react';
4+
import { useForm } from 'react-hook-form';
5+
6+
import { DeviceFloppy } from 'tabler-icons-react';
7+
import { useStorageData } from '~/components/plugins/hooks';
8+
import { VizConfigProps } from '~/types/plugin';
9+
import { HeatBlockField } from './heat_block';
10+
import { TooltipField } from './tooltip';
11+
import { XAxisField } from './x-axis';
12+
import { YAxisField } from './y-axis';
13+
import { DEFAULT_CONFIG, TMericoHeatmapConf } from '../type';
14+
15+
export function EditMericoHeatmap({ context }: VizConfigProps) {
16+
const { value: confValue, set: setConf } = useStorageData<TMericoHeatmapConf>(context.instanceData, 'config');
17+
const { variables } = context;
18+
const conf: TMericoHeatmapConf = useMemo(() => defaultsDeep({}, confValue, DEFAULT_CONFIG), [confValue]);
19+
const defaultValues: TMericoHeatmapConf = useMemo(() => {
20+
return _.cloneDeep(conf);
21+
}, [conf]);
22+
23+
useEffect(() => {
24+
const configMalformed = !isEqual(conf, defaultValues);
25+
if (configMalformed) {
26+
console.log('config malformed, resetting to defaults', conf, defaultValues);
27+
void setConf(defaultValues);
28+
}
29+
}, [conf, defaultValues]);
30+
31+
const { control, handleSubmit, watch, getValues, reset } = useForm<TMericoHeatmapConf>({ defaultValues });
32+
useEffect(() => {
33+
reset(defaultValues);
34+
}, [defaultValues]);
35+
36+
const values = getValues();
37+
const changed = useMemo(() => {
38+
return !isEqual(values, conf);
39+
}, [values, conf]);
40+
41+
return (
42+
<form onSubmit={handleSubmit(setConf)} style={{ flexGrow: 1 }}>
43+
<Stack spacing="xs" sx={{ height: '100%' }}>
44+
<Group position="left" py="md" pl="md" sx={{ borderBottom: '1px solid #eee', background: '#efefef' }}>
45+
<Text>Chart Config</Text>
46+
<ActionIcon type="submit" mr={5} variant="filled" color="blue" disabled={!changed}>
47+
<DeviceFloppy size={20} />
48+
</ActionIcon>
49+
</Group>
50+
<Tabs
51+
defaultValue="X Axis"
52+
orientation="vertical"
53+
styles={{
54+
root: {
55+
// height: '100%',
56+
flexGrow: 1,
57+
},
58+
tab: {
59+
paddingLeft: '6px',
60+
paddingRight: '6px',
61+
},
62+
panel: {
63+
paddingTop: '6px',
64+
paddingLeft: '12px',
65+
},
66+
}}
67+
>
68+
<Tabs.List>
69+
<Tabs.Tab value="X Axis">X Axis</Tabs.Tab>
70+
<Tabs.Tab value="Y Axis">Y Axis</Tabs.Tab>
71+
<Tabs.Tab value="Heat Block">Heat Block</Tabs.Tab>
72+
<Tabs.Tab value="Tooltip">Tooltip</Tabs.Tab>
73+
</Tabs.List>
74+
75+
<Tabs.Panel value="X Axis">
76+
<XAxisField control={control} watch={watch} />
77+
</Tabs.Panel>
78+
79+
<Tabs.Panel value="Y Axis">
80+
<YAxisField control={control} watch={watch} />
81+
</Tabs.Panel>
82+
83+
<Tabs.Panel value="Heat Block">
84+
<HeatBlockField control={control} watch={watch} />
85+
</Tabs.Panel>
86+
87+
<Tabs.Panel value="Tooltip">
88+
<TooltipField control={control} watch={watch} />
89+
</Tabs.Panel>
90+
</Tabs>
91+
</Stack>
92+
</form>
93+
);
94+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Control, UseFormWatch } from 'react-hook-form';
2+
import { TMericoHeatmapConf } from '../../type';
3+
import { TooltipMetricsField } from './metrics';
4+
5+
interface ITooltipField {
6+
control: Control<TMericoHeatmapConf, $TSFixMe>;
7+
watch: UseFormWatch<TMericoHeatmapConf>;
8+
}
9+
export function TooltipField({ control, watch }: ITooltipField) {
10+
return <TooltipMetricsField control={control} watch={watch} />;
11+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Button, Divider, Group, Stack, TextInput } from '@mantine/core';
2+
import { Control, Controller } from 'react-hook-form';
3+
import { Trash } from 'tabler-icons-react';
4+
import { DataFieldSelector } from '~/components/panel/settings/common/data-field-selector';
5+
import { TMericoHeatmapConf } from '../../type';
6+
7+
interface ITooltipMetricField {
8+
control: Control<TMericoHeatmapConf, $TSFixMe>;
9+
index: number;
10+
remove: (index: number) => void;
11+
}
12+
13+
export const TooltipMetricField = ({ control, index, remove }: ITooltipMetricField) => {
14+
return (
15+
<Stack>
16+
<Group grow noWrap>
17+
<Controller
18+
name={`tooltip.metrics.${index}.name`}
19+
control={control}
20+
render={({ field }) => <TextInput label="Name" required sx={{ flex: 1 }} {...field} />}
21+
/>
22+
<Controller
23+
name={`tooltip.metrics.${index}.data_key`}
24+
control={control}
25+
render={({ field }) => <DataFieldSelector label="Value Field" required sx={{ flex: 1 }} {...field} />}
26+
/>
27+
</Group>
28+
<Divider mb={-10} mt={10} variant="dashed" />
29+
<Button
30+
leftIcon={<Trash size={16} />}
31+
color="red"
32+
variant="light"
33+
onClick={() => remove(index)}
34+
sx={{ top: 15, right: 5 }}
35+
>
36+
Delete this Metric
37+
</Button>
38+
</Stack>
39+
);
40+
};

0 commit comments

Comments
 (0)