Skip to content

Commit

Permalink
feat: added signer id page
Browse files Browse the repository at this point in the history
  • Loading branch information
BLuEScioN committed Nov 8, 2024
1 parent 6ee9484 commit cacef8d
Show file tree
Hide file tree
Showing 29 changed files with 1,865 additions and 423 deletions.
835 changes: 608 additions & 227 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/app/_components/time-filter/DatePickerInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FormLabel } from '@/ui/FormLabel';
import { UTCDate } from '@date-fns/utc';
import { Field, FieldProps, Form, Formik } from 'formik';
import DatePicker from 'react-datepicker';
Expand All @@ -7,6 +6,7 @@ import 'react-datepicker/dist/react-datepicker.css';
import { Box } from '../../../ui/Box';
import { Button } from '../../../ui/Button';
import { FormControl } from '../../../ui/FormControl';
import { FormLabel } from '../../../ui/FormLabel';

Check warning on line 9 in src/app/_components/time-filter/DatePickerInput.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/time-filter/DatePickerInput.tsx#L9

Added line #L9 was not covered by tests
import { Stack } from '../../../ui/Stack';
import { DateInput } from './DateInput';

Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/time-filter/TimeFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Stack } from '@/ui/Stack';
import { useColorModeValue } from '@chakra-ui/react';
import { CaretDown } from '@phosphor-icons/react';
import { ReactNode, useEffect, useMemo, useState } from 'react';
Expand All @@ -10,6 +9,7 @@ import { Icon } from '../../../ui/Icon';
import { Popover } from '../../../ui/Popover';
import { PopoverContent } from '../../../ui/PopoverContent';
import { PopoverTrigger } from '../../../ui/PopoverTrigger';
import { Stack } from '../../../ui/Stack';

Check warning on line 12 in src/app/_components/time-filter/TimeFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/time-filter/TimeFilter.tsx#L12

Added line #L12 was not covered by tests
import { Text } from '../../../ui/Text';
import { useDisclosure } from '../../../ui/hooks/useDisclosure';
import { DatePickerInput, DatePickerValues } from './DatePickerInput';
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/time-filter/TimeInput.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FormLabel } from '@/ui/FormLabel';
import { Input } from '@/ui/Input';
import { Field, FieldProps, Form, Formik } from 'formik';

import { Box } from '../../../ui/Box';
import { Button } from '../../../ui/Button';
import { FormControl } from '../../../ui/FormControl';
import { FormLabel } from '../../../ui/FormLabel';
import { Input } from '../../../ui/Input';

Check warning on line 7 in src/app/_components/time-filter/TimeInput.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/time-filter/TimeInput.tsx#L6-L7

Added lines #L6 - L7 were not covered by tests
import { Stack } from '../../../ui/Stack';

export type Time = string;
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/time-filter/TimeRangeInput.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FormLabel } from '@/ui/FormLabel';
import { Input } from '@/ui/Input';
import { Field, FieldProps, Form, Formik } from 'formik';

import { Box } from '../../../ui/Box';
import { Button } from '../../../ui/Button';
import { FormControl } from '../../../ui/FormControl';
import { FormLabel } from '../../../ui/FormLabel';
import { Input } from '../../../ui/Input';

Check warning on line 7 in src/app/_components/time-filter/TimeRangeInput.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/time-filter/TimeRangeInput.tsx#L6-L7

Added lines #L6 - L7 were not covered by tests
import { Stack } from '../../../ui/Stack';

type Time = number | string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use client';

import { logError } from '@/common/utils/error-utils';
import { useEffect } from 'react';

import { ErrorMessageLayout } from '../common/components/ErrorMessageLayout';
import { Section } from '../common/components/Section';
import { logError } from '../common/utils/error-utils';

Check warning on line 7 in src/app/global-error.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/global-error.tsx#L7

Added line #L7 was not covered by tests
import { Box } from '../ui/Box';
import { Grid } from '../ui/Grid';

Expand Down
2 changes: 1 addition & 1 deletion src/app/search/filters/Date.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Stack } from '@/ui/Stack';
import { useColorModeValue } from '@chakra-ui/react';
import { CaretDown } from '@phosphor-icons/react';
import { ReactNode, useEffect, useState } from 'react';
Expand All @@ -11,6 +10,7 @@ import { Icon } from '../../../ui/Icon';
import { Popover } from '../../../ui/Popover';
import { PopoverContent } from '../../../ui/PopoverContent';
import { PopoverTrigger } from '../../../ui/PopoverTrigger';
import { Stack } from '../../../ui/Stack';

