feature(dashboard): add interval picker to the overview page
This commit is contained in:
@@ -32,7 +32,7 @@ import {
|
|||||||
} from '@openpanel/constants';
|
} from '@openpanel/constants';
|
||||||
import type { IServiceDashboard, getReportsByDashboardId } from '@openpanel/db';
|
import type { IServiceDashboard, getReportsByDashboardId } from '@openpanel/db';
|
||||||
|
|
||||||
import { OverviewReportRange } from '../../overview-sticky-header';
|
import { OverviewRange } from '@/components/overview/overview-range';
|
||||||
|
|
||||||
interface ListReportsProps {
|
interface ListReportsProps {
|
||||||
reports: Awaited<ReturnType<typeof getReportsByDashboardId>>;
|
reports: Awaited<ReturnType<typeof getReportsByDashboardId>>;
|
||||||
@@ -55,7 +55,7 @@ export function ListReports({ reports, dashboard }: ListReportsProps) {
|
|||||||
<div className="row mb-4 items-center justify-between">
|
<div className="row mb-4 items-center justify-between">
|
||||||
<h1 className="text-3xl font-semibold">{dashboard.name}</h1>
|
<h1 className="text-3xl font-semibold">{dashboard.name}</h1>
|
||||||
<div className="flex items-center justify-end gap-2">
|
<div className="flex items-center justify-end gap-2">
|
||||||
<OverviewReportRange />
|
<OverviewRange />
|
||||||
<Button
|
<Button
|
||||||
icon={PlusIcon}
|
icon={PlusIcon}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OverviewTopGeo from '@/components/overview/overview-top-geo';
|
|||||||
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
||||||
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
||||||
|
|
||||||
import { OverviewReportRange } from './overview-sticky-header';
|
import { OverviewInterval } from '@/components/overview/overview-interval';
|
||||||
|
import { OverviewRange } from '@/components/overview/overview-range';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: {
|
params: {
|
||||||
@@ -23,7 +24,8 @@ export default function Page({ params: { projectId } }: PageProps) {
|
|||||||
<div className="col gap-2 p-4">
|
<div className="col gap-2 p-4">
|
||||||
<div className="flex justify-between gap-2">
|
<div className="flex justify-between gap-2">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<OverviewReportRange />
|
<OverviewRange />
|
||||||
|
<OverviewInterval />
|
||||||
<OverviewFiltersDrawer projectId={projectId} mode="events" />
|
<OverviewFiltersDrawer projectId={projectId} mode="events" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { StickyBelowHeader } from '@/app/(app)/[organizationSlug]/[projectId]/layout-sticky-below-header';
|
import { StickyBelowHeader } from '@/app/(app)/[organizationSlug]/[projectId]/layout-sticky-below-header';
|
||||||
import { OverviewReportRange } from '@/app/(app)/[organizationSlug]/[projectId]/overview-sticky-header';
|
|
||||||
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
|
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
|
||||||
import ServerLiveCounter from '@/components/overview/live-counter';
|
import ServerLiveCounter from '@/components/overview/live-counter';
|
||||||
import OverviewMetrics from '@/components/overview/overview-metrics';
|
import OverviewMetrics from '@/components/overview/overview-metrics';
|
||||||
@@ -10,6 +9,7 @@ import OverviewTopPages from '@/components/overview/overview-top-pages';
|
|||||||
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
|
import { OverviewRange } from '@/components/overview/overview-range';
|
||||||
import { getOrganizationBySlug, getShareOverviewById } from '@openpanel/db';
|
import { getOrganizationBySlug, getShareOverviewById } from '@openpanel/db';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
@@ -56,7 +56,7 @@ export default async function Page({
|
|||||||
<StickyBelowHeader>
|
<StickyBelowHeader>
|
||||||
<div className="flex justify-between gap-2 p-4">
|
<div className="flex justify-between gap-2 p-4">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<OverviewReportRange />
|
<OverviewRange />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<ServerLiveCounter projectId={projectId} />
|
<ServerLiveCounter projectId={projectId} />
|
||||||
|
|||||||
48
apps/dashboard/src/components/overview/overview-interval.tsx
Normal file
48
apps/dashboard/src/components/overview/overview-interval.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||||
|
import { TimeWindowPicker } from '@/components/time-window-picker';
|
||||||
|
import {
|
||||||
|
isHourIntervalEnabledByRange,
|
||||||
|
isMinuteIntervalEnabledByRange,
|
||||||
|
} from '@openpanel/constants';
|
||||||
|
import { endOfDay, formatISO, startOfDay } from 'date-fns';
|
||||||
|
import { ClockIcon } from 'lucide-react';
|
||||||
|
import { Combobox } from '../ui/combobox';
|
||||||
|
|
||||||
|
export function OverviewInterval() {
|
||||||
|
const { interval, setInterval, range } = useOverviewOptions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Combobox
|
||||||
|
icon={ClockIcon}
|
||||||
|
placeholder="Interval"
|
||||||
|
onChange={(value) => {
|
||||||
|
setInterval(value);
|
||||||
|
}}
|
||||||
|
value={interval}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
value: 'minute',
|
||||||
|
label: 'Minute',
|
||||||
|
disabled: !isMinuteIntervalEnabledByRange(range),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'hour',
|
||||||
|
label: 'Hour',
|
||||||
|
disabled: !isHourIntervalEnabledByRange(range),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'day',
|
||||||
|
label: 'Day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'month',
|
||||||
|
label: 'Month',
|
||||||
|
disabled:
|
||||||
|
range === 'today' || range === 'lastHour' || range === '30min',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
|||||||
import { TimeWindowPicker } from '@/components/time-window-picker';
|
import { TimeWindowPicker } from '@/components/time-window-picker';
|
||||||
import { endOfDay, formatISO, startOfDay } from 'date-fns';
|
import { endOfDay, formatISO, startOfDay } from 'date-fns';
|
||||||
|
|
||||||
export function OverviewReportRange() {
|
export function OverviewRange() {
|
||||||
const { range, setRange, setStartDate, setEndDate, endDate, startDate } =
|
const { range, setRange, setStartDate, setEndDate, endDate, startDate } =
|
||||||
useOverviewOptions();
|
useOverviewOptions();
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ import { getStorageItem, setStorageItem } from '@/utils/storage';
|
|||||||
import {
|
import {
|
||||||
getDefaultIntervalByDates,
|
getDefaultIntervalByDates,
|
||||||
getDefaultIntervalByRange,
|
getDefaultIntervalByRange,
|
||||||
|
intervals,
|
||||||
timeWindows,
|
timeWindows,
|
||||||
} from '@openpanel/constants';
|
} from '@openpanel/constants';
|
||||||
import type { IChartRange } from '@openpanel/validation';
|
import type { IChartRange } from '@openpanel/validation';
|
||||||
@@ -36,6 +37,13 @@ export function useOverviewOptions() {
|
|||||||
clearOnDefault: false,
|
clearOnDefault: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const [overrideInterval, setInterval] = useQueryState(
|
||||||
|
'overrideInterval',
|
||||||
|
parseAsStringEnum(mapKeys(intervals)).withOptions({
|
||||||
|
...nuqsOptions,
|
||||||
|
clearOnDefault: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const range = getStorageItem('range', '7d');
|
const range = getStorageItem('range', '7d');
|
||||||
@@ -45,6 +53,7 @@ export function useOverviewOptions() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const interval =
|
const interval =
|
||||||
|
overrideInterval ||
|
||||||
getDefaultIntervalByDates(startDate, endDate) ||
|
getDefaultIntervalByDates(startDate, endDate) ||
|
||||||
getDefaultIntervalByRange(range);
|
getDefaultIntervalByRange(range);
|
||||||
|
|
||||||
@@ -78,8 +87,7 @@ export function useOverviewOptions() {
|
|||||||
setStartDate,
|
setStartDate,
|
||||||
endDate,
|
endDate,
|
||||||
setEndDate,
|
setEndDate,
|
||||||
|
|
||||||
// Computed
|
|
||||||
interval,
|
interval,
|
||||||
|
setInterval,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user