fix ui: more different cards...
This commit is contained in:
parent
b01a38ecc9
commit
ac661524aa
7 changed files with 389 additions and 17 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { Segmented } from 'antd';
|
||||
import { Angry, ArrowDownUp, Mouse, MousePointerClick, Unlink } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
|
|
@ -6,13 +7,44 @@ import React from 'react';
|
|||
import ExCard from './ExCard';
|
||||
|
||||
|
||||
function ExampleCount() {
|
||||
return <ExCard title={'Sessions by'}>
|
||||
<Frustrations />
|
||||
</ExCard>;
|
||||
const TYPES = {
|
||||
Frustrations: 0,
|
||||
Errors: 1,
|
||||
Users: 2
|
||||
}
|
||||
|
||||
function Frustrations() {
|
||||
function ExampleCount() {
|
||||
const [type, setType] = React.useState(TYPES.Frustrations);
|
||||
|
||||
const el = {
|
||||
[TYPES.Frustrations]: <Frustrations />,
|
||||
[TYPES.Errors]: <Errors />,
|
||||
[TYPES.Users]: <Users />
|
||||
};
|
||||
return (
|
||||
<ExCard
|
||||
title={
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<div>Sessions by</div>
|
||||
<div className={'font-normal'}>
|
||||
<Segmented
|
||||
options={[
|
||||
{ label: 'Frustrations', value: '0' },
|
||||
{ label: 'Errors', value: '1' },
|
||||
{ label: 'Users', value: '2'}
|
||||
]}
|
||||
onChange={(v) => setType(Number(v))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{el[type]}
|
||||
</ExCard>
|
||||
);
|
||||
}
|
||||
|
||||
export function Frustrations() {
|
||||
const rows = [
|
||||
{
|
||||
label: 'Rage Clicks',
|
||||
|
|
@ -46,12 +78,13 @@ function Frustrations() {
|
|||
},
|
||||
];
|
||||
|
||||
const lineWidth = 140
|
||||
return (
|
||||
<div className={'flex gap-2 flex-col'}>
|
||||
<div className={'flex gap-1 flex-col'}>
|
||||
{rows.map((r) => (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border-b border-dotted last:border-0 py-2 first:pt-0 last:pb-0'
|
||||
'flex items-center gap-2 border-b border-dotted py-2 last:border-0 first:pt-0 last:pb-0'
|
||||
}
|
||||
>
|
||||
<Circle badgeType={0}>{r.icon}</Circle>
|
||||
|
|
@ -60,7 +93,7 @@ function Frustrations() {
|
|||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: 140 * (0.01 * r.progress),
|
||||
width: lineWidth * (0.01 * r.progress),
|
||||
background: '#394EFF',
|
||||
}}
|
||||
className={'rounded-l'}
|
||||
|
|
@ -68,7 +101,7 @@ function Frustrations() {
|
|||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: 140-(140 * (0.01 * r.progress)),
|
||||
width: lineWidth - lineWidth * (0.01 * r.progress),
|
||||
background: '#E2E4F6',
|
||||
}}
|
||||
className={'rounded-r'}
|
||||
|
|
@ -81,7 +114,7 @@ function Frustrations() {
|
|||
);
|
||||
}
|
||||
|
||||
function Errors() {
|
||||
export function Errors() {
|
||||
const rows = [
|
||||
{
|
||||
label: 'HTTP response status code (404 Not Found)',
|
||||
|
|
@ -114,9 +147,89 @@ function Errors() {
|
|||
icon: <div className={'text-red text-xs'}>XHR</div>,
|
||||
},
|
||||
];
|
||||
|
||||
const lineWidth = 270
|
||||
return (
|
||||
<div className={'flex gap-1 flex-col'}>
|
||||
{rows.map((r) => (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border-b border-dotted last:border-0 py-2 first:pt-0 last:pb-0'
|
||||
}
|
||||
>
|
||||
<Circle badgeType={1}>{r.icon}</Circle>
|
||||
<div className={'ml-2 flex flex-col gap-0'}>
|
||||
<div>{r.label}</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: lineWidth * (0.01 * r.progress),
|
||||
background: '#394EFF',
|
||||
}}
|
||||
className={'rounded-l'}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: lineWidth - lineWidth * (0.01 * r.progress),
|
||||
background: '#E2E4F6',
|
||||
}}
|
||||
className={'rounded-r'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'min-w-8 ml-auto'}>{r.value}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Circle({
|
||||
export function Users() {
|
||||
const rows = [
|
||||
{
|
||||
label: 'pedro@mycompany.com',
|
||||
value: '9.5K',
|
||||
},
|
||||
{
|
||||
label: 'mauricio@mycompany.com',
|
||||
value: '2.5K',
|
||||
},
|
||||
{
|
||||
label: 'alex@mycompany.com',
|
||||
value: '405',
|
||||
},
|
||||
{
|
||||
label: 'jose@mycompany.com',
|
||||
value: '150',
|
||||
},
|
||||
{
|
||||
label: 'maria@mycompany.com',
|
||||
value: '123',
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={'flex gap-1 flex-col'}>
|
||||
{rows.map((r) => (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border-b border-dotted py-2 last:border-0 first:pt-0 last:pb-0'
|
||||
}
|
||||
>
|
||||
<Circle badgeType={2}>{r.label[0].toUpperCase()}</Circle>
|
||||
<div className={'ml-2'}>
|
||||
<div>{r.label}</div>
|
||||
</div>
|
||||
<div className={'min-w-8 ml-auto'}>{r.value}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Circle({
|
||||
children,
|
||||
badgeType,
|
||||
}: {
|
||||
|
|
@ -124,14 +237,17 @@ function Circle({
|
|||
badgeType: 0 | 1 | 2;
|
||||
}) {
|
||||
const colors = {
|
||||
// frustrations
|
||||
0: '#FFFBE6',
|
||||
// errors
|
||||
1: '#FFF1F0',
|
||||
// users and domains
|
||||
2: '#EBF4F5',
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={'p-2 rounded-full'}
|
||||
className={'w-8 h-8 flex items-center justify-center rounded-full'}
|
||||
style={{ background: colors[badgeType] }}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
import { GitCommitHorizontal } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
import ExCard from './ExCard';
|
||||
|
||||
function PerfBreakdown() {
|
||||
const rows = [
|
||||
['5K', '1K'],
|
||||
['4K', '750'],
|
||||
['3K', '500'],
|
||||
['2K', '250'],
|
||||
['1K', '0'],
|
||||
];
|
||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
|
||||
const values = [
|
||||
[3, 1, 9],
|
||||
[2, 4, 10],
|
||||
[3, 6, 2],
|
||||
[7, 4, 1],
|
||||
[5, 3, 4],
|
||||
];
|
||||
const bgs = ['#E2E4F6', '#A7BFFF', '#394EFF'];
|
||||
return (
|
||||
<ExCard title={'Breakdown'}>
|
||||
<div className={'relative'}>
|
||||
<div className={'flex flex-col gap-4'}>
|
||||
{rows.map((r) => (
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<div className={'text-gray-dark'}>{r[0]}</div>
|
||||
<div className="border-t border-dotted border-gray-lighter w-full"></div>
|
||||
<div className={'text-gray-dark min-w-8'}>{r[1]}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className={'px-4 flex items-center justify-around w-full'}>
|
||||
{months.map((m, i) => (
|
||||
<div className={'text-gray-dark relative'}>
|
||||
<span>{m}</span>
|
||||
<div
|
||||
className={'absolute flex flex-col'}
|
||||
style={{ bottom: 30, left: 0, width: 24 }}
|
||||
>
|
||||
{values[i].map((v, bg) => (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: v * 9 + 'px',
|
||||
background: bgs[bg],
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 30,
|
||||
left: 30,
|
||||
zIndex: 99,
|
||||
width: 308,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="332"
|
||||
height="37"
|
||||
viewBox="0 0 332 37"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M1 30.8715L4.66667 26.964C8.33333 23.0566 15.6667 15.2417 23 9.74387C30.3333 4.24605 37.6667 1.06529 45 1.54812C52.3333 2.03094 59.6667 6.17735 67 10.8175C74.3333 15.4577 81.6667 20.5916 89 19.6024C96.3333 18.6133 103.667 11.5009 111 7.69717C118.333 3.89339 125.667 3.39814 133 8.24328C140.333 13.0884 147.667 23.274 155 28.5047C162.333 33.7354 169.667 34.0114 177 33.4739C184.333 32.9365 191.667 31.5856 199 28.7677C206.333 25.9499 213.667 21.665 221 18.723C228.333 15.781 235.667 14.182 243 10.7612C250.333 7.34035 257.667 2.09783 265 3.39238C272.333 4.68693 279.667 12.5186 287 14.2932C294.333 16.0679 301.667 11.7856 309 14.3106C316.333 16.8356 323.667 26.1678 327.333 30.8339L331 35.5"
|
||||
stroke="#6A8CFF"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={'flex gap-4 justify-center'}>
|
||||
<div className={'flex gap-2 items-center'}>
|
||||
<div className={'w-4 h-4 rounded-full bg-[#E2E4F6]'} />
|
||||
<div className={'text-disabled-text'}>XHR</div>
|
||||
</div>
|
||||
<div className={'flex gap-2 items-center'}>
|
||||
<div className={'w-4 h-4 rounded-full bg-[#A7BFFF]'} />
|
||||
<div className={'text-disabled-text'}>Other</div>
|
||||
</div>
|
||||
<div className={'flex gap-2 items-center'}>
|
||||
<GitCommitHorizontal size={14} strokeWidth={1} color={'#6A8CFF'} />
|
||||
<div className={'text-disabled-text'}>Response End</div>
|
||||
</div>
|
||||
</div>
|
||||
</ExCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default PerfBreakdown;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react'
|
||||
import ExCard from "./ExCard";
|
||||
import { Errors } from "./Count";
|
||||
|
||||
function SessionsByErrors() {
|
||||
return (
|
||||
<ExCard
|
||||
title={'Sessions by Errors'}
|
||||
>
|
||||
<Errors />
|
||||
</ExCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default SessionsByErrors
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react'
|
||||
import ExCard from "./ExCard";
|
||||
import { Frustrations } from "./Count";
|
||||
|
||||
function SessionsByIssues() {
|
||||
return (
|
||||
<ExCard
|
||||
title={'Sessions by Issues'}
|
||||
>
|
||||
<Frustrations />
|
||||
</ExCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default SessionsByIssues
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { LinkOutlined } from '@ant-design/icons';
|
||||
import React from 'react';
|
||||
|
||||
import { Circle } from './Count';
|
||||
import ExCard from './ExCard';
|
||||
|
||||
function SlowestDomain() {
|
||||
const rows = [
|
||||
{
|
||||
label: 'kroger.com',
|
||||
value: '28,162 ms',
|
||||
progress: 97,
|
||||
icon: <LinkOutlined size={12} />,
|
||||
},
|
||||
{
|
||||
label: 'instacart.com',
|
||||
value: '3,165 ms',
|
||||
progress: 60,
|
||||
icon: <LinkOutlined size={12} />,
|
||||
},
|
||||
{
|
||||
label: 'gifs.eco.br',
|
||||
value: '1,503 ms',
|
||||
progress: 40,
|
||||
icon: <LinkOutlined size={12} />,
|
||||
},
|
||||
{
|
||||
label: 'cdn.byintera.com',
|
||||
value: '512 ms',
|
||||
progress: 10,
|
||||
icon: <LinkOutlined size={12} />,
|
||||
},
|
||||
{
|
||||
label: 'analytics.twitter.com',
|
||||
value: '110 ms',
|
||||
progress: 5,
|
||||
icon: <LinkOutlined size={12} />,
|
||||
},
|
||||
];
|
||||
|
||||
const lineWidth = 240;
|
||||
|
||||
return (
|
||||
<ExCard title={'Slowest Domain'}>
|
||||
<div className={'flex gap-1 flex-col'}>
|
||||
{rows.map((r) => (
|
||||
<div
|
||||
className={
|
||||
'flex items-center gap-2 border-b border-dotted last:border-0 py-2 first:pt-0 last:pb-0'
|
||||
}
|
||||
>
|
||||
<Circle badgeType={2}>
|
||||
{r.icon}
|
||||
</Circle>
|
||||
<div className={'ml-2 flex flex-col gap-0'}>
|
||||
<div>{r.label}</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: lineWidth * (0.01 * r.progress),
|
||||
background: '#394EFF',
|
||||
}}
|
||||
className={'rounded-l'}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
height: 2,
|
||||
width: lineWidth - lineWidth * (0.01 * r.progress),
|
||||
background: '#E2E4F6',
|
||||
}}
|
||||
className={'rounded-r'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'min-w-8 ml-auto'}>{r.value}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ExCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default SlowestDomain;
|
||||
|
|
@ -13,6 +13,7 @@ function ExampleTrend() {
|
|||
title={
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<div>Trend</div>
|
||||
<div className={'font-normal'}>
|
||||
<Segmented
|
||||
options={[
|
||||
{ label: 'Single-Series', value: 'single' },
|
||||
|
|
@ -20,6 +21,7 @@ function ExampleTrend() {
|
|||
]}
|
||||
onChange={(v) => setIsMulti(v === 'multi')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -7,9 +7,27 @@ import ExampleCount from "./Examples/Count";
|
|||
|
||||
import ExampleFunnel from './Examples/Funnel';
|
||||
import ExamplePath from './Examples/Path';
|
||||
import PerfBreakdown from "./Examples/PerfBreakdown";
|
||||
import SessionsByErrors from "./Examples/SessionsByErrors";
|
||||
import SessionsByIssues from "./Examples/SessionsByIssues";
|
||||
import SlowestDomain from "./Examples/SlowestDomain";
|
||||
import ExampleTrend from './Examples/Trend';
|
||||
|
||||
function NewDashboardModal(props: { onClose: () => void; open: boolean }) {
|
||||
const initial = 'performance-monitoring' //'product-analytics';
|
||||
const [selected, setSelected] = React.useState(initial);
|
||||
let item;
|
||||
switch (selected) {
|
||||
case 'product-analytics':
|
||||
item = <ProductAnalytics />
|
||||
break;
|
||||
case 'performance-monitoring':
|
||||
item = <PerformanceMonitoring />
|
||||
break;
|
||||
default:
|
||||
item = <div>under construction</div>
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<Modal onClose={props.onClose} open={props.open} size={'xlarge'}>
|
||||
<Modal.Content className={'bg-[#FAFAFA]'}>
|
||||
|
|
@ -62,13 +80,11 @@ function NewDashboardModal(props: { onClose: () => void; open: boolean }) {
|
|||
value: 'core-web-vitals',
|
||||
},
|
||||
]}
|
||||
onChange={(v) => setSelected(v)}
|
||||
/>
|
||||
|
||||
<div className={'mt-2 w-full flex flex-wrap gap-2 overflow-scroll'}>
|
||||
<ExampleFunnel />
|
||||
<ExamplePath />
|
||||
<ExampleTrend />
|
||||
<ExampleCount />
|
||||
<div style={{ maxHeight: 'calc(100vh - 210px)'}} className={'mt-2 w-full flex flex-wrap gap-2 overflow-scroll'}>
|
||||
{item}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -77,4 +93,26 @@ function NewDashboardModal(props: { onClose: () => void; open: boolean }) {
|
|||
);
|
||||
}
|
||||
|
||||
function ProductAnalytics() {
|
||||
return (
|
||||
<>
|
||||
<ExampleFunnel />
|
||||
<ExamplePath />
|
||||
<ExampleTrend />
|
||||
<ExampleCount />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function PerformanceMonitoring() {
|
||||
return (
|
||||
<>
|
||||
<PerfBreakdown />
|
||||
<SlowestDomain />
|
||||
<SessionsByErrors />
|
||||
<SessionsByIssues />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewDashboardModal;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue