add details button on overview
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import { pushModal } from '@/modals';
|
||||||
|
import { ScanEyeIcon } from 'lucide-react';
|
||||||
|
|
||||||
|
import type { IChartInput } from '@openpanel/validation';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
chart: IChartInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OverviewDetailsButton = ({ chart }: Props) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className="-mb-2 mt-5 flex w-full items-center justify-center gap-2 text-sm font-semibold"
|
||||||
|
onClick={() => {
|
||||||
|
pushModal('OverviewChartDetails', {
|
||||||
|
chart: chart,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ScanEyeIcon size={18} /> Details
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OverviewDetailsButton;
|
||||||
@@ -5,6 +5,7 @@ import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
|||||||
import { cn } from '@/utils/cn';
|
import { cn } from '@/utils/cn';
|
||||||
|
|
||||||
import { Widget, WidgetBody } from '../../widget';
|
import { Widget, WidgetBody } from '../../widget';
|
||||||
|
import OverviewDetailsButton from '../overview-details-button';
|
||||||
import { WidgetButtons, WidgetHead } from '../overview-widget';
|
import { WidgetButtons, WidgetHead } from '../overview-widget';
|
||||||
import { useOverviewOptions } from '../useOverviewOptions';
|
import { useOverviewOptions } from '../useOverviewOptions';
|
||||||
import { useOverviewWidget } from '../useOverviewWidget';
|
import { useOverviewWidget } from '../useOverviewWidget';
|
||||||
@@ -121,6 +122,7 @@ export default function OverviewLatestEvents({
|
|||||||
</WidgetHead>
|
</WidgetHead>
|
||||||
<WidgetBody>
|
<WidgetBody>
|
||||||
<LazyChart hideID {...widget.chart} previous={false} />
|
<LazyChart hideID {...widget.chart} previous={false} />
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type { IChartType } from '@openpanel/validation';
|
|||||||
import { LazyChart } from '../report/chart/LazyChart';
|
import { LazyChart } from '../report/chart/LazyChart';
|
||||||
import { Widget, WidgetBody } from '../widget';
|
import { Widget, WidgetBody } from '../widget';
|
||||||
import { OverviewChartToggle } from './overview-chart-toggle';
|
import { OverviewChartToggle } from './overview-chart-toggle';
|
||||||
|
import OverviewDetailsButton from './overview-details-button';
|
||||||
import { WidgetButtons, WidgetHead } from './overview-widget';
|
import { WidgetButtons, WidgetHead } from './overview-widget';
|
||||||
import { useOverviewOptions } from './useOverviewOptions';
|
import { useOverviewOptions } from './useOverviewOptions';
|
||||||
import { useOverviewWidget } from './useOverviewWidget';
|
import { useOverviewWidget } from './useOverviewWidget';
|
||||||
@@ -222,6 +223,7 @@ export default function OverviewTopDevices({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { ChartSwitch } from '@/components/report/chart';
|
|
||||||
import { LazyChart } from '@/components/report/chart/LazyChart';
|
import { LazyChart } from '@/components/report/chart/LazyChart';
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||||
import { cn } from '@/utils/cn';
|
import { cn } from '@/utils/cn';
|
||||||
import { BarChartIcon, LineChart, LineChartIcon } from 'lucide-react';
|
|
||||||
|
|
||||||
import type { IChartType } from '@openpanel/validation';
|
import type { IChartType } from '@openpanel/validation';
|
||||||
|
|
||||||
import { Widget, WidgetBody } from '../../widget';
|
import { Widget, WidgetBody } from '../../widget';
|
||||||
import { OverviewChartToggle } from '../overview-chart-toggle';
|
import { OverviewChartToggle } from '../overview-chart-toggle';
|
||||||
|
import OverviewDetailsButton from '../overview-details-button';
|
||||||
import { WidgetButtons, WidgetHead } from '../overview-widget';
|
import { WidgetButtons, WidgetHead } from '../overview-widget';
|
||||||
import { useOverviewOptions } from '../useOverviewOptions';
|
import { useOverviewOptions } from '../useOverviewOptions';
|
||||||
import { useOverviewWidget } from '../useOverviewWidget';
|
import { useOverviewWidget } from '../useOverviewWidget';
|
||||||
@@ -132,6 +130,7 @@ export default function OverviewTopEvents({
|
|||||||
</WidgetHead>
|
</WidgetHead>
|
||||||
<WidgetBody>
|
<WidgetBody>
|
||||||
<LazyChart hideID {...widget.chart} previous={false} />
|
<LazyChart hideID {...widget.chart} previous={false} />
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import type { IChartType } from '@openpanel/validation';
|
|||||||
import { LazyChart } from '../report/chart/LazyChart';
|
import { LazyChart } from '../report/chart/LazyChart';
|
||||||
import { Widget, WidgetBody } from '../widget';
|
import { Widget, WidgetBody } from '../widget';
|
||||||
import { OverviewChartToggle } from './overview-chart-toggle';
|
import { OverviewChartToggle } from './overview-chart-toggle';
|
||||||
|
import OverviewDetailsButton from './overview-details-button';
|
||||||
import { WidgetButtons, WidgetHead } from './overview-widget';
|
import { WidgetButtons, WidgetHead } from './overview-widget';
|
||||||
import { useOverviewOptions } from './useOverviewOptions';
|
import { useOverviewOptions } from './useOverviewOptions';
|
||||||
import { useOverviewWidget } from './useOverviewWidget';
|
import { useOverviewWidget } from './useOverviewWidget';
|
||||||
@@ -157,6 +158,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget className="col-span-6 md:col-span-3">
|
<Widget className="col-span-6 md:col-span-3">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type { IChartType } from '@openpanel/validation';
|
|||||||
import { LazyChart } from '../report/chart/LazyChart';
|
import { LazyChart } from '../report/chart/LazyChart';
|
||||||
import { Widget, WidgetBody } from '../widget';
|
import { Widget, WidgetBody } from '../widget';
|
||||||
import { OverviewChartToggle } from './overview-chart-toggle';
|
import { OverviewChartToggle } from './overview-chart-toggle';
|
||||||
|
import OverviewDetailsButton from './overview-details-button';
|
||||||
import OverviewTopBots from './overview-top-bots';
|
import OverviewTopBots from './overview-top-bots';
|
||||||
import { WidgetButtons, WidgetHead } from './overview-widget';
|
import { WidgetButtons, WidgetHead } from './overview-widget';
|
||||||
import { useOverviewOptions } from './useOverviewOptions';
|
import { useOverviewOptions } from './useOverviewOptions';
|
||||||
@@ -154,6 +155,7 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||||
|
import { pushModal } from '@/modals';
|
||||||
import { cn } from '@/utils/cn';
|
import { cn } from '@/utils/cn';
|
||||||
|
import { ScanEyeIcon } from 'lucide-react';
|
||||||
|
|
||||||
import type { IChartType } from '@openpanel/validation';
|
import type { IChartType } from '@openpanel/validation';
|
||||||
|
|
||||||
import { LazyChart } from '../report/chart/LazyChart';
|
import { LazyChart } from '../report/chart/LazyChart';
|
||||||
import { Widget, WidgetBody } from '../widget';
|
import { Widget, WidgetBody } from '../widget';
|
||||||
import { OverviewChartToggle } from './overview-chart-toggle';
|
import { OverviewChartToggle } from './overview-chart-toggle';
|
||||||
|
import OverviewDetailsButton from './overview-details-button';
|
||||||
import { WidgetButtons, WidgetHead } from './overview-widget';
|
import { WidgetButtons, WidgetHead } from './overview-widget';
|
||||||
import { useOverviewOptions } from './useOverviewOptions';
|
import { useOverviewOptions } from './useOverviewOptions';
|
||||||
import { useOverviewWidget } from './useOverviewWidget';
|
import { useOverviewWidget } from './useOverviewWidget';
|
||||||
@@ -324,6 +327,7 @@ export default function OverviewTopSources({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<OverviewDetailsButton chart={widget.chart} />
|
||||||
</WidgetBody>
|
</WidgetBody>
|
||||||
</Widget>
|
</Widget>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function WidgetHead({ className, ...props }: WidgetHeadProps) {
|
|||||||
return (
|
return (
|
||||||
<WidgetHeadBase
|
<WidgetHeadBase
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col rounded-t-xl p-0 [&_.title]:flex [&_.title]:items-center [&_.title]:justify-between [&_.title]:p-4',
|
'flex flex-col rounded-t-xl p-0 [&_.title]:flex [&_.title]:items-center [&_.title]:justify-between [&_.title]:p-4 [&_.title]:font-semibold',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export interface ChartContextType extends IChartInput {
|
|||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
hideID?: boolean;
|
hideID?: boolean;
|
||||||
onClick?: (item: IChartSerie) => void;
|
onClick?: (item: IChartSerie) => void;
|
||||||
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChartProviderProps = {
|
type ChartProviderProps = {
|
||||||
@@ -37,6 +38,7 @@ const ChartContext = createContext<ChartContextType | null>({
|
|||||||
metric: 'sum',
|
metric: 'sum',
|
||||||
previous: false,
|
previous: false,
|
||||||
projectId: '',
|
projectId: '',
|
||||||
|
limit: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ChartProvider({
|
export function ChartProvider({
|
||||||
@@ -44,6 +46,7 @@ export function ChartProvider({
|
|||||||
editMode,
|
editMode,
|
||||||
previous,
|
previous,
|
||||||
hideID,
|
hideID,
|
||||||
|
limit,
|
||||||
...props
|
...props
|
||||||
}: ChartProviderProps) {
|
}: ChartProviderProps) {
|
||||||
return (
|
return (
|
||||||
@@ -54,8 +57,9 @@ export function ChartProvider({
|
|||||||
editMode: editMode ?? false,
|
editMode: editMode ?? false,
|
||||||
previous: previous ?? false,
|
previous: previous ?? false,
|
||||||
hideID: hideID ?? false,
|
hideID: hideID ?? false,
|
||||||
|
limit,
|
||||||
}),
|
}),
|
||||||
[editMode, previous, hideID, props]
|
[editMode, previous, hideID, limit, props]
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ interface ReportBarChartProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ReportBarChart({ data }: ReportBarChartProps) {
|
export function ReportBarChart({ data }: ReportBarChartProps) {
|
||||||
const { editMode, metric, onClick } = useChartContext();
|
const { editMode, metric, onClick, limit } = useChartContext();
|
||||||
const number = useNumber();
|
const number = useNumber();
|
||||||
const series = useMemo(
|
const series = useMemo(
|
||||||
() => (editMode ? data.series : data.series.slice(0, 10)),
|
() => (editMode ? data.series : data.series.slice(0, limit || 10)),
|
||||||
[data, editMode]
|
[data, editMode, limit]
|
||||||
);
|
);
|
||||||
const maxCount = Math.max(...series.map((serie) => serie.metrics[metric]));
|
const maxCount = Math.max(...series.map((serie) => serie.metrics[metric]));
|
||||||
|
|
||||||
|
|||||||
25
apps/dashboard/src/modals/OverviewChartDetails.tsx
Normal file
25
apps/dashboard/src/modals/OverviewChartDetails.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { ChartSwitch } from '@/components/report/chart';
|
||||||
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
|
|
||||||
|
import type { IChartInput } from '@openpanel/validation';
|
||||||
|
|
||||||
|
import { ModalContent, ModalHeader } from './Modal/Container';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
chart: IChartInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OverviewChartDetails = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader title={props.chart.name} />
|
||||||
|
<ScrollArea className="-m-6 max-h-[calc(100vh-200px)]">
|
||||||
|
<div className="p-6">
|
||||||
|
<ChartSwitch {...props.chart} limit={999} chartType="bar" />
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</ModalContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OverviewChartDetails;
|
||||||
@@ -62,6 +62,9 @@ const modals = {
|
|||||||
DateRangerPicker: dynamic(() => import('./DateRangerPicker'), {
|
DateRangerPicker: dynamic(() => import('./DateRangerPicker'), {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
}),
|
}),
|
||||||
|
OverviewChartDetails: dynamic(() => import('./OverviewChartDetails'), {
|
||||||
|
loading: Loading,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|||||||
@@ -209,7 +209,9 @@ export const chartRouter = createTRPCRouter({
|
|||||||
const final: FinalChart = {
|
const final: FinalChart = {
|
||||||
events: input.events,
|
events: input.events,
|
||||||
series: series.map((serie, index) => {
|
series: series.map((serie, index) => {
|
||||||
const previousSerie = previousSeries?.[index];
|
const previousSerie = previousSeries?.find(
|
||||||
|
(item) => item.name === serie.name
|
||||||
|
);
|
||||||
const metrics = {
|
const metrics = {
|
||||||
sum: sum(serie.data.map((item) => item.count)),
|
sum: sum(serie.data.map((item) => item.count)),
|
||||||
average: round(average(serie.data.map((item) => item.count)), 2),
|
average: round(average(serie.data.map((item) => item.count)), 2),
|
||||||
|
|||||||
Reference in New Issue
Block a user