From 2571faddee86d3c93e7814eb9034e606578ac040 Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Wed, 17 Jul 2024 14:51:11 -0400 Subject: [PATCH] feat: Core plugins refactor, XComponent framework (#2150) - Add XComponent (eXtendable Component) framework to allow components to be wrapped/replaced - Similar to Swizzling in Docusaurus - Useful for components that we need to replace at the Enterprise level (e.g. `WidgetPanelTooltip` needs to display the query name in Enterprise) - Added to the StyleGuide - Pass a `VariableDescriptor` to `WidgetPanel` and `WidgetPanelTooltip` - Allows for more information to be included, e.g. a `QueryVariableDescriptor` which extends `VariableDescriptor` - Refactor the Core plugins to be consistent in how they handle the `PanelEvent.OPEN` event - Will allow Enterprise to use these plugins straight up and remove their duplicated panel code - Add functions for `PanelEvent.OPEN` - Instead of using `PanelEvent.OPEN` directly and not getting any type safety, add functions for emitting, listening, and a hook to enforce type safety --- package-lock.json | 20 +- .../code-studio/src/main/AppMainContainer.tsx | 17 +- .../code-studio/src/styleguide/StyleGuide.tsx | 4 +- .../src/styleguide/XComponents.tsx | 123 +++++++++++ packages/components/package.json | 6 +- .../components/src/ComponentUtils.test.tsx | 57 ++++++ packages/components/src/ComponentUtils.ts | 80 ++++++++ packages/components/src/XComponent.test.tsx | 191 ++++++++++++++++++ packages/components/src/XComponent.tsx | 71 +++++++ packages/components/src/XComponentMap.ts | 29 +++ packages/components/src/index.ts | 3 + .../src/ChartPanelPlugin.tsx | 2 + .../src/WidgetLoaderPlugin.tsx | 15 +- .../dropdown-filter/DropdownFilter.tsx | 35 ++-- .../src/panels/ChartPanel.tsx | 31 ++- .../src/panels/ConsolePanel.tsx | 3 +- .../src/panels/DropdownFilterPanel.tsx | 12 +- .../src/panels/IrisGridPanel.tsx | 33 ++- .../src/panels/IrisGridPanelTooltip.tsx | 31 +-- .../src/panels/Panel.tsx | 115 +++++------ .../src/panels/WidgetPanel.tsx | 148 ++++++-------- .../src/panels/WidgetPanelTooltip.tsx | 48 ++--- .../src/panels/WidgetPanelTypes.ts | 26 +++ .../src/panels/index.ts | 1 + packages/dashboard/package.json | 1 - packages/dashboard/src/DashboardPlugin.ts | 11 +- packages/dashboard/src/DashboardUtils.tsx | 28 +-- packages/dashboard/src/PanelEvent.ts | 31 ++- packages/dashboard/src/index.ts | 1 - packages/dashboard/src/layout/LayoutUtils.ts | 3 +- .../dashboard/src/layout/useDashboardPanel.ts | 5 +- packages/embed-widget/src/App.tsx | 4 +- .../src/utils/EventUtils.test.ts | 138 +++++++++++++ .../golden-layout/src/utils/EventUtils.ts | 79 ++++++++ packages/golden-layout/src/utils/index.ts | 1 + tests/styleguide.spec.ts | 3 +- .../xcomponents-chromium-linux.png | Bin 0 -> 35334 bytes .../xcomponents-firefox-linux.png | Bin 0 -> 67897 bytes .../xcomponents-webkit-linux.png | Bin 0 -> 12929 bytes 39 files changed, 1073 insertions(+), 333 deletions(-) create mode 100644 packages/code-studio/src/styleguide/XComponents.tsx create mode 100644 packages/components/src/ComponentUtils.test.tsx create mode 100644 packages/components/src/ComponentUtils.ts create mode 100644 packages/components/src/XComponent.test.tsx create mode 100644 packages/components/src/XComponent.tsx create mode 100644 packages/components/src/XComponentMap.ts create mode 100644 packages/dashboard-core-plugins/src/panels/WidgetPanelTypes.ts create mode 100644 packages/golden-layout/src/utils/EventUtils.test.ts create mode 100644 packages/golden-layout/src/utils/EventUtils.ts create mode 100644 tests/styleguide.spec.ts-snapshots/xcomponents-chromium-linux.png create mode 100644 tests/styleguide.spec.ts-snapshots/xcomponents-firefox-linux.png create mode 100644 tests/styleguide.spec.ts-snapshots/xcomponents-webkit-linux.png diff --git a/package-lock.json b/package-lock.json index b0d22cdf61..e9396ae09e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29227,14 +29227,16 @@ "react-window": "^1.8.6" }, "devDependencies": { - "@deephaven/mocks": "file:../mocks" + "@deephaven/mocks": "file:../mocks", + "react-redux": "^7.2.4" }, "engines": { "node": ">=10" }, "peerDependencies": { "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react-dom": ">=16.8.0", + "react-is": ">=16.8.0" } }, "packages/console": { @@ -29304,7 +29306,6 @@ "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0", - "react-is": ">=16.8.0", "react-redux": "^7.2.4" } }, @@ -29739,12 +29740,6 @@ "@types/lodash": "*" } }, - "packages/dashboard/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "peer": true - }, "packages/embed-chart": { "name": "@deephaven/embed-chart", "version": "0.85.0", @@ -31668,6 +31663,7 @@ "popper.js": "^1.16.1", "prop-types": "^15.7.2", "react-beautiful-dnd": "^13.1.0", + "react-redux": "^7.2.4", "react-transition-group": "^4.4.2", "react-virtualized-auto-sizer": "1.0.6", "react-window": "^1.8.6" @@ -31729,12 +31725,6 @@ "requires": { "@types/lodash": "*" } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "peer": true } } }, diff --git a/packages/code-studio/src/main/AppMainContainer.tsx b/packages/code-studio/src/main/AppMainContainer.tsx index eb96bb33de..fd2c6000bb 100644 --- a/packages/code-studio/src/main/AppMainContainer.tsx +++ b/packages/code-studio/src/main/AppMainContainer.tsx @@ -30,6 +30,7 @@ import { DashboardUtils, DEFAULT_DASHBOARD_ID, DehydratedDashboardPanelProps, + emitPanelOpen, getAllDashboardsData, getDashboardData, listenForCreateDashboard, @@ -75,8 +76,9 @@ import { copyToClipboard, PromiseUtils, EMPTY_ARRAY, + assertNotNull, } from '@deephaven/utils'; -import GoldenLayout from '@deephaven/golden-layout'; +import GoldenLayout, { EventHub } from '@deephaven/golden-layout'; import type { ItemConfig } from '@deephaven/golden-layout'; import { type PluginModuleMap, getDashboardPlugins } from '@deephaven/plugin'; import { @@ -394,10 +396,15 @@ export class AppMainContainer extends Component< this.emitLayoutEvent(PanelEvent.REOPEN_LAST); } - emitLayoutEvent(event: string, ...args: unknown[]): void { + getActiveEventHub(): EventHub { const { activeTabKey } = this.state; const layout = this.dashboardLayouts.get(activeTabKey); - layout?.eventHub.emit(event, ...args); + assertNotNull(layout, 'No active layout found'); + return layout.eventHub; + } + + emitLayoutEvent(event: string, ...args: unknown[]): void { + this.getActiveEventHub().emit(event, ...args); } handleCancelResetLayoutPrompt(): void { @@ -702,10 +709,10 @@ export class AppMainContainer extends Component< dragEvent?: WindowMouseEvent ): void { const { connection } = this.props; - this.emitLayoutEvent(PanelEvent.OPEN, { + emitPanelOpen(this.getActiveEventHub(), { + widget: getVariableDescriptor(widget), dragEvent, fetch: async () => connection?.getObject(widget), - widget: getVariableDescriptor(widget), }); } diff --git a/packages/code-studio/src/styleguide/StyleGuide.tsx b/packages/code-studio/src/styleguide/StyleGuide.tsx index 336b8ab9c4..3870644058 100644 --- a/packages/code-studio/src/styleguide/StyleGuide.tsx +++ b/packages/code-studio/src/styleguide/StyleGuide.tsx @@ -39,6 +39,7 @@ import SpectrumComparison from './SpectrumComparison'; import Pickers from './Pickers'; import ListViews from './ListViews'; import ErrorViews from './ErrorViews'; +import XComponents from './XComponents'; const stickyProps = { position: 'sticky', @@ -134,13 +135,14 @@ function StyleGuide(): React.ReactElement { + + - ); diff --git a/packages/code-studio/src/styleguide/XComponents.tsx b/packages/code-studio/src/styleguide/XComponents.tsx new file mode 100644 index 0000000000..a67204c857 --- /dev/null +++ b/packages/code-studio/src/styleguide/XComponents.tsx @@ -0,0 +1,123 @@ +import React, { useState } from 'react'; +import { + XComponentMapProvider, + createXComponent, + Button, +} from '@deephaven/components'; +import SampleSection from './SampleSection'; + +type FooComponentProps = { value: string }; + +function FooComponent({ value }: FooComponentProps) { + return ( + + ); +} +FooComponent.displayName = 'FooComponent'; + +// Create an XComponent from FooComponent to allow for replacement +const XFooComponent = createXComponent(FooComponent); + +function NestedFooComponent({ value }: FooComponentProps) { + // We're using the XComponent version so this panel can be replaced if it is mapped from a parent context to a replacement + return ; +} + +function MultiFooComponent({ value }: FooComponentProps) { + // Show multiple instances getting replaced + return ( +
+ + +
+ ); +} + +// What we're replacing the XFooComponent with. +function ReverseFooComponent({ value }: FooComponentProps) { + return ( + + ); +} + +/** + * Some examples showing usage of XComponents. + */ +export function XComponents(): JSX.Element { + const [value, setValue] = useState('hello'); + + return ( + +

XComponents

+

+ XComponents are a way to replace a component with another component + without needing to pass props all the way down the component tree. This + can be useful in cases where we have a component deep down in the + component tree that we want to replace with a different component, but + don't want to have to provide props at the top level just to hook + into that. +
+ Below is a component that is simply a button displaying the text + inputted in the input field. We will replace this component with a new + component that reverses the text, straight up, then in a nested + scenario, and then multiple instances. +

+
+ +
+
+
+ Original Component +
+ +
+ + Replaced with Reverse +
+ + + +
+
+
+ Nested component replaced +
+ + {/* The `FooComponent` that gets replaced is from within the `NestedFooComponent` */} + + +
+
+
+ Multiple Components replaced +
+ + + +
+
+
+
+ ); +} + +export default XComponents; diff --git a/packages/components/package.json b/packages/components/package.json index 6f6ea2c06d..4cab118211 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -53,10 +53,12 @@ }, "peerDependencies": { "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "react-dom": ">=16.8.0", + "react-is": ">=16.8.0" }, "devDependencies": { - "@deephaven/mocks": "file:../mocks" + "@deephaven/mocks": "file:../mocks", + "react-redux": "^7.2.4" }, "files": [ "dist", diff --git a/packages/components/src/ComponentUtils.test.tsx b/packages/components/src/ComponentUtils.test.tsx new file mode 100644 index 0000000000..bd347b81ad --- /dev/null +++ b/packages/components/src/ComponentUtils.test.tsx @@ -0,0 +1,57 @@ +import React, { PropsWithChildren } from 'react'; +// We only use react-redux from tests in @deephaven/components, so it is only added as a devDependency +import { connect } from 'react-redux'; +import { + canHaveRef, + isClassComponent, + isWrappedComponent, + isForwardRefComponentType, +} from './ComponentUtils'; + +function TestComponent() { + return
Test
; +} + +class TestClass extends React.PureComponent> { + render() { + return
Test
; + } +} + +test('isForwardRefComponent', () => { + expect(isForwardRefComponentType(TestComponent)).toBe(false); + expect(isForwardRefComponentType(React.forwardRef(TestComponent))).toBe(true); + expect(isForwardRefComponentType(TestClass)).toBe(false); + expect(isForwardRefComponentType(connect(null, null)(TestComponent))).toBe( + false + ); + expect(isForwardRefComponentType(connect(null, null)(TestClass))).toBe(false); +}); + +test('isClassComponent', () => { + expect(isClassComponent(TestComponent)).toBe(false); + expect(isClassComponent(TestClass)).toBe(true); + expect(isClassComponent(React.forwardRef(TestComponent))).toBe(false); + expect(isClassComponent(connect(null, null)(TestComponent))).toBe(false); + expect(isClassComponent(connect(null, null)(TestClass))).toBe(true); +}); + +test('isWrappedComponent', () => { + expect(isWrappedComponent(TestComponent)).toBe(false); + expect(isWrappedComponent(TestClass)).toBe(false); + expect(isWrappedComponent(connect(null, null)(TestComponent))).toBe(true); + expect(isWrappedComponent(React.forwardRef(TestComponent))).toBe(false); + expect(isWrappedComponent(connect(null, null)(TestClass))).toBe(true); +}); + +test('canHaveRef', () => { + const forwardedType = React.forwardRef(TestComponent); + + expect(canHaveRef(TestComponent)).toBe(false); + expect(canHaveRef(forwardedType)).toBe(true); + expect(canHaveRef(TestClass)).toBe(true); + expect(canHaveRef(connect(null, null)(TestClass))).toBe(true); + expect( + canHaveRef(connect(null, null, null, { forwardRef: true })(TestClass)) + ).toBe(true); +}); diff --git a/packages/components/src/ComponentUtils.ts b/packages/components/src/ComponentUtils.ts new file mode 100644 index 0000000000..c63e663725 --- /dev/null +++ b/packages/components/src/ComponentUtils.ts @@ -0,0 +1,80 @@ +import React, { + ComponentType, + ForwardRefExoticComponent, + RefAttributes, +} from 'react'; +import { ForwardRef } from 'react-is'; + +export type Props = Record | RefAttributes; + +/** + * Type that represents a component that has been wrapped by redux. + */ +export type WrappedComponentType< + P extends Props, + C extends ComponentType

, +> = ComponentType

& { + WrappedComponent: C; +}; + +/** + * Checks if a component is a wrapped component. + * @param Component The component to check + * @returns Whether the component is a wrapped component or not + */ +export function isWrappedComponent

>( + Component: React.ComponentType

+): Component is WrappedComponentType { + return ( + (Component as WrappedComponentType)?.WrappedComponent !== undefined + ); +} + +/** + * Checks if a component is a class component. + * @param Component The component to check + * @returns Whether the component is a class component or not + */ +export function isClassComponent

( + Component: React.ComponentType

+): Component is React.ComponentClass

{ + if ( + isWrappedComponent(Component) && + isClassComponent(Component.WrappedComponent) + ) { + return true; + } + return ( + (Component as React.ComponentClass

).prototype != null && + (Component as React.ComponentClass

).prototype.isReactComponent != null + ); +} + +/** + * Checks if a component is a forward ref component. + * @param Component The component to check + * @returns Whether the component is a forward ref component or not + */ +export function isForwardRefComponentType

( + Component: ComponentType

+): Component is ForwardRefExoticComponent

{ + return ( + !isWrappedComponent(Component) && + // Do a check right on the `$$typeof` the component. The `isForwardRef` function in `react-is` checks against a `Component` instance, whereas + // we want to check against a `ComponentType` which is the class/function that defines a component. + '$$typeof' in Component && + Component.$$typeof === ForwardRef + ); +} + +/** + * Checks if a component can have a ref. Helps silence react dev errors + * if a ref is passed to a functional component without forwardRef. + * @param Component The component to check if it can take a ref + * @returns Whether the component can have a ref or not + */ +export function canHaveRef

( + Component: ComponentType

| WrappedComponentType> +): boolean { + return isClassComponent(Component) || isForwardRefComponentType(Component); +} diff --git a/packages/components/src/XComponent.test.tsx b/packages/components/src/XComponent.test.tsx new file mode 100644 index 0000000000..af1946d3f6 --- /dev/null +++ b/packages/components/src/XComponent.test.tsx @@ -0,0 +1,191 @@ +/* eslint-disable max-classes-per-file */ +import React from 'react'; +import { render } from '@testing-library/react'; +import { createXComponent } from './XComponent'; +import { XComponentMapProvider } from './XComponentMap'; + +function MyComponent({ children }: { children?: React.ReactNode } = {}) { + return ( +

+ MyComponent +
{children}
+
+ ); +} + +function FooComponent({ foo = 'foo' }: { foo: string }) { + return
{foo}
; +} + +const MyRefComponent = React.forwardRef< + HTMLDivElement, + { children?: React.ReactNode } +>(function MyRefComponent({ children }, ref) { + return ( +
+ MyRefComponent +
{children}
+
+ ); +}); + +class MyClassComponent extends React.Component { + public foo = 'bar'; + + render() { + return
MyClassComponent
; + } +} + +const XMyComponent = createXComponent(MyComponent); +const XFooComponent = createXComponent(FooComponent); +const XMyRefComponent = createXComponent(MyRefComponent); +const XMyClassComponent = createXComponent(MyClassComponent); + +function MyReplacementComponent() { + return
MyReplacementComponent
; +} + +function MyReplacementWrapperComponent({ + children, +}: { children?: React.ReactNode } = {}) { + return ( +
+
MyReplacementWrapperComponent
+ {children} +
+ ); +} + +function ReverseFooComponent({ foo }: { foo: string }) { + return
{foo.split('').reverse().join('')}
; +} + +const MyReplacementRefComponent = React.forwardRef< + HTMLDivElement, + { children?: React.ReactNode } +>(function MyReplacementRefComponent({ children }, ref) { + return ( +
+ MyReplacementRefComponent +
{children}
+
+ ); +}); + +class MyReplacementClassComponent extends React.Component { + public foo = 'baz'; + + render() { + return
MyReplacementClassComponent
; + } +} + +describe('ExtendableComponent', () => { + it('should render the original component', () => { + const { getByText } = render(); + expect(getByText('MyComponent')).toBeInTheDocument(); + }); + + it('should render the replacement component', () => { + const { getByText } = render( + + + + ); + expect(getByText('MyReplacementComponent')).toBeInTheDocument(); + }); + + it('should render the original component inside the replacement component', () => { + const { getByText } = render( + + + + ); + expect(getByText('MyReplacementWrapperComponent')).toBeInTheDocument(); + expect(getByText('MyComponent')).toBeInTheDocument(); + }); + + it('should render the original component with props', () => { + const { getByText } = render(); + expect(getByText('bar')).toBeInTheDocument(); + }); + + it('should render the replacement component with props', () => { + const { getByText } = render( + + + + ); + expect(getByText('rab')).toBeInTheDocument(); + }); + + it('should render the original ref component', () => { + const ref = React.createRef(); + const { getByText } = render(); + expect(getByText('MyRefComponent')).toBeInTheDocument(); + expect(ref.current).toBeInTheDocument(); + expect(ref.current?.getAttribute('data-testid')).toBe('my-ref-component'); + }); + + it('should render the replacement ref component', () => { + const ref = React.createRef(); + const { getByText } = render( + + + + ); + expect(getByText('MyReplacementRefComponent')).toBeInTheDocument(); + expect(ref.current).toBeInTheDocument(); + expect(ref.current?.getAttribute('data-testid')).toBe( + 'my-replacement-ref-component' + ); + }); + + it('should render the original class component', () => { + const ref = React.createRef(); + const { getByText } = render(); + expect(getByText('MyClassComponent')).toBeInTheDocument(); + }); + + it('should render the replacement class component', () => { + const { getByText } = render( + + + + ); + expect(getByText('MyReplacementClassComponent')).toBeInTheDocument(); + }); + + it('should render the original class component with the ref', () => { + const ref = React.createRef(); + const { getByText } = render(); + expect(getByText('MyClassComponent')).toBeInTheDocument(); + expect(ref.current).toBeInstanceOf(MyClassComponent); + expect(ref.current?.foo).toBe('bar'); + }); + + it('should render the replacement class component with the ref', () => { + const ref = React.createRef(); + const { getByText } = render( + + + + ); + expect(getByText('MyReplacementClassComponent')).toBeInTheDocument(); + expect(ref.current).toBeInstanceOf(MyReplacementClassComponent); + expect(ref.current?.foo).toBe('baz'); + }); +}); diff --git a/packages/components/src/XComponent.tsx b/packages/components/src/XComponent.tsx new file mode 100644 index 0000000000..0f1c9c0cb6 --- /dev/null +++ b/packages/components/src/XComponent.tsx @@ -0,0 +1,71 @@ +import React, { ComponentType, forwardRef } from 'react'; +import { canHaveRef } from './ComponentUtils'; +import { useXComponent, XComponentType } from './XComponentMap'; + +/** + * Helper function that will wrap the provided component, and return an ExtendableComponent type. + * Whenever that ExtendableComponent is used, it will check if there is a replacement component for the provided component on the context. + * If there is, it will use that component instead of the provided component. + * This is a similar concept to how swizzling is done in Docusaurus or obj-c, but for any React component. + * + * Usage: + * + * ```tsx + * function MyComponent() { + * return
MyComponent
; + * } + * + * const XMyComponent = extendableComponent(MyComponent); + * + * function MyReplacementComponent() { + * return
MyReplacementComponent
; + * } + * + * // Will render MyComponent + * + * + * // Will render MyReplacementComponent + * + * + * ``` + * + * Is useful in cases where we have a component deep down in the component tree that we want to replace with a different component, but don't want to + * have to provide props at the top level just to hook into that. + * + * @param Component The component to wrap + * @returns The wrapped component + */ +export function createXComponent

>( + Component: React.ComponentType

+): XComponentType

{ + let forwardedRefComponent: XComponentType

; + function XComponent( + props: P, + ref: React.ForwardedRef> + ): JSX.Element { + const ReplacementComponent = useXComponent(forwardedRefComponent); + return canHaveRef(Component) ? ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ) : ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ); + } + + // Add the display name so this appears as a tag in the React DevTools + // Need to add it here, and then when it's wrapped with the `forwardRef` it will automatically get the display name of the original component + XComponent.displayName = `XComponent(${ + Component.displayName ?? Component.name + })`; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + forwardedRefComponent = forwardRef(XComponent) as any; + + forwardedRefComponent.Original = Component; + forwardedRefComponent.isXComponent = true; + + return forwardedRefComponent; +} + +export default createXComponent; diff --git a/packages/components/src/XComponentMap.ts b/packages/components/src/XComponentMap.ts new file mode 100644 index 0000000000..2b78a20819 --- /dev/null +++ b/packages/components/src/XComponentMap.ts @@ -0,0 +1,29 @@ +import React, { useContext } from 'react'; + +/** Type for an extended component. Can fetch the original component using `.Original` */ +export type XComponentType

> = + React.ForwardRefExoticComponent< + React.PropsWithoutRef

& React.RefAttributes + > & { + Original: React.ComponentType

; + isXComponent: boolean; + }; + +export const XComponentMapContext = React.createContext( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + new Map, React.ComponentType>() +); + +export const XComponentMapProvider = XComponentMapContext.Provider; + +/** + * Use the replacement component for the provided component if it exists, or just return the provided component. + * @param Component Component to check if there's a replacement for + * @returns The replacement component if it exists, otherwise the original component + */ +export function useXComponent

>( + Component: XComponentType

+): React.ComponentType

{ + const ctx = useContext(XComponentMapContext); + return ctx.get(Component) ?? Component.Original; +} diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 2b0ff450a6..69c8292f62 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -9,6 +9,7 @@ export { default as CardFlip } from './CardFlip'; export * from './context-actions'; export { default as Collapse } from './Collapse'; export { default as Checkbox } from './Checkbox'; +export * from './ComponentUtils'; export { default as CopyButton } from './CopyButton'; export { default as CustomTimeSelect } from './CustomTimeSelect'; export * from './DateTimeInput'; @@ -56,3 +57,5 @@ export { default as TimeSlider } from './TimeSlider'; export { default as ToastNotification } from './ToastNotification'; export * from './UIConstants'; export { default as UISwitch } from './UISwitch'; +export * from './XComponent'; +export * from './XComponentMap'; diff --git a/packages/dashboard-core-plugins/src/ChartPanelPlugin.tsx b/packages/dashboard-core-plugins/src/ChartPanelPlugin.tsx index dcd40c4fc4..92d9e8751d 100644 --- a/packages/dashboard-core-plugins/src/ChartPanelPlugin.tsx +++ b/packages/dashboard-core-plugins/src/ChartPanelPlugin.tsx @@ -75,6 +75,7 @@ async function createChartModel( if (metadata.type === dh.VariableType.FIGURE) { const descriptor = { + ...metadata, name: figureName, type: dh.VariableType.FIGURE, }; @@ -87,6 +88,7 @@ async function createChartModel( } const descriptor = { + ...metadata, name: tableName, type: dh.VariableType.TABLE, }; diff --git a/packages/dashboard-core-plugins/src/WidgetLoaderPlugin.tsx b/packages/dashboard-core-plugins/src/WidgetLoaderPlugin.tsx index 8fcfd8d86f..d4e951287a 100644 --- a/packages/dashboard-core-plugins/src/WidgetLoaderPlugin.tsx +++ b/packages/dashboard-core-plugins/src/WidgetLoaderPlugin.tsx @@ -5,12 +5,11 @@ import { assertIsDashboardPluginProps, DashboardPluginComponentProps, DehydratedDashboardPanelProps, - PanelEvent, PanelOpenEventDetail, LayoutUtils, - useListener, PanelProps, canHaveRef, + usePanelOpenListener, } from '@deephaven/dashboard'; import Log from '@deephaven/log'; import { @@ -19,6 +18,7 @@ import { type WidgetPlugin, } from '@deephaven/plugin'; import { WidgetPanel } from './panels'; +import { WidgetPanelDescriptor } from './panels/WidgetPanelTypes'; const log = Log.module('WidgetLoaderPlugin'); @@ -30,12 +30,17 @@ export function WrapWidgetPlugin( const C = plugin.component as any; const { metadata } = props; + const panelDescriptor: WidgetPanelDescriptor = { + ...metadata, + type: metadata?.type ?? plugin.type, + name: metadata?.name ?? 'Widget', + }; + const hasRef = canHaveRef(C); return ( @@ -156,7 +161,7 @@ export function WidgetLoaderPlugin( /** * Listen for panel open events so we know when to open a panel */ - useListener(layout.eventHub, PanelEvent.OPEN, handlePanelOpen); + usePanelOpenListener(layout.eventHub, handlePanelOpen); return null; } diff --git a/packages/dashboard-core-plugins/src/controls/dropdown-filter/DropdownFilter.tsx b/packages/dashboard-core-plugins/src/controls/dropdown-filter/DropdownFilter.tsx index b8ede97897..1d0e4e00af 100644 --- a/packages/dashboard-core-plugins/src/controls/dropdown-filter/DropdownFilter.tsx +++ b/packages/dashboard-core-plugins/src/controls/dropdown-filter/DropdownFilter.tsx @@ -37,7 +37,7 @@ export interface DropdownFilterColumn { export interface DropdownFilterProps { column: DropdownFilterColumn; - columns: DropdownFilterColumn[]; + columns: readonly DropdownFilterColumn[]; onSourceMouseEnter: () => void; onSourceMouseLeave: () => void; disableLinking: boolean; @@ -47,7 +47,7 @@ export interface DropdownFilterProps { settingsError: string; source: LinkPoint; value: string | null; - values: (string | null)[]; + values: readonly (string | null)[]; onChange: (change: { column: Partial | null; isValueShown?: boolean; @@ -159,7 +159,7 @@ export class DropdownFilter extends Component< dropdownRef: RefObject; getCompatibleColumns = memoize( - (source: LinkPoint, columns: DropdownFilterColumn[]) => + (source: LinkPoint, columns: readonly DropdownFilterColumn[]) => source != null ? columns.filter( ({ type }) => @@ -200,10 +200,11 @@ export class DropdownFilter extends Component< ); getSelectedOptionIndex = memoize( - (values: (string | null)[], value: string | null) => values.indexOf(value) + (values: readonly (string | null)[], value: string | null) => + values.indexOf(value) ); - getValueOptions = memoize((values: (string | null)[]) => [ + getValueOptions = memoize((values: readonly (string | null)[]) => [ , @@ -218,19 +219,21 @@ export class DropdownFilter extends Component< )), ]); - getItemLabel = memoizee((columns: DropdownFilterColumn[], index: number) => { - const { name, type } = columns[index]; + getItemLabel = memoizee( + (columns: readonly DropdownFilterColumn[], index: number) => { + const { name, type } = columns[index]; - if ( - (index > 0 && columns[index - 1].name === name) || - (index < columns.length - 1 && columns[index + 1].name === name) - ) { - const shortType = type.substring(type.lastIndexOf('.') + 1); - return `${name} (${shortType})`; - } + if ( + (index > 0 && columns[index - 1].name === name) || + (index < columns.length - 1 && columns[index + 1].name === name) + ) { + const shortType = type.substring(type.lastIndexOf('.') + 1); + return `${name} (${shortType})`; + } - return name; - }); + return name; + } + ); handleColumnChange(eventTargetValue: string): void { const value = eventTargetValue; diff --git a/packages/dashboard-core-plugins/src/panels/ChartPanel.tsx b/packages/dashboard-core-plugins/src/panels/ChartPanel.tsx index e6ebff54d1..e100ec5ef8 100644 --- a/packages/dashboard-core-plugins/src/panels/ChartPanel.tsx +++ b/packages/dashboard-core-plugins/src/panels/ChartPanel.tsx @@ -65,6 +65,7 @@ import { isChartPanelTableMetadata, } from './ChartPanelUtils'; import { ColumnSelectionValidator } from '../linker/ColumnSelectionValidator'; +import { WidgetPanelDescriptor } from './WidgetPanelTypes'; const log = Log.module('ChartPanel'); const UPDATE_MODEL_DEBOUNCE = 150; @@ -458,6 +459,24 @@ export class ChartPanel extends Component { })) ); + getWidgetPanelDescriptor = memoize( + (metadata: ChartPanelProps['metadata']): WidgetPanelDescriptor => { + let name = 'Chart'; + if (isChartPanelTableMetadata(metadata)) { + name = metadata.table; + } else if (isChartPanelFigureMetadata(metadata)) { + name = metadata.figure ?? name; + } else { + name = metadata.name ?? name; + } + return { + ...metadata, + type: 'Chart', + name, + }; + } + ); + startListeningToSource(table: dh.Table): void { log.debug('startListeningToSource', table); const { model } = this.state; @@ -1046,14 +1065,6 @@ export class ChartPanel extends Component { isLoaded, isLoading, } = this.state; - let name; - if (isChartPanelTableMetadata(metadata)) { - name = metadata.table; - } else if (isChartPanelFigureMetadata(metadata)) { - name = metadata.figure; - } else { - name = metadata.name; - } const inputFilterMap = this.getInputFilterColumnMap( columnMap, inputFilters @@ -1081,6 +1092,7 @@ export class ChartPanel extends Component { error != null ? `Unable to open chart. ${error}` : undefined; const isWaitingForFilter = waitingInputMap.size > 0; const isSelectingColumn = columnMap.size > 0 && isLinkerActive; + const descriptor = this.getWidgetPanelDescriptor(metadata); return ( { isDisconnected={isDisconnected} isLoading={isLoading} isLoaded={isLoaded} - widgetName={name ?? undefined} - widgetType="Chart" + descriptor={descriptor} >

{ + const name = getTableNameFromMetadata(metadata); + return { + type: 'Table', + displayType: 'Table', + ...metadata, + name, + description, + }; + } + ); + initModel(): void { this.setState({ isModelReady: false, isLoading: true, error: null }); const { makeModel } = this.props; @@ -712,7 +729,7 @@ export class IrisGridPanel extends PureComponent< this.setState( () => null, () => { - const { glEventHub, inputFilters } = this.props; + const { glEventHub, inputFilters, metadata } = this.props; const table = this.getTableName(); const { panelState } = this.state; const sourcePanelId = LayoutUtils.getIdFromPanel(this); @@ -726,6 +743,7 @@ export class IrisGridPanel extends PureComponent< } glEventHub.emit(IrisGridEvent.CREATE_CHART, { metadata: { + ...metadata, settings, sourcePanelId, table, @@ -1235,13 +1253,16 @@ export class IrisGridPanel extends PureComponent< } = this.state; const errorMessage = error != null ? `Unable to open table. ${error}` : undefined; - const name = getTableNameFromMetadata(metadata); const description = model?.description ?? undefined; const pluginState = panelState?.pluginState ?? null; const childrenContent = children ?? this.getPluginContent(Plugin, model, pluginState); const { permissions } = user; const { canCopy, canDownloadCsv } = permissions; + const widgetPanelDescriptor = this.getWidgetPanelDescriptor( + metadata, + description + ); return ( ( )} > diff --git a/packages/dashboard-core-plugins/src/panels/IrisGridPanelTooltip.tsx b/packages/dashboard-core-plugins/src/panels/IrisGridPanelTooltip.tsx index 88c3c862dd..2c71e3a00d 100644 --- a/packages/dashboard-core-plugins/src/panels/IrisGridPanelTooltip.tsx +++ b/packages/dashboard-core-plugins/src/panels/IrisGridPanelTooltip.tsx @@ -1,19 +1,14 @@ import React, { ReactElement } from 'react'; -import { GLPropTypes } from '@deephaven/dashboard'; -import type { ComponentConfig, Container } from '@deephaven/golden-layout'; import { IrisGridModel } from '@deephaven/iris-grid'; -import PropTypes from 'prop-types'; import WidgetPanelTooltip from './WidgetPanelTooltip'; +import { WidgetPanelTooltipProps } from './WidgetPanelTypes'; -interface IrisGridPanelTooltipProps { +type IrisGridPanelTooltipProps = WidgetPanelTooltipProps & { model?: IrisGridModel; - widgetName: string; - glContainer: Container; - description?: string; -} +}; function IrisGridPanelTooltip(props: IrisGridPanelTooltipProps): ReactElement { - const { model, widgetName, glContainer, description } = props; + const { model } = props; const rowCount = (model?.rowCount ?? 0) - @@ -26,12 +21,8 @@ function IrisGridPanelTooltip(props: IrisGridPanelTooltipProps): ReactElement { const formattedcolumnCount = model?.displayString(columnCount, 'long'); return ( - + // eslint-disable-next-line react/jsx-props-no-spreading +
Number of Columns @@ -43,14 +34,4 @@ function IrisGridPanelTooltip(props: IrisGridPanelTooltipProps): ReactElement { ); } -IrisGridPanelTooltip.propTypes = { - glContainer: GLPropTypes.Container.isRequired, - widgetName: PropTypes.string.isRequired, - description: PropTypes.string, -}; - -IrisGridPanelTooltip.defaultProps = { - description: null, -}; - export default IrisGridPanelTooltip; diff --git a/packages/dashboard-core-plugins/src/panels/Panel.tsx b/packages/dashboard-core-plugins/src/panels/Panel.tsx index 760a5276e6..c30b4c02f2 100644 --- a/packages/dashboard-core-plugins/src/panels/Panel.tsx +++ b/packages/dashboard-core-plugins/src/panels/Panel.tsx @@ -21,7 +21,7 @@ import type { ReactComponentConfig, Tab, } from '@deephaven/golden-layout'; -import { assertNotNull } from '@deephaven/utils'; +import { assertNotNull, EMPTY_ARRAY } from '@deephaven/utils'; import Log from '@deephaven/log'; import type { dh } from '@deephaven/jsapi-types'; import { ConsoleEvent, InputFilterEvent, TabEvent } from '../events'; @@ -41,30 +41,30 @@ interface PanelProps { children: ReactNode; glContainer: Container; glEventHub: EventEmitter; - className: string; - onFocus: FocusEventHandler; - onBlur: FocusEventHandler; - onTab: (tab: Tab) => void; - onTabClicked: (e: MouseEvent) => void; - onClearAllFilters: (...args: unknown[]) => void; - onHide: (...args: unknown[]) => void; - onResize: (...args: unknown[]) => void; - onSessionClose: (session: dh.IdeSession) => void; - onSessionOpen: ( + className?: string; + onFocus?: FocusEventHandler; + onBlur?: FocusEventHandler; + onTab?: (tab: Tab) => void; + onTabClicked?: (e: MouseEvent) => void; + onClearAllFilters?: (...args: unknown[]) => void; + onHide?: (...args: unknown[]) => void; + onResize?: (...args: unknown[]) => void; + onSessionClose?: (session: dh.IdeSession) => void; + onSessionOpen?: ( session: dh.IdeSession, { language, sessionId }: { language: string; sessionId: string } ) => void; - onBeforeShow: (...args: unknown[]) => void; - onShow: (...args: unknown[]) => void; - onTabBlur: (...args: unknown[]) => void; - onTabFocus: (...args: unknown[]) => void; - renderTabTooltip: () => ReactNode; - additionalActions: ContextAction[]; - errorMessage: string; - isLoading: boolean; - isLoaded: boolean; - isClonable: boolean; - isRenamable: boolean; + onBeforeShow?: (...args: unknown[]) => void; + onShow?: (...args: unknown[]) => void; + onTabBlur?: (...args: unknown[]) => void; + onTabFocus?: (...args: unknown[]) => void; + renderTabTooltip?: () => ReactNode; + additionalActions?: ContextAction[]; + errorMessage?: string; + isLoading?: boolean; + isLoaded?: boolean; + isClonable?: boolean; + isRenamable?: boolean; } interface PanelState { @@ -78,30 +78,6 @@ interface PanelState { * Focus, Resize, Show, Session open/close, client disconnect/reconnect. */ class Panel extends PureComponent { - static defaultProps = { - className: '', - onTab: (): void => undefined, - onTabClicked: (): void => undefined, - onClearAllFilters: (): void => undefined, - onFocus: (): void => undefined, - onBlur: (): void => undefined, - onHide: (): void => undefined, - onResize: (): void => undefined, - onSessionClose: (): void => undefined, - onSessionOpen: (): void => undefined, - onBeforeShow: (): void => undefined, - onShow: (): void => undefined, - onTabBlur: (): void => undefined, - onTabFocus: (): void => undefined, - renderTabTooltip: null, - additionalActions: [], - errorMessage: null, - isLoading: false, - isLoaded: true, - isClonable: false, - isRenamable: false, - }; - constructor(props: PanelProps) { super(props); @@ -193,17 +169,17 @@ class Panel extends PureComponent { this.forceUpdate(); const { onTab } = this.props; - onTab(tab); + onTab?.(tab); } handleTabClicked(e: MouseEvent): void { const { onTabClicked } = this.props; - onTabClicked(e); + onTabClicked?.(e); } handleClearAllFilters(...args: unknown[]): void { const { onClearAllFilters } = this.props; - onClearAllFilters(...args); + onClearAllFilters?.(...args); } handleFocus(event: FocusEvent): void { @@ -211,27 +187,27 @@ class Panel extends PureComponent { glEventHub.emit(PanelEvent.FOCUS, componentPanel ?? this); const { onFocus } = this.props; - onFocus(event); + onFocus?.(event); } handleBlur(event: FocusEvent): void { const { onBlur } = this.props; - onBlur(event); + onBlur?.(event); } handleHide(...args: unknown[]): void { const { onHide } = this.props; - onHide(...args); + onHide?.(...args); } handleResize(...args: unknown[]): void { const { onResize } = this.props; - onResize(...args); + onResize?.(...args); } handleSessionClosed(session: dh.IdeSession): void { const { onSessionClose } = this.props; - onSessionClose(session); + onSessionClose?.(session); } handleSessionOpened( @@ -239,27 +215,27 @@ class Panel extends PureComponent { params: { language: string; sessionId: string } ): void { const { onSessionOpen } = this.props; - onSessionOpen(session, params); + onSessionOpen?.(session, params); } handleBeforeShow(...args: unknown[]): void { const { onBeforeShow } = this.props; - onBeforeShow(...args); + onBeforeShow?.(...args); } handleShow(...args: unknown[]): void { const { onShow } = this.props; - onShow(...args); + onShow?.(...args); } handleTabBlur(...args: unknown[]): void { const { onTabBlur } = this.props; - onTabBlur(...args); + onTabBlur?.(...args); } handleTabFocus(...args: unknown[]): void { const { onTabFocus } = this.props; - onTabFocus(...args); + onTabFocus?.(...args); } handleRenameCancel(): void { @@ -314,8 +290,12 @@ class Panel extends PureComponent { }; } - getAdditionActions = memoize( - (actions: ContextAction[], isClonable: boolean, isRenamable: boolean) => { + getAdditionalActions = memoize( + ( + actions: readonly ContextAction[], + isClonable: boolean, + isRenamable: boolean + ) => { const additionalActions = []; if (isClonable) { additionalActions.push(this.getCloneAction()); @@ -334,13 +314,14 @@ class Panel extends PureComponent { renderTabTooltip, glContainer, glEventHub, - additionalActions, + additionalActions = EMPTY_ARRAY, errorMessage, - isLoaded, - isLoading, - isClonable, - isRenamable, + isLoaded = true, + isLoading = false, + isClonable = false, + isRenamable = false, } = this.props; + const { tab: glTab } = glContainer; const { showRenameDialog, title, isWithinPanel } = this.state; @@ -364,7 +345,7 @@ class Panel extends PureComponent { ReactNode; - description: string; - - onFocus: () => void; - onBlur: () => void; - onHide: () => void; - onClearAllFilters: () => void; - onResize: () => void; - onSessionClose: (...args: unknown[]) => void; - onSessionOpen: (...args: unknown[]) => void; - onShow: () => void; - onTabBlur: () => void; - onTabFocus: () => void; - onTabClicked: () => void; -} + className?: string; + errorMessage?: string; + isClonable?: boolean; + isDisconnected?: boolean; + isLoading?: boolean; + isLoaded?: boolean; + isRenamable?: boolean; + showTabTooltip?: boolean; + + renderTabTooltip?: () => ReactNode; + + onFocus?: () => void; + onBlur?: () => void; + onHide?: () => void; + onClearAllFilters?: () => void; + onResize?: () => void; + onSessionClose?: (...args: unknown[]) => void; + onSessionOpen?: (...args: unknown[]) => void; + onShow?: () => void; + onTabBlur?: () => void; + onTabFocus?: () => void; + onTabClicked?: () => void; +}; interface WidgetPanelState { isClientDisconnected: boolean; @@ -55,29 +56,12 @@ interface WidgetPanelState { class WidgetPanel extends PureComponent { static defaultProps = { className: '', - errorMessage: null, isClonable: true, isDisconnected: false, isLoading: false, isLoaded: true, isRenamable: true, showTabTooltip: true, - widgetName: 'Widget', - widgetType: 'Widget', - renderTabTooltip: null, - description: '', - - onFocus: (): void => undefined, - onBlur: (): void => undefined, - onHide: (): void => undefined, - onClearAllFilters: (): void => undefined, - onResize: (): void => undefined, - onSessionClose: (): void => undefined, - onSessionOpen: (): void => undefined, - onShow: (): void => undefined, - onTabBlur: (): void => undefined, - onTabFocus: (): void => undefined, - onTabClicked: (): void => undefined, }; constructor(props: WidgetPanelProps) { @@ -97,19 +81,19 @@ class WidgetPanel extends PureComponent { } handleCopyName(): void { - const { widgetName } = this.props; - copyToClipboard(widgetName); + const { descriptor } = this.props; + copyToClipboard(descriptor.name); } getErrorMessage(): string | undefined { - const { errorMessage } = this.props; + const { descriptor, errorMessage } = this.props; const { isClientDisconnected, isPanelDisconnected, isWidgetDisconnected, isWaitingForReconnect, } = this.state; - if (errorMessage) { + if (errorMessage != null && errorMessage !== '') { return `${errorMessage}`; } if (isClientDisconnected && isPanelDisconnected && isWaitingForReconnect) { @@ -119,36 +103,31 @@ class WidgetPanel extends PureComponent { return 'Disconnected from server.'; } if (isPanelDisconnected) { - const { widgetName, widgetType } = this.props; - return `Variable "${widgetName}" not set.\n${widgetType} does not exist yet.`; + const { name, type } = descriptor; + return `Variable "${name}" not set.\n${type} does not exist yet.`; } if (isWidgetDisconnected) { - const { widgetName } = this.props; - return `${widgetName} is unavailable.`; + return `${descriptor.name} is unavailable.`; } return undefined; } getCachedRenderTabTooltip = memoize( - ( - showTabTooltip: boolean, - glContainer: Container, - widgetType: string, - widgetName: string, - description: string - ) => + (showTabTooltip: boolean, descriptor: WidgetPanelDescriptor) => showTabTooltip - ? () => ( - - ) - : null + ? () => + : undefined ); + getCachedActions = memoize((descriptor: WidgetPanelDescriptor) => [ + { + title: `Copy ${descriptor.displayType ?? descriptor.type} Name`, + group: ContextActions.groups.medium, + order: 20, + action: this.handleCopyName, + }, + ]); + handleSessionClosed(...args: unknown[]): void { const { onSessionClose } = this.props; // The session has closed and we won't be able to reconnect, as this widget isn't persisted @@ -156,12 +135,12 @@ class WidgetPanel extends PureComponent { isPanelDisconnected: true, isWaitingForReconnect: false, }); - onSessionClose(...args); + onSessionClose?.(...args); } handleSessionOpened(...args: unknown[]): void { const { onSessionOpen } = this.props; - onSessionOpen(...args); + onSessionOpen?.(...args); } render(): ReactElement { @@ -169,6 +148,7 @@ class WidgetPanel extends PureComponent { children, className, componentPanel, + descriptor, isLoaded, isLoading, glContainer, @@ -176,11 +156,8 @@ class WidgetPanel extends PureComponent { isDisconnected, isClonable, isRenamable, - showTabTooltip, + showTabTooltip = false, renderTabTooltip, - widgetType, - widgetName, - description, onClearAllFilters, onHide, @@ -198,22 +175,9 @@ class WidgetPanel extends PureComponent { const errorMessage = this.getErrorMessage(); const doRenderTabTooltip = renderTabTooltip ?? - this.getCachedRenderTabTooltip( - showTabTooltip, - glContainer, - widgetType, - widgetName, - description - ); - - const additionalActions = [ - { - title: `Copy ${widgetType} Name`, - group: ContextActions.groups.medium, - order: 20, - action: this.handleCopyName, - }, - ]; + this.getCachedRenderTabTooltip(showTabTooltip, descriptor); + + const additionalActions = this.getCachedActions(descriptor); return ( { } } -export default WidgetPanel; +const XWidgetPanel = createXComponent(WidgetPanel); + +export default XWidgetPanel; diff --git a/packages/dashboard-core-plugins/src/panels/WidgetPanelTooltip.tsx b/packages/dashboard-core-plugins/src/panels/WidgetPanelTooltip.tsx index 832e6f4009..1c9896ea93 100644 --- a/packages/dashboard-core-plugins/src/panels/WidgetPanelTooltip.tsx +++ b/packages/dashboard-core-plugins/src/panels/WidgetPanelTooltip.tsx @@ -1,39 +1,30 @@ -import React, { ReactNode, ReactElement } from 'react'; -import PropTypes from 'prop-types'; -import { CopyButton } from '@deephaven/components'; -import { GLPropTypes, LayoutUtils } from '@deephaven/dashboard'; +import React, { ReactElement } from 'react'; +import { CopyButton, createXComponent } from '@deephaven/components'; import './WidgetPanelTooltip.scss'; -import type { Container } from '@deephaven/golden-layout'; +import { WidgetPanelTooltipProps } from './WidgetPanelTypes'; -interface WidgetPanelTooltipProps { - glContainer: Container; - widgetType: string; - widgetName: string; - description: string; - children: ReactNode; -} function WidgetPanelTooltip(props: WidgetPanelTooltipProps): ReactElement { - const { widgetType, widgetName, glContainer, description, children } = props; - const panelTitle = LayoutUtils.getTitleFromContainer(glContainer); + const { children, descriptor } = props; + const { name, type, description, displayName } = descriptor; return (
- {widgetType} Name + {type} Name
- {widgetName} + {name}
- {widgetName !== panelTitle && ( + {name !== displayName && Boolean(displayName) && ( <> Display Name - {panelTitle} + {displayName} )} - {description && ( + {Boolean(description) && (
{description}
)} {children} @@ -41,19 +32,6 @@ function WidgetPanelTooltip(props: WidgetPanelTooltipProps): ReactElement { ); } -WidgetPanelTooltip.propTypes = { - glContainer: GLPropTypes.Container.isRequired, - widgetType: PropTypes.string, - widgetName: PropTypes.string, - description: PropTypes.string, - children: PropTypes.node, -}; - -WidgetPanelTooltip.defaultProps = { - widgetType: '', - widgetName: '', - description: null, - children: null, -}; +const XWidgetPanelTooltip = createXComponent(WidgetPanelTooltip); -export default WidgetPanelTooltip; +export default XWidgetPanelTooltip; diff --git a/packages/dashboard-core-plugins/src/panels/WidgetPanelTypes.ts b/packages/dashboard-core-plugins/src/panels/WidgetPanelTypes.ts new file mode 100644 index 0000000000..c370d7beb3 --- /dev/null +++ b/packages/dashboard-core-plugins/src/panels/WidgetPanelTypes.ts @@ -0,0 +1,26 @@ +import { ReactNode } from 'react'; + +export type WidgetPanelDescriptor = { + /** Type of the widget. */ + type: string; + + /** Name of the widget. */ + name: string; + + /** Display name of the widget. May be different than the assigned name. */ + displayName?: string; + + /** Display type of the widget. May be different than the assigned type. */ + displayType?: string; + + /** Description of the widget. */ + description?: string; +}; + +export type WidgetPanelTooltipProps = { + /** A descriptor of the widget. */ + descriptor: WidgetPanelDescriptor; + + /** Children to render within this tooltip */ + children?: ReactNode; +}; diff --git a/packages/dashboard-core-plugins/src/panels/index.ts b/packages/dashboard-core-plugins/src/panels/index.ts index d0dcedaa34..294e3a4c26 100644 --- a/packages/dashboard-core-plugins/src/panels/index.ts +++ b/packages/dashboard-core-plugins/src/panels/index.ts @@ -18,6 +18,7 @@ export { default as NotebookPanel } from './NotebookPanel'; export { default as PandasPanel } from './PandasPanel'; export * from './PandasPanel'; export { default as Panel } from './Panel'; +export * from './WidgetPanelTypes'; export { default as WidgetPanel } from './WidgetPanel'; export { default as WidgetPanelTooltip } from './WidgetPanelTooltip'; export { default as MockFileStorage } from './MockFileStorage'; diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index 76012ca914..97be252f0a 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -37,7 +37,6 @@ "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0", - "react-is": ">=16.8.0", "react-redux": "^7.2.4" }, "devDependencies": { diff --git a/packages/dashboard/src/DashboardPlugin.ts b/packages/dashboard/src/DashboardPlugin.ts index e4d64c84f2..592c27928b 100644 --- a/packages/dashboard/src/DashboardPlugin.ts +++ b/packages/dashboard/src/DashboardPlugin.ts @@ -14,6 +14,8 @@ import type { import PanelManager from './PanelManager'; import { WidgetDescriptor } from './PanelEvent'; +export { isWrappedComponent } from '@deephaven/components'; + /** * Panel components can provide static props that provide meta data about the * panel. @@ -52,14 +54,7 @@ export type PanelComponentType< C extends ComponentType

= ComponentType

, > = (ComponentType

| WrappedComponentType) & PanelStaticMetaData; -export function isWrappedComponent< - P extends PanelProps, - C extends ComponentType

, ->(type: PanelComponentType): type is WrappedComponentType { - return (type as WrappedComponentType)?.WrappedComponent !== undefined; -} - -export type PanelMetadata = Partial; +export type PanelMetadata = WidgetDescriptor; export type PanelProps = GLPanelProps & { metadata?: PanelMetadata; diff --git a/packages/dashboard/src/DashboardUtils.tsx b/packages/dashboard/src/DashboardUtils.tsx index 917d159963..09d48607d8 100644 --- a/packages/dashboard/src/DashboardUtils.tsx +++ b/packages/dashboard/src/DashboardUtils.tsx @@ -1,12 +1,11 @@ -import { ForwardRef } from 'react-is'; import { DehydratedDashboardPanelProps, DehydratedPanelConfig, - isWrappedComponent, - PanelComponentType, PanelConfig, } from './DashboardPlugin'; +export { canHaveRef } from '@deephaven/components'; + /** * Dehydrate an existing panel to allow it to be serialized/saved. * Just takes what's in the panels `metadata` in the props and `panelState` in @@ -54,29 +53,6 @@ export function hydrate( }; } -/** - * Checks if a panel component can take a ref. Helps silence react dev errors - * if a ref is passed to a functional component without forwardRef. - * @param component The panel component to check if it can take a ref - * @returns Wheter the component can take a ref or not - */ -export function canHaveRef(component: PanelComponentType): boolean { - // Might be a redux connect wrapped component - const isClassComponent = - (isWrappedComponent(component) && - component.WrappedComponent.prototype != null && - component.WrappedComponent.prototype.isReactComponent != null) || - (component.prototype != null && - component.prototype.isReactComponent != null); - - const isForwardRef = - !isWrappedComponent(component) && - '$$typeof' in component && - component.$$typeof === ForwardRef; - - return isClassComponent || isForwardRef; -} - export default { dehydrate, hydrate, diff --git a/packages/dashboard/src/PanelEvent.ts b/packages/dashboard/src/PanelEvent.ts index ad0ff3e21b..c15eb98f50 100644 --- a/packages/dashboard/src/PanelEvent.ts +++ b/packages/dashboard/src/PanelEvent.ts @@ -1,4 +1,4 @@ -import { DragEvent } from 'react'; +import { makeEventFunctions } from '@deephaven/golden-layout'; export type WidgetDescriptor = { type: string; @@ -7,16 +7,29 @@ export type WidgetDescriptor = { }; export type PanelOpenEventDetail = { - dragEvent?: DragEvent; - fetch?: () => Promise; + /** + * Opening the widget was triggered by dragging from a list, such as the Panels dropdown. + * The coordinates are used as the starting location for the drag, where we will show the panel until the user drops it in the dashboard. + */ + dragEvent?: MouseEvent; + + /** ID of the panel to re-use. Will replace any existing panel with this ID. Otherwise a new panel is opened with a randomly generated ID. */ panelId?: string; + + /** Descriptor of the widget. */ widget: WidgetDescriptor; + + /** + * Function to fetch the instance of the widget + * @deprecated Use `useWidget` hook with the `widget` descriptor instead + */ + fetch?: () => Promise; }; /** * Events emitted by panels and to control panels */ -export default Object.freeze({ +export const PanelEvent = Object.freeze({ // Panel has received focus FOCUS: 'PanelEvent.FOCUS', @@ -58,3 +71,13 @@ export default Object.freeze({ // Panel is dropped DROPPED: 'PanelEvent.DROPPED', }); + +export const { + listen: listenForPanelOpen, + emit: emitPanelOpen, + useListener: usePanelOpenListener, +} = makeEventFunctions(PanelEvent.OPEN); + +// TODO (#2147): Add the rest of the event functions here. Need to create the correct types for all of them. + +export default PanelEvent; diff --git a/packages/dashboard/src/index.ts b/packages/dashboard/src/index.ts index 026255f5fc..41c3fd3fd0 100644 --- a/packages/dashboard/src/index.ts +++ b/packages/dashboard/src/index.ts @@ -14,6 +14,5 @@ export * from './layout'; export * from './redux'; export * from './PanelManager'; export * from './PanelEvent'; -export { default as PanelEvent } from './PanelEvent'; export { default as PanelErrorBoundary } from './PanelErrorBoundary'; export { default as PanelManager } from './PanelManager'; diff --git a/packages/dashboard/src/layout/LayoutUtils.ts b/packages/dashboard/src/layout/LayoutUtils.ts index 30c93a4a1c..9cecf91d58 100644 --- a/packages/dashboard/src/layout/LayoutUtils.ts +++ b/packages/dashboard/src/layout/LayoutUtils.ts @@ -1,4 +1,3 @@ -import { DragEvent } from 'react'; import deepEqual from 'fast-deep-equal'; import { nanoid } from 'nanoid'; import isMatch from 'lodash.ismatch'; @@ -524,7 +523,7 @@ class LayoutUtils { replaceConfig?: Partial; createNewStack?: boolean; focusElement?: string; - dragEvent?: DragEvent; + dragEvent?: MouseEvent; } = {}): void { // attempt to retain focus after dom manipulation, which can break focus const maintainFocusElement = document.activeElement; diff --git a/packages/dashboard/src/layout/useDashboardPanel.ts b/packages/dashboard/src/layout/useDashboardPanel.ts index 54ab26ca09..4b01168ac9 100644 --- a/packages/dashboard/src/layout/useDashboardPanel.ts +++ b/packages/dashboard/src/layout/useDashboardPanel.ts @@ -9,9 +9,8 @@ import { PanelDehydrateFunction, PanelHydrateFunction, } from '../DashboardPlugin'; -import PanelEvent, { PanelOpenEventDetail } from '../PanelEvent'; +import { PanelOpenEventDetail, usePanelOpenListener } from '../PanelEvent'; import LayoutUtils from './LayoutUtils'; -import useListener from './useListener'; import usePanelRegistration from './usePanelRegistration'; /** @@ -88,7 +87,7 @@ export function useDashboardPanel< /** * Listen for panel open events so we know when to open a panel */ - useListener(layout.eventHub, PanelEvent.OPEN, handlePanelOpen); + usePanelOpenListener(layout.eventHub, handlePanelOpen); } export default useDashboardPanel; diff --git a/packages/embed-widget/src/App.tsx b/packages/embed-widget/src/App.tsx index 7c2367c581..2b3e395d5d 100644 --- a/packages/embed-widget/src/App.tsx +++ b/packages/embed-widget/src/App.tsx @@ -27,12 +27,12 @@ import { import Log from '@deephaven/log'; import { useDashboardPlugins } from '@deephaven/plugin'; import { - PanelEvent, getAllDashboardsData, listenForCreateDashboard, CreateDashboardPayload, setDashboardPluginData, stopListenForCreateDashboard, + emitPanelOpen, } from '@deephaven/dashboard'; import { getVariableDescriptor, @@ -190,7 +190,7 @@ function App(): JSX.Element { } setHasEmittedWidget(true); - goldenLayout.eventHub.emit(PanelEvent.OPEN, { + emitPanelOpen(goldenLayout.eventHub, { fetch, widget: getVariableDescriptor(definition), }); diff --git a/packages/golden-layout/src/utils/EventUtils.test.ts b/packages/golden-layout/src/utils/EventUtils.test.ts new file mode 100644 index 0000000000..956a87d685 --- /dev/null +++ b/packages/golden-layout/src/utils/EventUtils.test.ts @@ -0,0 +1,138 @@ +import { renderHook } from '@testing-library/react-hooks'; +import EventEmitter from './EventEmitter'; +import { + listenForEvent, + makeListenFunction, + makeEmitFunction, + makeEventFunctions, + makeUseListenerFunction, +} from './EventUtils'; + +function makeEventEmitter(): EventEmitter { + return { + on: jest.fn(), + off: jest.fn(), + emit: jest.fn(), + } as unknown as EventEmitter; +} + +describe('EventUtils', () => { + const eventEmitter = makeEventEmitter(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('listenForEvent', () => { + const event = 'test'; + const handler = jest.fn(); + const remove = listenForEvent(eventEmitter, event, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + remove(); + expect(eventEmitter.on).not.toHaveBeenCalled(); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); + + it('makeListenFunction', () => { + const event = 'test'; + const listen = makeListenFunction(event); + const handler = jest.fn(); + listen(eventEmitter, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + }); + + it('makeEmitFunction', () => { + const event = 'test'; + const emit = makeEmitFunction(event); + const payload = { test: 'test' }; + emit(eventEmitter, payload); + expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload); + }); + + describe('makeUseListenerFunction', () => { + it('adds listener on mount, removes on unmount', () => { + const event = 'test'; + const useListener = makeUseListenerFunction(event); + const handler = jest.fn(); + const { unmount } = renderHook(() => useListener(eventEmitter, handler)); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); + + it('adds listener on handler change, removes old listener', () => { + const event = 'test'; + const useListener = makeUseListenerFunction(event); + const handler1 = jest.fn(); + const handler2 = jest.fn(); + const { rerender } = renderHook( + ({ handler }) => useListener(eventEmitter, handler), + { initialProps: { handler: handler1 } } + ); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler1); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + rerender({ handler: handler2 }); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler2); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler1); + }); + + it('re-adds the listener on emitter change', () => { + const event = 'test'; + const useListener = makeUseListenerFunction(event); + const handler = jest.fn(); + const eventEmitter2 = makeEventEmitter(); + const { rerender, unmount } = renderHook( + ({ eventEmitter, handler }) => useListener(eventEmitter, handler), + { initialProps: { eventEmitter, handler } } + ); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + rerender({ eventEmitter: eventEmitter2, handler }); + expect(eventEmitter.on).not.toHaveBeenCalled(); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + expect(eventEmitter2.on).toHaveBeenCalledWith(event, handler); + + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalled(); + expect(eventEmitter.off).not.toHaveBeenCalled(); + expect(eventEmitter2.on).not.toHaveBeenCalled(); + expect(eventEmitter2.off).toHaveBeenCalledWith(event, handler); + }); + }); + + describe('makeEventFunctions', () => { + const event = 'test'; + const { listen, emit, useListener } = makeEventFunctions(event); + const handler = jest.fn(); + + it('listen', () => { + listen(eventEmitter, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + }); + + it('emit', () => { + const payload = { test: 'test' }; + emit(eventEmitter, payload); + expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload); + }); + + it('useListener', () => { + const { unmount } = renderHook(() => useListener(eventEmitter, handler)); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); + }); +}); diff --git a/packages/golden-layout/src/utils/EventUtils.ts b/packages/golden-layout/src/utils/EventUtils.ts new file mode 100644 index 0000000000..9ae97437b0 --- /dev/null +++ b/packages/golden-layout/src/utils/EventUtils.ts @@ -0,0 +1,79 @@ +import EventEmitter from './EventEmitter'; +import { useEffect } from 'react'; + +export type EventListenerRemover = () => void; +export type EventListenFunction = ( + eventEmitter: EventEmitter, + handler: (p: TPayload) => void +) => EventListenerRemover; + +export type EventEmitFunction = ( + eventEmitter: EventEmitter, + payload: TPayload +) => void; + +export type EventListenerHook = ( + eventEmitter: EventEmitter, + handler: (p: TPayload) => void +) => void; + +/** + * Listen for an event + * @param eventEmitter The event emitter to listen to + * @param event The event to listen for + * @param handler The handler to call when the event is emitted + * @returns A function to stop listening for the event + */ +export function listenForEvent( + eventEmitter: EventEmitter, + event: string, + handler: (p: TPayload) => void +): EventListenerRemover { + eventEmitter.on(event, handler); + return () => { + eventEmitter.off(event, handler); + }; +} + +export function makeListenFunction( + event: string +): EventListenFunction { + return (eventEmitter, handler) => + listenForEvent(eventEmitter, event, handler); +} + +export function makeEmitFunction( + event: string +): EventEmitFunction { + return (eventEmitter, payload) => { + eventEmitter.emit(event, payload); + }; +} + +export function makeUseListenerFunction( + event: string +): EventListenerHook { + return (eventEmitter, handler) => { + useEffect( + () => listenForEvent(eventEmitter, event, handler), + [eventEmitter, handler] + ); + }; +} + +/** + * Create listener, emitter, and hook functions for an event + * @param event Name of the event to create functions for + * @returns Listener, Emitter, and Hook functions for the event + */ +export function makeEventFunctions(event: string): { + listen: EventListenFunction; + emit: EventEmitFunction; + useListener: EventListenerHook; +} { + return { + listen: makeListenFunction(event), + emit: makeEmitFunction(event), + useListener: makeUseListenerFunction(event), + }; +} diff --git a/packages/golden-layout/src/utils/index.ts b/packages/golden-layout/src/utils/index.ts index 5c29546667..308e8c6089 100644 --- a/packages/golden-layout/src/utils/index.ts +++ b/packages/golden-layout/src/utils/index.ts @@ -6,3 +6,4 @@ export { default as ReactComponentHandler } from './ReactComponentHandler'; export * from './ConfigMinifier'; export { default as BubblingEvent } from './BubblingEvent'; export { default as EventHub } from './EventHub'; +export * from './EventUtils'; diff --git a/tests/styleguide.spec.ts b/tests/styleguide.spec.ts index e688354ed5..a70b6921e6 100644 --- a/tests/styleguide.spec.ts +++ b/tests/styleguide.spec.ts @@ -38,13 +38,14 @@ const sampleSectionIds: string[] = [ 'sample-section-grids-tree', 'sample-section-grids-iris', 'sample-section-charts', + 'sample-section-error-views', + 'sample-section-xcomponents', 'sample-section-spectrum-buttons', 'sample-section-spectrum-collections', 'sample-section-spectrum-content', 'sample-section-spectrum-forms', 'sample-section-spectrum-overlays', 'sample-section-spectrum-well', - 'sample-section-error-views', ]; const buttonSectionIds: string[] = [ 'sample-section-buttons-regular', diff --git a/tests/styleguide.spec.ts-snapshots/xcomponents-chromium-linux.png b/tests/styleguide.spec.ts-snapshots/xcomponents-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..4e87ad75b350f382e7b851b17104dfd753111499 GIT binary patch literal 35334 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 znO®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

bcB`_+Heqc}iMF0Vh-&DrgpMu= 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�UqN(*rHlY^x#1UlobjbulcgJ6Ob;a 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 literal 0 HcmV?d00001