import { Suspense, forwardRef, cloneElement, useCallback, useMemo } from 'react' import { RemoteModule } from '@sentre/react-dynamic-remote-component' import useSWR from 'swr' import { Spin } from 'antd' import ErrorBoundary from 'components/errorBoundary' import { REGISTER_APP_STORE } from 'view/marketplace' import { useRegisterSelector } from 'hooks/useRegister' const ONE_HOUR = 60 * 60 * 1000 /** * Remote Static */ type StaticType = 'logo' | 'readme' type MultiStaticType = 'panels' /** * Load asset json */ const useRemoteStatic = ({ url, scope }: RemoteModule): any => { const fetchAsset = useCallback( async (appId) => { const root = url.replace('index.js', '') const prefix = (asset: string | string[]) => { if (typeof asset === 'string') return root + asset if (Array.isArray(asset)) return asset.map((value) => root + value) throw new Error('Invalid static asset') } const res = await fetch(root + `${appId}-asset-senhub.json`) const data = await res.json() Object.keys(data).forEach((key) => (data[key] = prefix(data[key]))) return data }, [url], ) const { data } = useSWR(scope, fetchAsset, { shouldRetryOnError: false, revalidateOnFocus: false, dedupingInterval: ONE_HOUR, }) return data || {} } const RemoteStatic = forwardRef< HTMLElement, { type?: StaticType manifest: RemoteModule render: (src: string) => JSX.Element } >(({ type = 'default', manifest, render }, ref) => { const { [type]: src } = useRemoteStatic(manifest) return cloneElement(render(src), ref ? { ref } : {}) }) RemoteStatic.displayName = 'RemoteStatic' /** * Static Loader */ export const StaticLoader = forwardRef< HTMLElement, { appId: string type: StaticType defaultData?: string render: (url: string) => JSX.Element } >(({ type, appId, defaultData = '', render }, ref) => { const { url: appUrl } = useRegisterSelector((register) => register[appId]) || {} const url = useMemo( () => appUrl || REGISTER_APP_STORE[appId]?.url || '', [appUrl, appId], ) const manifest: RemoteModule = useMemo( () => ({ url, scope: appId, module: './static' }), [url, appId], ) if (!url) return null return ( }> ) }) StaticLoader.displayName = 'StaticLoader' /** * Remote Multi Statics */ const RemoteMultiStatic = forwardRef< HTMLElement, { type?: MultiStaticType manifest: RemoteModule render: (src: string[]) => JSX.Element } >(({ type = 'default', manifest, render }, ref) => { const { [type]: arrSrc } = useRemoteStatic(manifest) return cloneElement(render(arrSrc || []), ref ? { ref } : {}) }) RemoteMultiStatic.displayName = 'RemoteMultiStatic' /** * Remote Multi Loader */ export const MultiStaticLoader = forwardRef< HTMLElement, { appId: string type: MultiStaticType defaultData?: string[] render: (url: string[]) => JSX.Element } >(({ type, appId, defaultData = [''], render }, ref) => { const { url } = useRegisterSelector((register) => register[appId]) || { url: '', } const manifest: RemoteModule = useMemo( () => ({ url, scope: appId, module: './static' }), [url, appId], ) if (!url) return null return ( }> ) }) MultiStaticLoader.displayName = 'MultiStaticLoader'