From 0081d6baf35b8cad100647387aced12a3729ad5c Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Fri, 6 Oct 2023 10:00:09 +0200 Subject: [PATCH] UI Extensions: Allow `React.memo()` objects as component extensions (#76098) fix: support the sandbox with component ui extensions --- .../features/plugins/extensions/validators.test.tsx | 12 ++++++++++++ public/app/features/plugins/extensions/validators.ts | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/public/app/features/plugins/extensions/validators.test.tsx b/public/app/features/plugins/extensions/validators.test.tsx index afaaa04b543..b57f1f9e3a8 100644 --- a/public/app/features/plugins/extensions/validators.test.tsx +++ b/public/app/features/plugins/extensions/validators.test.tsx @@ -272,6 +272,18 @@ describe('Plugin Extension Validators', () => { expect(isReactComponent(() =>
Some text
)).toBe(true); }); + it('should return TRUE if we pass in a component wrapped with React.memo()', () => { + const Component = () =>
Some text
; + const wrapped = React.memo(() => ( +
+ +
+ )); + wrapped.displayName = 'MyComponent'; + + expect(isReactComponent(wrapped)).toBe(true); + }); + it('should return FALSE if we pass in a valid React component', () => { expect(isReactComponent('Foo bar')).toBe(false); expect(isReactComponent(123)).toBe(false); diff --git a/public/app/features/plugins/extensions/validators.ts b/public/app/features/plugins/extensions/validators.ts index 4ea9d9072c0..add198e178f 100644 --- a/public/app/features/plugins/extensions/validators.ts +++ b/public/app/features/plugins/extensions/validators.ts @@ -129,7 +129,14 @@ export function isPromise(value: unknown): value is Promise { } export function isReactComponent(component: unknown): component is React.ComponentType { + const hasReactTypeProp = (obj: unknown): obj is { $$typeof: Symbol } => + typeof obj === 'object' && obj !== null && '$$typeof' in obj; + + // The sandbox wraps the plugin components with React.memo. + const isReactMemoObject = (obj: unknown): boolean => + hasReactTypeProp(obj) && obj.$$typeof === Symbol.for('react.memo'); + // We currently don't have any strict runtime-checking for this. // (The main reason is that we don't want to start depending on React implementation details.) - return typeof component === 'function'; + return typeof component === 'function' || isReactMemoObject(component); }