diff --git a/apps/web/src/components/StaffTools/RelayQueues.tsx b/apps/web/src/components/StaffTools/RelayQueues.tsx new file mode 100644 index 000000000000..1922ed910719 --- /dev/null +++ b/apps/web/src/components/StaffTools/RelayQueues.tsx @@ -0,0 +1,101 @@ +import MetaTags from '@components/Common/MetaTags'; +import useStaffMode from '@components/utils/hooks/useStaffMode'; +import { Mixpanel } from '@lib/mixpanel'; +import { t } from '@lingui/macro'; +import { APP_NAME, POLYGONSCAN_URL } from 'data/constants'; +import Errors from 'data/errors'; +import { useRelayQueuesQuery } from 'lens'; +import type { NextPage } from 'next'; +import type { FC } from 'react'; +import { useEffect } from 'react'; +import Custom404 from 'src/pages/404'; +import { PAGEVIEW } from 'src/tracking'; +import { Card, GridItemEight, GridItemFour, GridLayout, Spinner } from 'ui'; + +import StaffToolsSidebar from './Sidebar'; + +interface RelayProps { + address: string; + queue: number; + relayer: string; +} + +export const Relay: FC = ({ address, queue, relayer }) => { + function getRelayerName(name: string): string { + const words = name.split('_'); + const capitalizedWords = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()); + + return capitalizedWords.join(' '); + } + + return ( + +
+ {getRelayerName(relayer)} +
+ + {address} + +
+
+
+ {queue} + Transactions +
+
+ ); +}; + +const RelayQueues: NextPage = () => { + const { allowed } = useStaffMode(); + + useEffect(() => { + Mixpanel.track(PAGEVIEW, { page: 'stafftools', subpage: 'relayqueues' }); + }, []); + + const { data, loading, error } = useRelayQueuesQuery({ + pollInterval: 5000 + }); + + if (!allowed) { + return ; + } + + const sortedRelays = data?.relayQueues + .map((relay) => ({ + ...relay, + queue: relay.queue + })) + .sort((a, b) => b.queue - a.queue); + + return ( + + + + + + + + {error ? ( + {Errors.SomethingWentWrong} + ) : loading ? ( +
+ +
+ ) : ( +
+

Relay queues

+
+ {sortedRelays?.map(({ address, queue, relayer }) => ( + + ))} +
+
+ )} +
+
+
+ ); +}; + +export default RelayQueues; diff --git a/apps/web/src/components/StaffTools/Sidebar.tsx b/apps/web/src/components/StaffTools/Sidebar.tsx index da170d5fa3d4..a75a2917ebf6 100644 --- a/apps/web/src/components/StaffTools/Sidebar.tsx +++ b/apps/web/src/components/StaffTools/Sidebar.tsx @@ -1,5 +1,5 @@ import Sidebar from '@components/Shared/Sidebar'; -import { ChartPieIcon } from '@heroicons/react/outline'; +import { ChartPieIcon, ViewListIcon } from '@heroicons/react/outline'; import type { FC } from 'react'; const StaffToolsSidebar: FC = () => { @@ -10,6 +10,11 @@ const StaffToolsSidebar: FC = () => { title: 'Stats', icon: , url: '/stafftools' + }, + { + title: 'Relay queues', + icon: , + url: '/stafftools/relayqueues' } ]} /> diff --git a/apps/web/src/components/StaffTools/Stats/index.tsx b/apps/web/src/components/StaffTools/Stats/index.tsx index a6df2ed5a614..354a1beffb11 100644 --- a/apps/web/src/components/StaffTools/Stats/index.tsx +++ b/apps/web/src/components/StaffTools/Stats/index.tsx @@ -24,7 +24,7 @@ import type { FC, ReactNode } from 'react'; import { useEffect } from 'react'; import Custom404 from 'src/pages/404'; import { PAGEVIEW } from 'src/tracking'; -import { Card, GridItemEight, GridItemFour, GridLayout } from 'ui'; +import { Card, GridItemEight, GridItemFour, GridLayout, Spinner } from 'ui'; import StaffToolsSidebar from '../Sidebar'; @@ -111,7 +111,7 @@ const Stats: NextPage = () => { return ( - + @@ -120,7 +120,9 @@ const Stats: NextPage = () => { {error ? ( {Errors.SomethingWentWrong} ) : loading || todayLoading || yesterdayLoading ? ( -
Loading...
+
+ +
) : (

Stats

diff --git a/apps/web/src/pages/stafftools/relayqueues.tsx b/apps/web/src/pages/stafftools/relayqueues.tsx new file mode 100644 index 000000000000..234fed4489fd --- /dev/null +++ b/apps/web/src/pages/stafftools/relayqueues.tsx @@ -0,0 +1,3 @@ +import RelayQueues from '@components/StaffTools/RelayQueues'; + +export default RelayQueues; diff --git a/packages/lens/documents/queries/RelayQueues.graphql b/packages/lens/documents/queries/RelayQueues.graphql new file mode 100644 index 000000000000..c6c19e65b56f --- /dev/null +++ b/packages/lens/documents/queries/RelayQueues.graphql @@ -0,0 +1,7 @@ +query RelayQueues { + relayQueues { + relayer + address + queue + } +} diff --git a/packages/lens/generated.ts b/packages/lens/generated.ts index 1c03e64211c4..7193d17cdc1a 100644 --- a/packages/lens/generated.ts +++ b/packages/lens/generated.ts @@ -3494,6 +3494,7 @@ export type Query = { publications: PaginatedPublicationResult; recommendedProfiles: Array; rel?: Maybe; + relayQueues: Array; search: SearchResult; txIdToTxHash: Scalars['TxHash']; unknownEnabledModules: EnabledModules; @@ -3781,8 +3782,53 @@ export enum RelayErrorReasons { WrongWalletSigned = 'WRONG_WALLET_SIGNED' } +/** The */ +export type RelayQueueResult = { + __typename?: 'RelayQueueResult'; + /** The address of the relay */ + address: Scalars['EthereumAddress']; + /** The queue on the relay */ + queue: Scalars['Float']; + /** The relayer name */ + relayer: RelayRoleKey; +}; + export type RelayResult = RelayError | RelayerResult; +/** The relay role key */ +export enum RelayRoleKey { + CreateProfile = 'CREATE_PROFILE', + Dispatcher_1 = 'DISPATCHER_1', + Dispatcher_2 = 'DISPATCHER_2', + Dispatcher_3 = 'DISPATCHER_3', + Dispatcher_4 = 'DISPATCHER_4', + Dispatcher_5 = 'DISPATCHER_5', + Dispatcher_6 = 'DISPATCHER_6', + Dispatcher_7 = 'DISPATCHER_7', + Dispatcher_8 = 'DISPATCHER_8', + Dispatcher_9 = 'DISPATCHER_9', + Dispatcher_10 = 'DISPATCHER_10', + ProxyActionCollect_1 = 'PROXY_ACTION_COLLECT_1', + ProxyActionCollect_2 = 'PROXY_ACTION_COLLECT_2', + ProxyActionCollect_3 = 'PROXY_ACTION_COLLECT_3', + ProxyActionCollect_4 = 'PROXY_ACTION_COLLECT_4', + ProxyActionCollect_5 = 'PROXY_ACTION_COLLECT_5', + ProxyActionCollect_6 = 'PROXY_ACTION_COLLECT_6', + ProxyActionFollow_1 = 'PROXY_ACTION_FOLLOW_1', + ProxyActionFollow_2 = 'PROXY_ACTION_FOLLOW_2', + ProxyActionFollow_3 = 'PROXY_ACTION_FOLLOW_3', + ProxyActionFollow_4 = 'PROXY_ACTION_FOLLOW_4', + ProxyActionFollow_5 = 'PROXY_ACTION_FOLLOW_5', + ProxyActionFollow_6 = 'PROXY_ACTION_FOLLOW_6', + ProxyActionFollow_7 = 'PROXY_ACTION_FOLLOW_7', + ProxyActionFollow_8 = 'PROXY_ACTION_FOLLOW_8', + ProxyActionFollow_9 = 'PROXY_ACTION_FOLLOW_9', + ProxyActionFollow_10 = 'PROXY_ACTION_FOLLOW_10', + WithSig_1 = 'WITH_SIG_1', + WithSig_2 = 'WITH_SIG_2', + WithSig_3 = 'WITH_SIG_3' +} + /** The relayer result */ export type RelayerResult = { __typename?: 'RelayerResult'; @@ -22311,6 +22357,13 @@ export type RecommendedProfilesQuery = { }>; }; +export type RelayQueuesQueryVariables = Exact<{ [key: string]: never }>; + +export type RelayQueuesQuery = { + __typename?: 'Query'; + relayQueues: Array<{ __typename?: 'RelayQueueResult'; relayer: RelayRoleKey; address: any; queue: number }>; +}; + export type RelevantPeopleQueryVariables = Exact<{ request: ProfileQueryRequest; }>; @@ -33790,6 +33843,46 @@ export type RecommendedProfilesQueryResult = Apollo.QueryResult< RecommendedProfilesQuery, RecommendedProfilesQueryVariables >; +export const RelayQueuesDocument = gql` + query RelayQueues { + relayQueues { + relayer + address + queue + } + } +`; + +/** + * __useRelayQueuesQuery__ + * + * To run a query within a React component, call `useRelayQueuesQuery` and pass it any options that fit your needs. + * When your component renders, `useRelayQueuesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useRelayQueuesQuery({ + * variables: { + * }, + * }); + */ +export function useRelayQueuesQuery( + baseOptions?: Apollo.QueryHookOptions +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery(RelayQueuesDocument, options); +} +export function useRelayQueuesLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery(RelayQueuesDocument, options); +} +export type RelayQueuesQueryHookResult = ReturnType; +export type RelayQueuesLazyQueryHookResult = ReturnType; +export type RelayQueuesQueryResult = Apollo.QueryResult; export const RelevantPeopleDocument = gql` query RelevantPeople($request: ProfileQueryRequest!) { profiles(request: $request) {