fix(api): filter empty values when using sum and average, added min and max
This commit is contained in:
@@ -81,7 +81,7 @@
|
|||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"lottie-react": "^2.4.0",
|
"lottie-react": "^2.4.0",
|
||||||
"lucide-react": "^0.451.0",
|
"lucide-react": "^0.513.0",
|
||||||
"mathjs": "^12.3.2",
|
"mathjs": "^12.3.2",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"next": "14.2.1",
|
"next": "14.2.1",
|
||||||
|
|||||||
92
apps/dashboard/src/components/report/ReportSegment.tsx
Normal file
92
apps/dashboard/src/components/report/ReportSegment.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import {
|
||||||
|
ActivityIcon,
|
||||||
|
ClockIcon,
|
||||||
|
EqualApproximatelyIcon,
|
||||||
|
type LucideIcon,
|
||||||
|
SigmaIcon,
|
||||||
|
TrendingDownIcon,
|
||||||
|
TrendingUpIcon,
|
||||||
|
UserCheck2Icon,
|
||||||
|
UserCheckIcon,
|
||||||
|
UsersIcon,
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
import { chartSegments } from '@openpanel/constants';
|
||||||
|
import { type IChartEventSegment, mapKeys } from '@openpanel/validation';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuShortcut,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
import { Button } from '../ui/button';
|
||||||
|
|
||||||
|
interface ReportChartTypeProps {
|
||||||
|
className?: string;
|
||||||
|
value: IChartEventSegment;
|
||||||
|
onChange: (segment: IChartEventSegment) => void;
|
||||||
|
}
|
||||||
|
export function ReportSegment({
|
||||||
|
className,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: ReportChartTypeProps) {
|
||||||
|
const items = mapKeys(chartSegments).map((key) => ({
|
||||||
|
label: chartSegments[key],
|
||||||
|
value: key,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Icons: Record<IChartEventSegment, LucideIcon> = {
|
||||||
|
event: ActivityIcon,
|
||||||
|
user: UsersIcon,
|
||||||
|
session: ClockIcon,
|
||||||
|
user_average: UserCheck2Icon,
|
||||||
|
one_event_per_user: UserCheckIcon,
|
||||||
|
property_sum: SigmaIcon,
|
||||||
|
property_average: EqualApproximatelyIcon,
|
||||||
|
property_max: TrendingUpIcon,
|
||||||
|
property_min: TrendingDownIcon,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
icon={Icons[value]}
|
||||||
|
className={cn('justify-start', className)}
|
||||||
|
>
|
||||||
|
{items.find((item) => item.value === value)?.label}
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="w-56">
|
||||||
|
<DropdownMenuLabel>Available charts</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
|
||||||
|
<DropdownMenuGroup>
|
||||||
|
{items.map((item) => {
|
||||||
|
const Icon = Icons[item.value];
|
||||||
|
return (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={item.value}
|
||||||
|
onClick={() => onChange(item.value)}
|
||||||
|
className="group"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
<DropdownMenuShortcut>
|
||||||
|
<Icon className="size-4 group-hover:text-blue-500 group-hover:scale-125 transition-all group-hover:rotate-12" />
|
||||||
|
</DropdownMenuShortcut>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</DropdownMenuGroup>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
import { ColorSquare } from '@/components/color-square';
|
import { ColorSquare } from '@/components/color-square';
|
||||||
import { Combobox } from '@/components/ui/combobox';
|
import { Combobox } from '@/components/ui/combobox';
|
||||||
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
||||||
import { DropdownMenuComposed } from '@/components/ui/dropdown-menu';
|
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { useAppParams } from '@/hooks/useAppParams';
|
import { useAppParams } from '@/hooks/useAppParams';
|
||||||
import { useDebounceFn } from '@/hooks/useDebounceFn';
|
import { useDebounceFn } from '@/hooks/useDebounceFn';
|
||||||
@@ -28,7 +27,8 @@ import { CSS } from '@dnd-kit/utilities';
|
|||||||
import { shortId } from '@openpanel/common';
|
import { shortId } from '@openpanel/common';
|
||||||
import { alphabetIds } from '@openpanel/constants';
|
import { alphabetIds } from '@openpanel/constants';
|
||||||
import type { IChartEvent } from '@openpanel/validation';
|
import type { IChartEvent } from '@openpanel/validation';
|
||||||
import { FilterIcon, GanttChartIcon, HandIcon, Users } from 'lucide-react';
|
import { FilterIcon, GanttChartIcon, HandIcon } from 'lucide-react';
|
||||||
|
import { ReportSegment } from '../ReportSegment';
|
||||||
import {
|
import {
|
||||||
addEvent,
|
addEvent,
|
||||||
changeEvent,
|
changeEvent,
|
||||||
@@ -82,7 +82,8 @@ function SortableEvent({
|
|||||||
{(showSegment || showAddFilter) && (
|
{(showSegment || showAddFilter) && (
|
||||||
<div className="flex gap-2 p-2 pt-0">
|
<div className="flex gap-2 p-2 pt-0">
|
||||||
{showSegment && (
|
{showSegment && (
|
||||||
<DropdownMenuComposed
|
<ReportSegment
|
||||||
|
value={event.segment}
|
||||||
onChange={(segment) => {
|
onChange={(segment) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
changeEvent({
|
changeEvent({
|
||||||
@@ -91,73 +92,7 @@ function SortableEvent({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
items={[
|
/>
|
||||||
{
|
|
||||||
value: 'event',
|
|
||||||
label: 'All events',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'user',
|
|
||||||
label: 'Unique users',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'session',
|
|
||||||
label: 'Unique sessions',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'user_average',
|
|
||||||
label: 'Average event per user',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'one_event_per_user',
|
|
||||||
label: 'One event per user',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'property_sum',
|
|
||||||
label: 'Sum of property',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'property_average',
|
|
||||||
label: 'Average of property',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
label="Segment"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="flex items-center gap-1 rounded-md border border-border bg-card p-1 px-2 text-sm font-medium leading-none"
|
|
||||||
>
|
|
||||||
{event.segment === 'user' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> Unique users
|
|
||||||
</>
|
|
||||||
) : event.segment === 'session' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> Unique sessions
|
|
||||||
</>
|
|
||||||
) : event.segment === 'user_average' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> Average event per user
|
|
||||||
</>
|
|
||||||
) : event.segment === 'one_event_per_user' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> One event per user
|
|
||||||
</>
|
|
||||||
) : event.segment === 'property_sum' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> Sum of property
|
|
||||||
</>
|
|
||||||
) : event.segment === 'property_average' ? (
|
|
||||||
<>
|
|
||||||
<Users size={12} /> Average of property
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<GanttChartIcon size={12} /> All events
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</DropdownMenuComposed>
|
|
||||||
)}
|
)}
|
||||||
{showAddFilter && (
|
{showAddFilter && (
|
||||||
<PropertiesCombobox
|
<PropertiesCombobox
|
||||||
|
|||||||
@@ -102,6 +102,18 @@ export const chartTypes = {
|
|||||||
conversion: 'Conversion',
|
conversion: 'Conversion',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const chartSegments = {
|
||||||
|
event: 'All events',
|
||||||
|
user: 'Unique users',
|
||||||
|
session: 'Unique sessions',
|
||||||
|
user_average: 'Average users',
|
||||||
|
one_event_per_user: 'One event per user',
|
||||||
|
property_sum: 'Sum of property',
|
||||||
|
property_average: 'Average of property',
|
||||||
|
property_max: 'Max of property',
|
||||||
|
property_min: 'Min of property',
|
||||||
|
};
|
||||||
|
|
||||||
export const lineTypes = {
|
export const lineTypes = {
|
||||||
monotone: 'Monotone',
|
monotone: 'Monotone',
|
||||||
monotoneX: 'Monotone X',
|
monotoneX: 'Monotone X',
|
||||||
|
|||||||
@@ -162,12 +162,22 @@ export function getChartSql({
|
|||||||
|
|
||||||
if (event.segment === 'property_sum' && event.property) {
|
if (event.segment === 'property_sum' && event.property) {
|
||||||
sb.select.count = `sum(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
sb.select.count = `sum(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
||||||
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL`;
|
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.segment === 'property_average' && event.property) {
|
if (event.segment === 'property_average' && event.property) {
|
||||||
sb.select.count = `avg(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
sb.select.count = `avg(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
||||||
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL`;
|
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.segment === 'property_max' && event.property) {
|
||||||
|
sb.select.count = `max(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
||||||
|
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.segment === 'property_min' && event.property) {
|
||||||
|
sb.select.count = `min(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
|
||||||
|
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.segment === 'one_event_per_user') {
|
if (event.segment === 'one_event_per_user') {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
chartSegments,
|
||||||
chartTypes,
|
chartTypes,
|
||||||
intervals,
|
intervals,
|
||||||
lineTypes,
|
lineTypes,
|
||||||
@@ -29,6 +30,11 @@ export const zChartEventFilter = z.object({
|
|||||||
.describe('The values to filter on'),
|
.describe('The values to filter on'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const zChartEventSegment = z
|
||||||
|
.enum(objectToZodEnums(chartSegments))
|
||||||
|
.default('event')
|
||||||
|
.describe('Defines how the event data should be segmented or aggregated');
|
||||||
|
|
||||||
export const zChartEvent = z.object({
|
export const zChartEvent = z.object({
|
||||||
id: z
|
id: z
|
||||||
.string()
|
.string()
|
||||||
@@ -45,18 +51,7 @@ export const zChartEvent = z.object({
|
|||||||
.describe(
|
.describe(
|
||||||
'Optional property of the event used for specific segment calculations (e.g., value for property_sum/average)',
|
'Optional property of the event used for specific segment calculations (e.g., value for property_sum/average)',
|
||||||
),
|
),
|
||||||
segment: z
|
segment: zChartEventSegment,
|
||||||
.enum([
|
|
||||||
'event',
|
|
||||||
'user',
|
|
||||||
'session',
|
|
||||||
'user_average',
|
|
||||||
'one_event_per_user',
|
|
||||||
'property_sum',
|
|
||||||
'property_average',
|
|
||||||
])
|
|
||||||
.default('event')
|
|
||||||
.describe('Defines how the event data should be segmented or aggregated'),
|
|
||||||
filters: z
|
filters: z
|
||||||
.array(zChartEventFilter)
|
.array(zChartEventFilter)
|
||||||
.default([])
|
.default([])
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { z } from 'zod';
|
|||||||
import type {
|
import type {
|
||||||
zChartBreakdown,
|
zChartBreakdown,
|
||||||
zChartEvent,
|
zChartEvent,
|
||||||
|
zChartEventSegment,
|
||||||
zChartInput,
|
zChartInput,
|
||||||
zChartInputAI,
|
zChartInputAI,
|
||||||
zChartType,
|
zChartType,
|
||||||
@@ -23,6 +24,7 @@ export type IChartProps = z.infer<typeof zReportInput> & {
|
|||||||
previousIndicatorInverted?: boolean;
|
previousIndicatorInverted?: boolean;
|
||||||
};
|
};
|
||||||
export type IChartEvent = z.infer<typeof zChartEvent>;
|
export type IChartEvent = z.infer<typeof zChartEvent>;
|
||||||
|
export type IChartEventSegment = z.infer<typeof zChartEventSegment>;
|
||||||
export type IChartEventFilter = IChartEvent['filters'][number];
|
export type IChartEventFilter = IChartEvent['filters'][number];
|
||||||
export type IChartEventFilterValue =
|
export type IChartEventFilterValue =
|
||||||
IChartEvent['filters'][number]['value'][number];
|
IChartEvent['filters'][number]['value'][number];
|
||||||
|
|||||||
61
pnpm-lock.yaml
generated
61
pnpm-lock.yaml
generated
@@ -413,8 +413,8 @@ importers:
|
|||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
version: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.451.0
|
specifier: ^0.513.0
|
||||||
version: 0.451.0(react@18.2.0)
|
version: 0.513.0(react@18.2.0)
|
||||||
mathjs:
|
mathjs:
|
||||||
specifier: ^12.3.2
|
specifier: ^12.3.2
|
||||||
version: 12.3.2
|
version: 12.3.2
|
||||||
@@ -1072,40 +1072,6 @@ importers:
|
|||||||
specifier: ^5.2.2
|
specifier: ^5.2.2
|
||||||
version: 5.6.3
|
version: 5.6.3
|
||||||
|
|
||||||
packages/fire:
|
|
||||||
dependencies:
|
|
||||||
'@faker-js/faker':
|
|
||||||
specifier: ^9.0.1
|
|
||||||
version: 9.0.1
|
|
||||||
'@openpanel/common':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../common
|
|
||||||
'@openpanel/db':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../db
|
|
||||||
csv-parse:
|
|
||||||
specifier: ^5.6.0
|
|
||||||
version: 5.6.0
|
|
||||||
date-fns:
|
|
||||||
specifier: ^3.3.1
|
|
||||||
version: 3.3.1
|
|
||||||
devDependencies:
|
|
||||||
'@openpanel/tsconfig':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../tooling/typescript
|
|
||||||
'@openpanel/validation':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../validation
|
|
||||||
'@types/node':
|
|
||||||
specifier: 20.14.8
|
|
||||||
version: 20.14.8
|
|
||||||
tsup:
|
|
||||||
specifier: ^7.2.0
|
|
||||||
version: 7.3.0(postcss@8.5.3)(typescript@5.6.3)
|
|
||||||
typescript:
|
|
||||||
specifier: ^5.2.2
|
|
||||||
version: 5.6.3
|
|
||||||
|
|
||||||
packages/integrations:
|
packages/integrations:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@slack/bolt':
|
'@slack/bolt':
|
||||||
@@ -7526,9 +7492,6 @@ packages:
|
|||||||
csstype@3.1.3:
|
csstype@3.1.3:
|
||||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||||
|
|
||||||
csv-parse@5.6.0:
|
|
||||||
resolution: {integrity: sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==}
|
|
||||||
|
|
||||||
d3-array@2.12.1:
|
d3-array@2.12.1:
|
||||||
resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
|
resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
|
||||||
|
|
||||||
@@ -9630,16 +9593,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
lucide-react@0.451.0:
|
|
||||||
resolution: {integrity: sha512-OwQ3uljZLp2cerj8sboy5rnhtGTCl9UCJIhT1J85/yOuGVlEH+xaUPR7tvNdddPvmV5M5VLdr7cQuWE3hzA4jw==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
|
||||||
|
|
||||||
lucide-react@0.454.0:
|
lucide-react@0.454.0:
|
||||||
resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==}
|
resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
||||||
|
|
||||||
|
lucide-react@0.513.0:
|
||||||
|
resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
luxon@3.4.4:
|
luxon@3.4.4:
|
||||||
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
|
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -19949,8 +19912,6 @@ snapshots:
|
|||||||
|
|
||||||
csstype@3.1.3: {}
|
csstype@3.1.3: {}
|
||||||
|
|
||||||
csv-parse@5.6.0: {}
|
|
||||||
|
|
||||||
d3-array@2.12.1:
|
d3-array@2.12.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
internmap: 1.0.1
|
internmap: 1.0.1
|
||||||
@@ -22559,14 +22520,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
|
|
||||||
lucide-react@0.451.0(react@18.2.0):
|
|
||||||
dependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
|
|
||||||
lucide-react@0.454.0(react@18.3.1):
|
lucide-react@0.454.0(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
|
lucide-react@0.513.0(react@18.2.0):
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
|
||||||
luxon@3.4.4: {}
|
luxon@3.4.4: {}
|
||||||
|
|
||||||
luxon@3.6.1: {}
|
luxon@3.6.1: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user