feat: add MetricsTable value render
and change layout of website detail
This commit is contained in:
parent
9a922cf263
commit
fcb28d3456
@ -43,6 +43,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"maxmind": "^4.3.11",
|
||||
"millify": "^6.1.0",
|
||||
"morgan": "^1.10.0",
|
||||
"nanoid": "^3.3.6",
|
||||
"nodemailer": "^6.9.5",
|
||||
|
112
pnpm-lock.yaml
112
pnpm-lock.yaml
@ -91,6 +91,9 @@ dependencies:
|
||||
maxmind:
|
||||
specifier: ^4.3.11
|
||||
version: 4.3.11
|
||||
millify:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0
|
||||
morgan:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
@ -2245,6 +2248,11 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/ansi-styles@2.2.1:
|
||||
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -2257,6 +2265,13 @@ packages:
|
||||
color-convert: 1.9.3
|
||||
dev: true
|
||||
|
||||
/ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
dev: false
|
||||
|
||||
/antd@5.9.3(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-a7gY6hfsjoDLOENHKzjXZgmAxi1hDdsuIvYm6YMTctb08EhTEXCZoeFOekwz9S0vrTcdSpUMblRWsiwuYRdPYg==}
|
||||
peerDependencies:
|
||||
@ -2583,6 +2598,15 @@ packages:
|
||||
wordwrap: 0.0.2
|
||||
dev: false
|
||||
|
||||
/cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
dev: false
|
||||
|
||||
/clsx@2.0.0:
|
||||
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
|
||||
engines: {node: '>=6'}
|
||||
@ -2593,13 +2617,24 @@ packages:
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
|
||||
/color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: false
|
||||
|
||||
/color-name@1.1.3:
|
||||
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||
|
||||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: false
|
||||
|
||||
/color-string@1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
dev: false
|
||||
|
||||
@ -3007,6 +3042,10 @@ packages:
|
||||
resolution: {integrity: sha512-sSeXY9rNDp86bJODW68pxLcy3A5FrPZfIgOrJHzqgYzX513Zq6/ytdBigp7KeJEpZZopBBSiO1cVuiRkZpNxLw==}
|
||||
dev: false
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
dev: false
|
||||
|
||||
/encodeurl@1.0.2:
|
||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -3153,7 +3192,6 @@ packages:
|
||||
/escalade@3.1.1:
|
||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/escape-html@1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
@ -3408,6 +3446,11 @@ packages:
|
||||
resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==}
|
||||
dev: false
|
||||
|
||||
/get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
dev: false
|
||||
|
||||
/get-intrinsic@1.2.1:
|
||||
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
|
||||
dependencies:
|
||||
@ -3699,6 +3742,11 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -4056,6 +4104,13 @@ packages:
|
||||
picomatch: 2.3.1
|
||||
dev: true
|
||||
|
||||
/millify@6.1.0:
|
||||
resolution: {integrity: sha512-H/E3J6t+DQs/F2YgfDhxUVZz/dF8JXPPKTLHL/yHCcLZLtCXJDUaqvhJXQwqOVBvbyNn4T0WjLpIHd7PAw7fBA==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
yargs: 17.7.2
|
||||
dev: false
|
||||
|
||||
/mime-db@1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -5388,6 +5443,11 @@ packages:
|
||||
resolution: {integrity: sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==}
|
||||
dev: false
|
||||
|
||||
/require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
dev: false
|
||||
@ -5731,6 +5791,15 @@ packages:
|
||||
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
|
||||
dev: false
|
||||
|
||||
/string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
dev: false
|
||||
|
||||
/string.prototype.trim@1.2.7:
|
||||
resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -5763,6 +5832,13 @@ packages:
|
||||
ansi-regex: 2.1.1
|
||||
dev: false
|
||||
|
||||
/strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
dev: false
|
||||
|
||||
/stylis@4.3.0:
|
||||
resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==}
|
||||
dev: false
|
||||
@ -6244,6 +6320,15 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: false
|
||||
|
||||
/wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
dev: false
|
||||
|
||||
/wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
@ -6265,6 +6350,11 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: false
|
||||
|
||||
/y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
dev: true
|
||||
@ -6277,6 +6367,24 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
dev: true
|
||||
|
||||
/yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.1.1
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
dev: false
|
||||
|
||||
/yargs@3.10.0:
|
||||
resolution: {integrity: sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==}
|
||||
dependencies:
|
||||
|
@ -3,6 +3,8 @@ import { ColumnsType } from 'antd/es/table/interface';
|
||||
import React from 'react';
|
||||
import { trpc } from '../../api/trpc';
|
||||
import { useCurrentWorkspaceId } from '../../store/user';
|
||||
import { sum } from 'lodash-es';
|
||||
import millify from 'millify';
|
||||
|
||||
interface MetricsTableProps {
|
||||
websiteId: string;
|
||||
@ -31,6 +33,8 @@ export const MetricsTable: React.FC<MetricsTableProps> = React.memo((props) => {
|
||||
endAt,
|
||||
});
|
||||
|
||||
const total = sum(metrics.map((m) => m.y));
|
||||
|
||||
const columns: ColumnsType<{ x: string; y: number }> = [
|
||||
{
|
||||
title: title[0],
|
||||
@ -40,6 +44,27 @@ export const MetricsTable: React.FC<MetricsTableProps> = React.memo((props) => {
|
||||
title: title[1],
|
||||
dataIndex: 'y',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (val) => {
|
||||
const percent = (Number(val) / total) * 100;
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<div className="w-12 text-right">
|
||||
{millify(val, {
|
||||
lowercase: true,
|
||||
})}
|
||||
</div>
|
||||
<div className="inline-block w-10 relative border-l ml-1 pl-1">
|
||||
<div
|
||||
className="bg-blue-300 absolute h-full bg-opacity-25 left-0 top-0 pointer-events-none"
|
||||
style={{ width: `${percent}%` }}
|
||||
/>
|
||||
<span>{percent.toFixed(0)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -49,6 +74,10 @@ export const MetricsTable: React.FC<MetricsTableProps> = React.memo((props) => {
|
||||
loading={isLoading}
|
||||
dataSource={metrics}
|
||||
columns={columns}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
hideOnSinglePage: true,
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
|
@ -7,6 +7,6 @@ interface PagesTableProps {
|
||||
endAt: number;
|
||||
}
|
||||
export const PagesTable: React.FC<PagesTableProps> = React.memo((props) => {
|
||||
return <MetricsTable {...props} type="url" title={['pages', 'views']} />;
|
||||
return <MetricsTable {...props} type="url" title={['Pages', 'Views']} />;
|
||||
});
|
||||
PagesTable.displayName = 'PagesTable';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Divider } from 'antd';
|
||||
import { Card, Divider } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
@ -32,23 +32,21 @@ export const WebsiteDetail: React.FC = React.memo(() => {
|
||||
|
||||
return (
|
||||
<div className="py-6">
|
||||
<div>
|
||||
<WebsiteOverview website={website} />
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
<Card>
|
||||
<Card.Grid hoverable={false} className="!w-full">
|
||||
<WebsiteOverview website={website} />
|
||||
</Card.Grid>
|
||||
<Card.Grid hoverable={false} className="!w-1/2">
|
||||
<PagesTable
|
||||
websiteId={websiteId}
|
||||
startAt={dayjs().subtract(1, 'day').unix() * 1000}
|
||||
endAt={dayjs().unix() * 1000}
|
||||
/>
|
||||
</div>
|
||||
<Divider type="vertical" />
|
||||
<div className="flex-1">right</div>
|
||||
</div>
|
||||
</Card.Grid>
|
||||
<Card.Grid hoverable={false} className="!w-1/2">
|
||||
right
|
||||
</Card.Grid>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -70,6 +70,14 @@ export const websiteRouter = router({
|
||||
event: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.array(
|
||||
z.object({
|
||||
x: z.string(),
|
||||
y: z.bigint(),
|
||||
})
|
||||
)
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const {
|
||||
websiteId,
|
||||
|
Loading…
Reference in New Issue
Block a user