chore(root): migrate to biome

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-09-16 12:20:40 +02:00
parent 1f6e198336
commit 32e91959f6
383 changed files with 1943 additions and 3085 deletions

View File

@@ -1,6 +1,5 @@
'use client';
import React, { useCallback } from 'react';
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
import { api } from '@/trpc/client';
@@ -9,6 +8,7 @@ import { cn } from '@/utils/cn';
import { getChartColor } from '@/utils/theme';
import { isSameDay, isSameHour, isSameMonth } from 'date-fns';
import { last } from 'ramda';
import React, { useCallback } from 'react';
import {
Area,
CartesianGrid,
@@ -57,7 +57,7 @@ export function Chart({ data }: Props) {
},
{
staleTime: 1000 * 60 * 10,
}
},
);
const { series, setVisibleSeries } = useVisibleSeries(data);
const rechartData = useRechartDataModel(series);
@@ -73,7 +73,7 @@ export function Chart({ data }: Props) {
id: string,
col1: string,
col2: string,
percentChange: number
percentChange: number,
) => (
<linearGradient id={id} x1="0" y1="0" x2="100%" y2="0">
<stop offset="0%" stopColor={col1} />
@@ -177,29 +177,25 @@ export function Chart({ data }: Props) {
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor={color}
stopOpacity={0.8}
></stop>
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
<stop
offset="100%"
stopColor={color}
stopOpacity={0.1}
></stop>
/>
</linearGradient>
)}
{gradientTwoColors(
`hideAllButLastInterval_${serie.id}`,
'rgba(0,0,0,0)',
color,
lastIntervalPercent
lastIntervalPercent,
)}
{gradientTwoColors(
`hideJustLastInterval_${serie.id}`,
color,
'rgba(0,0,0,0)',
lastIntervalPercent
lastIntervalPercent,
)}
</defs>
<Line

View File

@@ -1,6 +1,5 @@
'use client';
import { useMemo } from 'react';
import {
DropdownMenu,
DropdownMenuContent,
@@ -11,6 +10,7 @@ import { useNumber } from '@/hooks/useNumerFormatter';
import type { IChartData } from '@/trpc/client';
import { cn } from '@/utils/cn';
import { DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
import { useMemo } from 'react';
import { round } from '@openpanel/common';
import { NOT_SET_VALUE } from '@openpanel/constants';
@@ -33,7 +33,7 @@ export function Chart({ data }: Props) {
const number = useNumber();
const series = useMemo(
() => (isEditMode ? data.series : data.series.slice(0, limit || 10)),
[data, isEditMode, limit]
[data, isEditMode, limit],
);
const maxCount = Math.max(...series.map((serie) => serie.metrics[metric]));
@@ -41,7 +41,7 @@ export function Chart({ data }: Props) {
<div
className={cn(
'flex flex-col text-sm',
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1'
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1',
)}
>
{series.map((serie) => {
@@ -56,7 +56,7 @@ export function Chart({ data }: Props) {
<div
className={cn(
'relative',
(isClickable || isDropDownEnabled) && 'cursor-pointer'
(isClickable || isDropDownEnabled) && 'cursor-pointer',
)}
{...(isClickable && !isDropDownEnabled
? { onClick: () => onClick?.(serie) }
@@ -80,7 +80,7 @@ export function Chart({ data }: Props) {
{serie.metrics.previous?.[metric]?.value}
<div className="text-muted-foreground">
{number.format(
round((serie.metrics.sum / data.metrics.sum) * 100, 2)
round((serie.metrics.sum / data.metrics.sum) * 100, 2),
)}
%
</div>

View File

@@ -33,12 +33,15 @@ function Loading() {
return (
<AspectContainer className="col gap-4 overflow-hidden">
{Array.from({ length: 10 }).map((_, index) => (
<div key={index} className="row animate-pulse justify-between">
<div className="h-4 w-2/5 rounded bg-def-200"></div>
<div
key={index as number}
className="row animate-pulse justify-between"
>
<div className="h-4 w-2/5 rounded bg-def-200" />
<div className="row w-1/5 gap-2">
<div className="h-4 w-full rounded bg-def-200"></div>
<div className="h-4 w-full rounded bg-def-200"></div>
<div className="h-4 w-full rounded bg-def-200"></div>
<div className="h-4 w-full rounded bg-def-200" />
<div className="h-4 w-full rounded bg-def-200" />
<div className="h-4 w-full rounded bg-def-200" />
</div>
</div>
))}

View File

@@ -1,8 +1,8 @@
import { useRef, useState } from 'react';
import { useDebounceFn } from '@/hooks/useDebounceFn';
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
import { useNumber } from '@/hooks/useNumerFormatter';
import { isNil } from 'ramda';
import { useRef, useState } from 'react';
import type { AxisDomain } from 'recharts/types/util/types';
import type { IInterval } from '@openpanel/validation';
@@ -60,10 +60,10 @@ export const useXAxisProps = (
} = {
hide: false,
interval: 'auto',
}
},
) => {
const formatDate = useFormatDateInterval(
interval === 'auto' ? 'day' : interval
interval === 'auto' ? 'day' : interval,
);
return {
height: hide ? 0 : 14,

View File

@@ -1,3 +1,3 @@
export function ReportChartLoading() {
return <div className="h-full w-full animate-pulse rounded bg-def-100"></div>;
return <div className="h-full w-full animate-pulse rounded bg-def-100" />;
}

View File

@@ -9,7 +9,7 @@ export function getDiffIndicator<A, B, C>(
state: string | undefined | null,
positive: A,
negative: B,
neutral: C
neutral: C,
): A | B | C {
if (state === 'neutral' || !state) {
return neutral;
@@ -48,7 +48,7 @@ export function PreviousDiffIndicator({
state,
'bg-emerald-300',
'bg-rose-300',
undefined
undefined,
);
const number = useNumber();
@@ -72,14 +72,14 @@ export function PreviousDiffIndicator({
className={cn(
'flex items-center gap-1 font-mono font-medium',
size === 'lg' && 'gap-2',
className
className,
)}
>
<div
className={cn(
`flex size-4 items-center justify-center rounded-full`,
'flex size-4 items-center justify-center rounded-full',
variant,
size === 'lg' && 'size-8'
size === 'lg' && 'size-8',
)}
>
{renderIcon()}

View File

@@ -1,4 +1,3 @@
import React, { useEffect, useState } from 'react';
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
import { useNumber } from '@/hooks/useNumerFormatter';
import type { IRechartPayloadItem } from '@/hooks/useRechartDataModel';
@@ -6,6 +5,7 @@ import type { IToolTipProps } from '@/types';
import * as Portal from '@radix-ui/react-portal';
import { bind } from 'bind-event-listener';
import throttle from 'lodash.throttle';
import React, { useEffect, useState } from 'react';
import { useReportChartContext } from '../context';
import { PreviousDiffIndicator } from './previous-diff-indicator';
@@ -29,7 +29,7 @@ export function ReportChartTooltip({
const formatDate = useFormatDateInterval(interval);
const number = useNumber();
const [position, setPosition] = useState<{ x: number; y: number } | null>(
null
null,
);
const inactive = !active || !payload?.length;

View File

@@ -1,4 +1,3 @@
import * as React from 'react';
import { Pagination, usePagination } from '@/components/pagination';
import { Stats, StatsCard } from '@/components/stats';
import { Badge } from '@/components/ui/badge';
@@ -18,6 +17,7 @@ import { useSelector } from '@/redux';
import { getPropertyLabel } from '@/translations/properties';
import type { IChartData } from '@/trpc/client';
import { getChartColor } from '@/utils/theme';
import type * as React from 'react';
import { PreviousDiffIndicator } from './previous-diff-indicator';
import { SerieName } from './serie-name';
@@ -45,9 +45,8 @@ export function ReportTable({
setVisibleSeries((prev) => {
if (checked) {
return [...prev, name];
} else {
return prev.filter((item) => item !== name);
}
return prev.filter((item) => item !== name);
});
}
@@ -77,7 +76,7 @@ export function ReportTable({
<TableBody className="bg-def-100">
{paginate(data.series).map((serie, index) => {
const checked = !!visibleSeries.find(
(item) => item.id === serie.id
(item) => item.id === serie.id,
);
return (

View File

@@ -1,13 +1,11 @@
import type { LucideIcon, LucideProps } from 'lucide-react';
const createFlagIcon = (url: string) => {
return function (_props: LucideProps) {
return (
<span
className={`fi !block aspect-[1.33] overflow-hidden rounded-[2px] fi-${url}`}
></span>
);
} as LucideIcon;
return ((_props: LucideProps) => (
<span
className={`fi !block aspect-[1.33] overflow-hidden rounded-[2px] fi-${url}`}
/>
)) as LucideIcon;
};
const data = {

View File

@@ -1,4 +1,3 @@
import { useMemo } from 'react';
import type { LucideIcon, LucideProps } from 'lucide-react';
import {
ActivityIcon,
@@ -15,6 +14,7 @@ import {
TabletIcon,
TvIcon,
} from 'lucide-react';
import { useMemo } from 'react';
import { NOT_SET_VALUE } from '@openpanel/constants';
@@ -30,9 +30,13 @@ function getProxyImage(url: string) {
}
const createImageIcon = (url: string) => {
return function (_props: LucideProps) {
return <img className="max-h-4 rounded-[2px] object-contain" src={url} />;
} as LucideIcon;
return ((_props: LucideProps) => (
<img
alt="serie icon"
className="max-h-4 rounded-[2px] object-contain"
src={url}
/>
)) as LucideIcon;
};
const mapper: Record<string, LucideIcon> = {
@@ -60,7 +64,7 @@ const mapper: Record<string, LucideIcon> = {
...acc,
[key]: createImageIcon(getProxyImage(value)),
}),
{}
{},
),
...flags,

View File

@@ -1,19 +1,20 @@
// prettier-ignore
// biome-ignore format: annoying
const data = {
'chromium os': 'https://upload.wikimedia.org/wikipedia/commons/2/28/Chromium_Logo.svg',
'mac os': 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/MacOS_logo.svg/1200px-MacOS_logo.svg.png',
'apple': 'https://sladesportfolio.wordpress.com/wp-content/uploads/2015/08/apple_logo_black-svg.png',
'huawei': 'https://upload.wikimedia.org/wikipedia/en/0/04/Huawei_Standard_logo.svg',
'xiaomi': 'https://upload.wikimedia.org/wikipedia/commons/2/29/Xiaomi_logo.svg',
'sony': 'https://serialtrainer7.com/wp-content/uploads/2021/07/sony-logo-300px-square.png',
'lg': 'https://upload.wikimedia.org/wikipedia/commons/2/20/LG_symbol.svg',
'samsung': 'https://seekvectors.com/storage/images/Samsung-Logo-22.svg',
'oppo': 'https://indoleads.nyc3.cdn.digitaloceanspaces.com/uploads/offers/logos/8695_95411e367b832.png',
'motorola': 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Motorola_M_symbol_blue.svg',
'oneplus': 'https://pbs.twimg.com/profile_images/1709165009148809216/ebHb4xhF_400x400.png',
'asus': 'https://cdn-icons-png.freepik.com/512/5969/5969050.png',
'fairphone': 'https://cdn.dribbble.com/users/433772/screenshots/2109827/fairphone_dribbble.jpg',
'nokia': 'https://www.gizchina.com/wp-content/uploads/images/2023/02/Nokia-logo.webp',
apple: 'https://sladesportfolio.wordpress.com/wp-content/uploads/2015/08/apple_logo_black-svg.png',
huawei: 'https://upload.wikimedia.org/wikipedia/en/0/04/Huawei_Standard_logo.svg',
xiaomi: 'https://upload.wikimedia.org/wikipedia/commons/2/29/Xiaomi_logo.svg',
sony: 'https://serialtrainer7.com/wp-content/uploads/2021/07/sony-logo-300px-square.png',
lg: 'https://upload.wikimedia.org/wikipedia/commons/2/20/LG_symbol.svg',
samsung: 'https://seekvectors.com/storage/images/Samsung-Logo-22.svg',
oppo: 'https://indoleads.nyc3.cdn.digitaloceanspaces.com/uploads/offers/logos/8695_95411e367b832.png',
motorola: 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Motorola_M_symbol_blue.svg',
oneplus: 'https://pbs.twimg.com/profile_images/1709165009148809216/ebHb4xhF_400x400.png',
asus: 'https://cdn-icons-png.freepik.com/512/5969/5969050.png',
fairphone: 'https://cdn.dribbble.com/users/433772/screenshots/2109827/fairphone_dribbble.jpg',
nokia: 'https://www.gizchina.com/wp-content/uploads/images/2023/02/Nokia-logo.webp',
'mobile safari': 'https://upload.wikimedia.org/wikipedia/commons/5/52/Safari_browser_logo.svg',
'openpanel.dev': 'https://openpanel.dev',
'samsung internet': 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Samsung_Internet_logo.svg/1024px-Samsung_Internet_logo.svg.png',
@@ -21,12 +22,12 @@ const data = {
'yahoo!': 'https://yahoo.com',
android: 'https://image.similarpng.com/very-thumbnail/2020/08/Android-icon-on-transparent--background-PNG.png',
'android browser': 'https://image.similarpng.com/very-thumbnail/2020/08/Android-icon-on-transparent--background-PNG.png',
'silk': 'https://m.media-amazon.com/images/I/51VCjQCvF0L.png',
'kakaotalk': 'https://www.kakaocorp.com/',
silk: 'https://m.media-amazon.com/images/I/51VCjQCvF0L.png',
kakaotalk: 'https://www.kakaocorp.com/',
bing: 'https://bing.com',
'electron': 'https://www.electronjs.org',
'whale': 'https://whale.naver.com',
'wechat': 'https://wechat.com',
electron: 'https://www.electronjs.org',
whale: 'https://whale.naver.com',
wechat: 'https://wechat.com',
chrome: 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
'chrome webview': 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
'chrome headless': 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
@@ -68,8 +69,8 @@ const data = {
tiktok: 'https://tiktok.com',
sharpspring: 'https://sharpspring.com',
'hacker news': 'https://news.ycombinator.com',
'betalist': 'https://betalist.com',
'qwant': 'https://www.qwant.com',
betalist: 'https://betalist.com',
qwant: 'https://www.qwant.com',
flipboard: 'https://flipboard.com/',
trustpilot: 'https://trustpilot.com',
'outlook.com': 'https://login.live.com/',

View File

@@ -3,6 +3,7 @@ import { ChevronRightIcon } from 'lucide-react';
import { NOT_SET_VALUE } from '@openpanel/constants';
import React, { Fragment } from 'react';
import { useReportChartContext } from '../context';
interface SerieNameProps {
@@ -23,12 +24,12 @@ export function SerieName({ name, className }: SerieNameProps) {
<div className={cn('flex items-center gap-1', className)}>
{name.map((n, index) => {
return (
<>
<Fragment key={n}>
<span>{n || NOT_SET_VALUE}</span>
{name.length - 1 > index && (
<ChevronRightIcon className="text-muted-foreground" size={12} />
)}
</>
</Fragment>
);
})}
</div>

View File

@@ -1,6 +1,6 @@
import { createContext, useContext, useEffect, useState } from 'react';
import isEqual from 'lodash.isequal';
import type { LucideIcon } from 'lucide-react';
import { createContext, useContext, useEffect, useState } from 'react';
import type {
IChartInput,
@@ -46,14 +46,14 @@ export const useReportChartContext = () => {
const ctx = useContext(context);
if (!ctx) {
throw new Error(
'useReportChartContext must be used within a ReportChartProvider'
'useReportChartContext must be used within a ReportChartProvider',
);
}
return ctx;
};
export const useSelectReportChartContext = <T,>(
selector: (ctx: ReportChartContextType) => T
selector: (ctx: ReportChartContextType) => T,
) => {
const ctx = useReportChartContext();
const [state, setState] = useState(selector(ctx));

View File

@@ -17,7 +17,7 @@ import { PreviousDiffIndicator } from '../common/previous-diff-indicator';
import { useReportChartContext } from '../context';
const findMostDropoffs = (
steps: RouterOutputs['chart']['funnel']['current']['steps']
steps: RouterOutputs['chart']['funnel']['current']['steps'],
) => {
return steps.reduce((acc, step) => {
if (step.dropoffCount > acc.dropoffCount) {
@@ -58,7 +58,7 @@ export function Chart({
<div
className={cn(
'border border-border',
!isEditMode && 'border-0 border-b'
!isEditMode && 'border-0 border-b',
)}
>
<div className="flex items-center gap-8 p-4">
@@ -72,7 +72,7 @@ export function Chart({
<div
className="w-full bg-def-400"
style={{ height: `${step.percent}%` }}
></div>
/>
</div>
);
})}
@@ -129,7 +129,7 @@ export function Chart({
<PreviousDiffIndicator
{...getPreviousMetric(
step.previousCount,
previous.steps[index]?.previousCount
previous.steps[index]?.previousCount,
)}
/>
</div>
@@ -160,7 +160,7 @@ export function Chart({
inverted
{...getPreviousMetric(
step.dropoffCount,
previous.steps[index]?.dropoffCount
previous.steps[index]?.dropoffCount,
)}
/>
</div>
@@ -174,7 +174,7 @@ export function Chart({
<span
className={cn(
'flex items-center gap-1 text-lg font-bold',
isMostDropoffs && 'text-rose-500'
isMostDropoffs && 'text-rose-500',
)}
>
{isMostDropoffs && <AlertCircleIcon size={14} />}
@@ -196,7 +196,7 @@ export function Chart({
<PreviousDiffIndicator
{...getPreviousMetric(
step.count,
previous.steps[index]?.count
previous.steps[index]?.count,
)}
/>
</div>
@@ -208,7 +208,7 @@ export function Chart({
</span>
<div className="flex items-center gap-4">
<span className="text-lg font-bold">{step.count}</span>
{/* <button
{/* <button type="button"
className="ml-2 underline"
onClick={() =>
pushModal('FunnelStepDetails', {
@@ -234,6 +234,6 @@ export function Chart({
);
})}
</div>
</div>
</div>,
);
}

View File

@@ -1,10 +1,10 @@
import React from 'react';
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
import type { IChartData } from '@/trpc/client';
import { cn } from '@/utils/cn';
import { getChartColor, theme } from '@/utils/theme';
import { useTheme } from 'next-themes';
import React from 'react';
import {
Bar,
BarChart,

View File

@@ -1,7 +1,7 @@
'use client';
import React, { useEffect, useRef } from 'react';
import { mergeDeepRight } from 'ramda';
import React, { useEffect, useRef } from 'react';
import { useInViewport } from 'react-in-viewport';
import { ReportAreaChart } from './area';

View File

@@ -1,6 +1,5 @@
'use client';
import React, { useCallback } from 'react';
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
import { api } from '@/trpc/client';
@@ -9,6 +8,7 @@ import { cn } from '@/utils/cn';
import { getChartColor } from '@/utils/theme';
import { isSameDay, isSameHour, isSameMonth } from 'date-fns';
import { last } from 'ramda';
import React, { useCallback } from 'react';
import {
Area,
CartesianGrid,
@@ -57,7 +57,7 @@ export function Chart({ data }: Props) {
},
{
staleTime: 1000 * 60 * 10,
}
},
);
const { series, setVisibleSeries } = useVisibleSeries(data);
const rechartData = useRechartDataModel(series);
@@ -73,7 +73,7 @@ export function Chart({ data }: Props) {
id: string,
col1: string,
col2: string,
percentChange: number
percentChange: number,
) => (
<linearGradient id={id} x1="0" y1="0" x2="100%" y2="0">
<stop offset="0%" stopColor={col1} />
@@ -177,29 +177,25 @@ export function Chart({ data }: Props) {
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor={color}
stopOpacity={0.8}
></stop>
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
<stop
offset="100%"
stopColor={color}
stopOpacity={0.1}
></stop>
/>
</linearGradient>
)}
{gradientTwoColors(
`hideAllButLastInterval_${serie.id}`,
'rgba(0,0,0,0)',
color,
lastIntervalPercent
lastIntervalPercent,
)}
{gradientTwoColors(
`hideJustLastInterval_${serie.id}`,
color,
'rgba(0,0,0,0)',
lastIntervalPercent
lastIntervalPercent,
)}
</defs>
<Line

View File

@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
import type { IChartData } from '@/trpc/client';
import { theme } from '@/utils/theme';
import { useMemo } from 'react';
import WorldMap from 'react-svg-worldmap';
import AutoSizer from 'react-virtualized-auto-sizer';
@@ -23,7 +23,7 @@ export function Chart({ data }: Props) {
country: s.names[0]?.toLowerCase() ?? '',
value: s.metrics[metric],
})),
[series, metric]
[series, metric],
);
return (

View File

@@ -21,7 +21,7 @@ export function Chart({ data }: Props) {
<div
className={cn(
'grid grid-cols-1 gap-4',
isEditMode && 'md:grid-cols-2 lg:grid-cols-3'
isEditMode && 'md:grid-cols-2 lg:grid-cols-3',
)}
>
{series.map((serie) => {

View File

@@ -29,10 +29,10 @@ export function ReportMetricChart() {
export function Loading() {
return (
<div className="flex h-[78px] flex-col justify-between p-4">
<div className="h-3 w-1/2 animate-pulse rounded bg-def-200"></div>
<div className="h-3 w-1/2 animate-pulse rounded bg-def-200" />
<div className="row items-end justify-between">
<div className="h-6 w-1/3 animate-pulse rounded bg-def-200"></div>
<div className="h-3 w-1/5 animate-pulse rounded bg-def-200"></div>
<div className="h-6 w-1/3 animate-pulse rounded bg-def-200" />
<div className="h-3 w-1/5 animate-pulse rounded bg-def-200" />
</div>
</div>
);

View File

@@ -9,8 +9,8 @@ import { Area, AreaChart } from 'recharts';
import type { IChartMetric } from '@openpanel/validation';
import {
getDiffIndicator,
PreviousDiffIndicator,
getDiffIndicator,
} from '../common/previous-diff-indicator';
import { SerieName } from '../common/serie-name';
import { useReportChartContext } from '../context';
@@ -54,7 +54,7 @@ export function MetricCard({
previous?.state,
'#6ee7b7', // green
'#fda4af', // red
'#93c5fd' // blue
'#93c5fd', // blue
);
return (
@@ -64,7 +64,7 @@ export function MetricCard({
>
<div
className={cn(
'pointer-events-none absolute -left-1 -right-1 bottom-0 top-0 z-0 opacity-50 transition-opacity duration-300 group-hover:opacity-100'
'pointer-events-none absolute -left-1 -right-1 bottom-0 top-0 z-0 opacity-50 transition-opacity duration-300 group-hover:opacity-100',
)}
>
<AutoSizer>