diff --git a/apps/cli/package.json b/apps/cli/package.json index b187a2a0e..f92736ff3 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,7 @@ { "name": "auf-cli", "version": "1.0.10", + "type": "module", "bin": { "auf-cli": "./dist/auf-cli.js" }, diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts index 52e831b43..254b73c16 100644 --- a/apps/web/next-env.d.ts +++ b/apps/web/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/apps/web/package.json b/apps/web/package.json index 398c8d72e..2c72b9c45 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -61,7 +61,7 @@ "react-i18next": "^16.0.0", "react-select": "^5.10.2", "react-use": "^17.6.0", - "recharts": "^2.15.4", + "recharts": "^3.2.1", "sharp": "^0.34.4", "swiper": "^12.0.2", "tailwind-merge": "^3.3.1", diff --git a/apps/web/src/entities/dashboard/ui/feedback-line-chart.ui.tsx b/apps/web/src/entities/dashboard/ui/feedback-line-chart.ui.tsx index cfade7c74..7d51debc5 100644 --- a/apps/web/src/entities/dashboard/ui/feedback-line-chart.ui.tsx +++ b/apps/web/src/entities/dashboard/ui/feedback-line-chart.ui.tsx @@ -26,7 +26,13 @@ import { Icon, } from '@ufb/react'; -import { SimpleLineChart, useAllChannels, useOAIQuery } from '@/shared'; +import { + ChartCard, + Legend, + LineChart, + useAllChannels, + useOAIQuery, +} from '@/shared'; import type { Channel } from '@/entities/channel'; import { useLineChartData } from '../lib'; @@ -73,47 +79,65 @@ const FeedbackLineChartWrapper: React.FC = (props) => { ); return ( - - - - Filter - - - - {channels?.items.map((channel) => ( - id === channel.id)} - onSelect={() => { - const isChecked = currentChannels.some( - ({ id }) => id === channel.id, - ); - setCurrentChannels((prev) => - isChecked ? prev.filter(({ id }) => id !== channel.id) - : prev.length === 5 ? [...prev.slice(1), channel] - : [...prev, channel], - ); - }} - > - {channel.name} - - ))} - - - + extra={ +
+ + +
} - showLegend - /> + > + + + ); +}; + +interface ChannelSelectComboboxProps { + channels?: { items: Channel[] }; + currentChannels: Channel[]; + setCurrentChannels: React.Dispatch>; +} + +const ChannelSelectCombobox = (props: ChannelSelectComboboxProps) => { + const { channels, currentChannels, setCurrentChannels } = props; + return ( + + + + Filter + + + + {channels?.items.map((channel) => ( + id === channel.id)} + onSelect={() => { + const isChecked = currentChannels.some( + ({ id }) => id === channel.id, + ); + setCurrentChannels((prev) => + isChecked ? prev.filter(({ id }) => id !== channel.id) + : prev.length === 5 ? [...prev.slice(1), channel] + : [...prev, channel], + ); + }} + > + {channel.name} + + ))} + + + ); }; diff --git a/apps/web/src/entities/dashboard/ui/issue-bar-chart.ui.tsx b/apps/web/src/entities/dashboard/ui/issue-bar-chart.ui.tsx index 1785cd497..e1684ed50 100644 --- a/apps/web/src/entities/dashboard/ui/issue-bar-chart.ui.tsx +++ b/apps/web/src/entities/dashboard/ui/issue-bar-chart.ui.tsx @@ -19,10 +19,11 @@ import { useTranslation } from 'next-i18next'; import { ToggleGroup, ToggleGroupItem } from '@ufb/react'; import { + BarChart, + ChartCard, ISSUES, Path, - SimpleBarChart, - SimplePieChart, + PieChart, useOAIQuery, } from '@/shared'; import type { IssueStatus } from '@/entities/issue'; @@ -44,7 +45,7 @@ const IssueBarChart: React.FC = ({ projectId }) => { const { t } = useTranslation(); const [type, setType] = useState('bar'); - const { data } = useOAIQuery({ + const { data: statisticsData } = useOAIQuery({ path: '/api/admin/statistics/issue/count-by-status', variables: { projectId }, queryOptions: { @@ -57,82 +58,89 @@ const IssueBarChart: React.FC = ({ projectId }) => { const onChangeType = (type: 'bar' | 'pie') => (v: string) => { setType(v === '' ? type : v); }; + const data = ISSUES(t).map(({ key, name }) => ({ + name, + value: +( + statisticsData?.statistics.find((v) => v.status === key)?.count ?? 0 + ), + color: COLOR_MAP[key], + })); + const onClickIssue = (name: string | undefined) => { + if (!name) return; + const issue = ISSUES(t).find((v) => v.name === name); + window.open( + Path.ISSUE.replace('[projectId]', projectId.toString()) + + '?queries=' + + JSON.stringify([{ key: 'status', value: issue?.key, condition: 'IS' }]), + '_blank', + ); + }; return ( - <> + + Bar + Pie + + } + > {type === 'pie' && ( - ({ - name, - value: +( - data?.statistics.find((v) => v.status === key)?.count ?? 0 - ), - color: COLOR_MAP[key], - }))} - title={t('chart.issue-status-count.title')} - description={t('chart.issue-status-count.description')} - height={415} - filterContent={ - - Bar - Pie - - } - onClick={(data) => { - if (!data) return; - const issue = ISSUES(t).find((v) => v.name === data.name); - window.open( - Path.ISSUE.replace('[projectId]', projectId.toString()) + - '?queries=' + - JSON.stringify([ - { key: 'status', value: issue?.key, condition: 'IS' }, - ]), - '_blank', - ); - }} - /> +
+ + +
)} {type === 'bar' && ( - ({ - name, - value: +( - data?.statistics.find((v) => v.status === key)?.count ?? 0 - ), - color: COLOR_MAP[key], - }))} - title={t('chart.issue-status-count.title')} - description={t('chart.issue-status-count.description')} - height={415} - filterContent={ - - Bar - Pie - - } - onClick={(data) => { - if (!data) return; - const issue = ISSUES(t).find((v) => v.name === data.name); - window.open( - Path.ISSUE.replace('[projectId]', projectId.toString()) + - '?queries=' + - JSON.stringify([ - { key: 'status', value: issue?.key, condition: 'IS' }, - ]), - '_blank', - ); - }} - /> + )} - +
+ ); +}; +interface IssueLegendProps { + data?: { name: string; value: number; color: string }[]; +} + +const IssueLegend: React.FC = ({ data }) => { + return ( +
+ + + + + + + + + {data?.map((item, index) => ( + + + + + ))} + +
+ Status + + Issue Count +
+
+ + {item.name} +
+
+ {item.value} +
+
); }; diff --git a/apps/web/src/entities/dashboard/ui/issue-feedback-line-chart.ui.tsx b/apps/web/src/entities/dashboard/ui/issue-feedback-line-chart.ui.tsx index 9953a96ea..3ae3bd238 100644 --- a/apps/web/src/entities/dashboard/ui/issue-feedback-line-chart.ui.tsx +++ b/apps/web/src/entities/dashboard/ui/issue-feedback-line-chart.ui.tsx @@ -32,11 +32,13 @@ import { } from '@ufb/react'; import { + ChartCard, client, commandFilter, getDayCount, InfiniteScrollArea, - SimpleLineChart, + Legend, + LineChart, useOAIQuery, } from '@/shared'; import type { Issue } from '@/entities/issue'; @@ -130,77 +132,79 @@ const IssueFeedbackLineChart: React.FC = ({ from, projectId, to }) => { }; return ( - - - - Filter - - - setSearchName(value)} - value={searchName} - /> - - No results found. - - Selected Issue - - } - > - {currentIssues.map((issue) => ( - handleIssueUncheck(issue)} - > - - - ))} - - {allIssues.length > 0 && ( + extra={ +
+ + + + + Filter + + + setSearchName(value)} + value={searchName} + /> + + No results found. - Issue List + Selected Issue } > - {allIssues - .filter( - (v) => !currentIssues.some((issue) => issue.id === v.id), - ) - .map((issue) => ( - handleIssueCheck(issue)} - > - - - ))} - + {currentIssues.map((issue) => ( + handleIssueUncheck(issue)} + > + + + ))} - )} - - - + {allIssues.length > 0 && ( + + Issue List + + } + > + {allIssues + .filter( + (v) => + !currentIssues.some((issue) => issue.id === v.id), + ) + .map((issue) => ( + handleIssueCheck(issue)} + > + + + ))} + + + )} + + + +
} - /> + > + + ); }; diff --git a/apps/web/src/entities/dashboard/ui/issue-line-chart.ui.tsx b/apps/web/src/entities/dashboard/ui/issue-line-chart.ui.tsx index 8dde69094..a05d9e2d7 100644 --- a/apps/web/src/entities/dashboard/ui/issue-line-chart.ui.tsx +++ b/apps/web/src/entities/dashboard/ui/issue-line-chart.ui.tsx @@ -16,7 +16,7 @@ import dayjs from 'dayjs'; import { useTranslation } from 'next-i18next'; -import { getDayCount, SimpleLineChart, useOAIQuery } from '@/shared'; +import { ChartCard, getDayCount, LineChart, useOAIQuery } from '@/shared'; import { useLineChartData } from '../lib'; @@ -53,15 +53,14 @@ const IssueLineChart: React.FC = ({ from, projectId, to }) => { ); return ( - + > + + ); }; diff --git a/apps/web/src/entities/feedback/ui/feedback-table.ui.tsx b/apps/web/src/entities/feedback/ui/feedback-table.ui.tsx index b72fb8d7c..e3ce7e8b9 100644 --- a/apps/web/src/entities/feedback/ui/feedback-table.ui.tsx +++ b/apps/web/src/entities/feedback/ui/feedback-table.ui.tsx @@ -30,15 +30,7 @@ import { import { useOverlay } from '@toss/use-overlay'; import { useTranslation } from 'next-i18next'; -import { - Badge, - Button, - Icon, - toast, - Tooltip, - TooltipContent, - TooltipTrigger, -} from '@ufb/react'; +import { Badge, Button, Icon, toast } from '@ufb/react'; import type { TableFilterField } from '@/shared'; import { @@ -317,20 +309,14 @@ const FeedbackTable = (props: Props) => { )} )} - - - - - - {t('tooltip.feedback-date-picker-button')} - - + diff --git a/apps/web/src/features/update-ai-setting/ui/ai-usage.ui.tsx b/apps/web/src/features/update-ai-setting/ui/ai-usage.ui.tsx index a95e2aa73..7559c8005 100644 --- a/apps/web/src/features/update-ai-setting/ui/ai-usage.ui.tsx +++ b/apps/web/src/features/update-ai-setting/ui/ai-usage.ui.tsx @@ -39,10 +39,12 @@ import { CardDescription, CardHeader, CardTitle, + ChartCard, DateRangePicker, + Legend, + LineChart, SelectInput, SettingAlert, - SimpleLineChart, useOAIMutation, useOAIQuery, useWarnIfUnsavedChanges, @@ -280,6 +282,12 @@ export const AIUsageFormButton = () => { ); }; +const dataKeys = [ + { name: 'Total', color: '#4A90E2' }, + { name: 'AI Field', color: '#50E3C2' }, + { name: 'AI Issue', color: '#F5A623' }, +]; + const AIChartCard = ({ projectId }: { projectId: number }) => { const [dateRange, setDateRange] = useState({ startDate: dayjs().startOf('month').toDate(), @@ -334,25 +342,22 @@ const AIChartCard = ({ projectId }: { projectId: number }) => { }, [dailyData, dateRange]); return ( - + extra={ +
+ + +
} - showLegend - /> + > + + ); }; const AIChartUsageCard = ({ projectId }: { projectId: number }) => { @@ -418,30 +423,46 @@ const AIChartUsageCard = ({ projectId }: { projectId: number }) => { height={180} > value.toLocaleString()} + formatter={(value: unknown) => { + if (typeof value === 'number') { + return value.toLocaleString(); + } + return String(value); + }} cursor={{ fill: 'var(--bg-neutral-tertiary)' }} content={({ payload }) => { return (
- {payload?.map(({ value, payload }, i) => ( -
-
-
-

- {(payload as { name: string | undefined }).name} + {payload.map((item, i) => { + const { value, payload: itemPayload } = item as { + value: unknown; + payload: unknown; + }; + return ( +

+
+
+

+ {(itemPayload as { name: string | undefined }).name} +

+
+

+ {typeof value === 'number' ? + value.toLocaleString() + : String(value)}

-

{value?.toLocaleString()}

-
- ))} + ); + })}
); }} @@ -467,7 +488,7 @@ const AIChartUsageCard = ({ projectId }: { projectId: number }) => { > {integrationData?.tokenThreshold ? @@ -476,7 +497,7 @@ const AIChartUsageCard = ({ projectId }: { projectId: number }) => { Remaining Tokens diff --git a/apps/web/src/pages/main/project/[projectId]/dashboard.tsx b/apps/web/src/pages/main/project/[projectId]/dashboard.tsx index ee6e11fcc..cac6f229b 100644 --- a/apps/web/src/pages/main/project/[projectId]/dashboard.tsx +++ b/apps/web/src/pages/main/project/[projectId]/dashboard.tsx @@ -27,9 +27,6 @@ import { ComboboxSelectItem, ComboboxTrigger, Icon, - Tooltip, - TooltipContent, - TooltipTrigger, } from '@ufb/react'; import { DateRangePicker, parseAsDateRange } from '@/shared'; @@ -166,20 +163,14 @@ const DashboardPage: NextPageWithLayout = ({ projectId }) => {
- - - - - - {t('tooltip.dashboard-date-picker-button')} - - + diff --git a/apps/web/src/shared/types/chart-payload.type.ts b/apps/web/src/shared/types/chart-payload.type.ts new file mode 100644 index 000000000..f78959cba --- /dev/null +++ b/apps/web/src/shared/types/chart-payload.type.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2025 LY Corporation + * + * LY Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +export type PayloadItem = { + value: number; + payload: { + fill: string; + name: string | undefined; + color: string; + }; +}; diff --git a/apps/web/src/shared/types/index.ts b/apps/web/src/shared/types/index.ts index 39154ced9..c4580ec76 100644 --- a/apps/web/src/shared/types/index.ts +++ b/apps/web/src/shared/types/index.ts @@ -23,3 +23,4 @@ export * from './form-overlay-props.type'; export * from './entity-table.type'; export * from './search-query.type'; export * from './common-form-item.type'; +export * from './chart-payload.type'; diff --git a/apps/web/src/shared/ui/charts/bar-chart.tsx b/apps/web/src/shared/ui/charts/bar-chart.tsx new file mode 100644 index 000000000..1d22c9a9f --- /dev/null +++ b/apps/web/src/shared/ui/charts/bar-chart.tsx @@ -0,0 +1,110 @@ +/** + * Copyright 2025 LY Corporation + * + * LY Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import { + Bar, + CartesianGrid, + Cell, + BarChart as RechartBarChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; + +import type { PayloadItem } from '@/shared/types'; + +interface Data { + name: string; + value: number; + color: string; +} + +interface IProps { + height?: number; + data: Data[]; + onClick?: (name?: string) => void; +} + +const BarChart: React.FC = (props) => { + const { data, height, onClick } = props; + return ( + + onClick?.(nextState.activeLabel)} + > + + ( +
+ {payload.map( + ({ value, payload: itemPayload }: PayloadItem, i) => ( +
+
+
+

+ {itemPayload.name} +

+
+

+ {typeof value === 'number' ? + value.toLocaleString() + : value} +

+
+ ), + )} +
+ )} + /> + + v.toLocaleString()} + className="text-neutral-tertiary text-small-normal" + tickLine={false} + axisLine={false} + /> + + {data.map((entry, index) => ( + + ))} + + + + ); +}; + +export default BarChart; diff --git a/apps/web/src/shared/ui/charts/chart-card.tsx b/apps/web/src/shared/ui/charts/chart-card.tsx index 3a851913f..6263073dc 100644 --- a/apps/web/src/shared/ui/charts/chart-card.tsx +++ b/apps/web/src/shared/ui/charts/chart-card.tsx @@ -15,19 +15,16 @@ */ import DescriptionTooltip from '../description-tooltip'; -import Legend from './legend'; interface IProps extends React.PropsWithChildren { title: string; description?: string; - dataKeys?: { name: string; color: string }[]; - showLegend?: boolean; - filterContent?: React.ReactNode; + extra?: React.ReactNode; } const ChartCard: React.FC = (props) => { - const { children, description, title, dataKeys, filterContent, showLegend } = - props; + const { children, description, title, extra } = props; + return (
@@ -37,10 +34,7 @@ const ChartCard: React.FC = (props) => { )}
-
- {showLegend && } - {filterContent} -
+
{extra}
{children}
diff --git a/apps/web/src/shared/ui/charts/index.ts b/apps/web/src/shared/ui/charts/index.ts index 53e79d503..c86d07848 100644 --- a/apps/web/src/shared/ui/charts/index.ts +++ b/apps/web/src/shared/ui/charts/index.ts @@ -13,6 +13,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -export { default as SimpleBarChart } from './simple-bar-chart'; -export { default as SimpleLineChart } from './simple-line-chart'; -export { default as SimplePieChart } from './simple-pie-chart'; + +export { default as BarChart } from './bar-chart'; +export { default as LineChart } from './line-chart'; +export { default as PieChart } from './pie-chart'; +export { default as ChartCard } from './chart-card'; +export { default as Legend } from './legend'; diff --git a/apps/web/src/shared/ui/charts/line-chart.tsx b/apps/web/src/shared/ui/charts/line-chart.tsx new file mode 100644 index 000000000..92238d5fc --- /dev/null +++ b/apps/web/src/shared/ui/charts/line-chart.tsx @@ -0,0 +1,165 @@ +/** + * Copyright 2025 LY Corporation + * + * LY Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +import { useMemo } from 'react'; +import dayjs from 'dayjs'; +import { useTranslation } from 'next-i18next'; +import { + Area, + AreaChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import type { TooltipContentProps } from 'recharts'; + +interface IProps { + height?: number; + data: unknown[]; + dataKeys: { color: string; name: string }[]; +} + +const LineChart: React.FC = (props) => { + const { height, data, dataKeys } = props; + + return ( + + + + + content={(props) => } + formatter={(value) => value.toLocaleString()} + /> + + v.toLocaleString()} + className="text-neutral-tertiary text-small-normal" + tickSize={15} + tickLine={false} + min={0} + axisLine={false} + /> + + {dataKeys.map(({ color }, index) => ( + + + + + ))} + + {dataKeys.map(({ color, name }, index) => ( + + ))} + + + ); +}; + +interface ICustomTooltipProps extends TooltipContentProps {} + +const CustomTooltip: React.FC = (props) => { + const { active, payload, label } = props; + const { t } = useTranslation(); + const days = useMemo(() => { + if (!label || typeof label !== 'string' || !label.includes('-')) { + return null; + } + const [start, end] = label.split(' - '); + const dates = dayjs(end).diff(dayjs(start), 'day') + 1; + return dates > 0 ? dates : 365 + dates; + }, [label]); + + if (!active) return null; + return ( +
+

+ {label} + {days && ( + + ({t('text.days', { days })}) + + )} +

+
+ {payload.map((item, i) => { + const { + color, + name, + value, + payload: itemPayload, + } = item as { + color: string; + name: string; + value: unknown; + payload: unknown; + }; + return ( +
+
+
+

+ {name || (itemPayload as { date: string | undefined }).date} +

+
+

+ {typeof value === 'number' ? + value.toLocaleString() + : String(value)} +

+
+ ); + })} +
+
+ ); +}; + +export default LineChart; diff --git a/apps/web/src/shared/ui/charts/pie-chart.tsx b/apps/web/src/shared/ui/charts/pie-chart.tsx new file mode 100644 index 000000000..218e60a42 --- /dev/null +++ b/apps/web/src/shared/ui/charts/pie-chart.tsx @@ -0,0 +1,117 @@ +/** + * Copyright 2025 LY Corporation + * + * LY Corporation licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import { useMemo } from 'react'; +import { + Cell, + Label, + Pie, + PieChart as RechartPieChart, + ResponsiveContainer, + Tooltip, +} from 'recharts'; + +import type { PayloadItem } from '@/shared'; + +interface Data { + name: string; + value: number; + color?: string; + [key: string]: unknown; +} + +interface IProps { + height?: number; + data: Data[]; + onClick?: (name?: string) => void; +} + +const PieChart: React.FC = (props) => { + const { data, height, onClick } = props; + + const total = useMemo( + () => data.reduce((acc, item) => acc + item.value, 0), + [data], + ); + + return ( + + + + {data.map((entry, index) => ( + onClick?.(entry.name)} + className="focus:outline-none" + /> + ))} + + ( +
+ {payload.map(({ payload, value }: PayloadItem, i) => ( +
+
+
+

+ {payload.name} +

+
+

{value.toLocaleString()}

+
+ ))} +
+ )} + /> + + + ); +}; + +export default PieChart; diff --git a/apps/web/src/shared/ui/charts/simple-bar-chart.tsx b/apps/web/src/shared/ui/charts/simple-bar-chart.tsx deleted file mode 100644 index 7ff2c4b82..000000000 --- a/apps/web/src/shared/ui/charts/simple-bar-chart.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright 2025 LY Corporation - * - * LY Corporation licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -import { - Bar, - BarChart, - CartesianGrid, - Cell, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, -} from 'recharts'; - -import ChartCard from './chart-card'; - -interface Data { - name: string; - value: number; - color: string; -} - -interface IProps { - title: string; - description: string; - height?: number; - data: Data[]; - showLegend?: boolean; - onClick?: (data?: Data) => void; - filterContent?: React.ReactNode; -} - -const SimpleBarChart: React.FC = (props) => { - const { - data, - title, - description, - height, - showLegend, - onClick, - filterContent, - } = props; - return ( - - - - onClick?.(e.activePayload?.[0]?.payload) - } - > - - value.toLocaleString()} - cursor={{ fill: 'var(--bg-neutral-tertiary)' }} - content={({ payload }) => ( -
- {payload?.map(({ value, payload }, i) => ( -
-
-
-

- {(payload as { name: string | undefined }).name} -

-
-

{value?.toLocaleString()}

-
- ))} -
- )} - /> - - v.toLocaleString()} - className="text-neutral-tertiary text-small-normal" - tickLine={false} - axisLine={false} - /> - - {data.map((entry, index) => ( - - ))} - - - - - ); -}; - -export default SimpleBarChart; diff --git a/apps/web/src/shared/ui/charts/simple-line-chart.tsx b/apps/web/src/shared/ui/charts/simple-line-chart.tsx deleted file mode 100644 index 57e8dc1e7..000000000 --- a/apps/web/src/shared/ui/charts/simple-line-chart.tsx +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright 2025 LY Corporation - * - * LY Corporation licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -import { useMemo } from 'react'; -import dayjs from 'dayjs'; -import { useTranslation } from 'next-i18next'; -import { - Area, - AreaChart, - CartesianGrid, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, -} from 'recharts'; -import type { TooltipProps } from 'recharts'; -import type { - NameType, - ValueType, -} from 'recharts/types/component/DefaultTooltipContent'; - -import ChartCard from './chart-card'; - -interface IProps { - title: string; - description?: string; - height?: number; - data: unknown[]; - dataKeys: { color: string; name: string }[]; - showLegend?: boolean; - filterContent?: React.ReactNode; - noLabel?: boolean; -} - -const SimpleLineChart: React.FC = (props) => { - const { - title, - description, - height, - data, - dataKeys, - showLegend, - filterContent, - noLabel = false, - } = props; - - return ( - - - - - } - formatter={(value) => value.toLocaleString()} - /> - - v.toLocaleString()} - className="text-neutral-tertiary text-small-normal" - tickSize={15} - tickLine={false} - min={0} - axisLine={false} - /> - - {dataKeys.map(({ color }, index) => ( - - - - - ))} - - {dataKeys.map(({ color, name }, index) => ( - - ))} - - - - ); -}; - -interface ICustomTooltipProps - extends Omit, 'label'> { - noLabel: boolean; - label?: string; -} - -const CustomTooltip: React.FC = (props) => { - const { active, payload, label, noLabel } = props; - const { t } = useTranslation(); - const days = useMemo(() => { - if (!label || typeof label !== 'string' || !label.includes('-')) { - return null; - } - const [start, end] = label.split(' - '); - const dates = dayjs(end).diff(dayjs(start), 'day') + 1; - return dates > 0 ? dates : 365 + dates; - }, [label]); - - if (!active || !payload) return null; - return ( -
-

- {label} - {days && ( - - ({t('text.days', { days })}) - - )} -

-
- {payload.map(({ color, name, value, payload }, i) => ( -
- {!noLabel && ( -
-
-

- {name ?? (payload as { date: string | undefined }).date} -

-
- )} -

{value?.toLocaleString()}

-
- ))} -
-
- ); -}; - -export default SimpleLineChart; diff --git a/apps/web/src/shared/ui/charts/simple-pie-chart.tsx b/apps/web/src/shared/ui/charts/simple-pie-chart.tsx deleted file mode 100644 index d871642ff..000000000 --- a/apps/web/src/shared/ui/charts/simple-pie-chart.tsx +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright 2025 LY Corporation - * - * LY Corporation licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -import { useMemo } from 'react'; -import { - Cell, - Label, - Legend, - Pie, - PieChart, - ResponsiveContainer, - Tooltip, -} from 'recharts'; -import type { ContentType } from 'recharts/types/component/DefaultLegendContent'; - -import ChartCard from './chart-card'; - -interface Data { - name: string; - value: number; - color?: string; -} - -interface IProps { - title: string; - description: string; - height?: number; - data: Data[]; - showLegend?: boolean; - onClick?: (data?: Data) => void; - filterContent?: React.ReactNode; -} - -const SimplePieChart: React.FC = (props) => { - const { - data, - title, - description, - height, - showLegend, - onClick, - filterContent, - } = props; - const total = useMemo( - () => data.reduce((acc, item) => acc + item.value, 0), - [data], - ); - return ( - - - - - {data.map((entry, index) => ( - onClick?.(entry)} - className="focus:outline-none" - /> - ))} - - - value.toLocaleString()} - cursor={{ fill: 'var(--bg-neutral-tertiary)' }} - content={({ payload }) => { - return ( -
- {payload?.map(({ value, payload }, i) => ( -
-
-
-

- {(payload as { name: string | undefined }).name} -

-
-

{value?.toLocaleString()}

-
- ))} -
- ); - }} - /> - - - - ); -}; - -const CustomLegend: ContentType = ({ payload }) => { - return ( -
- - - - - - - - - {payload?.map((entry, index) => ( - - - - - ))} - -
- Status - - Issue Count -
-
- - {entry.value} -
-
- {entry.payload?.value} -
-
- ); -}; - -export default SimplePieChart; diff --git a/apps/web/src/shared/ui/date-range-picker.tsx b/apps/web/src/shared/ui/date-range-picker.tsx index 02cd2d8ad..ddb65dc87 100644 --- a/apps/web/src/shared/ui/date-range-picker.tsx +++ b/apps/web/src/shared/ui/date-range-picker.tsx @@ -30,6 +30,9 @@ import { PopoverContent, PopoverTrigger, toast, + Tooltip, + TooltipContent, + TooltipTrigger, } from '@ufb/react'; import type { DateRangeType } from '../types/date-range.type'; @@ -58,6 +61,7 @@ interface IProps { }[]; children?: React.ReactNode; numberOfMonths?: number; + tooltipContent?: string; } const DateRangePicker: React.FC = (props) => { @@ -71,6 +75,7 @@ const DateRangePicker: React.FC = (props) => { children, numberOfMonths = 2, allowEntirePeriod = true, + tooltipContent, } = props; const { t, i18n } = useTranslation(); @@ -318,20 +323,25 @@ const DateRangePicker: React.FC = (props) => { return ( - - {children ? - - : - } - + + + + {children ? + + : + } + + + {tooltipContent && {tooltipContent}} +
{numberOfMonths === 2 && ( diff --git a/apps/web/src/widgets/issue-table/ui/issue-table.ui.tsx b/apps/web/src/widgets/issue-table/ui/issue-table.ui.tsx index c8d6a7c94..9076c08ca 100644 --- a/apps/web/src/widgets/issue-table/ui/issue-table.ui.tsx +++ b/apps/web/src/widgets/issue-table/ui/issue-table.ui.tsx @@ -18,15 +18,7 @@ import { useOverlay } from '@toss/use-overlay'; import { useTranslation } from 'next-i18next'; import { parseAsString, useQueryState } from 'nuqs'; -import { - Button, - Icon, - ToggleGroup, - ToggleGroupItem, - Tooltip, - TooltipContent, - TooltipTrigger, -} from '@ufb/react'; +import { Button, Icon, ToggleGroup, ToggleGroupItem } from '@ufb/react'; import type { TableFilterField } from '@/shared'; import { @@ -151,18 +143,12 @@ const IssueTable: React.FC = ({ projectId }) => { {t('main.feedback.issue-cell.create-issue')}
- - - - - - {t('tooltip.issue-date-picker-button')} - - + ( ((node as HTMLElement).nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName.toLowerCase() === 'svg') || ((node as HTMLElement).nodeType === Node.TEXT_NODE && - !(node as HTMLElement).textContent.trim()), + !((node as HTMLElement).textContent || '').trim()), ); if (isSvgOnly) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db1ce6a10..cd765980a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -458,8 +458,8 @@ importers: specifier: ^17.6.0 version: 17.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) recharts: - specifier: ^2.15.4 - version: 2.15.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + specifier: ^3.2.1 + version: 3.2.1(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1) sharp: specifier: ^0.34.4 version: 0.34.4 @@ -4059,6 +4059,17 @@ packages: resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@reduxjs/toolkit@2.9.0': + resolution: {integrity: sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + '@remixicon/react@4.6.0': resolution: {integrity: sha512-bY56maEgT5IYUSRotqy9h03IAKJC85vlKtWFg2FKzfs8JPrkdBAYSa9dxoUSKFwGzup8Ux6vjShs9Aec3jvr2w==} peerDependencies: @@ -4849,9 +4860,6 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -4982,6 +4990,9 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/validator@13.12.0': resolution: {integrity: sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==} @@ -6475,6 +6486,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es-toolkit@1.39.10: + resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} + esbuild@0.25.0: resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} engines: {node: '>=18'} @@ -6644,8 +6658,8 @@ packages: eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} @@ -6711,10 +6725,6 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.2.2: - resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} - engines: {node: '>=6.0.0'} - fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -9137,6 +9147,18 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -9163,12 +9185,6 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-smooth@4.0.4: - resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -9226,20 +9242,26 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} - recharts-scale@0.4.5: - resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} - - recharts@2.15.4: - resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} - engines: {node: '>=14'} + recharts@3.2.1: + resolution: {integrity: sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw==} + engines: {node: '>=18'} peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -9288,6 +9310,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -10396,8 +10421,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - victory-vendor@36.9.2: - resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + victory-vendor@37.3.6: + resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} void-elements@3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} @@ -14627,6 +14652,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1))(react@19.1.1)': + dependencies: + '@standard-schema/spec': 1.0.0 + '@standard-schema/utils': 0.3.0 + immer: 10.1.3 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.1.1 + react-redux: 9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1) + '@remixicon/react@4.6.0(react@19.1.1)': dependencies: react: 19.1.1 @@ -14645,7 +14682,7 @@ snapshots: '@rollup/pluginutils@5.1.4(rollup@4.34.8)': dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: @@ -15542,8 +15579,6 @@ snapshots: '@types/estree@1.0.6': {} - '@types/estree@1.0.7': {} - '@types/estree@1.0.8': {} '@types/express-serve-static-core@5.0.6': @@ -15703,6 +15738,8 @@ snapshots: '@types/tough-cookie@4.0.5': {} + '@types/use-sync-external-store@0.0.6': {} + '@types/validator@13.12.0': {} '@types/yargs-parser@21.0.3': {} @@ -17444,6 +17481,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.39.10: {} + esbuild@0.25.0: optionalDependencies: '@esbuild/aix-ppc64': 0.25.0 @@ -17623,7 +17662,7 @@ snapshots: '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 @@ -17665,7 +17704,7 @@ snapshots: '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 @@ -17730,7 +17769,7 @@ snapshots: eventemitter2@6.4.9: {} - eventemitter3@4.0.7: {} + eventemitter3@5.0.1: {} events@3.3.0: {} @@ -17855,8 +17894,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-equals@5.2.2: {} - fast-fifo@1.3.2: {} fast-glob@3.3.1: @@ -18598,7 +18635,7 @@ snapshots: is-reference@1.2.1: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 is-regex@1.2.1: dependencies: @@ -20829,6 +20866,15 @@ snapshots: react-is@18.3.1: {} + react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.1.1 + use-sync-external-store: 1.4.0(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.16 + redux: 5.0.1 + react-remove-scroll-bar@2.3.8(@types/react@19.1.16)(react@19.1.1): dependencies: react: 19.1.1 @@ -20865,14 +20911,6 @@ snapshots: - '@types/react' - supports-color - react-smooth@4.0.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): - dependencies: - fast-equals: 5.2.2 - prop-types: 15.8.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react-style-singleton@2.2.3(@types/react@19.1.16)(react@19.1.1): dependencies: get-nonce: 1.0.1 @@ -20948,28 +20986,37 @@ snapshots: real-require@0.2.0: {} - recharts-scale@0.4.5: - dependencies: - decimal.js-light: 2.5.1 - - recharts@2.15.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + recharts@3.2.1(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1): dependencies: + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1))(react@19.1.1) clsx: 2.1.1 - eventemitter3: 4.0.7 - lodash: 4.17.21 + decimal.js-light: 2.5.1 + es-toolkit: 1.39.10 + eventemitter3: 5.0.1 + immer: 10.1.3 react: 19.1.1 react-dom: 19.1.1(react@19.1.1) react-is: 18.3.1 - react-smooth: 4.0.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - recharts-scale: 0.4.5 + react-redux: 9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1) + reselect: 5.1.1 tiny-invariant: 1.3.3 - victory-vendor: 36.9.2 + use-sync-external-store: 1.4.0(react@19.1.1) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux redent@3.0.0: dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: @@ -21026,6 +21073,8 @@ snapshots: require-from-string@2.0.2: {} + reselect@5.1.1: {} + resize-observer-polyfill@1.5.1: {} resolve-alpn@1.2.1: {} @@ -22193,7 +22242,6 @@ snapshots: use-sync-external-store@1.4.0(react@19.1.1): dependencies: react: 19.1.1 - optional: true util-deprecate@1.0.2: {} @@ -22223,7 +22271,7 @@ snapshots: vary@1.1.2: {} - victory-vendor@36.9.2: + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.1 '@types/d3-ease': 3.0.2