Check warning on line 13 in src/app/search/filters/Date.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/search/filters/Date.tsx#L13

Added line #L13 was not covered by tests
import { Text } from '../../../ui/Text';
import { useDisclosure } from '../../../ui/hooks/useDisclosure';
import { AfterForm } from './After';
Expand Down
125 changes: 125 additions & 0 deletions src/app/signer/[signerKey]/AssociatedAddressesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { ReactNode, Suspense, useMemo } from 'react';

Check warning on line 1 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L1

Added line #L1 was not covered by tests

import {
SignersStackersData,
useSuspenseSignerStackersInfinite,
} from '../../../app/signers/data/UseSignerAddresses';
import { CopyButton } from '../../../common/components/CopyButton';
import { ListFooter } from '../../../common/components/ListFooter';
import { Section } from '../../../common/components/Section';
import { Box } from '../../../ui/Box';
import { Flex } from '../../../ui/Flex';
import { Stack } from '../../../ui/Stack';
import { Text } from '../../../ui/Text';
import { ExplorerErrorBoundary } from '../../_components/ErrorBoundary';
import { useSuspenseCurrentStackingCycle } from '../../_components/Stats/CurrentStackingCycle/useCurrentStackingCycle';
import { AssociatedAddressesTableSkeleton } from './skeleton';

Check warning on line 16 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L6-L16

Added lines #L6 - L16 were not covered by tests

export const addressItemHeight = 69;

Check warning on line 18 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L18

Added line #L18 was not covered by tests

export const AssociatedAddressesTableLayout = ({ children }: { children: ReactNode }) => {

Check warning on line 20 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L20

Added line #L20 was not covered by tests
return <Section title="Associated addresses">{children}</Section>;
};

export const AssociatedAddressListItemLayout = ({

Check warning on line 24 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L24

Added line #L24 was not covered by tests
children,
isLast,
}: {
children: ReactNode;
isLast: boolean;
}) => {

Check warning on line 30 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L30

Added line #L30 was not covered by tests
return (
<Flex
alignItems={'center'}
gap={1}
py={6}
borderBottom={isLast ? 'none' : '1px solid var(--stacks-colors-borderSecondary)'}
>
{children}
</Flex>
);
};

export const AssociatedAddressListItem = ({

Check warning on line 43 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L43

Added line #L43 was not covered by tests
stacker,
isLast,
}: {
stacker: SignersStackersData;
isLast: boolean;
}) => {

Check warning on line 49 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L49

Added line #L49 was not covered by tests
return (
<AssociatedAddressListItemLayout isLast={isLast}>
<Text fontSize={'sm'}>{stacker.stacker_address}</Text>
<CopyButton
className={'fancy-copy'}
initialValue={stacker.pox_address}
aria-label={'copy row'}
size={4}
color="textSubdued"
/>
</AssociatedAddressListItemLayout>
);
};

export const AssociatedAddressesTableBase = ({ signerKey }: { signerKey: string }) => {
const { currentCycleId } = useSuspenseCurrentStackingCycle();

Check warning on line 65 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L64-L65

Added lines #L64 - L65 were not covered by tests
const {
data: signerStackers,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
} = useSuspenseSignerStackersInfinite(currentCycleId, signerKey);

Check warning on line 71 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L71

Added line #L71 was not covered by tests

const stackers = useMemo(

Check warning on line 73 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L73

Added line #L73 was not covered by tests
() => signerStackers?.pages.flatMap(page => page.results) ?? [],
[signerStackers]
);

return (
<AssociatedAddressesTableLayout>
<Stack gap={0}>
<Box h={addressItemHeight * 10} overflow="auto">
{signerStackers?.pages
.flatMap(page => page.results)

Check warning on line 83 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L83

Added line #L83 was not covered by tests
.map((stacker, i) => (
<AssociatedAddressListItem

Check warning on line 85 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L85

Added line #L85 was not covered by tests
key={stacker.stacker_address}
stacker={stacker}
isLast={i === stackers.length - 1}
/>
))}
</Box>

<ListFooter
label="addresses"
isLoading={isFetchingNextPage}
fetchNextPage={fetchNextPage}
hasNextPage={hasNextPage}
pb={6}
position={'sticky'}
bottom={0}
bg="surface"
/>
</Stack>
</AssociatedAddressesTableLayout>
);
};

export const AssociatedAddressesTable = ({ signerKey }: { signerKey: string }) => {

Check warning on line 108 in src/app/signer/[signerKey]/AssociatedAddressesTable.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/AssociatedAddressesTable.tsx#L108

Added line #L108 was not covered by tests
return (
<ExplorerErrorBoundary
Wrapper={Section}
wrapperProps={{
title: 'Associated Addresses',
gridColumnStart: ['1', '1', '2'],
gridColumnEnd: ['2', '2', '3'],
minWidth: 0,
}}
tryAgainButton
>
<Suspense fallback={<AssociatedAddressesTableSkeleton />}>
<AssociatedAddressesTableBase signerKey={signerKey} />
</Suspense>
</ExplorerErrorBoundary>
);
};
45 changes: 45 additions & 0 deletions src/app/signer/[signerKey]/CycleSortFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { SortDescending } from '@phosphor-icons/react';
import { useMemo } from 'react';

Check warning on line 2 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L1-L2

Added lines #L1 - L2 were not covered by tests

import { FilterMenu } from '../../../common/components/FilterMenu';

Check warning on line 4 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L4

Added line #L4 was not covered by tests

export enum CycleSortOrder {
Asc = 'asc',
Desc = 'desc',
}

function getSortOptionLabel(order: CycleSortOrder) {

Check warning on line 11 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L11

Added line #L11 was not covered by tests
switch (order) {
case CycleSortOrder.Asc:
return 'Cycle Asc';
case CycleSortOrder.Desc:
return 'Cycle Desc';

Check warning on line 16 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L13-L16

Added lines #L13 - L16 were not covered by tests
}
}

export function CycleSortFilter({

Check warning on line 20 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L20

Added line #L20 was not covered by tests
cycleSortOrder,
setCycleSortOrder,
}: {
cycleSortOrder: CycleSortOrder;
setCycleSortOrder: (order: CycleSortOrder) => void;
}) {
const menuItems = useMemo(

Check warning on line 27 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L26-L27

Added lines #L26 - L27 were not covered by tests
() =>
Object.values(CycleSortOrder).map(order => ({
onClick: () => {
setCycleSortOrder(order);

Check warning on line 31 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L29-L31

Added lines #L29 - L31 were not covered by tests
},
label: getSortOptionLabel(order),
})),
[setCycleSortOrder]
);

return (
<FilterMenu
filterLabel={() => getSortOptionLabel(cycleSortOrder)}

Check warning on line 40 in src/app/signer/[signerKey]/CycleSortFilter.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/CycleSortFilter.tsx#L40

Added line #L40 was not covered by tests
menuItems={menuItems}
leftIcon={SortDescending}
/>
);
}
51 changes: 51 additions & 0 deletions src/app/signer/[signerKey]/PageClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use client';

import { useParams } from 'next/navigation';

Check warning on line 3 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L3

Added line #L3 was not covered by tests

import { Grid, GridProps } from '../../../ui/Grid';
import { Stack } from '../../../ui/Stack';
import { PageTitle } from '../../_components/PageTitle';
import { AssociatedAddressesTable } from './AssociatedAddressesTable';
import { SignerStats } from './SignerStats';
import { SignerSummary } from './SignerSummary';
import { StackingHistoryTable } from './StackingHistoryTable';

Check warning on line 11 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L5-L11

Added lines #L5 - L11 were not covered by tests

export function SignerKeyPageLayout(props: GridProps) {

Check warning on line 13 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L13

Added line #L13 was not covered by tests
return (
<Grid
gridColumnGap={8}
gridTemplateColumns={['100%', '100%', 'repeat(1, calc(100% - 352px) 320px)']}
gridRowGap={[8, 8, 'unset']}
maxWidth="100%"
alignItems="flex-start"
{...props}
/>
);
}

