import { useEffect, useRef, useState } from 'react'; import isEqual from 'lodash.isequal'; import type { ExtensionAttributes, Context } from '@atlassian/clientside-extensions-registry'; import { onDebug } from '@atlassian/clientside-extensions-debug'; import { getValidatedExtensions } from './ExtensionsObservable'; import type { ExtensionState, Options } from './types'; const useDeepCompareMemoize = (value: T): T => { const ref = useRef({} as T); if (!isEqual(value, ref.current)) { ref.current = value; } return ref.current; }; export const useExtensionsAll = | null = null, AttributesT extends ExtensionAttributes = ExtensionAttributes>( extensionPoint: string, context: ContextT, options: Options, ): ExtensionState => { const [descriptorsState, setDescriptorsState] = useState>([[], [], true]); const cachedContext = useDeepCompareMemoize(context); const cachedOptions = useDeepCompareMemoize(options); useEffect(() => { const subscription = getValidatedExtensions(extensionPoint, cachedContext, cachedOptions).subscribe( (update) => { onDebug(({ debug }) => ({ level: debug, message: `useExtensionsAll React hook received a new state`, components: 'useExtensionsAll', meta: { extensionPoint, context: cachedContext, update, }, })); setDescriptorsState(update); }, ); return () => subscription.unsubscribe(); }, [extensionPoint, cachedContext, cachedOptions]); return descriptorsState; }; export const useExtensions = | null = null, AttributesT extends ExtensionAttributes = ExtensionAttributes>( extensionPoint: string, context: ContextT, options: Options, ) => { const extensionsPayload = useExtensionsAll(extensionPoint, context, options); return extensionsPayload[0]; }; export const useExtensionsUnsupported = < ContextT extends Context<{}> | null = null, AttributesU extends ExtensionAttributes = ExtensionAttributes, >( name: string, context: ContextT, options: Options, ) => { const extensionsPayload = useExtensionsAll(name, context, options); return extensionsPayload[1]; }; export const useExtensionsLoadingState = < ContextT extends Context<{}> | null = null, AttributesU extends ExtensionAttributes = ExtensionAttributes, >( name: string, context: ContextT, options: Options, ) => { const extensionsPayload = useExtensionsAll(name, context, options); return extensionsPayload[2]; };