@xyo-network/react-api 2.32.0-rc.11
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/LICENSE +165 -0
- package/README.md +70 -0
- package/dist/cjs/components/ApiErrorAlert.d.ts +9 -0
- package/dist/cjs/components/ApiErrorAlert.d.ts.map +1 -0
- package/dist/cjs/components/ApiErrorAlert.js +13 -0
- package/dist/cjs/components/ApiErrorAlert.js.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonApiButton.d.ts +4 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonApiButton.d.ts.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonApiButton.js +15 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonApiButton.js.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonRouteWrapper.d.ts +11 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonRouteWrapper.d.ts.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonRouteWrapper.js +47 -0
- package/dist/cjs/components/JsonRouteWrapper/JsonRouteWrapper.js.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/index.d.ts +3 -0
- package/dist/cjs/components/JsonRouteWrapper/index.d.ts.map +1 -0
- package/dist/cjs/components/JsonRouteWrapper/index.js +6 -0
- package/dist/cjs/components/JsonRouteWrapper/index.js.map +1 -0
- package/dist/cjs/components/ResultLoader.d.ts +9 -0
- package/dist/cjs/components/ResultLoader.d.ts.map +1 -0
- package/dist/cjs/components/ResultLoader.js +24 -0
- package/dist/cjs/components/ResultLoader.js.map +1 -0
- package/dist/cjs/components/index.d.ts +4 -0
- package/dist/cjs/components/index.d.ts.map +1 -0
- package/dist/cjs/components/index.js +7 -0
- package/dist/cjs/components/index.js.map +1 -0
- package/dist/cjs/hooks/ResolvePayloadArgs.d.ts +5 -0
- package/dist/cjs/hooks/ResolvePayloadArgs.d.ts.map +1 -0
- package/dist/cjs/hooks/ResolvePayloadArgs.js +3 -0
- package/dist/cjs/hooks/ResolvePayloadArgs.js.map +1 -0
- package/dist/cjs/hooks/index.d.ts +6 -0
- package/dist/cjs/hooks/index.d.ts.map +1 -0
- package/dist/cjs/hooks/index.js +9 -0
- package/dist/cjs/hooks/index.js.map +1 -0
- package/dist/cjs/hooks/lib/FetchHuriHashOptions.d.ts +4 -0
- package/dist/cjs/hooks/lib/FetchHuriHashOptions.d.ts.map +1 -0
- package/dist/cjs/hooks/lib/FetchHuriHashOptions.js +3 -0
- package/dist/cjs/hooks/lib/FetchHuriHashOptions.js.map +1 -0
- package/dist/cjs/hooks/lib/findHuriNetwork.d.ts +4 -0
- package/dist/cjs/hooks/lib/findHuriNetwork.d.ts.map +1 -0
- package/dist/cjs/hooks/lib/findHuriNetwork.js +14 -0
- package/dist/cjs/hooks/lib/findHuriNetwork.js.map +1 -0
- package/dist/cjs/hooks/lib/index.d.ts +3 -0
- package/dist/cjs/hooks/lib/index.d.ts.map +1 -0
- package/dist/cjs/hooks/lib/index.js +6 -0
- package/dist/cjs/hooks/lib/index.js.map +1 -0
- package/dist/cjs/hooks/useHuriHash.d.ts +13 -0
- package/dist/cjs/hooks/useHuriHash.d.ts.map +1 -0
- package/dist/cjs/hooks/useHuriHash.js +33 -0
- package/dist/cjs/hooks/useHuriHash.js.map +1 -0
- package/dist/cjs/hooks/useLoadPayload.d.ts +3 -0
- package/dist/cjs/hooks/useLoadPayload.d.ts.map +1 -0
- package/dist/cjs/hooks/useLoadPayload.js +57 -0
- package/dist/cjs/hooks/useLoadPayload.js.map +1 -0
- package/dist/cjs/hooks/useResolveHuri.d.ts +10 -0
- package/dist/cjs/hooks/useResolveHuri.d.ts.map +1 -0
- package/dist/cjs/hooks/useResolveHuri.js +68 -0
- package/dist/cjs/hooks/useResolveHuri.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/docs.json +19042 -0
- package/dist/esm/components/ApiErrorAlert.d.ts +9 -0
- package/dist/esm/components/ApiErrorAlert.d.ts.map +1 -0
- package/dist/esm/components/ApiErrorAlert.js +7 -0
- package/dist/esm/components/ApiErrorAlert.js.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/JsonApiButton.d.ts +4 -0
- package/dist/esm/components/JsonRouteWrapper/JsonApiButton.d.ts.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/JsonApiButton.js +11 -0
- package/dist/esm/components/JsonRouteWrapper/JsonApiButton.js.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/JsonRouteWrapper.d.ts +11 -0
- package/dist/esm/components/JsonRouteWrapper/JsonRouteWrapper.d.ts.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/JsonRouteWrapper.js +41 -0
- package/dist/esm/components/JsonRouteWrapper/JsonRouteWrapper.js.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/index.d.ts +3 -0
- package/dist/esm/components/JsonRouteWrapper/index.d.ts.map +1 -0
- package/dist/esm/components/JsonRouteWrapper/index.js +3 -0
- package/dist/esm/components/JsonRouteWrapper/index.js.map +1 -0
- package/dist/esm/components/ResultLoader.d.ts +9 -0
- package/dist/esm/components/ResultLoader.d.ts.map +1 -0
- package/dist/esm/components/ResultLoader.js +20 -0
- package/dist/esm/components/ResultLoader.js.map +1 -0
- package/dist/esm/components/index.d.ts +4 -0
- package/dist/esm/components/index.d.ts.map +1 -0
- package/dist/esm/components/index.js +4 -0
- package/dist/esm/components/index.js.map +1 -0
- package/dist/esm/hooks/ResolvePayloadArgs.d.ts +5 -0
- package/dist/esm/hooks/ResolvePayloadArgs.d.ts.map +1 -0
- package/dist/esm/hooks/ResolvePayloadArgs.js +2 -0
- package/dist/esm/hooks/ResolvePayloadArgs.js.map +1 -0
- package/dist/esm/hooks/index.d.ts +6 -0
- package/dist/esm/hooks/index.d.ts.map +1 -0
- package/dist/esm/hooks/index.js +6 -0
- package/dist/esm/hooks/index.js.map +1 -0
- package/dist/esm/hooks/lib/FetchHuriHashOptions.d.ts +4 -0
- package/dist/esm/hooks/lib/FetchHuriHashOptions.d.ts.map +1 -0
- package/dist/esm/hooks/lib/FetchHuriHashOptions.js +2 -0
- package/dist/esm/hooks/lib/FetchHuriHashOptions.js.map +1 -0
- package/dist/esm/hooks/lib/findHuriNetwork.d.ts +4 -0
- package/dist/esm/hooks/lib/findHuriNetwork.d.ts.map +1 -0
- package/dist/esm/hooks/lib/findHuriNetwork.js +9 -0
- package/dist/esm/hooks/lib/findHuriNetwork.js.map +1 -0
- package/dist/esm/hooks/lib/index.d.ts +3 -0
- package/dist/esm/hooks/lib/index.d.ts.map +1 -0
- package/dist/esm/hooks/lib/index.js +3 -0
- package/dist/esm/hooks/lib/index.js.map +1 -0
- package/dist/esm/hooks/useHuriHash.d.ts +13 -0
- package/dist/esm/hooks/useHuriHash.d.ts.map +1 -0
- package/dist/esm/hooks/useHuriHash.js +30 -0
- package/dist/esm/hooks/useHuriHash.js.map +1 -0
- package/dist/esm/hooks/useLoadPayload.d.ts +3 -0
- package/dist/esm/hooks/useLoadPayload.d.ts.map +1 -0
- package/dist/esm/hooks/useLoadPayload.js +52 -0
- package/dist/esm/hooks/useLoadPayload.js.map +1 -0
- package/dist/esm/hooks/useResolveHuri.d.ts +10 -0
- package/dist/esm/hooks/useResolveHuri.d.ts.map +1 -0
- package/dist/esm/hooks/useResolveHuri.js +64 -0
- package/dist/esm/hooks/useResolveHuri.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +80 -0
- package/src/components/ApiErrorAlert.tsx +21 -0
- package/src/components/JsonRouteWrapper/JsonApiButton.tsx +19 -0
- package/src/components/JsonRouteWrapper/JsonRouteWrapper.stories.tsx +68 -0
- package/src/components/JsonRouteWrapper/JsonRouteWrapper.tsx +85 -0
- package/src/components/JsonRouteWrapper/index.ts +2 -0
- package/src/components/ResultLoader.stories.tsx +37 -0
- package/src/components/ResultLoader.tsx +26 -0
- package/src/components/index.ts +3 -0
- package/src/hooks/ResolvePayloadArgs.ts +6 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/lib/FetchHuriHashOptions.ts +3 -0
- package/src/hooks/lib/findHuriNetwork.ts +13 -0
- package/src/hooks/lib/index.ts +2 -0
- package/src/hooks/useHuriHash.stories.tsx +108 -0
- package/src/hooks/useHuriHash.tsx +40 -0
- package/src/hooks/useLoadPayload.stories.tsx +69 -0
- package/src/hooks/useLoadPayload.tsx +59 -0
- package/src/hooks/useResolveHuri.tsx +75 -0
- package/src/index.ts +1 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
import { Alert, AlertProps, AlertTitle, Typography } from '@mui/material'
|
2
|
+
import { XyoApiError } from '@xyo-network/api'
|
3
|
+
|
4
|
+
export interface ApiErrorAlertProps extends AlertProps {
|
5
|
+
call?: XyoApiError
|
6
|
+
}
|
7
|
+
|
8
|
+
const ApiErrorAlert: React.FC<ApiErrorAlertProps> = ({ call, ...props }) => {
|
9
|
+
return (
|
10
|
+
<Alert severity="error" {...props}>
|
11
|
+
<AlertTitle>Whoops! Something went wrong</AlertTitle>
|
12
|
+
<Typography sx={{ wordBreak: 'break-all' }}>{call?.config?.url}</Typography>
|
13
|
+
<Typography variant="caption" mr={0.5} fontWeight="bold">
|
14
|
+
Error:
|
15
|
+
</Typography>
|
16
|
+
<Typography variant="caption">{call?.message}</Typography>
|
17
|
+
</Alert>
|
18
|
+
)
|
19
|
+
}
|
20
|
+
|
21
|
+
export { ApiErrorAlert }
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { ButtonEx, ButtonExProps } from '@xylabs/react-button'
|
2
|
+
import { useSearchParams } from 'react-router-dom'
|
3
|
+
|
4
|
+
export const JsonApiButton: React.FC<ButtonExProps> = (props) => {
|
5
|
+
const [searchParams, setSearchParams] = useSearchParams()
|
6
|
+
return (
|
7
|
+
<ButtonEx
|
8
|
+
marginX={2}
|
9
|
+
variant="outlined"
|
10
|
+
onClick={() => {
|
11
|
+
searchParams.set('json', 'true')
|
12
|
+
setSearchParams(searchParams)
|
13
|
+
}}
|
14
|
+
{...props}
|
15
|
+
>
|
16
|
+
JSON
|
17
|
+
</ButtonEx>
|
18
|
+
)
|
19
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import { ComponentMeta, ComponentStory, DecoratorFn } from '@storybook/react'
|
2
|
+
import { ButtonEx } from '@xylabs/react-button'
|
3
|
+
import { FlexCol } from '@xylabs/react-flexbox'
|
4
|
+
import { XyoArchivistApi } from '@xyo-network/api'
|
5
|
+
import { BrowserRouter, useSearchParams } from 'react-router-dom'
|
6
|
+
|
7
|
+
import { JsonRouteWrapper } from './JsonRouteWrapper'
|
8
|
+
|
9
|
+
const JsonDecorator: DecoratorFn = (Story) => (
|
10
|
+
<BrowserRouter>
|
11
|
+
<Story />
|
12
|
+
</BrowserRouter>
|
13
|
+
)
|
14
|
+
|
15
|
+
const StorybookEntry = {
|
16
|
+
argTypes: {
|
17
|
+
apiDomain: 'https://beta.api.archivist.xyo.network',
|
18
|
+
},
|
19
|
+
component: JsonRouteWrapper,
|
20
|
+
decorators: [JsonDecorator],
|
21
|
+
parameters: {
|
22
|
+
docs: {
|
23
|
+
page: null,
|
24
|
+
},
|
25
|
+
},
|
26
|
+
title: 'shared/JsonRouteWrapper',
|
27
|
+
} as ComponentMeta<typeof JsonRouteWrapper>
|
28
|
+
|
29
|
+
const Template: ComponentStory<typeof JsonRouteWrapper> = (props) => {
|
30
|
+
const [searchParams, setSearchParams] = useSearchParams()
|
31
|
+
const activeJson = searchParams.get('json')
|
32
|
+
return (
|
33
|
+
<FlexCol>
|
34
|
+
<ButtonEx
|
35
|
+
marginY={3}
|
36
|
+
onClick={() => {
|
37
|
+
activeJson === 'true' ? searchParams.delete('json') : searchParams.set('json', 'true')
|
38
|
+
setSearchParams(searchParams)
|
39
|
+
}}
|
40
|
+
variant="outlined"
|
41
|
+
>
|
42
|
+
Toggle JSON Page
|
43
|
+
</ButtonEx>
|
44
|
+
<JsonRouteWrapper {...props}></JsonRouteWrapper>
|
45
|
+
</FlexCol>
|
46
|
+
)
|
47
|
+
}
|
48
|
+
|
49
|
+
const Default = Template.bind({})
|
50
|
+
Default.args = {
|
51
|
+
callback: () => new XyoArchivistApi({ apiDomain: 'https://beta.api.archivist.xyo.network' }).archive('temp').block.stats.get(),
|
52
|
+
}
|
53
|
+
|
54
|
+
const HideBackButton = Template.bind({})
|
55
|
+
HideBackButton.args = {
|
56
|
+
callback: () =>
|
57
|
+
new XyoArchivistApi({
|
58
|
+
apiDomain: 'https://beta.api.archivist.xyo.network',
|
59
|
+
})
|
60
|
+
.archive('temp')
|
61
|
+
.block.stats.get(),
|
62
|
+
noBackButton: true,
|
63
|
+
}
|
64
|
+
|
65
|
+
export { Default, HideBackButton }
|
66
|
+
|
67
|
+
// eslint-disable-next-line import/no-default-export
|
68
|
+
export default StorybookEntry
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import { ButtonEx } from '@xylabs/react-button'
|
2
|
+
import { ErrorDialog } from '@xylabs/react-dialogs'
|
3
|
+
import { FlexBoxProps, FlexCol, FlexRow } from '@xylabs/react-flexbox'
|
4
|
+
import { useAsyncEffect } from '@xylabs/react-shared'
|
5
|
+
import { XyoApiError } from '@xyo-network/api'
|
6
|
+
import { lazy, Suspense, useState } from 'react'
|
7
|
+
import { ReactJsonViewProps } from 'react-json-view'
|
8
|
+
import { useSearchParams } from 'react-router-dom'
|
9
|
+
|
10
|
+
import { JsonApiButton } from './JsonApiButton'
|
11
|
+
|
12
|
+
const JsonView = lazy(() => import(/* webpackChunkName: "jsonView" */ 'react-json-view'))
|
13
|
+
|
14
|
+
export interface JsonFromPromiseProps extends FlexBoxProps {
|
15
|
+
callback: () => Promise<object | undefined>
|
16
|
+
noBackButton?: boolean
|
17
|
+
noJsonButton?: boolean
|
18
|
+
jsonViewProps?: ReactJsonViewProps
|
19
|
+
}
|
20
|
+
|
21
|
+
export const JsonRouteWrapper: React.FC<JsonFromPromiseProps> = ({
|
22
|
+
callback,
|
23
|
+
children,
|
24
|
+
noBackButton = false,
|
25
|
+
noJsonButton = false,
|
26
|
+
jsonViewProps,
|
27
|
+
...props
|
28
|
+
}) => {
|
29
|
+
const [apiResponse, setApiResponse] = useState<object>()
|
30
|
+
const [apiError, setApiError] = useState<XyoApiError>()
|
31
|
+
const [searchParams, setSearchParams] = useSearchParams()
|
32
|
+
const active = !!searchParams.get('json')
|
33
|
+
|
34
|
+
useAsyncEffect(
|
35
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
36
|
+
async (mounted) => {
|
37
|
+
try {
|
38
|
+
const response = await callback()
|
39
|
+
if (mounted()) {
|
40
|
+
setApiResponse(response)
|
41
|
+
}
|
42
|
+
} catch (ex) {
|
43
|
+
if (mounted()) {
|
44
|
+
const error = ex as XyoApiError
|
45
|
+
if (error.isXyoError) {
|
46
|
+
setApiError(error)
|
47
|
+
} else {
|
48
|
+
throw ex
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
},
|
53
|
+
[callback],
|
54
|
+
)
|
55
|
+
|
56
|
+
return (
|
57
|
+
<FlexCol {...props}>
|
58
|
+
{active ? (
|
59
|
+
<>
|
60
|
+
<Suspense fallback={null}>{apiResponse && <JsonView src={apiResponse} collapseStringsAfterLength={64} {...jsonViewProps} />}</Suspense>
|
61
|
+
{!noBackButton && (
|
62
|
+
<FlexRow marginY={3}>
|
63
|
+
<ButtonEx
|
64
|
+
flexDirection="row"
|
65
|
+
variant="outlined"
|
66
|
+
onClick={() => {
|
67
|
+
searchParams.delete('json')
|
68
|
+
setSearchParams(searchParams)
|
69
|
+
}}
|
70
|
+
>
|
71
|
+
Back
|
72
|
+
</ButtonEx>
|
73
|
+
</FlexRow>
|
74
|
+
)}
|
75
|
+
<ErrorDialog title="Error Fetching JSON" error={apiError} open={!!apiError} onAction={() => setApiError(undefined)} />
|
76
|
+
</>
|
77
|
+
) : (
|
78
|
+
<>
|
79
|
+
{children}
|
80
|
+
{!noJsonButton && <JsonApiButton marginTop={2} />}
|
81
|
+
</>
|
82
|
+
)}
|
83
|
+
</FlexCol>
|
84
|
+
)
|
85
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
/* eslint-disable import/no-internal-modules */
|
2
|
+
import { ComponentStory, Meta } from '@storybook/react'
|
3
|
+
import { AxiosError } from 'axios'
|
4
|
+
|
5
|
+
import { ResultLoader } from './ResultLoader'
|
6
|
+
|
7
|
+
const StorybookEntry: Meta = {
|
8
|
+
argTypes: {},
|
9
|
+
component: ResultLoader,
|
10
|
+
parameters: {
|
11
|
+
docs: {
|
12
|
+
page: null,
|
13
|
+
},
|
14
|
+
},
|
15
|
+
title: 'webapp/ResultLoader',
|
16
|
+
}
|
17
|
+
|
18
|
+
const Template: ComponentStory<typeof ResultLoader> = (props) => {
|
19
|
+
return <ResultLoader {...props} />
|
20
|
+
}
|
21
|
+
|
22
|
+
const Default = Template.bind({})
|
23
|
+
Default.args = {}
|
24
|
+
|
25
|
+
const NotFound = Template.bind({})
|
26
|
+
NotFound.args = { notFound: true }
|
27
|
+
|
28
|
+
const ApiError = Template.bind({})
|
29
|
+
ApiError.args = { apiError: new AxiosError(), children: <h1>Shown in case of error</h1> }
|
30
|
+
|
31
|
+
const SearchResult = Template.bind({})
|
32
|
+
SearchResult.args = { children: <h1>Shown when there is a valid result</h1>, searchResult: 'foo' }
|
33
|
+
|
34
|
+
export { ApiError, Default, NotFound, SearchResult }
|
35
|
+
|
36
|
+
// eslint-disable-next-line import/no-default-export
|
37
|
+
export default StorybookEntry
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { FlexGrowRow } from '@xylabs/react-flexbox'
|
2
|
+
import { XyoApiError } from '@xyo-network/api'
|
3
|
+
import { NotFound } from '@xyo-network/react-shared'
|
4
|
+
import { PropsWithChildren } from 'react'
|
5
|
+
|
6
|
+
export interface HandleItemDetailLoadingProps<T> {
|
7
|
+
apiError: Error | XyoApiError | undefined
|
8
|
+
notFound: boolean
|
9
|
+
searchResult: T | undefined
|
10
|
+
}
|
11
|
+
|
12
|
+
export function ResultLoader<T>(props: PropsWithChildren<HandleItemDetailLoadingProps<T>>) {
|
13
|
+
const { notFound, apiError, searchResult, children } = props
|
14
|
+
if (notFound) {
|
15
|
+
return <NotFound />
|
16
|
+
}
|
17
|
+
// Defer error handling to the children
|
18
|
+
if (apiError) {
|
19
|
+
return <>{children}</>
|
20
|
+
}
|
21
|
+
if (searchResult === undefined) {
|
22
|
+
return <FlexGrowRow busy minHeight="50px" />
|
23
|
+
} else {
|
24
|
+
return <>{children}</>
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { XyoNetworkPayload } from '@xyo-network/network'
|
2
|
+
import { Huri } from '@xyo-network/payload'
|
3
|
+
|
4
|
+
export const findHuriNetwork = (huriInstance: Huri, networks?: XyoNetworkPayload[]) => {
|
5
|
+
// see if huri archivist matches any archivist in the network configs
|
6
|
+
return networks
|
7
|
+
?.filter((network) =>
|
8
|
+
network.nodes?.find((node) => {
|
9
|
+
return node.type === 'archivist' && new URL(node.uri).hostname === huriInstance.archivist
|
10
|
+
}),
|
11
|
+
)
|
12
|
+
.shift()
|
13
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
/* eslint-disable import/no-internal-modules */
|
2
|
+
import { Alert, Typography } from '@mui/material'
|
3
|
+
import { ComponentStory, Meta } from '@storybook/react'
|
4
|
+
import { ButtonEx } from '@xylabs/react-button'
|
5
|
+
import { FlexCol, FlexRow } from '@xylabs/react-flexbox'
|
6
|
+
import { Huri } from '@xyo-network/payload'
|
7
|
+
import { ArchivistApiProvider } from '@xyo-network/react-archivist-api'
|
8
|
+
import { NetworkMemoryProvider } from '@xyo-network/react-network'
|
9
|
+
import { XyoSchemaCache } from '@xyo-network/utils'
|
10
|
+
import { lazy, Suspense, useState } from 'react'
|
11
|
+
|
12
|
+
import { FetchHuriHashOptions } from './lib'
|
13
|
+
import { useHuriHash } from './useHuriHash'
|
14
|
+
|
15
|
+
const JsonView = lazy(() => import(/* webpackChunkName: "jsonView" */ 'react-json-view'))
|
16
|
+
|
17
|
+
interface UseHuriHashComponentProps {
|
18
|
+
huriOrHash: string | Huri
|
19
|
+
huriUri?: string
|
20
|
+
options?: FetchHuriHashOptions
|
21
|
+
reTestable?: boolean
|
22
|
+
}
|
23
|
+
|
24
|
+
const apiDomain = 'https://beta.api.archivist.xyo.network'
|
25
|
+
const hash = '5605fabad11b10bb5fb86b309ca0970894eda8f22362dda1a489817723bca992'
|
26
|
+
XyoSchemaCache.instance.proxy = `${apiDomain}/domain`
|
27
|
+
|
28
|
+
const mainApiDomain = 'https://api.archivist.xyo.network'
|
29
|
+
const mainHash = 'd3a3936e31ba1d835c528784ab77c1eaaeedd6e16b7aad68a88241ce539853cb'
|
30
|
+
|
31
|
+
const Wrapper: React.FC<UseHuriHashComponentProps> = (props) => (
|
32
|
+
<NetworkMemoryProvider>
|
33
|
+
<ArchivistApiProvider apiDomain={apiDomain}>
|
34
|
+
<UseHuriHashComponent {...props} />
|
35
|
+
</ArchivistApiProvider>
|
36
|
+
</NetworkMemoryProvider>
|
37
|
+
)
|
38
|
+
|
39
|
+
const UseHuriHashComponent: React.FC<UseHuriHashComponentProps> = ({ huriOrHash, huriUri, options, reTestable }) => {
|
40
|
+
const [trigger, setTrigger] = useState<string | Huri>(huriOrHash)
|
41
|
+
const [payload, notFound, , networkNotFound] = useHuriHash(trigger, huriUri, options)
|
42
|
+
|
43
|
+
return (
|
44
|
+
<>
|
45
|
+
<Typography variant="body1" fontWeight="bold">
|
46
|
+
Fetches the payload for a huriOrHash.
|
47
|
+
</Typography>
|
48
|
+
{reTestable ? (
|
49
|
+
<FlexRow columnGap={2}>
|
50
|
+
<ButtonEx variant="contained" onClick={() => setTrigger(hash)}>
|
51
|
+
Fetch Valid Hash
|
52
|
+
</ButtonEx>
|
53
|
+
<ButtonEx variant="contained" onClick={() => setTrigger('foo')}>
|
54
|
+
Hash Not Found
|
55
|
+
</ButtonEx>
|
56
|
+
</FlexRow>
|
57
|
+
) : null}
|
58
|
+
<FlexCol my={3}>
|
59
|
+
{notFound === undefined && networkNotFound === undefined ? 'Loading...' : null}
|
60
|
+
{notFound ? <Alert severity="warning">Not Found</Alert> : null}
|
61
|
+
{networkNotFound ? <Alert severity="warning">Network Not Found</Alert> : null}
|
62
|
+
<Suspense fallback={<FlexCol busy />}>
|
63
|
+
<JsonView src={payload || {}} />
|
64
|
+
</Suspense>
|
65
|
+
</FlexCol>
|
66
|
+
</>
|
67
|
+
)
|
68
|
+
}
|
69
|
+
|
70
|
+
const StorybookEntry: Meta = {
|
71
|
+
argTypes: {},
|
72
|
+
component: UseHuriHashComponent,
|
73
|
+
parameters: {
|
74
|
+
docs: {
|
75
|
+
page: null,
|
76
|
+
},
|
77
|
+
},
|
78
|
+
title: 'payload/useHuriHash',
|
79
|
+
}
|
80
|
+
|
81
|
+
const Template: ComponentStory<typeof UseHuriHashComponent> = (props) => {
|
82
|
+
return <Wrapper {...props} />
|
83
|
+
}
|
84
|
+
|
85
|
+
const Default = Template.bind({})
|
86
|
+
Default.args = { huriOrHash: hash }
|
87
|
+
|
88
|
+
const NotFound = Template.bind({})
|
89
|
+
NotFound.args = { huriOrHash: 'foo', reTestable: true }
|
90
|
+
|
91
|
+
const WithHuri = Template.bind({})
|
92
|
+
WithHuri.args = { huriOrHash: new Huri(`${apiDomain}/${hash}`) }
|
93
|
+
|
94
|
+
const WithHuriUri = Template.bind({})
|
95
|
+
WithHuriUri.args = { huriUri: `${mainApiDomain}/${mainHash}` }
|
96
|
+
|
97
|
+
const WithHuriUriNetworkNotFound = Template.bind({})
|
98
|
+
WithHuriUriNetworkNotFound.args = { huriUri: `http://badarchivisturl.com/${mainHash}` }
|
99
|
+
|
100
|
+
// Note - story will work correctly once main net return 200 instead of 404 when payloads aren't found
|
101
|
+
// Resolve huriUri when network is different from the current network
|
102
|
+
const WithHuriUriNotFound = Template.bind({})
|
103
|
+
WithHuriUriNotFound.args = { huriUri: `${mainApiDomain}/foo` }
|
104
|
+
|
105
|
+
export { Default, NotFound, WithHuri, WithHuriUri, WithHuriUriNetworkNotFound, WithHuriUriNotFound }
|
106
|
+
|
107
|
+
// eslint-disable-next-line import/no-default-export
|
108
|
+
export default StorybookEntry
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { Huri } from '@xyo-network/payload'
|
2
|
+
import { useCallback } from 'react'
|
3
|
+
|
4
|
+
import { FetchHuriHashOptions } from './lib'
|
5
|
+
import { UseHuriOrHash } from './ResolvePayloadArgs'
|
6
|
+
import { useLoadPayload } from './useLoadPayload'
|
7
|
+
import { useResolveHuri } from './useResolveHuri'
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Resolve a hash or a huri regardless of network
|
11
|
+
*/
|
12
|
+
const useHuriHash = (huriOrHash?: string | Huri, huriUri?: string, options?: FetchHuriHashOptions): UseHuriOrHash => {
|
13
|
+
const hash = useCallback((huriOrHash?: string | Huri) => {
|
14
|
+
if (huriOrHash) {
|
15
|
+
if (typeof huriOrHash === 'string') {
|
16
|
+
return huriOrHash
|
17
|
+
}
|
18
|
+
if (huriOrHash instanceof Huri) {
|
19
|
+
return huriOrHash.hash
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}, [])
|
23
|
+
|
24
|
+
const providedHash = hash(huriOrHash)
|
25
|
+
|
26
|
+
//AT: TODO -> Talk about this pattern
|
27
|
+
|
28
|
+
// Optimistically try to grab the has from the current network and archive
|
29
|
+
const [payload, notFound, apiError] = useLoadPayload(providedHash)
|
30
|
+
|
31
|
+
// if a huriUri was passed, we can safely override the notFound from the hash only query
|
32
|
+
const notFoundOverride = huriUri ? true : notFound
|
33
|
+
|
34
|
+
// If payload isn't found, fallback to the huriUri
|
35
|
+
const [huriPayload, huriPayloadNotFound, huriApiError, networkNotFound] = useResolveHuri(huriUri, notFoundOverride, options)
|
36
|
+
|
37
|
+
return [payload ?? huriPayload, huriPayloadNotFound, apiError ?? huriApiError, networkNotFound]
|
38
|
+
}
|
39
|
+
|
40
|
+
export { useHuriHash }
|
@@ -0,0 +1,69 @@
|
|
1
|
+
/* eslint-disable import/no-internal-modules */
|
2
|
+
import { ComponentStory, Meta } from '@storybook/react'
|
3
|
+
import { ButtonEx } from '@xylabs/react-button'
|
4
|
+
import { FlexCol } from '@xylabs/react-flexbox'
|
5
|
+
import { ArchivistApiProvider, useArchivistApi } from '@xyo-network/react-archivist-api'
|
6
|
+
import { lazy, Suspense, useState } from 'react'
|
7
|
+
|
8
|
+
import { useLoadPayload } from './useLoadPayload'
|
9
|
+
|
10
|
+
const JsonView = lazy(() => import(/* webpackChunkName: "jsonView" */ 'react-json-view'))
|
11
|
+
|
12
|
+
const apiDomain = 'https://beta.api.archivist.xyo.network'
|
13
|
+
const hash = '5605fabad11b10bb5fb86b309ca0970894eda8f22362dda1a489817723bca992'
|
14
|
+
|
15
|
+
const Wrapper: React.FC<{ hash?: string }> = ({ hash }) => (
|
16
|
+
<ArchivistApiProvider apiDomain={apiDomain}>
|
17
|
+
<UsePayloadComponent hash={hash} />
|
18
|
+
</ArchivistApiProvider>
|
19
|
+
)
|
20
|
+
|
21
|
+
const UsePayloadComponent: React.FC<{ hash?: string }> = ({ hash }) => {
|
22
|
+
const { api } = useArchivistApi()
|
23
|
+
const [trigger, setTrigger] = useState<string>()
|
24
|
+
const [payload, notFound] = useLoadPayload(trigger)
|
25
|
+
|
26
|
+
return (
|
27
|
+
<>
|
28
|
+
{api ? (
|
29
|
+
<>
|
30
|
+
<ButtonEx variant="contained" marginBottom={2} onClick={() => setTrigger(hash)}>
|
31
|
+
Fetch Payload
|
32
|
+
</ButtonEx>
|
33
|
+
<ButtonEx variant="contained" onClick={() => setTrigger('foo')}>
|
34
|
+
Fetch Not Found
|
35
|
+
</ButtonEx>
|
36
|
+
</>
|
37
|
+
) : null}
|
38
|
+
<FlexCol my={3}>
|
39
|
+
<Suspense fallback={<FlexCol busy />}>
|
40
|
+
{notFound ? 'Not Found' : null}
|
41
|
+
<JsonView src={payload || {}} />
|
42
|
+
</Suspense>
|
43
|
+
</FlexCol>
|
44
|
+
</>
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
const StorybookEntry: Meta = {
|
49
|
+
argTypes: {},
|
50
|
+
component: UsePayloadComponent,
|
51
|
+
parameters: {
|
52
|
+
docs: {
|
53
|
+
page: null,
|
54
|
+
},
|
55
|
+
},
|
56
|
+
title: 'payload/usePayload',
|
57
|
+
}
|
58
|
+
|
59
|
+
const Template: ComponentStory<typeof UsePayloadComponent> = (props) => {
|
60
|
+
return <Wrapper {...props} />
|
61
|
+
}
|
62
|
+
|
63
|
+
const Default = Template.bind({})
|
64
|
+
Default.args = { hash }
|
65
|
+
|
66
|
+
export { Default }
|
67
|
+
|
68
|
+
// eslint-disable-next-line import/no-default-export
|
69
|
+
export default StorybookEntry
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { useAsyncEffect } from '@xylabs/react-shared'
|
2
|
+
import { XyoApiError } from '@xyo-network/api'
|
3
|
+
import { XyoPayload } from '@xyo-network/payload'
|
4
|
+
import { useArchive } from '@xyo-network/react-archive'
|
5
|
+
import { useArchivistApi } from '@xyo-network/react-archivist-api'
|
6
|
+
import { useEffect, useState } from 'react'
|
7
|
+
|
8
|
+
import { UsePayload } from './ResolvePayloadArgs'
|
9
|
+
|
10
|
+
export const useLoadPayload = (hash?: string): UsePayload => {
|
11
|
+
const { api } = useArchivistApi()
|
12
|
+
const { archive } = useArchive()
|
13
|
+
const [localHash, setLocalHash] = useState<string>()
|
14
|
+
const [notFound, setNotFound] = useState<boolean>()
|
15
|
+
const [apiError, setApiError] = useState<XyoApiError>()
|
16
|
+
const [payload, setPayload] = useState<XyoPayload>()
|
17
|
+
|
18
|
+
const reset = () => {
|
19
|
+
setPayload(undefined)
|
20
|
+
setApiError(undefined)
|
21
|
+
setNotFound(undefined)
|
22
|
+
}
|
23
|
+
|
24
|
+
// allow for hash changes to retrigger the api call
|
25
|
+
useEffect(() => {
|
26
|
+
if (hash !== localHash) {
|
27
|
+
setLocalHash(hash)
|
28
|
+
reset()
|
29
|
+
}
|
30
|
+
}, [hash, localHash])
|
31
|
+
|
32
|
+
useAsyncEffect(
|
33
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
34
|
+
async (mounted) => {
|
35
|
+
if (api && localHash && localHash.length > 0 && notFound === undefined) {
|
36
|
+
reset()
|
37
|
+
try {
|
38
|
+
const result = await api?.archive(archive).payload.hash(localHash).get()
|
39
|
+
if (mounted()) {
|
40
|
+
if (result?.length) {
|
41
|
+
setPayload(result[0])
|
42
|
+
setNotFound(false)
|
43
|
+
} else if (result?.length === 0) {
|
44
|
+
setNotFound(true)
|
45
|
+
setPayload(undefined)
|
46
|
+
}
|
47
|
+
}
|
48
|
+
} catch (e) {
|
49
|
+
reset()
|
50
|
+
setNotFound(false)
|
51
|
+
setApiError(e as XyoApiError)
|
52
|
+
console.error(e)
|
53
|
+
}
|
54
|
+
}
|
55
|
+
},
|
56
|
+
[hash, api, archive, payload, notFound, localHash],
|
57
|
+
)
|
58
|
+
return [payload, notFound, apiError]
|
59
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { useAsyncEffect } from '@xylabs/react-shared'
|
2
|
+
import { XyoApiError } from '@xyo-network/api'
|
3
|
+
import { Huri, XyoPayload } from '@xyo-network/payload'
|
4
|
+
import { useNetwork } from '@xyo-network/react-network'
|
5
|
+
import { useEffect, useState } from 'react'
|
6
|
+
|
7
|
+
import { FetchHuriHashOptions, findHuriNetwork } from './lib'
|
8
|
+
import { UseHuriOrHash } from './ResolvePayloadArgs'
|
9
|
+
|
10
|
+
const useResolveHuri = (huriUri?: string, dependentNotFound?: boolean, options?: FetchHuriHashOptions): UseHuriOrHash => {
|
11
|
+
const { network, networks, setNetwork } = useNetwork()
|
12
|
+
const [huriPayload, setHuriPayload] = useState<XyoPayload>()
|
13
|
+
const [huriPayloadNotFound, setHuriPayloadNotFound] = useState<boolean>()
|
14
|
+
const [huriNetworkNotFound, setHuriNetworkNotFound] = useState<boolean>()
|
15
|
+
const [huriApiError, setHuriApiError] = useState<XyoApiError>()
|
16
|
+
|
17
|
+
const { changeActiveNetwork } = options ?? {}
|
18
|
+
|
19
|
+
//AT: TODO -> Talk about this pattern
|
20
|
+
const reset = () => {
|
21
|
+
setHuriPayload(undefined)
|
22
|
+
setHuriPayloadNotFound(undefined)
|
23
|
+
setHuriApiError(undefined)
|
24
|
+
}
|
25
|
+
|
26
|
+
useEffect(() => {
|
27
|
+
// Initially, sync local not found with dependent's status
|
28
|
+
setHuriPayloadNotFound(dependentNotFound)
|
29
|
+
}, [dependentNotFound])
|
30
|
+
|
31
|
+
useAsyncEffect(
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
33
|
+
async (mounted) => {
|
34
|
+
// if dependent value is resolved, don't do anything, if not resolved, try to resolve huriUri
|
35
|
+
if (dependentNotFound && huriUri) {
|
36
|
+
reset()
|
37
|
+
const huriInstance = new Huri(huriUri)
|
38
|
+
|
39
|
+
const foundHuriNetwork = findHuriNetwork(huriInstance, networks)
|
40
|
+
|
41
|
+
if (foundHuriNetwork && mounted()) {
|
42
|
+
if (network !== foundHuriNetwork && changeActiveNetwork) {
|
43
|
+
setNetwork?.(foundHuriNetwork)
|
44
|
+
return
|
45
|
+
}
|
46
|
+
|
47
|
+
try {
|
48
|
+
const huriPayload = await huriInstance.fetch()
|
49
|
+
if (mounted()) {
|
50
|
+
if (huriPayload) {
|
51
|
+
setHuriPayload(huriPayload)
|
52
|
+
setHuriPayloadNotFound(false)
|
53
|
+
} else {
|
54
|
+
setHuriPayloadNotFound(true)
|
55
|
+
}
|
56
|
+
}
|
57
|
+
} catch (e) {
|
58
|
+
if (mounted()) {
|
59
|
+
setHuriPayloadNotFound(false)
|
60
|
+
setHuriPayload(undefined)
|
61
|
+
setHuriApiError(e as XyoApiError)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
} else {
|
65
|
+
setHuriNetworkNotFound(true)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
},
|
69
|
+
[huriUri, network, networks, dependentNotFound, setNetwork, changeActiveNetwork],
|
70
|
+
)
|
71
|
+
|
72
|
+
return [huriPayload, huriPayloadNotFound, huriApiError, huriNetworkNotFound]
|
73
|
+
}
|
74
|
+
|
75
|
+
export { useResolveHuri }
|
package/src/index.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from './components'
|