ui: better granularity support, comparison view for bar chart
This commit is contained in:
parent
92412685b0
commit
08be943ae0
16 changed files with 277 additions and 83 deletions
|
|
@ -33,8 +33,6 @@ function CustomMetricLineChart(props: Props) {
|
|||
hideLegend = false,
|
||||
} = props;
|
||||
|
||||
|
||||
console.log(data.namesMap, data.chart)
|
||||
return (
|
||||
<ResponsiveContainer height={240} width="100%">
|
||||
<AreaChart
|
||||
|
|
@ -50,7 +48,7 @@ function CustomMetricLineChart(props: Props) {
|
|||
vertical={false}
|
||||
stroke="#EEEEEE"
|
||||
/>
|
||||
<XAxis {...Styles.xaxis} dataKey="time" interval={params.density / 7} />
|
||||
<XAxis {...Styles.xaxis} dataKey="time" interval={'equidistantPreserveStart'} />
|
||||
<YAxis
|
||||
{...yaxis}
|
||||
allowDecimals={false}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import {
|
|||
BarChart,
|
||||
Bar,
|
||||
Legend,
|
||||
Rectangle,
|
||||
} from 'recharts';
|
||||
|
||||
interface Props {
|
||||
data: any;
|
||||
data: { chart: any[], namesMap: string[] };
|
||||
compData: { chart: any[], namesMap: string[] } | null;
|
||||
params: any;
|
||||
colors: any;
|
||||
onClick?: (event, index) => void;
|
||||
|
|
@ -22,6 +22,7 @@ interface Props {
|
|||
label?: string;
|
||||
hideLegend?: boolean;
|
||||
}
|
||||
|
||||
const getPath = (x, y, width, height) => {
|
||||
const radius = Math.min(width / 2, height / 2);
|
||||
return `
|
||||
|
|
@ -39,15 +40,35 @@ const getPath = (x, y, width, height) => {
|
|||
};
|
||||
|
||||
const PillBar = (props) => {
|
||||
const { fill, x, y, width, height } = props;
|
||||
const { fill, x, y, width, height, striped } = props;
|
||||
|
||||
return <path d={getPath(x, y, width, height)} stroke="none" fill={fill} />;
|
||||
return (
|
||||
<g transform={`translate(${x}, ${y})`}>
|
||||
<rect
|
||||
width={width}
|
||||
height={height}
|
||||
rx={Math.min(width / 2, height / 2)}
|
||||
ry={Math.min(width / 2, height / 2)}
|
||||
fill={fill}
|
||||
/>
|
||||
{striped && (
|
||||
<rect
|
||||
width={width}
|
||||
height={height}
|
||||
clipPath="url(#pillClip)"
|
||||
fill="url(#diagonalStripes)"
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
function CustomMetricLineChart(props: Props) {
|
||||
const {
|
||||
data = { chart: [], namesMap: [] },
|
||||
compData,
|
||||
params,
|
||||
colors,
|
||||
onClick = () => null,
|
||||
|
|
@ -56,13 +77,32 @@ function CustomMetricLineChart(props: Props) {
|
|||
hideLegend = false,
|
||||
} = props;
|
||||
|
||||
const resultChart = data.chart.map((item, i) => {
|
||||
if (compData && compData.chart[i]) return { ...compData.chart[i], ...item };
|
||||
return item;
|
||||
});
|
||||
|
||||
return (
|
||||
<ResponsiveContainer height={240} width="100%">
|
||||
<BarChart
|
||||
data={data.chart}
|
||||
data={resultChart}
|
||||
margin={Styles.chartMargins}
|
||||
onClick={onClick}
|
||||
>
|
||||
<defs>
|
||||
<clipPath id="pillClip">
|
||||
<rect x="0" y="0" width="100%" height="100%" rx="10" ry="10" />
|
||||
</clipPath>
|
||||
<pattern
|
||||
id="diagonalStripes"
|
||||
patternUnits="userSpaceOnUse"
|
||||
width="8"
|
||||
height="8"
|
||||
patternTransform="rotate(45)"
|
||||
>
|
||||
<line x1="0" y="0" x2="0" y2="8" stroke="white" strokeWidth="6" />
|
||||
</pattern>
|
||||
</defs>
|
||||
{!hideLegend && (
|
||||
<Legend iconType={'circle'} wrapperStyle={{ top: -26 }} />
|
||||
)}
|
||||
|
|
@ -71,7 +111,11 @@ function CustomMetricLineChart(props: Props) {
|
|||
vertical={false}
|
||||
stroke="#EEEEEE"
|
||||
/>
|
||||
<XAxis {...Styles.xaxis} dataKey="time" interval={params.density / 7} />
|
||||
<XAxis
|
||||
{...Styles.xaxis}
|
||||
dataKey="time"
|
||||
interval={'equidistantPreserveStart'}
|
||||
/>
|
||||
<YAxis
|
||||
{...yaxis}
|
||||
allowDecimals={false}
|
||||
|
|
@ -89,13 +133,32 @@ function CustomMetricLineChart(props: Props) {
|
|||
name={key}
|
||||
type="monotone"
|
||||
dataKey={key}
|
||||
shape={<PillBar />}
|
||||
fill={colors[index]}
|
||||
shape={(barProps) => (
|
||||
<PillBar {...barProps} fill={colors[index]} />
|
||||
)}
|
||||
legendType={key === 'Total' ? 'none' : 'line'}
|
||||
activeBar={<PillBar fill={colors[index]} stroke={colors[index]} />}
|
||||
// strokeDasharray={'4 3'} FOR COPMARISON ONLY
|
||||
activeBar={
|
||||
<PillBar fill={colors[index]} stroke={colors[index]} />
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{compData
|
||||
? compData.namesMap.map((key, i) => (
|
||||
<Bar
|
||||
key={key}
|
||||
name={key}
|
||||
type="monotone"
|
||||
dataKey={key}
|
||||
shape={(barProps) => (
|
||||
<PillBar {...barProps} fill={colors[i]} barKey={i} stroke={colors[i]} striped />
|
||||
)}
|
||||
legendType={key === 'Total' ? 'none' : 'line'}
|
||||
activeBar={
|
||||
<PillBar fill={colors[i]} stroke={colors[i]} barKey={i} striped />
|
||||
}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { formatTimeOrDate } from 'App/date';
|
||||
import cn from 'classnames';
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react'
|
||||
|
||||
function CustomTooltip({ active, payload, label }) {
|
||||
if (!active) return;
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ function CustomTooltip({ active, payload, label }) {
|
|||
className={'flex flex-col gap-1 bg-white shadow border rounded p-2 z-30'}
|
||||
>
|
||||
{transformedArray.map((p, index) => (
|
||||
<>
|
||||
<React.Fragment key={p.name + index}>
|
||||
<div className={'flex gap-2 items-center'}>
|
||||
<div
|
||||
style={{ borderRadius: 99, background: p.color }}
|
||||
|
|
@ -67,7 +68,7 @@ function CustomTooltip({ active, payload, label }) {
|
|||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ function CustomMetricLineChart(props: Props) {
|
|||
if (compData && compData.chart[i]) return { ...compData.chart[i], ...item }
|
||||
return item
|
||||
})
|
||||
|
||||
return (
|
||||
<ResponsiveContainer height={240} width="100%">
|
||||
<LineChart
|
||||
|
|
@ -60,7 +61,7 @@ function CustomMetricLineChart(props: Props) {
|
|||
vertical={false}
|
||||
stroke="#EEEEEE"
|
||||
/>
|
||||
<XAxis {...Styles.xaxis} dataKey="time" interval={params.density / 7} />
|
||||
<XAxis {...Styles.xaxis} dataKey="time" interval={'equidistantPreserveStart'} />
|
||||
<YAxis
|
||||
{...yaxis}
|
||||
allowDecimals={false}
|
||||
|
|
@ -72,25 +73,25 @@ function CustomMetricLineChart(props: Props) {
|
|||
/>
|
||||
<Tooltip {...Styles.tooltip} content={CustomTooltip} />
|
||||
{Array.isArray(data.namesMap) &&
|
||||
data.namesMap.map((key, index) => key ? (
|
||||
<Line
|
||||
key={key}
|
||||
name={key}
|
||||
animationDuration={0}
|
||||
type="monotone"
|
||||
dataKey={key}
|
||||
stroke={colors[index]}
|
||||
fillOpacity={1}
|
||||
strokeWidth={2}
|
||||
strokeOpacity={key === 'Total' ? 0 : 0.6}
|
||||
legendType={key === 'Total' ? 'none' : 'line'}
|
||||
dot={false}
|
||||
// strokeDasharray={'4 3'} FOR COPMARISON ONLY
|
||||
activeDot={{
|
||||
fill: key === 'Total' ? 'transparent' : colors[index],
|
||||
}}
|
||||
/>
|
||||
) : null)}
|
||||
data.namesMap.map((key, index) => key ? (
|
||||
<Line
|
||||
key={key}
|
||||
name={key}
|
||||
animationDuration={0}
|
||||
type="monotone"
|
||||
dataKey={key}
|
||||
stroke={colors[index]}
|
||||
fillOpacity={1}
|
||||
strokeWidth={2}
|
||||
strokeOpacity={key === 'Total' ? 0 : 0.6}
|
||||
legendType={key === 'Total' ? 'none' : 'line'}
|
||||
dot={false}
|
||||
// strokeDasharray={'4 3'} FOR COPMARISON ONLY
|
||||
activeDot={{
|
||||
fill: key === 'Total' ? 'transparent' : colors[index],
|
||||
}}
|
||||
/>
|
||||
) : null)}
|
||||
{compData ? compData.namesMap.map((key, i) => (
|
||||
<Line
|
||||
key={key}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ function WidgetChart(props: Props) {
|
|||
const drillDownFilter = dashboardStore.drillDownFilter;
|
||||
const colors = Styles.customMetricColors;
|
||||
const [loading, setLoading] = useState(true);
|
||||
const params = { density: 70 };
|
||||
const metricParams = { ...params };
|
||||
const params = { density: dashboardStore.selectedDensity }
|
||||
const metricParams = _metric.params;
|
||||
const prevMetricRef = useRef<any>();
|
||||
const isMounted = useIsMounted();
|
||||
const [data, setData] = useState<any>(metric.data);
|
||||
|
|
@ -153,8 +153,8 @@ function WidgetChart(props: Props) {
|
|||
prevMetricRef.current = metric;
|
||||
const timestmaps = drillDownPeriod.toTimestamps();
|
||||
const payload = isSaved
|
||||
? { ...params }
|
||||
: { ...metricParams, ...timestmaps, ...metric.toJson() };
|
||||
? { ...metricParams }
|
||||
: { ...params, ...timestmaps, ...metric.toJson() };
|
||||
debounceRequest(
|
||||
metric,
|
||||
payload,
|
||||
|
|
@ -167,7 +167,7 @@ function WidgetChart(props: Props) {
|
|||
if (!dashboardStore.comparisonPeriod) return setCompData(null);
|
||||
|
||||
const timestamps = dashboardStore.comparisonPeriod.toTimestamps();
|
||||
const payload = { ...metricParams, ...timestamps, ...metric.toJson() };
|
||||
const payload = { ...params, ...timestamps, ...metric.toJson() };
|
||||
fetchMetricChartData(metric, payload, isSaved, dashboardStore.comparisonPeriod, true);
|
||||
}
|
||||
useEffect(() => {
|
||||
|
|
@ -180,6 +180,7 @@ function WidgetChart(props: Props) {
|
|||
drillDownPeriod,
|
||||
period,
|
||||
depsString,
|
||||
dashboardStore.selectedDensity,
|
||||
metric.metricType,
|
||||
metric.metricOf,
|
||||
metric.metricValue,
|
||||
|
|
@ -257,6 +258,7 @@ function WidgetChart(props: Props) {
|
|||
return (
|
||||
<BarChart
|
||||
data={chartData}
|
||||
compData={compData}
|
||||
params={params}
|
||||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
import React from 'react'
|
||||
import AntlikeDropdown from "Shared/Dropdown";
|
||||
import { DownOutlined } from "@ant-design/icons";
|
||||
|
||||
function RangeGranularity({
|
||||
period,
|
||||
density,
|
||||
onDensityChange
|
||||
}: {
|
||||
period: any,
|
||||
density: number,
|
||||
onDensityChange: (density: number) => void
|
||||
}) {
|
||||
const granularityOptions = React.useMemo(() => {
|
||||
return calculateGranularities(period.getDuration());
|
||||
}, [period]);
|
||||
|
||||
const menuProps = {
|
||||
items: granularityOptions,
|
||||
onClick: (item: any) => onDensityChange(item.key),
|
||||
}
|
||||
const selected = React.useMemo(() => {
|
||||
let selected = 'Custom';
|
||||
for (const option of granularityOptions) {
|
||||
if (option.key <= density) {
|
||||
selected = option.label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}, [])
|
||||
return (
|
||||
<AntlikeDropdown
|
||||
useButtonStyle
|
||||
label={selected}
|
||||
rightIcon={<DownOutlined />}
|
||||
menuProps={menuProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function calculateGranularities(periodDurationMs: number) {
|
||||
const granularities = [
|
||||
{ label: 'Minute', durationMs: 60 * 1000 },
|
||||
{ label: 'Hourly', durationMs: 60 * 60 * 1000 },
|
||||
{ label: 'Daily', durationMs: 24 * 60 * 60 * 1000 },
|
||||
{ label: 'Weekly', durationMs: 7 * 24 * 60 * 60 * 1000 },
|
||||
{ label: 'Monthly', durationMs: 30 * 24 * 60 * 60 * 1000 },
|
||||
{ label: 'Quarterly', durationMs: 3 * 30 * 24 * 60 * 60 * 1000 },
|
||||
];
|
||||
|
||||
const result = [];
|
||||
|
||||
for (const granularity of granularities) {
|
||||
if (periodDurationMs >= granularity.durationMs) {
|
||||
const density = Math.floor(periodDurationMs / granularity.durationMs);
|
||||
result.push({ label: granularity.label, key: density });
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default RangeGranularity;
|
||||
|
|
@ -3,9 +3,14 @@ import SelectDateRange from 'Shared/SelectDateRange';
|
|||
import { useStore } from 'App/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Space } from 'antd';
|
||||
import RangeGranularity from "./RangeGranularity";
|
||||
|
||||
function WidgetDateRange({ label = 'Time Range', isTimeseries = false }: any) {
|
||||
function WidgetDateRange({ viewType = undefined, label = 'Time Range', isTimeseries = false }: any) {
|
||||
const { dashboardStore } = useStore();
|
||||
const density = dashboardStore.selectedDensity
|
||||
const onDensityChange = (density: number) => {
|
||||
dashboardStore.setDensity(density);
|
||||
}
|
||||
const period = dashboardStore.drillDownPeriod;
|
||||
const compPeriod = dashboardStore.comparisonPeriod;
|
||||
const drillDownFilter = dashboardStore.drillDownFilter;
|
||||
|
|
@ -29,6 +34,8 @@ function WidgetDateRange({ label = 'Time Range', isTimeseries = false }: any) {
|
|||
});
|
||||
}
|
||||
|
||||
const hasGranularity = ['lineChart', 'barChart', 'areaChart'].includes(viewType);
|
||||
const hasCompare = ['lineChart', 'barChart', 'table', 'progressChart'].includes(viewType);
|
||||
return (
|
||||
<Space>
|
||||
{label && <span className="mr-1 color-gray-medium">{label}</span>}
|
||||
|
|
@ -40,16 +47,27 @@ function WidgetDateRange({ label = 'Time Range', isTimeseries = false }: any) {
|
|||
useButtonStyle={true}
|
||||
/>
|
||||
{isTimeseries ? (
|
||||
<SelectDateRange
|
||||
period={period}
|
||||
compPeriod={compPeriod}
|
||||
onChange={onChangePeriod}
|
||||
onChangeComparison={onChangeComparison}
|
||||
right={true}
|
||||
isAnt={true}
|
||||
useButtonStyle={true}
|
||||
comparison={true}
|
||||
/>
|
||||
<>
|
||||
{hasGranularity ? (
|
||||
<RangeGranularity
|
||||
period={period}
|
||||
density={density}
|
||||
onDensityChange={onDensityChange}
|
||||
/>
|
||||
) : null}
|
||||
{hasCompare ?
|
||||
<SelectDateRange
|
||||
period={period}
|
||||
compPeriod={compPeriod}
|
||||
onChange={onChangePeriod}
|
||||
onChangeComparison={onChangeComparison}
|
||||
right={true}
|
||||
isAnt={true}
|
||||
useButtonStyle={true}
|
||||
comparison={true}
|
||||
/>
|
||||
: null}
|
||||
</>
|
||||
) : null}
|
||||
</Space>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => {
|
|||
metric.updateKey('hasChanged', true)
|
||||
}
|
||||
|
||||
console.log(metric.series, isTable, isClickMap, isInsights, isPathAnalysis, isFunnel)
|
||||
return (
|
||||
<>
|
||||
{metric.series.length > 0 &&
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ import { observer } from 'mobx-react-lite';
|
|||
import { ChartLine, ChartArea, ChartColumn, ChartBar, ChartPie, Table } from 'lucide-react'
|
||||
|
||||
function WidgetOptions() {
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
const { metricStore } = useStore();
|
||||
const metric: any = metricStore.instance;
|
||||
|
||||
const handleChange = (value: any) => {
|
||||
metric.update({ metricFormat: value });
|
||||
};
|
||||
|
||||
const chartTypes = {
|
||||
const chartTypes = {
|
||||
lineChart: 'Chart',
|
||||
barChart: 'Column',
|
||||
areaChart: 'Area',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ function WidgetPreview(props: Props) {
|
|||
className={cn(className, 'bg-white rounded-xl border shadow-sm mt-0')}
|
||||
>
|
||||
<div className="flex items-center gap-2 px-4 pt-2">
|
||||
<WidgetDateRange label="" isTimeseries={metric.metricType === TIMESERIES} />
|
||||
<WidgetDateRange label="" isTimeseries={metric.metricType === TIMESERIES} viewType={metric.viewType} />
|
||||
<div className="flex items-center ml-auto">
|
||||
<WidgetOptions />
|
||||
{/*{metric.metricType === USER_PATH && (*/}
|
||||
|
|
|
|||
36
frontend/app/components/shared/Dropdown/index.tsx
Normal file
36
frontend/app/components/shared/Dropdown/index.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import React from 'react';
|
||||
import { Dropdown } from 'antd';
|
||||
|
||||
function AntlikeDropdown(props: {
|
||||
label: string;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
menuProps: any;
|
||||
useButtonStyle?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
const { label, leftIcon, rightIcon, menuProps, useButtonStyle, className } = props;
|
||||
return (
|
||||
<Dropdown menu={menuProps} className={'px-2 py-1'}>
|
||||
{useButtonStyle ? (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border border-gray-light rounded cursor-pointer'
|
||||
}
|
||||
>
|
||||
{leftIcon}
|
||||
<span>{label}</span>
|
||||
{rightIcon}
|
||||
</div>
|
||||
) : (
|
||||
<div className={'cursor-pointer flex items-center gap-2'}>
|
||||
{leftIcon}
|
||||
<span>{label}</span>
|
||||
{rightIcon}
|
||||
</div>
|
||||
)}
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
export default AntlikeDropdown;
|
||||
|
|
@ -146,13 +146,28 @@ export function AutoCompleteContainer(props: Props) {
|
|||
: props.value[0]}
|
||||
</div>
|
||||
{props.value.length > 1 ? (
|
||||
<div
|
||||
className={
|
||||
'rounded-xl bg-gray-lighter leading-none px-1 py-0.5'
|
||||
}
|
||||
>
|
||||
+ {props.value.length - 1} More
|
||||
</div>
|
||||
props.value.length === 2 ? (
|
||||
<>
|
||||
or
|
||||
<div
|
||||
className={
|
||||
'rounded-xl bg-gray-lighter leading-none px-1 py-0.5'
|
||||
}
|
||||
>
|
||||
{props.mapValues
|
||||
? props.mapValues(props.value[1])
|
||||
: props.value[1]}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
className={
|
||||
'rounded-xl bg-gray-lighter leading-none px-1 py-0.5'
|
||||
}
|
||||
>
|
||||
+ {props.value.length - 1} More
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ const FilterAutoComplete = observer(
|
|||
setOptions(topValues.map((i) => ({ value: i.value, label: i.value })));
|
||||
};
|
||||
|
||||
console.log(options)
|
||||
return <AutocompleteModal
|
||||
values={values}
|
||||
onClose={onClose}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { Calendar } from 'lucide-react';
|
|||
import DateRangePopup from 'Shared/DateRangeDropdown/DateRangePopup';
|
||||
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
|
||||
import Select from 'Shared/Select';
|
||||
import AntlikeDropdown from "Shared/Dropdown";
|
||||
|
||||
interface Props {
|
||||
period: any | null;
|
||||
|
|
@ -24,8 +25,8 @@ interface Props {
|
|||
isAnt?: boolean;
|
||||
small?: boolean;
|
||||
useButtonStyle?: boolean; // New prop to control button style
|
||||
compPeriod: any | null;
|
||||
onChangeComparison: (data: any) => void;
|
||||
compPeriod?: any | null;
|
||||
onChangeComparison?: (data: any) => void;
|
||||
comparison?: boolean;
|
||||
[x: string]: any;
|
||||
}
|
||||
|
|
@ -217,24 +218,13 @@ function AndDateRange({
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Dropdown menu={menuProps} className={'px-2 py-1'}>
|
||||
{useButtonStyle ? (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border border-gray-light rounded cursor-pointer'
|
||||
}
|
||||
>
|
||||
<Calendar size={16} />
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
) : (
|
||||
<div className={'cursor-pointer flex items-center gap-2'}>
|
||||
<span>{isCustomRange ? customRange : selectedValue?.label}</span>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
)}
|
||||
</Dropdown>
|
||||
<AntlikeDropdown
|
||||
label={isCustomRange ? customRange : selectedValue?.label}
|
||||
menuProps={menuProps}
|
||||
useButtonStyle={useButtonStyle}
|
||||
leftIcon={useButtonStyle ? <Calendar size={16} /> : null}
|
||||
rightIcon={<DownOutlined />}
|
||||
/>
|
||||
)}
|
||||
{isCustom && (
|
||||
<OutsideClickDetectingDiv
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default class DashboardStore {
|
|||
drillDownFilter: Filter = new Filter();
|
||||
comparisonFilter: Filter = new Filter();
|
||||
drillDownPeriod: Record<string, any> = Period({ rangeName: LAST_7_DAYS });
|
||||
selectedDensity: number = 7 // depends on default drilldown, 7 points here!!!;
|
||||
comparisonPeriod: Record<string, any> | null = null
|
||||
startTimestamp: number = 0;
|
||||
endTimestamp: number = 0;
|
||||
|
|
@ -57,6 +58,10 @@ export default class DashboardStore {
|
|||
this.resetDrillDownFilter();
|
||||
}
|
||||
|
||||
setDensity = (density: any) => {
|
||||
this.selectedDensity = parseInt(density, 10);
|
||||
}
|
||||
|
||||
get sortedDashboards() {
|
||||
const sortOrder = this.sort.by;
|
||||
return [...this.dashboards].sort((a, b) =>
|
||||
|
|
|
|||
|
|
@ -130,6 +130,9 @@ export default Record(
|
|||
endTimestamp: this.end,
|
||||
};
|
||||
},
|
||||
getDuration() {
|
||||
return this.range.end.diff(this.range.start).as("milliseconds");
|
||||
},
|
||||
rangeFormatted(format = "MMM dd yyyy, HH:mm", tz) {
|
||||
const start = this.range.start.setZone(tz);
|
||||
const end = this.range.end.setZone(tz);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue