Skip to content

Commit

Permalink
WIP Add "Export Layout" button
Browse files Browse the repository at this point in the history
Now need to import it - I think should be able to do that through updateWorkspaceData and just setting the new layout config, then having DashboardContainer to a prevProps.layoutConfig !== layoutConfig check and updating the layout if necessary.

WIP import layout

Not working correctly right now, dashboard is updating too frequently

Export/Import layout testing functionality

WIP load the first layout from the layouts folder

WIP hydrate the makeModel

This will probably change up when I've split out the dashboard plugins, but it's fine here for now

WIP hydrate ChartPanel tab

The way we are hydrating panels isn't great yet. Still need lots of cleanup, and need to make sure the session initializes even without a ConsolePanel present. Lots to cleanup, but coming along!

Move session initialization to AppInit instead of ConsolePanel

- In Application Mode, we may not have a ConsolePanel
- Just initialize the session before the layout is loaded

Add a workaround when getting a file with JSON contents

I still don't like this workaround because you're not getting the raw file contents.
Needs an upstream fix: perry-mitchell/webdav-client#267

WIP add panels menu - currently has hardcoded items

JSAPI currently doesn't report which objects are available

Move the Export/Import layout buttons to the WidgetList

... might still rename it PanelList

Bring layout initialization up to AppInit

Cleans it up a little bit

Clean up styling of export/import buttons

- Icons/styling doesn't look perfect yet, I'll ask Don when he gets back how to do the circle behind the arrow
- Background colour doesn't match the spec yet, but it's the same colour as the controls menu. Will confirm with Don

NEXT: empty dashboard screen

Add the empty dashboard view

- Button to autofill objects
- Hint pointing to panels menu

Clean up tests

Still have a few TODOs to do, but all the tests currently pass

Clean up based on self-review

- Remove unused redux actions
- Clean up some other code

Point to the new layouts directory

Added reset layout functionality

Cleaned up app init a little bit

Now you can reset your layout to the default easily.

Fix linting errors

Fix missing layout storage issue

Subscribe to field updates

Now the connection has the field updates to get the list of variables from

Clean up to match Nate's latest spec, add some unit tests

Update packages/code-studio/src/main/LayoutStorage.ts

Co-authored-by: vbabich <vladimir.babich@gmail.com>

Remove kludge for fetching webdav content

It is no longer required

Clean up based on review

- Rename session to sessionWrapper
- Fix a couple of spelling errors

Update based on Nate's latest changes

Need to fetch based on widget id rather than name...

Add error listener on connection

Add additional error handling based on Colin's updates

Remove `getTable` and `getFigure` from DhSession definition

There is only `getObject` now.

Fix up sorting of panels, dashboard not coming back from empty

Update the error message

Fix up how fonts are pre-loaded

Now they're done in AppInit, so while loading the workspace. Also listen for when fonts are finished loading before loading the rest of the app.

Fix how charts are opened

There's still a problem with the chart opening though...

Fix up the order of arguments in ChartModelFactory
  • Loading branch information
mofojed committed Aug 23, 2021
1 parent 1ea5c89 commit ff00dc8
Show file tree
Hide file tree
Showing 40 changed files with 1,313 additions and 259 deletions.
17 changes: 17 additions & 0 deletions packages/chart/src/ChartModelFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ class ChartModelFactory {
).then(figure => new FigureChartModel(figure, settings));
});
}

/**
* Creates a model from the settings provided.
* Tries to create a Figure in the API with it.
* @param {Object} settings The chart builder settings
* @param {boolean} settings.isLinked Whether the newly created chart should stay linked with the original table, update when filters are updated
* @param {string[]} settings.series The column names to use for creating the series of this chart
* @param {string} settings.sourcePanelId The panel ID the chart was created from
* @param {string} settings.type Chart builder type, from ChartBuilder.types
* @param {string} settings.xAxis The column name to use for the x-axis
* @param {string[]} settings.hiddenSeries Array of hidden series names
* @param {dh.Figure} figure The figure to build the model for
* @returns {Promise<FigureChartModel>} The FigureChartModel representing the figure
*/
static async makeModel(settings, figure) {
return new FigureChartModel(figure, settings);
}
}

export default ChartModelFactory;
1 change: 1 addition & 0 deletions packages/code-studio/.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name
REACT_APP_PLUGIN_URL=/ide/plugins/
REACT_APP_NOTEBOOKS_URL=/notebooks
REACT_APP_LAYOUTS_URL=/layouts
REACT_APP_INTERNAL_PLUGINS=
REACT_APP_ENABLE_LOG_PROXY=true
REACT_APP_SUPPORT_LINK=https://github.com/deephaven/web-client-ui/
Expand Down
1 change: 1 addition & 0 deletions packages/code-studio/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ REACT_APP_LOG_LEVEL=3
REACT_APP_ENABLE_LOG_PROXY=false
REACT_APP_CORE_API_URL=http://localhost:10000/jsapi
REACT_APP_NOTEBOOKS_URL=http://localhost:10000/notebooks
REACT_APP_LAYOUTS_URL=http://localhost:10000/layouts
REACT_APP_ROUTER_BASE_NAME=/
REACT_APP_INTERNAL_PLUGINS=ExamplePlugin
PORT=4000
Expand Down
56 changes: 53 additions & 3 deletions packages/code-studio/src/dashboard/DashboardContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect, Provider, ReactReduxContext } from 'react-redux';
import throttle from 'lodash.throttle';
import { PropTypes as APIPropTypes } from '@deephaven/jsapi-shim';
import Log from '@deephaven/log';
import {
getActiveTool,
Expand Down Expand Up @@ -48,6 +49,8 @@ import './DashboardContainer.scss';
import { UIPropTypes } from '../include/prop-types';
import PanelErrorBoundary from './panels/PanelErrorBoundary';
import FileExplorerPanel from './panels/FileExplorerPanel';
import { getSessionWrapper } from '../redux';
import { createChartModel, createGridModel } from '../main/WidgetUtils';

const log = Log.module('DashboardContainer');
const RESIZE_THROTTLE = 100;
Expand Down Expand Up @@ -95,6 +98,7 @@ export class DashboardContainer extends Component {
this.state = {
dashboardIsEmpty: true,
layout: null,
layoutConfig: null,
panelManager: null,
};
}
Expand All @@ -103,6 +107,17 @@ export class DashboardContainer extends Component {
this.init();
}

componentDidUpdate(prevProps) {
const { layoutConfig } = this.props;
const { layoutConfig: currentLayoutConfig } = this.state;
if (
prevProps.layoutConfig !== layoutConfig &&
layoutConfig !== currentLayoutConfig
) {
this.reloadLayoutConfig();
}
}

componentWillUnmount() {
if (this.isInitialised) {
this.deinit(false);
Expand Down Expand Up @@ -137,6 +152,11 @@ export class DashboardContainer extends Component {
ChartPanel: props => ({
...props,
localDashboardId,
makeModel: () => {
const { session } = this.props;
const { metadata, panelState } = props;
return createChartModel(session, metadata, panelState);
},
}),
ConsolePanel: props => ({
metadata: {},
Expand All @@ -162,8 +182,9 @@ export class DashboardContainer extends Component {
IrisGridPanel: props => ({
...props,
localDashboardId,
makeModel: async () => {
throw new Error('Re-hydration not yet implemented.');
makeModel: () => {
const { session } = this.props;
return createGridModel(session, props.metadata);
},
}),
LogPanel: props => ({
Expand Down Expand Up @@ -254,7 +275,7 @@ export class DashboardContainer extends Component {
content,
};

log.debug('InitLayout', content);
log.debug('initLayout layoutConfig', layoutConfig, 'content', content);

const layout = new GoldenLayout(config, this.layoutElement.current);

Expand Down Expand Up @@ -297,6 +318,31 @@ export class DashboardContainer extends Component {
return layout;
}

reloadLayoutConfig() {
const { layoutConfig } = this.props;
const { layout } = this.state;

const hydrateComponentPropsMap = this.makeHydrateComponentPropsMap();
const content = LayoutUtils.hydrateLayoutConfig(
layoutConfig,
hydrateComponentPropsMap
);

// Remove the old layout before add the new one
while (layout.root.contentItems.length > 0) {
layout.root.contentItems[0].remove();
}

// Add the new content. It is usally just one item from the root
for (let i = 0; i < content.length; i += 1) {
layout.root.addChild(content[i]);
}

this.setState({
dashboardIsEmpty: layoutConfig.length === 0,
});
}

registerComponent(layout, name, ComponentType) {
const { store } = this.context;

Expand Down Expand Up @@ -480,6 +526,8 @@ export class DashboardContainer extends Component {
this.setState({ dashboardIsEmpty: false });
}

this.setState({ layoutConfig: newLayoutConfig });

onLayoutConfigChange(newLayoutConfig);
}

Expand Down Expand Up @@ -551,6 +599,7 @@ DashboardContainer.propTypes = {
onDataChange: PropTypes.func,
onLayoutConfigChange: PropTypes.func,
onGoldenLayoutChange: PropTypes.func,
session: APIPropTypes.IdeSession.isRequired,
setActiveTool: PropTypes.func.isRequired,
setDashboardColumns: PropTypes.func.isRequired,
setDashboardInputFilters: PropTypes.func.isRequired,
Expand All @@ -575,6 +624,7 @@ DashboardContainer.contextType = ReactReduxContext;

const mapStateToProps = state => ({
activeTool: getActiveTool(state),
session: getSessionWrapper(state).session,
});

export default connect(mapStateToProps, {
Expand Down
17 changes: 14 additions & 3 deletions packages/code-studio/src/dashboard/panels/CommandHistoryPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ConsoleEvent, NotebookEvent } from '../events';
import './CommandHistoryPanel.scss';
import { GLPropTypes } from '../../include/prop-types';
import Panel from './Panel';
import { getSessionWrapper } from '../../redux';

const log = Log.module('CommandHistoryPanel');

Expand Down Expand Up @@ -189,9 +190,19 @@ CommandHistoryPanel.defaultProps = {
language: null,
};

const mapStateToProps = state => ({
commandHistoryStorage: getCommandHistoryStorage(state),
});
const mapStateToProps = state => {
const commandHistoryStorage = getCommandHistoryStorage(state);
const sessionWrapper = getSessionWrapper(state);
const { session, config: sessionConfig } = sessionWrapper;
const { type: language, id: sessionId } = sessionConfig;

return {
commandHistoryStorage,
language,
session,
sessionId,
};
};

export default connect(mapStateToProps, null, null, { forwardRef: true })(
CommandHistoryPanel
Expand Down
101 changes: 19 additions & 82 deletions packages/code-studio/src/dashboard/panels/ConsolePanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { connect } from 'react-redux';
import { Console, ConsoleConstants, ConsoleUtils } from '@deephaven/console';
import { FigureChartModel } from '@deephaven/chart';
import { IrisGridModelFactory } from '@deephaven/iris-grid';
import dh from '@deephaven/jsapi-shim';
import { PropTypes as APIPropTypes } from '@deephaven/jsapi-shim';
import { ThemeExport } from '@deephaven/components';
import Log from '@deephaven/log';
import { getCommandHistoryStorage } from '@deephaven/redux';
import { Pending, PromiseUtils } from '@deephaven/utils';
import {
ChartEvent,
ConsoleEvent,
Expand All @@ -25,6 +24,7 @@ import {
import { GLPropTypes } from '../../include/prop-types';
import './ConsolePanel.scss';
import Panel from './Panel';
import { getSessionWrapper } from '../../redux';

const log = Log.module('ConsolePanel');

Expand Down Expand Up @@ -59,7 +59,6 @@ class ConsolePanel extends PureComponent {
);

this.consoleRef = React.createRef();
this.pending = new Pending();

const { panelState: initialPanelState } = props;
const panelState = {
Expand All @@ -70,14 +69,8 @@ class ConsolePanel extends PureComponent {

this.state = {
consoleSettings,
language: null,
itemIds: new Map(itemIds),

isLoading: true,

session: null,
sessionId: null,

// eslint-disable-next-line react/no-unused-state
panelState, // Dehydrated panel state that can load this panel
};
Expand All @@ -89,8 +82,6 @@ class ConsolePanel extends PureComponent {
// as they may have been saved with the dashboard
this.closeDisconnectedPanels();
glEventHub.on(PanelEvent.MOUNT, this.handlePanelMount);

this.initSession();
}

componentDidUpdate(prevProps, prevState) {
Expand All @@ -107,67 +98,6 @@ class ConsolePanel extends PureComponent {
const { glEventHub } = this.props;
this.savePanelState.flush();
glEventHub.off(PanelEvent.MOUNT, this.handlePanelMount);

this.pending.cancel();

const { session } = this.state;
session?.close();
}

async initSession() {
try {
const baseUrl = new URL(
process.env.REACT_APP_CORE_API_URL,
window.location
);

const websocketUrl = `${baseUrl.protocol}//${baseUrl.host}`;

log.info(`Starting connection to '${websocketUrl}'...`);

const connection = new dh.IdeConnection(websocketUrl);

log.info('Getting console types...');

const types = await this.pending.add(connection.getConsoleTypes());

log.info('Available types:', types);

if (types.length === 0) {
throw new Error('No console types available');
}

const type = types[0];

log.info('Starting session with type', type);

const session = await this.pending.add(connection.startSession(type));

const sessionId = shortid.generate();

log.info('Console session established');

const { glEventHub } = this.props;
glEventHub.emit(ConsoleEvent.SESSION_OPENED, session, {
language: type,
sessionId,
});

this.setState(
{ isLoading: false, language: type, session, sessionId },
() => {
this.consoleRef.current?.focus();
}
);
} catch (error) {
if (PromiseUtils.isCanceled(error)) {
return;
}

log.error('Error Creating Console: ', error);

this.setState({ isLoading: false, error });
}
}

setItemId(name, id) {
Expand Down Expand Up @@ -228,7 +158,8 @@ class ConsolePanel extends PureComponent {
}

handleOpenObject(object) {
const { session } = this.state;
const { sessionWrapper } = this.props;
const { session } = sessionWrapper;
const { type } = object;
if (ConsoleUtils.isTableType(type)) {
this.openTable(object, session);
Expand Down Expand Up @@ -338,15 +269,16 @@ class ConsolePanel extends PureComponent {
}

render() {
const { commandHistoryStorage, glContainer, glEventHub } = this.props;
const {
consoleSettings,
error,
isLoading,
language,
session,
sessionId,
} = this.state;
commandHistoryStorage,
glContainer,
glEventHub,
sessionWrapper,
} = this.props;
const { consoleSettings, error } = this.state;
const { config, session } = sessionWrapper;
const { id: sessionId, type: language } = config;

return (
<Panel
componentPanel={this}
Expand All @@ -356,7 +288,6 @@ class ConsolePanel extends PureComponent {
onShow={this.handleShow}
onTabFocus={this.handleTabFocus}
onTabBlur={this.handleTabBlur}
isLoading={isLoading}
isLoaded={session != null}
errorMessage={error != null ? `${error}` : null}
>
Expand Down Expand Up @@ -405,6 +336,11 @@ ConsolePanel.propTypes = {
consoleSettings: PropTypes.shape({}),
itemIds: PropTypes.array,
}),

sessionWrapper: PropTypes.shape({
session: APIPropTypes.IdeSession,
config: PropTypes.shape({ type: PropTypes.string, id: PropTypes.string }),
}).isRequired,
};

ConsolePanel.defaultProps = {
Expand All @@ -413,6 +349,7 @@ ConsolePanel.defaultProps = {

const mapStateToProps = state => ({
commandHistoryStorage: getCommandHistoryStorage(state),
sessionWrapper: getSessionWrapper(state),
});

export default connect(mapStateToProps, null, null, { forwardRef: true })(
Expand Down
Loading

0 comments on commit ff00dc8

Please sign in to comment.