export default function PageClient() {
const params = useParams<{ signerKey: string }>();

Check warning on line 27 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L26-L27

Added lines #L26 - L27 were not covered by tests

if (!params) {
console.error('params is undefined. This component should receive params from its parent.');
return null; // or some error UI

Check warning on line 31 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L30-L31

Added lines #L30 - L31 were not covered by tests
}

const { signerKey } = params;

Check warning on line 34 in src/app/signer/[signerKey]/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/PageClient.tsx#L34

Added line #L34 was not covered by tests
return (
<>
<PageTitle>Signer key</PageTitle>

<SignerKeyPageLayout>
<Stack gap={8}>
<SignerSummary signerKey={signerKey} />
<AssociatedAddressesTable signerKey={signerKey} />
<StackingHistoryTable signerKey={signerKey} />
</Stack>
<Stack gap={8}>
<SignerStats signerKey={signerKey} />
</Stack>
</SignerKeyPageLayout>
</>
);
}
86 changes: 86 additions & 0 deletions src/app/signer/[signerKey]/SignerStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { ReactNode, Suspense } from 'react';

Check warning on line 1 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L1

Added line #L1 was not covered by tests

import { ExplorerErrorBoundary } from '../../../app/_components/ErrorBoundary';
import { formatSignerLatency, formatSignerProposalMetric } from '../../../app/signers/SignersTable';
import { useSignerMetricsSignerForCycle } from '../../../app/signers/data/signer-metrics-hooks';
import { Section } from '../../../common/components/Section';
import { Box } from '../../../ui/Box';
import { Stack } from '../../../ui/Stack';
import { Caption } from '../../../ui/typography';
import { useSuspenseCurrentStackingCycle } from '../../_components/Stats/CurrentStackingCycle/useCurrentStackingCycle';
import { SignerKeyStatsSkeleton } from './skeleton';

Check warning on line 11 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L3-L11

Added lines #L3 - L11 were not covered by tests

interface SignerStatsProps {
signerKey: string;
}

export const SignerStatsLayout = ({ children }: { children: ReactNode }) => {

Check warning on line 17 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L17

Added line #L17 was not covered by tests
return <Section title={'Stats'}>{children}</Section>;
};

export const SignerKeyStat = ({

Check warning on line 21 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L21

Added line #L21 was not covered by tests
label,
value,
}: {
label: string | ReactNode;
value: string | ReactNode;
}) => {

Check warning on line 27 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L27

Added line #L27 was not covered by tests
return (
<Stack gap={2} py={4}>
<Caption>{label}</Caption>
<Box>{value}</Box>
</Stack>
);
};

function SignerStatsBase({ signerKey }: SignerStatsProps) {
const { currentCycleId } = useSuspenseCurrentStackingCycle();
const { data: signerMetrics } = useSignerMetricsSignerForCycle(currentCycleId, signerKey);

Check warning on line 38 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L36-L38

Added lines #L36 - L38 were not covered by tests
const totalProposals =
signerMetrics?.proposals_accepted_count +

Check warning on line 40 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L40

Added line #L40 was not covered by tests
signerMetrics?.proposals_rejected_count +
signerMetrics?.proposals_missed_count;

return (
<SignerStatsLayout>
<SignerKeyStat
label="Latency"
value={formatSignerLatency(
signerMetrics?.average_response_time_ms,
signerMetrics?.proposals_missed_count
)}
/>
<SignerKeyStat
label="Accepted proposals %"
value={formatSignerProposalMetric(signerMetrics?.proposals_accepted_count / totalProposals)}
/>
<SignerKeyStat
label="Rejected proposals %"
value={formatSignerProposalMetric(signerMetrics?.proposals_rejected_count / totalProposals)}
/>
<SignerKeyStat
label="Missed proposals %"
value={formatSignerProposalMetric(signerMetrics?.proposals_missed_count / totalProposals)}
/>
</SignerStatsLayout>
);
}

export function SignerStats(props: SignerStatsProps) {

Check warning on line 69 in src/app/signer/[signerKey]/SignerStats.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/signer/[signerKey]/SignerStats.tsx#L69

Added line #L69 was not covered by tests
return (
<ExplorerErrorBoundary
Wrapper={Section}
wrapperProps={{
title: 'Signer Stats',
gridColumnStart: ['1', '1', '2'],
gridColumnEnd: ['2', '2', '3'],
minWidth: 0,
}}
tryAgainButton
>
<Suspense fallback={<SignerKeyStatsSkeleton />}>
<SignerStatsBase {...props} />
</Suspense>
</ExplorerErrorBoundary>
);
}
Loading

0 comments on commit cacef8d

Please sign in to comment.