@xyo-network/react-chain-network 1.20.14 → 1.20.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -540
- package/dist/browser/context/network/context.d.ts +12 -12
- package/dist/browser/context/network/use.d.ts +4 -4
- package/dist/browser/hooks/provider/useViewerInPage.d.ts.map +1 -1
- package/dist/browser/index.mjs.map +1 -1
- package/package.json +158 -48
- package/src/components/broadcast/CloseDrawerIconButton.tsx +0 -23
- package/src/components/broadcast/Drawer.tsx +0 -88
- package/src/components/broadcast/details/Card.tsx +0 -71
- package/src/components/broadcast/details/SummaryStack.stories.tsx +0 -36
- package/src/components/broadcast/details/SummaryStack.tsx +0 -68
- package/src/components/broadcast/details/index.ts +0 -2
- package/src/components/broadcast/index.ts +0 -1
- package/src/components/broadcast/usePaginatedEventPairs.ts +0 -69
- package/src/components/index.ts +0 -3
- package/src/components/menu/Avatar.tsx +0 -42
- package/src/components/menu/Icon.tsx +0 -21
- package/src/components/menu/MenuItem.tsx +0 -38
- package/src/components/menu/index.ts +0 -3
- package/src/components/status/Alert.stories.tsx +0 -74
- package/src/components/status/Alert.tsx +0 -51
- package/src/components/status/Dialog.tsx +0 -51
- package/src/components/status/NetworkStatus.tsx +0 -21
- package/src/components/status/index.ts +0 -2
- package/src/context/ActiveGatewayProvider.tsx +0 -21
- package/src/context/index.ts +0 -2
- package/src/context/network/Provider.tsx +0 -85
- package/src/context/network/context.ts +0 -5
- package/src/context/network/index.ts +0 -5
- package/src/context/network/settings/defaultChainNetworkSettings.ts +0 -5
- package/src/context/network/settings/index.ts +0 -3
- package/src/context/network/settings/types.ts +0 -7
- package/src/context/network/settings/useChainNetworkSettings.ts +0 -27
- package/src/context/network/state.ts +0 -13
- package/src/context/network/use.ts +0 -5
- package/src/hooks/index.ts +0 -2
- package/src/hooks/provider/UseViewerInPageV2.stories.tsx +0 -126
- package/src/hooks/provider/index.ts +0 -2
- package/src/hooks/provider/useRpcBroadcastListener.ts +0 -70
- package/src/hooks/provider/useViewerInPage.ts +0 -49
- package/src/hooks/status/index.ts +0 -1
- package/src/hooks/status/usePollNetworkStatus.ts +0 -39
- package/src/index.ts +0 -5
- package/src/model/BroadcastRpc.ts +0 -29
- package/src/model/index.ts +0 -1
- package/src/story/NetworkGatewayDecorators.tsx +0 -44
- package/src/story/index.ts +0 -1
- package/src/types/global.d.ts +0 -9
- package/src/types/images.d.ts +0 -20
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { DrawerProps } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
Box, Button, Drawer, Pagination, Stack, Typography,
|
|
4
|
-
} from '@mui/material'
|
|
5
|
-
import React, { useState } from 'react'
|
|
6
|
-
|
|
7
|
-
import { useRpcBroadcastListener } from '../../hooks/index.ts'
|
|
8
|
-
import type { RpcRequestResponsePairsById } from '../../model/index.ts'
|
|
9
|
-
import { CloseDrawerIconButton } from './CloseDrawerIconButton.tsx'
|
|
10
|
-
import { BroadcastedRpcCallDetailsCard } from './details/index.ts'
|
|
11
|
-
import { usePaginatedEventPairs } from './usePaginatedEventPairs.ts'
|
|
12
|
-
|
|
13
|
-
export interface BroadcastRpcCallsDrawer extends DrawerProps {
|
|
14
|
-
drawerTitle?: string
|
|
15
|
-
events: RpcRequestResponsePairsById
|
|
16
|
-
numberOfVisibleEvents?: number
|
|
17
|
-
onClearEvents?: () => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const BroadcastedRpcCallsDrawer: React.FC<BroadcastRpcCallsDrawer> = ({
|
|
21
|
-
anchor = 'right',
|
|
22
|
-
onClearEvents,
|
|
23
|
-
drawerTitle,
|
|
24
|
-
events,
|
|
25
|
-
onClose,
|
|
26
|
-
numberOfVisibleEvents = 25,
|
|
27
|
-
...props
|
|
28
|
-
}) => {
|
|
29
|
-
const [scrollableDiv, setScrollableDiv] = useState<HTMLDivElement | null>(null)
|
|
30
|
-
const {
|
|
31
|
-
allEventEntries,
|
|
32
|
-
visibleEvents,
|
|
33
|
-
totalPages,
|
|
34
|
-
effectiveCurrentPage,
|
|
35
|
-
handleClearEvents,
|
|
36
|
-
handlePageChange,
|
|
37
|
-
} = usePaginatedEventPairs(
|
|
38
|
-
events,
|
|
39
|
-
numberOfVisibleEvents,
|
|
40
|
-
onClearEvents,
|
|
41
|
-
scrollableDiv,
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<Drawer anchor={anchor} onClose={onClose} keepMounted={false} {...props}>
|
|
46
|
-
<CloseDrawerIconButton anchor={anchor} onClose={onClose} />
|
|
47
|
-
<Stack gap={2} sx={{ p: 3 }} flexShrink={0}>
|
|
48
|
-
<Stack direction="row" justifyContent="space-between" alignItems="center" gap={4}>
|
|
49
|
-
<Typography variant="h6">{drawerTitle ?? 'Broadcasted RPC Calls'}</Typography>
|
|
50
|
-
<Button variant="outlined" size="small" onClick={handleClearEvents}>Clear All</Button>
|
|
51
|
-
</Stack>
|
|
52
|
-
{allEventEntries.length > 0 && (
|
|
53
|
-
<Pagination
|
|
54
|
-
count={totalPages}
|
|
55
|
-
page={effectiveCurrentPage}
|
|
56
|
-
onChange={handlePageChange}
|
|
57
|
-
color="primary"
|
|
58
|
-
/>
|
|
59
|
-
)}
|
|
60
|
-
|
|
61
|
-
</Stack>
|
|
62
|
-
<Stack direction="column" id="events-container" flexGrow={1} sx={{ overflowY: 'hidden' }}>
|
|
63
|
-
<Box
|
|
64
|
-
ref={(el: HTMLDivElement) => setScrollableDiv(el)}
|
|
65
|
-
sx={{
|
|
66
|
-
overflowY: 'auto', px: 3, pb: 3,
|
|
67
|
-
}}
|
|
68
|
-
>
|
|
69
|
-
{visibleEvents.map(([id, broadcastedRpcCall], index) => {
|
|
70
|
-
return <BroadcastedRpcCallDetailsCard key={id} rpcRequestResponsePairs={broadcastedRpcCall} sx={{ mb: index < visibleEvents.length - 1 ? 2 : 0 }} />
|
|
71
|
-
})}
|
|
72
|
-
</Box>
|
|
73
|
-
</Stack>
|
|
74
|
-
</Drawer>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export const BroadcastedRpcCallsDrawerWithEvents: React.FC<DrawerProps> = (props) => {
|
|
79
|
-
const { clearEvents, events } = useRpcBroadcastListener()
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<BroadcastedRpcCallsDrawer
|
|
83
|
-
events={events}
|
|
84
|
-
onClearEvents={clearEvents}
|
|
85
|
-
{...props}
|
|
86
|
-
/>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { CardProps } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
Card, Collapse,
|
|
4
|
-
Stack, Typography,
|
|
5
|
-
} from '@mui/material'
|
|
6
|
-
import { isDefined } from '@xylabs/sdk-js'
|
|
7
|
-
import { JsonViewerEx } from '@xyo-network/react-payload-raw-info'
|
|
8
|
-
import React, { memo, useState } from 'react'
|
|
9
|
-
|
|
10
|
-
import type { RpcRequestResponsePairs } from '../../../model/index.ts'
|
|
11
|
-
import { BroadcastedRpcCallDetailsSummaryStack } from './SummaryStack.tsx'
|
|
12
|
-
|
|
13
|
-
const JSON_VIEWER_WIDTH = 600
|
|
14
|
-
|
|
15
|
-
export interface BroadcastRpcCallDetailsCardProps extends CardProps {
|
|
16
|
-
rpcRequestResponsePairs?: RpcRequestResponsePairs
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const BroadcastedRpcCallDetailsCard: React.FC<BroadcastRpcCallDetailsCardProps> = memo(({
|
|
20
|
-
rpcRequestResponsePairs, sx, ...props
|
|
21
|
-
}) => {
|
|
22
|
-
const [expanded, setExpanded] = useState(false)
|
|
23
|
-
|
|
24
|
-
if (!rpcRequestResponsePairs) return null
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
request, result, source,
|
|
28
|
-
} = rpcRequestResponsePairs
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Card
|
|
32
|
-
sx={{
|
|
33
|
-
p: 1, display: 'flex', flexDirection: 'column', width: JSON_VIEWER_WIDTH, ...sx,
|
|
34
|
-
}}
|
|
35
|
-
{...props}
|
|
36
|
-
>
|
|
37
|
-
<BroadcastedRpcCallDetailsSummaryStack
|
|
38
|
-
expanded={expanded}
|
|
39
|
-
params={request.rpcCall.params}
|
|
40
|
-
hasResult={isDefined(result)}
|
|
41
|
-
method={request.rpcCall.method}
|
|
42
|
-
setExpanded={setExpanded}
|
|
43
|
-
timestamp={request.timestamp}
|
|
44
|
-
/>
|
|
45
|
-
<Collapse in={expanded} mountOnEnter unmountOnExit>
|
|
46
|
-
<Stack direction="column" p={1} gap={2} alignItems="stretch">
|
|
47
|
-
<Typography variant="body2">
|
|
48
|
-
Source:
|
|
49
|
-
<Typography variant="caption" component="span" fontFamily="monospace" sx={{ ml: 1 }}>{source}</Typography>
|
|
50
|
-
</Typography>
|
|
51
|
-
<Typography variant="body2">Request:</Typography>
|
|
52
|
-
<JsonViewerEx
|
|
53
|
-
value={request}
|
|
54
|
-
sx={{ maxHeight: 300, overflow: 'auto' }}
|
|
55
|
-
/>
|
|
56
|
-
{isDefined(result)
|
|
57
|
-
? (
|
|
58
|
-
<>
|
|
59
|
-
<Typography variant="body2">Result:</Typography>
|
|
60
|
-
<JsonViewerEx
|
|
61
|
-
value={result}
|
|
62
|
-
sx={{ maxHeight: 300, overflow: 'auto' }}
|
|
63
|
-
/>
|
|
64
|
-
</>
|
|
65
|
-
)
|
|
66
|
-
: null}
|
|
67
|
-
</Stack>
|
|
68
|
-
</Collapse>
|
|
69
|
-
</Card>
|
|
70
|
-
)
|
|
71
|
-
})
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import { BroadcastedRpcCallDetailsSummaryStack } from './index.ts'
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
title: 'network/Broadcast/Details/SummaryStack',
|
|
8
|
-
component: BroadcastedRpcCallDetailsSummaryStack,
|
|
9
|
-
} as Meta
|
|
10
|
-
|
|
11
|
-
const Template: StoryFn<typeof BroadcastedRpcCallDetailsSummaryStack> = args => <BroadcastedRpcCallDetailsSummaryStack {...args} />
|
|
12
|
-
|
|
13
|
-
const Default = Template.bind({})
|
|
14
|
-
Default.args = {}
|
|
15
|
-
|
|
16
|
-
const WithHashParam = Template.bind({})
|
|
17
|
-
WithHashParam.args = {
|
|
18
|
-
expanded: true,
|
|
19
|
-
hasResult: true,
|
|
20
|
-
method: 'xyoViewer_blocksByHash',
|
|
21
|
-
params: ['5378eddddc7f5a16766988eafcfd28499a9d0248974c23bef2d92eb359834bca', 1],
|
|
22
|
-
timestamp: Date.now(),
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const WithUnknownParam = Template.bind({})
|
|
26
|
-
WithUnknownParam.args = {
|
|
27
|
-
expanded: true,
|
|
28
|
-
hasResult: true,
|
|
29
|
-
method: 'xyoViewer_currentBlock',
|
|
30
|
-
params: [],
|
|
31
|
-
timestamp: Date.now(),
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export {
|
|
35
|
-
Default, WithHashParam, WithUnknownParam,
|
|
36
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { JsonRpcParams } from '@metamask/json-rpc-engine/v2'
|
|
2
|
-
import {
|
|
3
|
-
ArrowRight, CheckCircle, Warning,
|
|
4
|
-
} from '@mui/icons-material'
|
|
5
|
-
import {
|
|
6
|
-
Avatar,
|
|
7
|
-
Icon, IconButton, Stack, type StackProps, Tooltip, Typography,
|
|
8
|
-
useTheme,
|
|
9
|
-
} from '@mui/material'
|
|
10
|
-
import { Identicon } from '@xylabs/react-identicon'
|
|
11
|
-
import { usePromise } from '@xylabs/react-promise'
|
|
12
|
-
import { isDefined } from '@xylabs/sdk-js'
|
|
13
|
-
import { ObjectHasher } from '@xyo-network/hash'
|
|
14
|
-
import React, { useMemo } from 'react'
|
|
15
|
-
|
|
16
|
-
export interface BroadcastRpcCallDetailsSummaryStackProps extends StackProps {
|
|
17
|
-
expanded?: boolean
|
|
18
|
-
hasResult?: boolean
|
|
19
|
-
method?: string
|
|
20
|
-
params?: JsonRpcParams
|
|
21
|
-
setExpanded?: (expanded: boolean) => void
|
|
22
|
-
timestamp?: number
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const BroadcastedRpcCallDetailsSummaryStack: React.FC<BroadcastRpcCallDetailsSummaryStackProps> = ({
|
|
26
|
-
expanded, setExpanded, method, timestamp, hasResult, params, ...props
|
|
27
|
-
}) => {
|
|
28
|
-
const theme = useTheme()
|
|
29
|
-
const [hash, hashError] = usePromise(async () => {
|
|
30
|
-
if (isDefined(params)) {
|
|
31
|
-
return await ObjectHasher.hash(params)
|
|
32
|
-
}
|
|
33
|
-
}, [params])
|
|
34
|
-
|
|
35
|
-
const formattedTimestamp = useMemo(() => isDefined(timestamp) ? new Date(timestamp).toLocaleString() : '', [timestamp])
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<Stack direction="row" gap={2} alignItems="center" justifyContent="space-between" {...props}>
|
|
39
|
-
<Stack direction="row" gap={2} alignItems="center">
|
|
40
|
-
<IconButton
|
|
41
|
-
size="small"
|
|
42
|
-
onClick={() => setExpanded?.(!expanded)}
|
|
43
|
-
>
|
|
44
|
-
<ArrowRight sx={{ transform: expanded ? 'rotate(90deg)' : 'rotate(0deg)', transition: 'transform 0.2s ease-in-out' }} fontSize="small" />
|
|
45
|
-
</IconButton>
|
|
46
|
-
<Tooltip
|
|
47
|
-
title={isDefined(hashError)
|
|
48
|
-
? `Error generating hash of params: ${hashError.message}`
|
|
49
|
-
: isDefined(params) ? `Params : ${JSON.stringify(params, null, 2)}` : 'No Params Provided'}
|
|
50
|
-
>
|
|
51
|
-
<Avatar sx={{
|
|
52
|
-
backgroundColor: theme.vars?.palette.text.primary, width: 20, height: 20, opacity: isDefined(hash) ? 1 : 0.5,
|
|
53
|
-
}}
|
|
54
|
-
>
|
|
55
|
-
<Identicon value={hash} size={14} />
|
|
56
|
-
</Avatar>
|
|
57
|
-
</Tooltip>
|
|
58
|
-
<Typography component="span" variant="body2" fontFamily="monospace">
|
|
59
|
-
{method}
|
|
60
|
-
</Typography>
|
|
61
|
-
<Typography component="span" variant="caption" color="text.secondary" sx={{ opacity: 0.6 }}>
|
|
62
|
-
{formattedTimestamp}
|
|
63
|
-
</Typography>
|
|
64
|
-
</Stack>
|
|
65
|
-
<Icon sx={{ justifySelf: 'end' }}>{hasResult ? <CheckCircle color="success" /> : <Warning color="warning" />}</Icon>
|
|
66
|
-
</Stack>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './Drawer.tsx'
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { isDefinedNotNull } from '@xylabs/sdk-js'
|
|
2
|
-
import type { ChangeEvent } from 'react'
|
|
3
|
-
import {
|
|
4
|
-
useCallback, useMemo, useState,
|
|
5
|
-
} from 'react'
|
|
6
|
-
|
|
7
|
-
import type { RpcRequestResponsePairsById } from '../../model/index.ts'
|
|
8
|
-
|
|
9
|
-
export const usePaginatedEventPairs = (
|
|
10
|
-
formattedEvents: RpcRequestResponsePairsById,
|
|
11
|
-
numberOfVisiblePairs: number,
|
|
12
|
-
onClearEvents?: () => void,
|
|
13
|
-
scrollableDiv?: HTMLDivElement | null,
|
|
14
|
-
) => {
|
|
15
|
-
const [currentPage, setCurrentPage] = useState(0)
|
|
16
|
-
|
|
17
|
-
const allEventEntries = useMemo(() => {
|
|
18
|
-
return Object.entries(formattedEvents ?? {}).toSorted(([, a], [, b]) => b.request.timestamp - a.request.timestamp)
|
|
19
|
-
}, [formattedEvents])
|
|
20
|
-
|
|
21
|
-
const totalPages = useMemo(() => {
|
|
22
|
-
return Math.ceil(allEventEntries.length / numberOfVisiblePairs)
|
|
23
|
-
}, [allEventEntries.length, numberOfVisiblePairs])
|
|
24
|
-
|
|
25
|
-
// Clamp current page to valid range
|
|
26
|
-
const effectiveCurrentPage = useMemo(() => {
|
|
27
|
-
if (totalPages === 0) return 0
|
|
28
|
-
return Math.min(currentPage, totalPages - 1)
|
|
29
|
-
}, [currentPage, totalPages])
|
|
30
|
-
|
|
31
|
-
const visibleEvents = useMemo(() => {
|
|
32
|
-
if (isDefinedNotNull(scrollableDiv)) {
|
|
33
|
-
scrollableDiv.scrollTo({ top: 0, behavior: 'smooth' })
|
|
34
|
-
}
|
|
35
|
-
const startIndex = effectiveCurrentPage * numberOfVisiblePairs
|
|
36
|
-
const endIndex = startIndex + numberOfVisiblePairs
|
|
37
|
-
return allEventEntries.slice(startIndex, endIndex)
|
|
38
|
-
}, [allEventEntries, effectiveCurrentPage, numberOfVisiblePairs, scrollableDiv])
|
|
39
|
-
|
|
40
|
-
const handlePreviousPage = useCallback(() => {
|
|
41
|
-
setCurrentPage(prev => Math.max(0, prev - 1))
|
|
42
|
-
}, [])
|
|
43
|
-
|
|
44
|
-
const handleNextPage = useCallback(() => {
|
|
45
|
-
setCurrentPage(prev => Math.min(totalPages - 1, prev + 1))
|
|
46
|
-
}, [totalPages])
|
|
47
|
-
|
|
48
|
-
const handleClearEvents = useCallback(() => {
|
|
49
|
-
setCurrentPage(0)
|
|
50
|
-
onClearEvents?.()
|
|
51
|
-
}, [onClearEvents])
|
|
52
|
-
|
|
53
|
-
// Compatible with TablePagination's onPageChange signature
|
|
54
|
-
// Accepts 1-indexed page, converts to 0-indexed internally
|
|
55
|
-
const handlePageChange = useCallback((_event: ChangeEvent<unknown>, page: number) => {
|
|
56
|
-
setCurrentPage(page - 1)
|
|
57
|
-
}, [])
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
allEventEntries,
|
|
61
|
-
visibleEvents,
|
|
62
|
-
effectiveCurrentPage: effectiveCurrentPage + 1, // Return 1-indexed page
|
|
63
|
-
totalPages,
|
|
64
|
-
handlePreviousPage,
|
|
65
|
-
handleNextPage,
|
|
66
|
-
handleClearEvents,
|
|
67
|
-
handlePageChange,
|
|
68
|
-
}
|
|
69
|
-
}
|
package/src/components/index.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { AvatarProps } from '@mui/material'
|
|
2
|
-
import { Avatar } from '@mui/material'
|
|
3
|
-
import type { CSSProperties } from 'react'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { useChainNetwork } from '../../context/index.ts'
|
|
7
|
-
import { NetworkIcon } from './Icon.tsx'
|
|
8
|
-
|
|
9
|
-
export interface NetworkAvatarProps extends AvatarProps {
|
|
10
|
-
icon?: string
|
|
11
|
-
iconStyles?: CSSProperties
|
|
12
|
-
name?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const NetworkAvatar: React.FC<NetworkAvatarProps> = ({
|
|
16
|
-
icon, iconStyles, name, sx, ...props
|
|
17
|
-
}) => {
|
|
18
|
-
return (
|
|
19
|
-
<Avatar
|
|
20
|
-
sx={{ backgroundColor: 'white', ...sx }}
|
|
21
|
-
alt={name}
|
|
22
|
-
{...props}
|
|
23
|
-
>
|
|
24
|
-
<NetworkIcon
|
|
25
|
-
icon={icon}
|
|
26
|
-
style={{ ...iconStyles }}
|
|
27
|
-
/>
|
|
28
|
-
</Avatar>
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const ActiveNetworkAvatar: React.FC<AvatarProps> = (props) => {
|
|
33
|
-
const { activeNetwork } = useChainNetwork()
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<NetworkAvatar
|
|
37
|
-
icon={activeNetwork?.icon}
|
|
38
|
-
name={activeNetwork?.name}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { DetailedHTMLProps, HtmlHTMLAttributes } from 'react'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
export interface NetworkIconProps extends DetailedHTMLProps<HtmlHTMLAttributes<HTMLSpanElement>, HTMLSpanElement> {
|
|
5
|
-
icon?: string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const NetworkIcon: React.FC<NetworkIconProps> = ({
|
|
9
|
-
icon, style, ...props
|
|
10
|
-
}) => {
|
|
11
|
-
return (
|
|
12
|
-
<span
|
|
13
|
-
// eslint-disable-next-line react-dom/no-dangerously-set-innerhtml
|
|
14
|
-
dangerouslySetInnerHTML={{ __html: icon ?? '' }} // Placeholder for SVG\
|
|
15
|
-
style={{
|
|
16
|
-
display: 'inline-flex', width: 24, height: 24, ...style,
|
|
17
|
-
}}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
)
|
|
21
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { MenuItemProps } from '@mui/material'
|
|
2
|
-
import { ListItemText } from '@mui/material'
|
|
3
|
-
import { ActiveMenuItem } from '@xyo-network/react-chain-shared'
|
|
4
|
-
import type { NetworkBootstrap, NetworkId } from '@xyo-network/xl1-sdk'
|
|
5
|
-
import type { MouseEvent as ReactMouseEvent } from 'react'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
|
|
8
|
-
import { NetworkAvatar } from './Avatar.tsx'
|
|
9
|
-
|
|
10
|
-
export interface NetworkMenuItemProps extends MenuItemProps {
|
|
11
|
-
active?: boolean
|
|
12
|
-
network?: NetworkBootstrap
|
|
13
|
-
updateActiveNetwork?: (networkId: NetworkId) => void
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const NetworkMenuItem: React.FC<NetworkMenuItemProps> = ({
|
|
17
|
-
active, network, onClick, updateActiveNetwork, ...props
|
|
18
|
-
}) => {
|
|
19
|
-
const handleClick = (event: ReactMouseEvent<HTMLLIElement, MouseEvent>) => {
|
|
20
|
-
if (network === undefined) throw new Error('Network is undefined')
|
|
21
|
-
updateActiveNetwork?.(network.id)
|
|
22
|
-
onClick?.(event)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<ActiveMenuItem
|
|
27
|
-
title={network?.name}
|
|
28
|
-
disableRipple
|
|
29
|
-
onClick={handleClick}
|
|
30
|
-
active={active}
|
|
31
|
-
sx={{ py: 1 }}
|
|
32
|
-
{...props}
|
|
33
|
-
>
|
|
34
|
-
<NetworkAvatar icon={network?.icon} name={network?.name} sx={{ width: 30, height: 30 }} />
|
|
35
|
-
<ListItemText>{network?.name}</ListItemText>
|
|
36
|
-
</ActiveMenuItem>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
-
import type { NetworkStatus } from '@xyo-network/xl1-sdk'
|
|
3
|
-
import { NetworkStatusSchema } from '@xyo-network/xl1-sdk'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { NetworkStatusAlert } from './Alert.tsx'
|
|
7
|
-
|
|
8
|
-
const exampleOnlineStatus: NetworkStatus = {
|
|
9
|
-
state: 'online',
|
|
10
|
-
schema: NetworkStatusSchema,
|
|
11
|
-
description: 'The network is online and functioning normally.',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const exampleOfflineStatus: NetworkStatus = {
|
|
15
|
-
state: 'offline',
|
|
16
|
-
schema: NetworkStatusSchema,
|
|
17
|
-
description: 'The network is offline and not functioning.',
|
|
18
|
-
updates: [
|
|
19
|
-
{
|
|
20
|
-
start: Date.now() - 1000 * 60 * 60,
|
|
21
|
-
end: Date.now(),
|
|
22
|
-
update: 'The network was offline for 1 hour.',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
}
|
|
26
|
-
const exampleUnknown: NetworkStatus = {
|
|
27
|
-
state: 'unknown',
|
|
28
|
-
schema: NetworkStatusSchema,
|
|
29
|
-
description: 'Unable to fetch network status.',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const exampleDegradedStatus: NetworkStatus = {
|
|
33
|
-
state: 'degraded',
|
|
34
|
-
schema: NetworkStatusSchema,
|
|
35
|
-
description: 'The network is degraded and may be experiencing issues.',
|
|
36
|
-
updates: [
|
|
37
|
-
{
|
|
38
|
-
start: Date.now() - 1000 * 60 * 60,
|
|
39
|
-
end: Date.now(),
|
|
40
|
-
update: 'Blocks are being produced, but some nodes are offline.',
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
start: Date.now() - 1000 * 60 * 60,
|
|
44
|
-
end: Date.now(),
|
|
45
|
-
update: 'Blocks are being produced, but some nodes are offline.',
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export default {
|
|
51
|
-
title: 'Network/Status/Alert',
|
|
52
|
-
component: NetworkStatusAlert,
|
|
53
|
-
} as Meta
|
|
54
|
-
|
|
55
|
-
const Template: StoryFn<typeof NetworkStatusAlert> = args => <NetworkStatusAlert {...args} />
|
|
56
|
-
|
|
57
|
-
const Default = Template.bind({})
|
|
58
|
-
Default.args = {}
|
|
59
|
-
|
|
60
|
-
const WithOnlineStatus = Template.bind({})
|
|
61
|
-
WithOnlineStatus.args = { status: exampleOnlineStatus }
|
|
62
|
-
|
|
63
|
-
const WithOfflineStatus = Template.bind({})
|
|
64
|
-
WithOfflineStatus.args = { status: exampleOfflineStatus }
|
|
65
|
-
|
|
66
|
-
const WithDegradedStatus = Template.bind({})
|
|
67
|
-
WithDegradedStatus.args = { status: exampleDegradedStatus }
|
|
68
|
-
|
|
69
|
-
const WithUnknownStatus = Template.bind({})
|
|
70
|
-
WithUnknownStatus.args = { status: exampleUnknown }
|
|
71
|
-
|
|
72
|
-
export {
|
|
73
|
-
Default, WithDegradedStatus, WithOfflineStatus, WithOnlineStatus, WithUnknownStatus,
|
|
74
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { AlertProps } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
Alert, AlertTitle, Button,
|
|
4
|
-
} from '@mui/material'
|
|
5
|
-
import type { NetworkStatus } from '@xyo-network/xl1-sdk'
|
|
6
|
-
import React, { useMemo, useState } from 'react'
|
|
7
|
-
|
|
8
|
-
import { NetworkStatusDialog } from './Dialog.tsx'
|
|
9
|
-
|
|
10
|
-
export interface NetworkStatusAlertProps extends AlertProps {
|
|
11
|
-
status?: NetworkStatus
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const NetworkStatusAlert: React.FC<NetworkStatusAlertProps> = ({ status, ...props }) => {
|
|
15
|
-
const [open, setOpen] = useState(false)
|
|
16
|
-
const handleClose = () => setOpen(false)
|
|
17
|
-
|
|
18
|
-
const severity = useMemo(() => {
|
|
19
|
-
if (!status) return
|
|
20
|
-
switch (status.state) {
|
|
21
|
-
case 'online': {
|
|
22
|
-
return 'success'
|
|
23
|
-
}
|
|
24
|
-
case 'offline': {
|
|
25
|
-
return 'error'
|
|
26
|
-
}
|
|
27
|
-
case 'degraded': {
|
|
28
|
-
return 'warning'
|
|
29
|
-
}
|
|
30
|
-
case 'unknown': {
|
|
31
|
-
return 'error'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}, [status])
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<Alert severity={severity} {...props}>
|
|
38
|
-
<AlertTitle>{status?.description}</AlertTitle>
|
|
39
|
-
{status?.updates && status.updates.length > 0
|
|
40
|
-
? (
|
|
41
|
-
<>
|
|
42
|
-
<Button color={severity} variant="outlined" size="small" onClick={() => setOpen(true)}>
|
|
43
|
-
Updates
|
|
44
|
-
</Button>
|
|
45
|
-
<NetworkStatusDialog open={open} onClose={handleClose} updates={status.updates} />
|
|
46
|
-
</>
|
|
47
|
-
)
|
|
48
|
-
: null}
|
|
49
|
-
</Alert>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { DialogProps } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
Button, Dialog, DialogActions, DialogContent, DialogTitle, List, ListItem, Typography,
|
|
4
|
-
} from '@mui/material'
|
|
5
|
-
import type { NetworkStatusUpdate } from '@xyo-network/xl1-sdk'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
|
|
8
|
-
export interface NetworkStatusDialogProps extends DialogProps {
|
|
9
|
-
updates: NetworkStatusUpdate[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const NetworkStatusDialog: React.FC<NetworkStatusDialogProps> = ({ updates, ...props }) => {
|
|
13
|
-
return (
|
|
14
|
-
<Dialog {...props}>
|
|
15
|
-
<DialogTitle>Recent Status Updates</DialogTitle>
|
|
16
|
-
<DialogContent>
|
|
17
|
-
<List>
|
|
18
|
-
{updates.map(({
|
|
19
|
-
start, end, update,
|
|
20
|
-
}) => (
|
|
21
|
-
<ListItem
|
|
22
|
-
key={start + update}
|
|
23
|
-
sx={{
|
|
24
|
-
flexDirection: 'column', alignItems: 'start', pl: 0,
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
27
|
-
<Typography>
|
|
28
|
-
{update}
|
|
29
|
-
</Typography>
|
|
30
|
-
<Typography gutterBottom sx={{ opacity: 0.75, fontSize: '.8333rem' }}>
|
|
31
|
-
Start:
|
|
32
|
-
{' '}
|
|
33
|
-
{new Date(start).toLocaleString()}
|
|
34
|
-
{' '}
|
|
35
|
-
<br />
|
|
36
|
-
End:
|
|
37
|
-
{' '}
|
|
38
|
-
{new Date(end).toLocaleString()}
|
|
39
|
-
</Typography>
|
|
40
|
-
</ListItem>
|
|
41
|
-
))}
|
|
42
|
-
</List>
|
|
43
|
-
</DialogContent>
|
|
44
|
-
<DialogActions>
|
|
45
|
-
<Button onClick={e => props.onClose?.(e, 'backdropClick')} color="primary" variant="outlined">
|
|
46
|
-
Close
|
|
47
|
-
</Button>
|
|
48
|
-
</DialogActions>
|
|
49
|
-
</Dialog>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AlertProps } from '@mui/material'
|
|
2
|
-
import type { PropsWithChildren } from 'react'
|
|
3
|
-
import React from 'react'
|
|
4
|
-
|
|
5
|
-
import { usePollNetworkStatus } from '../../hooks/index.ts'
|
|
6
|
-
import { NetworkStatusAlert } from './Alert.tsx'
|
|
7
|
-
|
|
8
|
-
const validNetworkStates = new Set(['online', 'unknown'])
|
|
9
|
-
|
|
10
|
-
export interface NetworkStatusProps extends PropsWithChildren<AlertProps> {}
|
|
11
|
-
|
|
12
|
-
export const NetworkStatus: React.FC<NetworkStatusProps> = ({ children, ...props }) => {
|
|
13
|
-
const [networkStatus] = usePollNetworkStatus()
|
|
14
|
-
const showStatus = networkStatus && !validNetworkStates.has(networkStatus.state)
|
|
15
|
-
return (
|
|
16
|
-
<>
|
|
17
|
-
{showStatus ? <NetworkStatusAlert status={networkStatus} {...props} /> : null}
|
|
18
|
-
{children}
|
|
19
|
-
</>
|
|
20
|
-
)
|
|
21
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { GatewayProvider, InPageGatewaysProvider } from '@xyo-network/react-chain-provider'
|
|
2
|
-
import type { AccountInstance } from '@xyo-network/sdk-js'
|
|
3
|
-
import type { PropsWithChildren } from 'react'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { useChainNetwork } from './network/index.ts'
|
|
7
|
-
|
|
8
|
-
export interface ActiveGatewayProviderProps extends PropsWithChildren {
|
|
9
|
-
account?: AccountInstance
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const ActiveGatewayProvider: React.FC<ActiveGatewayProviderProps> = ({ account, children }) => {
|
|
13
|
-
const { activeNetwork } = useChainNetwork()
|
|
14
|
-
return (
|
|
15
|
-
<InPageGatewaysProvider account={account}>
|
|
16
|
-
<GatewayProvider gatewayName={activeNetwork?.id}>
|
|
17
|
-
{children}
|
|
18
|
-
</GatewayProvider>
|
|
19
|
-
</InPageGatewaysProvider>
|
|
20
|
-
)
|
|
21
|
-
}
|