ui: add comparison to more charts, add "metric" chart (BigNumChart.tsx)
This commit is contained in:
parent
08be943ae0
commit
817f039ddc
16 changed files with 267 additions and 126 deletions
|
|
@ -68,7 +68,7 @@ const PillBar = (props) => {
|
|||
function CustomMetricLineChart(props: Props) {
|
||||
const {
|
||||
data = { chart: [], namesMap: [] },
|
||||
compData,
|
||||
compData = { chart: [], namesMap: [] },
|
||||
params,
|
||||
colors,
|
||||
onClick = () => null,
|
||||
|
|
@ -82,6 +82,14 @@ function CustomMetricLineChart(props: Props) {
|
|||
return item;
|
||||
});
|
||||
|
||||
// we mix 1 original, then 1 comparison, etc
|
||||
const mergedNameMap: { data: any, isComp: boolean, index: number }[] = [];
|
||||
for (let i = 0; i < data.namesMap.length; i++) {
|
||||
mergedNameMap.push({ data: data.namesMap[i], isComp: false, index: i });
|
||||
if (compData && compData.namesMap[i]) {
|
||||
mergedNameMap.push({ data: compData.namesMap[i], isComp: true, index: i });
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ResponsiveContainer height={240} width="100%">
|
||||
<BarChart
|
||||
|
|
@ -126,39 +134,23 @@ function CustomMetricLineChart(props: Props) {
|
|||
}}
|
||||
/>
|
||||
<Tooltip {...Styles.tooltip} content={CustomTooltip} />
|
||||
{Array.isArray(data.namesMap) &&
|
||||
data.namesMap.map((key, index) => (
|
||||
<Bar
|
||||
key={key}
|
||||
name={key}
|
||||
type="monotone"
|
||||
dataKey={key}
|
||||
shape={(barProps) => (
|
||||
<PillBar {...barProps} fill={colors[index]} />
|
||||
)}
|
||||
legendType={key === 'Total' ? 'none' : 'line'}
|
||||
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}
|
||||
{mergedNameMap.map((item) => (
|
||||
<Bar
|
||||
key={item.data}
|
||||
name={item.data}
|
||||
type="monotone"
|
||||
dataKey={item.data}
|
||||
fill={colors[item.index]}
|
||||
stroke={colors[item.index]}
|
||||
shape={(barProps: any) => (
|
||||
<PillBar {...barProps} fill={colors[item.index]} barKey={item.index} stroke={colors[item.index]} striped={item.isComp} />
|
||||
)}
|
||||
legendType={'line'}
|
||||
activeBar={
|
||||
<PillBar fill={colors[item.index]} stroke={colors[item.index]} barKey={item.index} striped={item.isComp} />
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
import React from 'react'
|
||||
import { CompareTag } from "./CustomChartTooltip";
|
||||
|
||||
interface Props {
|
||||
data: { chart: any[], namesMap: string[] };
|
||||
compData: { chart: any[], namesMap: string[] } | null;
|
||||
colors: any;
|
||||
onClick?: (event, index) => void;
|
||||
yaxis?: any;
|
||||
label?: string;
|
||||
hideLegend?: boolean;
|
||||
}
|
||||
function BigNumChart(props: Props) {
|
||||
const {
|
||||
data = { chart: [], namesMap: [] },
|
||||
compData = { chart: [], namesMap: [] },
|
||||
colors,
|
||||
onClick = () => null,
|
||||
label = 'Number of Sessions',
|
||||
} = props;
|
||||
|
||||
const values: { value: number, compData?: number, series: string }[] = [];
|
||||
for (let i = 0; i < data.namesMap.length; i++) {
|
||||
if (!data.namesMap[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values.push({
|
||||
value: data.chart.reduce((acc, curr) => acc + curr[data.namesMap[i]], 0),
|
||||
compData: compData ? compData.chart.reduce((acc, curr) => acc + curr[compData.namesMap[i]], 0) : undefined,
|
||||
series: data.namesMap[i],
|
||||
});
|
||||
}
|
||||
console.log(values, data, compData)
|
||||
return (
|
||||
<div className={'flex justify-around gap-2 w-full'} style={{ height: 240 }}>
|
||||
{values.map((val, i) => (
|
||||
<BigNum
|
||||
key={i}
|
||||
color={colors[i]}
|
||||
series={val.series}
|
||||
value={val.value}
|
||||
label={label}
|
||||
compData={val.compData}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function BigNum({ color, series, value, label, compData }: {
|
||||
color: string,
|
||||
series: string,
|
||||
value: number,
|
||||
label: string,
|
||||
compData?: number,
|
||||
}) {
|
||||
const formattedNumber = (num: number) => {
|
||||
return Intl.NumberFormat().format(num);
|
||||
}
|
||||
|
||||
const changePercent = React.useMemo(() => {
|
||||
if (!compData) return 0;
|
||||
return `${(((value - compData) / compData) * 100).toFixed(2)}%`;
|
||||
}, [value, compData])
|
||||
return (
|
||||
<div className={'flex flex-col gap-2 py-8 items-center'}>
|
||||
<div className={'flex items-center gap-2 font-semibold text-gray-darkest'}>
|
||||
<div className={'rounded w-4 h-4'} style={{ background: color }} />
|
||||
<div>{series}</div>
|
||||
</div>
|
||||
<div className={'font-bold leading-none'} style={{ fontSize: 56 }}>
|
||||
{formattedNumber(value)}
|
||||
</div>
|
||||
<div className={'text-disabled-text text-xs'}>
|
||||
{label}
|
||||
</div>
|
||||
{compData ? (
|
||||
<CompareTag isHigher={value > compData} prevValue={changePercent} />
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BigNumChart;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { formatTimeOrDate } from 'App/date';
|
||||
import cn from 'classnames';
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react'
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react';
|
||||
|
||||
function CustomTooltip({ active, payload, label }) {
|
||||
if (!active) return;
|
||||
|
|
@ -54,17 +54,10 @@ function CustomTooltip({ active, payload, label }) {
|
|||
<div className={'flex items-center gap-2'}>
|
||||
<div className={'font-semibold'}>{p.value}</div>
|
||||
{p.prevValue !== null ? (
|
||||
<div
|
||||
className={cn(
|
||||
'px-2 py-1 rounded flex items-center gap-1',
|
||||
isHigher(p) ? 'bg-green2 text-xs' : 'bg-red2 text-xs'
|
||||
)}
|
||||
>
|
||||
{!isHigher(p) ? <ArrowDown size={12} /> : <ArrowUp size={12} />}
|
||||
<div>
|
||||
{p.prevValue}
|
||||
</div>
|
||||
</div>
|
||||
<CompareTag
|
||||
isHigher={isHigher(p)}
|
||||
prevValue={p.prevValue}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -74,4 +67,24 @@ function CustomTooltip({ active, payload, label }) {
|
|||
);
|
||||
}
|
||||
|
||||
export function CompareTag({
|
||||
isHigher,
|
||||
prevValue,
|
||||
}: {
|
||||
isHigher: boolean;
|
||||
prevValue: number | string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'px-2 py-1 rounded flex items-center gap-1',
|
||||
isHigher ? 'bg-green2 text-xs' : 'bg-red2 text-xs'
|
||||
)}
|
||||
>
|
||||
{!isHigher ? <ArrowDown size={12} /> : <ArrowUp size={12} />}
|
||||
<div>{prevValue}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomTooltip;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ interface Props {
|
|||
function CustomMetricLineChart(props: Props) {
|
||||
const {
|
||||
data = { chart: [], namesMap: [] },
|
||||
compData,
|
||||
compData = { chart: [], namesMap: [] },
|
||||
params,
|
||||
colors,
|
||||
onClick = () => null,
|
||||
|
|
@ -86,13 +86,12 @@ function CustomMetricLineChart(props: Props) {
|
|||
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) => (
|
||||
{compData?.namesMap.map((key, i) => data.namesMap[i] ? (
|
||||
<Line
|
||||
key={key}
|
||||
name={key}
|
||||
|
|
@ -110,7 +109,7 @@ function CustomMetricLineChart(props: Props) {
|
|||
fill: colors[i],
|
||||
}}
|
||||
/>
|
||||
)) : null}
|
||||
) : null)}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
interface Props {
|
||||
data: { chart: any[], namesMap: string[] };
|
||||
compData: { chart: any[], namesMap: string[] } | null;
|
||||
params: any;
|
||||
colors: any;
|
||||
onClick?: (event, index) => void;
|
||||
|
|
@ -13,38 +14,64 @@ interface Props {
|
|||
function ProgressBarChart(props: Props) {
|
||||
const {
|
||||
data = { chart: [], namesMap: [] },
|
||||
compData = { chart: [], namesMap: [] },
|
||||
colors,
|
||||
onClick = () => null,
|
||||
label = 'Number of Sessions',
|
||||
} = props;
|
||||
|
||||
const getTotalForSeries = (series: string) => {
|
||||
const getTotalForSeries = (series: string, isComp: boolean) => {
|
||||
if (isComp) {
|
||||
return compData.chart.reduce((acc, curr) => acc + curr[series], 0);
|
||||
}
|
||||
return data.chart.reduce((acc, curr) => acc + curr[series], 0);
|
||||
}
|
||||
const values = data.namesMap.map((k, i) => {
|
||||
|
||||
const formattedNumber = (num: number) => {
|
||||
return Intl.NumberFormat().format(num);
|
||||
}
|
||||
|
||||
// we mix 1 original, then 1 comparison, etc
|
||||
const mergedNameMap: { data: any, isComp: boolean, index: number }[] = [];
|
||||
for (let i = 0; i < data.namesMap.length; i++) {
|
||||
if (!data.namesMap[i]) {
|
||||
continue;
|
||||
}
|
||||
mergedNameMap.push({ data: data.namesMap[i], isComp: false, index: i });
|
||||
if (compData && compData.namesMap[i]) {
|
||||
mergedNameMap.push({ data: compData.namesMap[i], isComp: true, index: i });
|
||||
}
|
||||
}
|
||||
|
||||
const values = mergedNameMap.map((k, i) => {
|
||||
return {
|
||||
name: k,
|
||||
value: getTotalForSeries(k)
|
||||
name: k.data,
|
||||
value: getTotalForSeries(k.data, k.isComp),
|
||||
isComp: k.isComp,
|
||||
index: k.index,
|
||||
}
|
||||
})
|
||||
const highest = values.reduce(
|
||||
(acc, curr) =>
|
||||
acc.value > curr.value ? acc : curr,
|
||||
{ name: '', value: 0 });
|
||||
|
||||
const formattedNumber = (num: number) => {
|
||||
return Intl.NumberFormat().format(num);
|
||||
}
|
||||
return (
|
||||
<div className={'w-full'} style={{ height: 240 }}>
|
||||
{values.map((val, i) => (
|
||||
<div key={i} className={'flex items-center gap-1'}>
|
||||
<div className={'flex items-center'} style={{ flex: 1}}>
|
||||
<div className={'w-4 h-4 rounded-full mr-2'} style={{ backgroundColor: colors[i] }} />
|
||||
<div className={'w-4 h-4 rounded-full mr-2'} style={{ backgroundColor: colors[val.index] }} />
|
||||
<span>{val.name}</span>
|
||||
</div>
|
||||
<div className={'flex items-center gap-2'} style={{ flex: 4 }}>
|
||||
<div style={{ height: 16, borderRadius: 16, backgroundColor: colors[i], width: `${(val.value/highest.value)*100}%` }} />
|
||||
<div style={{
|
||||
height: 16,
|
||||
borderRadius: 16,
|
||||
backgroundImage: val.isComp ? `linear-gradient(45deg, #ffffff 25%, ${colors[val.index]} 25%, ${colors[val.index]} 50%, #ffffff 50%, #ffffff 75%, ${colors[val.index]} 75%, ${colors[val.index]} 100%)` : undefined,
|
||||
backgroundSize: val.isComp ? '20px 20px' : undefined,
|
||||
backgroundColor: val.isComp ? undefined : colors[val.index],
|
||||
width: `${(val.value/highest.value)*100}%` }}
|
||||
/>
|
||||
<div>{formattedNumber(val.value)}</div>
|
||||
</div>
|
||||
<div style={{ flex: 1}}/>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ export default {
|
|||
lineHeight: '0.75rem',
|
||||
color: '#000',
|
||||
fontSize: '12px'
|
||||
},
|
||||
cursor: {
|
||||
fill: '#eee'
|
||||
}
|
||||
},
|
||||
gradientDef: () => (
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { useStore } from 'App/mstore';
|
|||
import AreaChart from '../../Widgets/CustomMetricsWidgets/AreaChart';
|
||||
import BarChart from '../../Widgets/CustomMetricsWidgets/BarChart';
|
||||
import ProgressBarChart from '../../Widgets/CustomMetricsWidgets/ProgressBarChart';
|
||||
|
||||
import BugNumChart from '../../Widgets/CustomMetricsWidgets/BigNumChart'
|
||||
import WidgetDatatable from '../WidgetDatatable/WidgetDatatable';
|
||||
import WidgetPredefinedChart from '../WidgetPredefinedChart';
|
||||
import { getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
|
||||
|
|
@ -274,6 +274,7 @@ function WidgetChart(props: Props) {
|
|||
return (
|
||||
<ProgressBarChart
|
||||
data={chartData}
|
||||
compData={compData}
|
||||
params={params}
|
||||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
|
|
@ -291,8 +292,12 @@ function WidgetChart(props: Props) {
|
|||
metric={metric}
|
||||
data={chartData}
|
||||
colors={colors}
|
||||
// params={params}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -302,12 +307,32 @@ function WidgetChart(props: Props) {
|
|||
data={data[0]}
|
||||
colors={colors}
|
||||
params={params}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (viewType === 'table') {
|
||||
return null;
|
||||
}
|
||||
if (viewType === 'metric') {
|
||||
return (
|
||||
<BugNumChart
|
||||
data={data}
|
||||
compData={compData}
|
||||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (metricType === TABLE) {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ const initTableProps = [
|
|||
dataIndex: 'seriesName',
|
||||
key: 'seriesName',
|
||||
sorter: (a, b) => a.seriesName.localeCompare(b.seriesName),
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: 'Avg.',
|
||||
dataIndex: 'average',
|
||||
key: 'average',
|
||||
sorter: (a, b) => a.average - b.average,
|
||||
fixed: 'left',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -132,6 +134,7 @@ function WidgetDatatable(props: Props) {
|
|||
pagination={false}
|
||||
rowSelection={rowSelection}
|
||||
size={'small'}
|
||||
scroll={{ x: 'max-content' }}
|
||||
/>
|
||||
{/* 1.23+ export menu floater */}
|
||||
{/*<div className={'absolute top-0 -right-1'}>*/}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ function RangeGranularity({
|
|||
return calculateGranularities(period.getDuration());
|
||||
}, [period]);
|
||||
|
||||
|
||||
const menuProps = {
|
||||
items: granularityOptions,
|
||||
onClick: (item: any) => onDensityChange(item.key),
|
||||
|
|
@ -22,13 +23,19 @@ function RangeGranularity({
|
|||
const selected = React.useMemo(() => {
|
||||
let selected = 'Custom';
|
||||
for (const option of granularityOptions) {
|
||||
if (option.key <= density) {
|
||||
if (option.key === density) {
|
||||
selected = option.label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}, [])
|
||||
}, [period, density])
|
||||
|
||||
React.useEffect(() => {
|
||||
const defaultOption = Math.max(granularityOptions.length - 2, 0);
|
||||
onDensityChange(granularityOptions[defaultOption].key);
|
||||
}, [period]);
|
||||
|
||||
return (
|
||||
<AntlikeDropdown
|
||||
useButtonStyle
|
||||
|
|
@ -41,7 +48,7 @@ function RangeGranularity({
|
|||
|
||||
function calculateGranularities(periodDurationMs: number) {
|
||||
const granularities = [
|
||||
{ label: 'Minute', durationMs: 60 * 1000 },
|
||||
{ label: 'By 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 },
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ function WidgetDateRange({ viewType = undefined, label = 'Time Range', isTimeser
|
|||
<SelectDateRange
|
||||
period={period}
|
||||
onChange={onChangePeriod}
|
||||
right={true}
|
||||
isAnt={true}
|
||||
useButtonStyle={true}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -136,21 +136,6 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => {
|
|||
</Button>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{metric.series[0] ?
|
||||
<div className={'rounded-xl border border-gray-lighter'}>
|
||||
<FilterList
|
||||
filter={metric.series[0].filter}
|
||||
onUpdateFilter={onUpdateFilter}
|
||||
onRemoveFilter={onRemoveFilter}
|
||||
onChangeEventsOrder={onChangeEventsOrder}
|
||||
supportsEmpty
|
||||
onFilterMove={onFilterMove}
|
||||
excludeFilterKeys={excludeFilterKeys}
|
||||
onAddFilter={onAddFilter}
|
||||
/>
|
||||
</div>
|
||||
: null}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useStore } from 'App/mstore';
|
|||
import ClickMapRagePicker from 'Components/Dashboard/components/ClickMapRagePicker/ClickMapRagePicker';
|
||||
import { FilterKey } from 'Types/filter/filterType';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { ChartLine, ChartArea, ChartColumn, ChartBar, ChartPie, Table } from 'lucide-react'
|
||||
import { ChartLine, ChartArea, ChartColumn, ChartBar, ChartPie, Table, Hash } from 'lucide-react'
|
||||
|
||||
function WidgetOptions() {
|
||||
const { metricStore } = useStore();
|
||||
|
|
@ -23,6 +23,7 @@ function WidgetOptions() {
|
|||
pieChart: 'Pie',
|
||||
progressChart: 'Bar',
|
||||
table: 'Table',
|
||||
metric: 'Metric',
|
||||
}
|
||||
const chartIcons = {
|
||||
lineChart: <ChartLine size={16} strokeWidth={1} />,
|
||||
|
|
@ -31,6 +32,7 @@ function WidgetOptions() {
|
|||
pieChart: <ChartPie size={16} strokeWidth={1} />,
|
||||
progressChart: <ChartBar size={16} strokeWidth={1} />,
|
||||
table: <Table size={16} strokeWidth={1} />,
|
||||
metric: <Hash size={16} strokeWidth={1} />,
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,47 +1,50 @@
|
|||
import React from 'react';
|
||||
import cn from "classnames";
|
||||
import WidgetName from "Components/Dashboard/components/WidgetName";
|
||||
import {useStore} from "App/mstore";
|
||||
import {useObserver} from "mobx-react-lite";
|
||||
import AddToDashboardButton from "Components/Dashboard/components/AddToDashboardButton";
|
||||
import {Button, Space} from "antd";
|
||||
import CardViewMenu from "Components/Dashboard/components/WidgetView/CardViewMenu";
|
||||
import cn from 'classnames';
|
||||
import WidgetName from 'Components/Dashboard/components/WidgetName';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { useObserver } from 'mobx-react-lite';
|
||||
import AddToDashboardButton from 'Components/Dashboard/components/AddToDashboardButton';
|
||||
import { Button, Space } from 'antd';
|
||||
import CardViewMenu from 'Components/Dashboard/components/WidgetView/CardViewMenu';
|
||||
|
||||
interface Props {
|
||||
onClick?: () => void;
|
||||
onSave: () => void;
|
||||
undoChanges?: () => void;
|
||||
onClick?: () => void;
|
||||
onSave: () => void;
|
||||
undoChanges?: () => void;
|
||||
}
|
||||
|
||||
function WidgetViewHeader({onClick, onSave, undoChanges}: Props) {
|
||||
const {metricStore, dashboardStore} = useStore();
|
||||
const widget = useObserver(() => metricStore.instance);
|
||||
function WidgetViewHeader({ onClick, onSave, undoChanges }: Props) {
|
||||
const { metricStore, dashboardStore } = useStore();
|
||||
const widget = useObserver(() => metricStore.instance);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('flex justify-between items-center')}
|
||||
onClick={onClick}
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex justify-between items-center bg-white rounded px-4 py-2 border border-gray-lighter'
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<h1 className="mb-0 text-2xl mr-4 min-w-fit">
|
||||
<WidgetName
|
||||
name={widget.name}
|
||||
onUpdate={(name) => metricStore.merge({ name })}
|
||||
canEdit={true}
|
||||
/>
|
||||
</h1>
|
||||
<Space>
|
||||
<AddToDashboardButton metricId={widget.metricId} />
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onSave}
|
||||
loading={metricStore.isSaving}
|
||||
disabled={metricStore.isSaving || !widget.hasChanged}
|
||||
>
|
||||
<h1 className="mb-0 text-2xl mr-4 min-w-fit">
|
||||
<WidgetName name={widget.name}
|
||||
onUpdate={(name) => metricStore.merge({name})}
|
||||
canEdit={true}
|
||||
/>
|
||||
</h1>
|
||||
<Space>
|
||||
<AddToDashboardButton metricId={widget.metricId}/>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onSave}
|
||||
loading={metricStore.isSaving}
|
||||
disabled={metricStore.isSaving || !widget.hasChanged}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
<CardViewMenu/>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
Update
|
||||
</Button>
|
||||
<CardViewMenu />
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default WidgetViewHeader;
|
||||
|
|
|
|||
|
|
@ -81,11 +81,11 @@ function SelectDateRange(props: Props) {
|
|||
setIsCustom(false);
|
||||
};
|
||||
|
||||
const isCustomRange = period ? period.rangeName === CUSTOM_RANGE : false;
|
||||
const isCustomRange = usedPeriod ? usedPeriod.rangeName === CUSTOM_RANGE : false;
|
||||
const isUSLocale =
|
||||
navigator.language === 'en-US' || navigator.language.startsWith('en-US');
|
||||
const customRange = isCustomRange
|
||||
? period.rangeFormatted(
|
||||
? usedPeriod.rangeFormatted(
|
||||
isUSLocale ? 'MMM dd yyyy, hh:mm a' : 'MMM dd yyyy, HH:mm'
|
||||
)
|
||||
: '';
|
||||
|
|
@ -97,6 +97,7 @@ function SelectDateRange(props: Props) {
|
|||
selectedValue={selectedValue}
|
||||
onChange={onChange}
|
||||
isCustomRange={isCustomRange}
|
||||
isCustom={isCustom}
|
||||
customRange={customRange}
|
||||
setIsCustom={setIsCustom}
|
||||
onApplyDateRange={onApplyDateRange}
|
||||
|
|
@ -189,6 +190,7 @@ function AndDateRange({
|
|||
},
|
||||
};
|
||||
|
||||
const comparisonValue = isCustomRange && selectedValue ? customRange : selectedValue?.label;
|
||||
return (
|
||||
<div className={'relative'}>
|
||||
{comparison ? (
|
||||
|
|
@ -200,9 +202,7 @@ function AndDateRange({
|
|||
}
|
||||
>
|
||||
<span>
|
||||
{isCustomRange
|
||||
? customRange
|
||||
: `Compare to ${selectedValue ? selectedValue?.label : ''}`}
|
||||
{`Compare to ${comparisonValue || ''}`}
|
||||
</span>
|
||||
<DownOutlined />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export const FUNNEL = 'funnel';
|
|||
export const ERRORS = 'errors';
|
||||
export const USER_PATH = 'pathAnalysis';
|
||||
export const RETENTION = 'retention';
|
||||
export const FEATURE_ADOPTION = 'featureAdoption';
|
||||
export const INSIGHTS = 'insights';
|
||||
export const PERFORMANCE = 'performance';
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ export default class MetricStore {
|
|||
}
|
||||
}
|
||||
|
||||
console.log('ch', obj)
|
||||
Object.assign(this.instance, obj);
|
||||
this.instance.updateKey('hasChanged', updateChangeFlag);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue