mirror of
https://github.com/logto-io/logto.git
synced 2025-02-03 21:48:55 -05:00
feat(console): dashboard blocks and curve (#1076)
This commit is contained in:
parent
02f98ed259
commit
c38fab89e1
8 changed files with 372 additions and 69 deletions
|
@ -20,7 +20,6 @@
|
|||
"@fontsource/roboto-mono": "^4.5.7",
|
||||
"@logto/phrases": "^0.1.0",
|
||||
"@logto/react": "^0.1.14",
|
||||
"@logto/shared": "^0.1.0",
|
||||
"@logto/schemas": "^0.1.0",
|
||||
"@logto/shared": "^0.1.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
|
@ -69,6 +68,7 @@
|
|||
"react-paginate": "^8.1.2",
|
||||
"react-router-dom": "^6.2.2",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"recharts": "^2.1.10",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"stylelint": "^14.8.2",
|
||||
"swr": "^1.2.2",
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.number {
|
||||
font: var(--font-headline-small);
|
||||
}
|
||||
|
||||
.delta {
|
||||
font: var(--font-title-medium);
|
||||
color: var(--color-success-50);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.down {
|
||||
color: var(--color-error-50);
|
||||
}
|
||||
}
|
||||
|
||||
.block {
|
||||
flex: 1;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: _.unit(4);
|
||||
}
|
||||
|
||||
&.bordered {
|
||||
border: 1px solid var(--color-divider);
|
||||
width: 360px;
|
||||
flex: unset;
|
||||
}
|
||||
|
||||
.title {
|
||||
font: var(--font-title-medium);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
.number {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.plain {
|
||||
padding: 0;
|
||||
|
||||
.title {
|
||||
font: var(--font-title-medium);
|
||||
margin-bottom: _.unit(6);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.number {
|
||||
margin-right: _.unit(2);
|
||||
flex: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
packages/console/src/pages/Dashboard/components/Block.tsx
Normal file
42
packages/console/src/pages/Dashboard/components/Block.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { AdminConsoleKey } from '@logto/phrases';
|
||||
import { conditionalString } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
import { ArrowDown, ArrowUp } from '@/icons/Arrow';
|
||||
import { formatNumberWithComma } from '@/utilities/number';
|
||||
|
||||
import * as styles from './Block.module.scss';
|
||||
|
||||
type Props = {
|
||||
count: number;
|
||||
delta?: number;
|
||||
title: AdminConsoleKey;
|
||||
varient?: 'bordered' | 'default' | 'plain';
|
||||
};
|
||||
|
||||
const Block = ({ varient = 'default', count, delta, title }: Props) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const deltaLable = delta !== undefined && `${conditionalString(delta >= 0 && '+')}${delta}`;
|
||||
|
||||
return (
|
||||
<Card className={classNames(styles.block, styles[varient])}>
|
||||
<div className={styles.title}>{t(title)}</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.number}>{formatNumberWithComma(count)}</div>
|
||||
{delta !== undefined && (
|
||||
<div className={classNames(styles.delta, delta < 0 && styles.down)}>
|
||||
<span>(${deltaLable})</span>
|
||||
{delta > 0 && <ArrowUp />}
|
||||
{delta < 0 && <ArrowDown />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
|
@ -22,41 +22,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.topBlocks {
|
||||
.blocks {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.block {
|
||||
flex: 1;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: _.unit(4);
|
||||
}
|
||||
|
||||
.title {
|
||||
font: var(--font-title-medium);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
.number {
|
||||
flex: 1;
|
||||
font: var(--font-headline-small);
|
||||
}
|
||||
|
||||
.delta {
|
||||
font: var(--font-title-medium);
|
||||
color: var(--color-success-50);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.down {
|
||||
color: var(--color-error-50);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
margin-bottom: _.unit(4);
|
||||
}
|
||||
|
||||
.curve {
|
||||
margin: _.unit(10) 0 _.unit(6);
|
||||
width: 100%;
|
||||
height: 168px;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
CartesianGrid,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from 'recharts';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
import { ArrowDown, ArrowUp } from '@/icons/Arrow';
|
||||
|
||||
import Block from './components/Block';
|
||||
import * as styles from './index.module.scss';
|
||||
import { NewUsersResponse, TotalUsersResponse } from './types';
|
||||
import { ActiveUsersResponse, NewUsersResponse, TotalUsersResponse } from './types';
|
||||
|
||||
const Dashboard = () => {
|
||||
const { data: totalData } = useSWR<TotalUsersResponse>('/api/dashboard/users/total');
|
||||
const { data: newData } = useSWR<NewUsersResponse>('/api/dashboard/users/new');
|
||||
const { data: activeData } = useSWR<ActiveUsersResponse>('/api/dashboard/users/active');
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const isLoading = !totalData || !newData;
|
||||
const isLoading = !totalData || !newData || !activeData;
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
@ -23,35 +32,68 @@ const Dashboard = () => {
|
|||
<div className={styles.subtitle}>{t('dashboard.description')}</div>
|
||||
</div>
|
||||
{!isLoading && (
|
||||
<div className={styles.topBlocks}>
|
||||
<Card className={styles.block}>
|
||||
<div className={styles.title}>{t('dashboard.total_users')}</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.number}>{totalData.totalUserCount}</div>
|
||||
<>
|
||||
<div className={styles.blocks}>
|
||||
<Block title="dashboard.total_users" count={totalData.totalUserCount} />
|
||||
<Block
|
||||
title="dashboard.new_users_today"
|
||||
count={newData.today.count}
|
||||
delta={newData.today.delta}
|
||||
/>
|
||||
<Block
|
||||
title="dashboard.new_users_7_days"
|
||||
count={newData.last7Days.count}
|
||||
delta={newData.last7Days.delta}
|
||||
/>
|
||||
</div>
|
||||
<Card>
|
||||
<Block
|
||||
title="dashboard.daily_active_users"
|
||||
count={activeData.dau.count}
|
||||
delta={activeData.dau.delta}
|
||||
varient="plain"
|
||||
/>
|
||||
<div className={styles.curve}>
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={activeData.dauCurve.map((item) => ({
|
||||
...item,
|
||||
// Remove "year" for a compact label.
|
||||
date: item.date.replace(/\d{4}-/, ''),
|
||||
}))}
|
||||
width={1100}
|
||||
height={168}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="count"
|
||||
stroke="#5D34F2"
|
||||
strokeWidth={2}
|
||||
fill="#F2EFFD"
|
||||
/>
|
||||
<XAxis dataKey="date" />
|
||||
<YAxis orientation="right" axisLine={false} tickLine={false} />
|
||||
<Tooltip />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<div className={styles.blocks}>
|
||||
<Block
|
||||
title="dashboard.weekly_active_users"
|
||||
count={activeData.wau.count}
|
||||
delta={activeData.wau.delta}
|
||||
varient="bordered"
|
||||
/>
|
||||
<Block
|
||||
title="dashboard.monthly_active_users"
|
||||
count={activeData.mau.count}
|
||||
delta={activeData.mau.delta}
|
||||
varient="bordered"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className={styles.block}>
|
||||
<div className={styles.title}>{t('dashboard.new_users_today')}</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.number}>{newData.today.count}</div>
|
||||
<div className={classNames(styles.delta, newData.today.delta < 0 && styles.down)}>
|
||||
({newData.today.delta > 0 && '+'}
|
||||
{newData.today.delta}){newData.today.delta > 0 ? <ArrowUp /> : <ArrowDown />}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className={styles.block}>
|
||||
<div className={styles.title}>{t('dashboard.new_users_7_days')}</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.number}>{newData.last7Days.count}</div>
|
||||
<div className={classNames(styles.delta, newData.last7Days.delta < 0 && styles.down)}>
|
||||
({newData.last7Days.delta > 0 && '+'}
|
||||
{newData.last7Days.delta})
|
||||
{newData.last7Days.delta > 0 ? <ArrowUp /> : <ArrowDown />}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -11,3 +11,10 @@ export type NewUsersResponse = {
|
|||
today: CountAndDelta;
|
||||
last7Days: CountAndDelta;
|
||||
};
|
||||
|
||||
export type ActiveUsersResponse = {
|
||||
dau: CountAndDelta;
|
||||
wau: CountAndDelta;
|
||||
mau: CountAndDelta;
|
||||
dauCurve: Array<{ date: string; count: number }>;
|
||||
};
|
||||
|
|
2
packages/console/src/utilities/number.ts
Normal file
2
packages/console/src/utilities/number.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export const formatNumberWithComma = (value: number): string =>
|
||||
value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
178
pnpm-lock.yaml
generated
178
pnpm-lock.yaml
generated
|
@ -670,6 +670,7 @@ importers:
|
|||
react-paginate: ^8.1.2
|
||||
react-router-dom: ^6.2.2
|
||||
react-syntax-highlighter: ^15.5.0
|
||||
recharts: ^2.1.10
|
||||
remark-gfm: ^3.0.1
|
||||
stylelint: ^14.8.2
|
||||
swr: ^1.2.2
|
||||
|
@ -727,6 +728,7 @@ importers:
|
|||
react-paginate: 8.1.2_react@17.0.2
|
||||
react-router-dom: 6.2.2_sfoxds7t5ydpegc3knd667wn6m
|
||||
react-syntax-highlighter: 15.5.0_react@17.0.2
|
||||
recharts: 2.1.10_sfoxds7t5ydpegc3knd667wn6m
|
||||
remark-gfm: 3.0.1
|
||||
stylelint: 14.8.2
|
||||
swr: 1.2.2_react@17.0.2
|
||||
|
@ -7779,6 +7781,10 @@ packages:
|
|||
csstype: 3.0.11
|
||||
dev: true
|
||||
|
||||
/@types/resize-observer-browser/0.1.7:
|
||||
resolution: {integrity: sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg==}
|
||||
dev: true
|
||||
|
||||
/@types/responselike/1.0.0:
|
||||
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
|
||||
dependencies:
|
||||
|
@ -10526,6 +10532,10 @@ packages:
|
|||
source-map: 0.6.1
|
||||
dev: true
|
||||
|
||||
/css-unit-converter/1.1.2:
|
||||
resolution: {integrity: sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==}
|
||||
dev: true
|
||||
|
||||
/css-what/2.1.3:
|
||||
resolution: {integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==}
|
||||
dev: true
|
||||
|
@ -10646,6 +10656,58 @@ packages:
|
|||
resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
|
||||
dev: true
|
||||
|
||||
/d3-array/2.12.1:
|
||||
resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==}
|
||||
dependencies:
|
||||
internmap: 1.0.1
|
||||
dev: true
|
||||
|
||||
/d3-color/2.0.0:
|
||||
resolution: {integrity: sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==}
|
||||
dev: true
|
||||
|
||||
/d3-format/2.0.0:
|
||||
resolution: {integrity: sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==}
|
||||
dev: true
|
||||
|
||||
/d3-interpolate/2.0.1:
|
||||
resolution: {integrity: sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==}
|
||||
dependencies:
|
||||
d3-color: 2.0.0
|
||||
dev: true
|
||||
|
||||
/d3-path/2.0.0:
|
||||
resolution: {integrity: sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==}
|
||||
dev: true
|
||||
|
||||
/d3-scale/3.3.0:
|
||||
resolution: {integrity: sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==}
|
||||
dependencies:
|
||||
d3-array: 2.12.1
|
||||
d3-format: 2.0.0
|
||||
d3-interpolate: 2.0.1
|
||||
d3-time: 2.1.1
|
||||
d3-time-format: 3.0.0
|
||||
dev: true
|
||||
|
||||
/d3-shape/2.1.0:
|
||||
resolution: {integrity: sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==}
|
||||
dependencies:
|
||||
d3-path: 2.0.0
|
||||
dev: true
|
||||
|
||||
/d3-time-format/3.0.0:
|
||||
resolution: {integrity: sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==}
|
||||
dependencies:
|
||||
d3-time: 2.1.1
|
||||
dev: true
|
||||
|
||||
/d3-time/2.1.1:
|
||||
resolution: {integrity: sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==}
|
||||
dependencies:
|
||||
d3-array: 2.12.1
|
||||
dev: true
|
||||
|
||||
/dargs/7.0.0:
|
||||
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -10737,6 +10799,10 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/decimal.js-light/2.5.1:
|
||||
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||
dev: true
|
||||
|
||||
/decimal.js/10.3.1:
|
||||
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
|
||||
dev: true
|
||||
|
@ -11005,6 +11071,12 @@ packages:
|
|||
utila: 0.4.0
|
||||
dev: true
|
||||
|
||||
/dom-helpers/3.4.0:
|
||||
resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.18.3
|
||||
dev: true
|
||||
|
||||
/dom-serializer/0.1.1:
|
||||
resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==}
|
||||
dependencies:
|
||||
|
@ -11986,6 +12058,10 @@ packages:
|
|||
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
|
||||
dev: true
|
||||
|
||||
/fast-equals/2.0.4:
|
||||
resolution: {integrity: sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w==}
|
||||
dev: true
|
||||
|
||||
/fast-glob/3.2.11:
|
||||
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
@ -13591,6 +13667,10 @@ packages:
|
|||
side-channel: 1.0.4
|
||||
dev: true
|
||||
|
||||
/internmap/1.0.1:
|
||||
resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==}
|
||||
dev: true
|
||||
|
||||
/interpret/1.4.0:
|
||||
resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
@ -16017,7 +16097,6 @@ packages:
|
|||
/mime-db/1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: true
|
||||
|
||||
/mime-types/2.1.18:
|
||||
resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==}
|
||||
|
@ -16037,7 +16116,6 @@ packages:
|
|||
engines: {node: '>= 0.6'}
|
||||
dependencies:
|
||||
mime-db: 1.52.0
|
||||
dev: true
|
||||
|
||||
/mime/1.6.0:
|
||||
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||
|
@ -17501,6 +17579,10 @@ packages:
|
|||
resolution: {integrity: sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==}
|
||||
dev: true
|
||||
|
||||
/performance-now/2.1.0:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
dev: true
|
||||
|
||||
/pg-connection-string/2.5.0:
|
||||
resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==}
|
||||
dev: false
|
||||
|
@ -18186,6 +18268,10 @@ packages:
|
|||
postcss-selector-parser: 6.0.10
|
||||
dev: true
|
||||
|
||||
/postcss-value-parser/3.3.1:
|
||||
resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==}
|
||||
dev: true
|
||||
|
||||
/postcss-value-parser/4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
dev: true
|
||||
|
@ -18626,6 +18712,12 @@ packages:
|
|||
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
/raf/3.4.1:
|
||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
||||
dependencies:
|
||||
performance-now: 2.1.0
|
||||
dev: true
|
||||
|
||||
/randombytes/2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
dependencies:
|
||||
|
@ -18962,6 +19054,19 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/react-resize-detector/6.7.8_sfoxds7t5ydpegc3knd667wn6m:
|
||||
resolution: {integrity: sha512-0FaEcUBAbn+pq3PT5a9hHRebUfuS1SRLGLpIw8LydU7zX429I6XJgKerKAMPsJH0qWAl6o5bVKNqFJqr6tGPYw==}
|
||||
peerDependencies:
|
||||
react: ^16.0.0 || ^17.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0
|
||||
dependencies:
|
||||
'@types/resize-observer-browser': 0.1.7
|
||||
lodash: 4.17.21
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
resize-observer-polyfill: 1.5.1
|
||||
dev: true
|
||||
|
||||
/react-router-config/5.1.1_oyuskl3t7voyrff2xstzuy4hqu:
|
||||
resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==}
|
||||
peerDependencies:
|
||||
|
@ -19060,6 +19165,20 @@ packages:
|
|||
react: 17.0.2
|
||||
dev: true
|
||||
|
||||
/react-smooth/2.0.0_sfoxds7t5ydpegc3knd667wn6m:
|
||||
resolution: {integrity: sha512-wK4dBBR6P21otowgMT9toZk+GngMplGS1O5gk+2WSiHEXIrQgDvhR5IIlT74Vtu//qpTcipkgo21dD7a7AUNxw==}
|
||||
peerDependencies:
|
||||
prop-types: ^15.6.0
|
||||
react: ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||
dependencies:
|
||||
fast-equals: 2.0.4
|
||||
raf: 3.4.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-transition-group: 2.9.0_sfoxds7t5ydpegc3knd667wn6m
|
||||
dev: true
|
||||
|
||||
/react-string-replace/1.0.0:
|
||||
resolution: {integrity: sha512-+iLsyE4AeSmnfctgswXOf1PmKRgns6wJ4LVb+8ADMU6mDK3jvBE11QzfMQf7CYtPUUiBCDjZ9ZppzXOIYrzCRg==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
@ -19112,6 +19231,20 @@ packages:
|
|||
react-dom: 17.0.2_react@17.0.2
|
||||
dev: true
|
||||
|
||||
/react-transition-group/2.9.0_sfoxds7t5ydpegc3knd667wn6m:
|
||||
resolution: {integrity: sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==}
|
||||
peerDependencies:
|
||||
react: '>=15.0.0'
|
||||
react-dom: '>=15.0.0'
|
||||
dependencies:
|
||||
dom-helpers: 3.4.0
|
||||
loose-envify: 1.4.0
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-lifecycles-compat: 3.0.4
|
||||
dev: true
|
||||
|
||||
/react/17.0.2:
|
||||
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -19259,6 +19392,36 @@ packages:
|
|||
resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==}
|
||||
dev: true
|
||||
|
||||
/recharts-scale/0.4.5:
|
||||
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
||||
dependencies:
|
||||
decimal.js-light: 2.5.1
|
||||
dev: true
|
||||
|
||||
/recharts/2.1.10_sfoxds7t5ydpegc3knd667wn6m:
|
||||
resolution: {integrity: sha512-me6c8m2Gs88X/nuM2gDSTDIhpSLNMbiTrlE4Cu53hjZNegT3g3xLlTrbYSAQuBCFWuWJAZXCmEuMr6AwizLyaA==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
react: ^16.0.0 || ^17.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0
|
||||
dependencies:
|
||||
classnames: 2.3.1
|
||||
d3-interpolate: 2.0.1
|
||||
d3-scale: 3.3.0
|
||||
d3-shape: 2.1.0
|
||||
eventemitter3: 4.0.7
|
||||
lodash: 4.17.21
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-is: 16.13.1
|
||||
react-resize-detector: 6.7.8_sfoxds7t5ydpegc3knd667wn6m
|
||||
react-smooth: 2.0.0_sfoxds7t5ydpegc3knd667wn6m
|
||||
recharts-scale: 0.4.5
|
||||
reduce-css-calc: 2.1.8
|
||||
transitivePeerDependencies:
|
||||
- prop-types
|
||||
dev: true
|
||||
|
||||
/rechoir/0.6.2:
|
||||
resolution: {integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
@ -19348,6 +19511,13 @@ packages:
|
|||
- webpack
|
||||
dev: true
|
||||
|
||||
/reduce-css-calc/2.1.8:
|
||||
resolution: {integrity: sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==}
|
||||
dependencies:
|
||||
css-unit-converter: 1.1.2
|
||||
postcss-value-parser: 3.3.1
|
||||
dev: true
|
||||
|
||||
/redux/4.1.2:
|
||||
resolution: {integrity: sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==}
|
||||
dependencies:
|
||||
|
@ -19575,6 +19745,10 @@ packages:
|
|||
/requires-port/1.0.0:
|
||||
resolution: {integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=}
|
||||
|
||||
/resize-observer-polyfill/1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
dev: true
|
||||
|
||||
/resolve-alpn/1.2.1:
|
||||
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue