Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Widget plugins #1564

Merged
merged 15 commits into from
Oct 19, 2023
47 changes: 45 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"@types/react": "^17.0.2",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^17.0.9",
"@types/react-is": "^17.0.2",
"@types/react-plotly.js": "^2.6.0",
"@types/react-router-dom": "^5.1.2",
"@types/react-test-renderer": "^17.0.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/app-utils/src/components/AppBootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
RefreshTokenBootstrap,
useBroadcastLoginListener,
} from '@deephaven/jsapi-components';
import { type DashboardPlugin } from '@deephaven/plugin';
import { type Plugin } from '@deephaven/plugin';
import FontBootstrap from './FontBootstrap';
import PluginsBootstrap from './PluginsBootstrap';
import AuthBootstrap from './AuthBootstrap';
Expand All @@ -24,7 +24,7 @@ export type AppBootstrapProps = {
pluginsUrl: string;

/** The core plugins to load. */
getCorePlugins?: () => Promise<DashboardPlugin[]>;
getCorePlugins?: () => Promise<Plugin[]>;

/** Font class names to load. */
fontClassNames?: string[];
Expand Down
4 changes: 2 additions & 2 deletions packages/app-utils/src/components/PluginsBootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type DashboardPlugin } from '@deephaven/plugin';
import { type Plugin } from '@deephaven/plugin';
import React, { createContext, useEffect, useState } from 'react';
import { PluginModuleMap, loadModulePlugins } from '../plugins';

Expand All @@ -11,7 +11,7 @@ export type PluginsBootstrapProps = {
pluginsUrl: string;

/** The core plugins to load. */
getCorePlugins?: () => Promise<DashboardPlugin[]>;
getCorePlugins?: () => Promise<Plugin[]>;

/**
* The children to render wrapped with the PluginsContext.
Expand Down
2 changes: 2 additions & 0 deletions packages/code-studio/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async function getCorePlugins() {
FilterPluginConfig,
MarkdownPluginConfig,
LinkerPluginConfig,
WidgetLoaderPluginConfig,
} = dashboardCorePlugins;
return [
GridPluginConfig,
Expand All @@ -51,6 +52,7 @@ async function getCorePlugins() {
FilterPluginConfig,
MarkdownPluginConfig,
LinkerPluginConfig,
WidgetLoaderPluginConfig,
];
}

Expand Down
18 changes: 18 additions & 0 deletions packages/console/src/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ interface ConsoleProps {
* (file:File) => Promise<File[]>
*/
unzip: (file: File) => Promise<JSZipObject[]>;
supportsType(type: string): boolean;
iconForType(type: string): ReactElement;
}

interface ConsoleState {
Expand All @@ -105,6 +107,16 @@ interface ConsoleState {
isPrintStdOutEnabled: boolean;
isClosePanelsOnDisconnectEnabled: boolean;
}

function defaultSupportsType(): boolean {
return true;
}

function defaultIconForType(type: string): ReactElement {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <></>;
}

export class Console extends PureComponent<ConsoleProps, ConsoleState> {
static defaultProps = {
statusBarChildren: null,
Expand All @@ -117,6 +129,8 @@ export class Console extends PureComponent<ConsoleProps, ConsoleState> {
objectMap: new Map(),
disabled: false,
unzip: null,
supportsType: defaultSupportsType,
iconForType: defaultIconForType,
};

static LOG_THROTTLE = 500;
Expand Down Expand Up @@ -951,6 +965,8 @@ export class Console extends PureComponent<ConsoleProps, ConsoleState> {
timeZone,
disabled,
unzip,
supportsType,
iconForType,
} = this.props;
const {
consoleHeight,
Expand Down Expand Up @@ -1013,6 +1029,8 @@ export class Console extends PureComponent<ConsoleProps, ConsoleState> {
openObject={openObject}
language={language}
disabled={disabled}
supportsType={supportsType}
iconForType={iconForType}
/>
{historyChildren}
</div>
Expand Down
68 changes: 35 additions & 33 deletions packages/console/src/console-history/ConsoleHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Console display for use in the Iris environment.
*/
import React, { Component, ReactElement } from 'react';
import { type ReactElement } from 'react';
import type { VariableDefinition } from '@deephaven/jsapi-types';
import ConsoleHistoryItem from './ConsoleHistoryItem';

Expand All @@ -13,43 +13,45 @@ interface ConsoleHistoryProps {
language: string;
openObject: (object: VariableDefinition) => void;
disabled?: boolean;
supportsType(type: string): boolean;
iconForType(type: string): ReactElement;
}

class ConsoleHistory extends Component<
ConsoleHistoryProps,
Record<string, never>
> {
static defaultProps = {
disabled: false,
};

static itemKey(i: number, item: ConsoleHistoryActionItem): string {
return `${i}.${item.command}.${item.result && item.result.message}.${
item.result && item.result.error
}`;
}

render(): ReactElement {
const { disabled, items, language, openObject } = this.props;
const historyElements = [];
for (let i = 0; i < items.length; i += 1) {
const item = items[i];
const historyElement = (
<ConsoleHistoryItem
key={ConsoleHistory.itemKey(i, item)}
disabled={disabled}
item={item}
openObject={openObject}
language={language}
/>
);
historyElements.push(historyElement);
}
function itemKey(i: number, item: ConsoleHistoryActionItem): string {
return `${i}.${item.command}.${item.result && item.result.message}.${
item.result && item.result.error
}`;
}

return (
<div className="container-fluid console-history">{historyElements}</div>
function ConsoleHistory(props: ConsoleHistoryProps): ReactElement {
const {
disabled = false,
items,
language,
openObject,
supportsType,
iconForType,
} = props;
const historyElements = [];
for (let i = 0; i < items.length; i += 1) {
const item = items[i];
const historyElement = (
<ConsoleHistoryItem
key={itemKey(i, item)}
disabled={disabled}
item={item}
openObject={openObject}
language={language}
supportsType={supportsType}
iconForType={iconForType}
/>
);
historyElements.push(historyElement);
}

return (
<div className="container-fluid console-history">{historyElements}</div>
);
mattrunyon marked this conversation as resolved.
Show resolved Hide resolved
}

export default ConsoleHistory;
13 changes: 10 additions & 3 deletions packages/console/src/console-history/ConsoleHistoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Button } from '@deephaven/components';
import Log from '@deephaven/log';
import type { VariableDefinition } from '@deephaven/jsapi-types';
import classNames from 'classnames';
import { Code, ObjectIcon } from '../common';
import { Code } from '../common';
import ConsoleHistoryItemResult from './ConsoleHistoryItemResult';
import ConsoleHistoryResultInProgress from './ConsoleHistoryResultInProgress';
import ConsoleHistoryResultErrorMessage from './ConsoleHistoryResultErrorMessage';
Expand All @@ -20,6 +20,10 @@ interface ConsoleHistoryItemProps {
language: string;
openObject: (object: VariableDefinition) => void;
disabled?: boolean;
// TODO: #1573 Remove this eslint disable
// eslint-disable-next-line react/no-unused-prop-types
supportsType: (type: string) => boolean;
iconForType: (type: string) => ReactElement;
}

class ConsoleHistoryItem extends PureComponent<
Expand Down Expand Up @@ -53,7 +57,7 @@ class ConsoleHistoryItem extends PureComponent<
}

render(): ReactElement {
const { disabled, item, language } = this.props;
const { disabled, item, language, iconForType } = this.props;
const { disabledObjects, result } = item;
const hasCommand = item.command != null && item.command !== '';

Expand All @@ -77,6 +81,9 @@ class ConsoleHistoryItem extends PureComponent<

if (changes) {
const { created, updated } = changes;
// TODO: #1573 filter for supported types or change button kind
// based on if type is supported. Possibly a warn state for widgets
// that the UI doesn't have anything registered to support.
[...created, ...updated].forEach(object => {
hasButtons = true;
const { title } = object;
Expand All @@ -92,7 +99,7 @@ class ConsoleHistoryItem extends PureComponent<
onClick={() => this.handleObjectClick(object)}
className="btn-console-object"
disabled={btnDisabled}
icon={<ObjectIcon type={object.type} />}
icon={iconForType(object.type)}
>
{title}
</Button>
Expand Down
37 changes: 16 additions & 21 deletions packages/dashboard-core-plugins/src/PandasPlugin.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
import {
assertIsDashboardPluginProps,
DashboardPluginComponentProps,
useDashboardPanel,
} from '@deephaven/dashboard';
import { useApi } from '@deephaven/jsapi-bootstrap';
import { DashboardPanelProps } from '@deephaven/dashboard';
import { WidgetComponentProps } from '@deephaven/plugin';
import { forwardRef, useMemo } from 'react';
import { PandasPanel } from './panels';
import useHydrateGrid from './useHydrateGrid';

export function PandasPlugin(
props: DashboardPluginComponentProps
): JSX.Element | null {
assertIsDashboardPluginProps(props);
const dh = useApi();
const hydrate = useHydrateGrid();
export const PandasPlugin = forwardRef(
(props: WidgetComponentProps, ref: React.Ref<PandasPanel>) => {
const hydrate = useHydrateGrid<DashboardPanelProps>();
const { localDashboardId } = props;
const hydratedProps = useMemo(
() => hydrate(props, localDashboardId),
[hydrate, props, localDashboardId]
);

useDashboardPanel({
dashboardProps: props,
componentName: PandasPanel.COMPONENT,
component: PandasPanel,
supportedTypes: dh.VariableType.PANDAS,
hydrate,
});
// eslint-disable-next-line react/jsx-props-no-spreading
return <PandasPanel ref={ref} {...hydratedProps} />;
mofojed marked this conversation as resolved.
Show resolved Hide resolved
}
);

return null;
}
PandasPlugin.displayName = 'PandasPlugin';

export default PandasPlugin;
Loading
Loading