1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- import {Component, lazy, Suspense} from 'react';
- import HookStore from 'sentry/stores/hookStore';
- import {HookName, Hooks} from 'sentry/types/hooks';
- type Params<H extends HookName> = {
- /**
- * The name of the hook as listed in hookstore.add(hookName, callback)
- */
- hookName: H;
- /**
- * Component that will be shown if no hook is available
- */
- defaultComponent?: ReturnType<Hooks[H]>;
- /**
- * This is a function that returns a promise (more specifically a function
- * that returns the result of a dynamic import using `import()`. This will
- * use React.Suspense and React.lazy to render the component.
- */
- defaultComponentPromise?: () => Promise<ReturnType<Hooks[H]>>;
- };
- /**
- * Use this instead of the usual ternery operator when using getsentry hooks.
- * So in lieu of:
- *
- * HookStore.get('component:org-auth-view').length
- * ? HookStore.get('component:org-auth-view')[0]()
- * : OrganizationAuth
- *
- * do this instead:
- *
- * const HookedOrganizationAuth = HookOrDefault({
- * hookName:'component:org-auth-view',
- * defaultComponent: OrganizationAuth,
- * })
- *
- * Note, you will need to add the hookstore function in getsentry [0] first and
- * then register the types [2] and validHookName [1] in sentry.
- *
- * [0] /getsentry/static/getsentry/gsApp/registerHooks.jsx
- * [1] /sentry/app/stores/hookStore.tsx
- * [2] /sentry/app/types/hooks.ts
- */
- function HookOrDefault<H extends HookName>({
- hookName,
- defaultComponent,
- defaultComponentPromise,
- }: Params<H>) {
- type Props = React.ComponentProps<ReturnType<Hooks[H]>>;
- type State = {hooks: Hooks[H][]};
- class HookOrDefaultComponent extends Component<Props, State> {
- static displayName = `HookOrDefaultComponent(${hookName})`;
- state: State = {
- hooks: HookStore.get(hookName),
- };
- componentWillUnmount() {
- this.unlistener?.();
- }
- unlistener = HookStore.listen(
- (name: string, hooks: Hooks[HookName][]) =>
- name === hookName && this.setState({hooks}),
- undefined
- );
- get defaultComponent() {
- // If `defaultComponentPromise` is passed, then return a Suspended component
- if (defaultComponentPromise) {
- const DefaultComponent = lazy(defaultComponentPromise);
- return (props: Props) => (
- <Suspense fallback={null}>
- <DefaultComponent {...props} />
- </Suspense>
- );
- }
- return defaultComponent;
- }
- render() {
- const hookExists = this.state.hooks && this.state.hooks.length;
- const componentFromHook = this.state.hooks[0]?.();
- const HookComponent =
- hookExists && componentFromHook ? componentFromHook : this.defaultComponent;
- return HookComponent ? <HookComponent {...this.props} /> : null;
- }
- }
- return HookOrDefaultComponent;
- }
- export default HookOrDefault;
|