Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/app-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@deephaven/iris-grid": "file:../iris-grid",
"@deephaven/jsapi-bootstrap": "file:../jsapi-bootstrap",
"@deephaven/jsapi-components": "file:../jsapi-components",
"@deephaven/jsapi-shim": "file:../jsapi-shim",
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
"@deephaven/jsapi-types": "1.0.0-dev0.34.0",
"@deephaven/jsapi-utils": "file:../jsapi-utils",
"@deephaven/log": "file:../log",
Expand Down
4 changes: 2 additions & 2 deletions packages/app-utils/src/components/AppBootstrap.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ it('should log in automatically when the anonymous handler is supported', async
});

expect(screen.queryByTestId('auth-base-loading')).toBeNull();
expect(screen.queryByTestId('connection-bootstrap-loading')).not.toBeNull();
expect(screen.queryByText(mockChildText)).toBeNull();
expect(screen.queryByTestId('connection-bootstrap-loading')).toBeNull();
expect(screen.queryByText(mockChildText)).not.toBeNull();
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
expect(mockChannel.postMessage).toHaveBeenCalledWith(
expect.objectContaining({
message: BROADCAST_LOGIN_MESSAGE,
Expand Down
117 changes: 113 additions & 4 deletions packages/app-utils/src/components/ConnectionBootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React, { useCallback, useEffect, useState } from 'react';
import { LoadingOverlay } from '@deephaven/components';
import {
BasicModal,
DebouncedModal,
InfoModal,
LoadingOverlay,
LoadingSpinner,
} from '@deephaven/components';
import {
ObjectFetcherContext,
sanitizeVariableDescriptor,
Expand All @@ -9,6 +15,7 @@ import {
import type { dh } from '@deephaven/jsapi-types';
import Log from '@deephaven/log';
import { assertNotNull } from '@deephaven/utils';
import { vsDebugDisconnect } from '@deephaven/icons';
import ConnectionContext from './ConnectionContext';

const log = Log.module('@deephaven/app-utils.ConnectionBootstrap');
Expand All @@ -29,8 +36,13 @@ export function ConnectionBootstrap({
}: ConnectionBootstrapProps): JSX.Element {
const api = useApi();
const client = useClient();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
const [error, setError] = useState<unknown>();
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
const [connection, setConnection] = useState<dh.IdeConnection>();
const [isAuthFailed, setIsAuthFailed] = useState<boolean>(false);
const [isShutdown, setIsShutdown] = useState<boolean>(false);
const [isReconnecting, setIsReconnecting] = useState<boolean>(false);

useEffect(
function initConnection() {
let isCanceled = false;
Expand All @@ -56,20 +68,85 @@ export function ConnectionBootstrap({
[api, client]
);

useEffect(function listenForDisconnect() {
if (connection == null) return;

// handles the disconnect event
function handleDisconnect(event: CustomEvent): void {
const { detail } = event;
log.info('Disconnect', `${JSON.stringify(detail)}`);
setIsReconnecting(true);
}
const removerFn = connection.addEventListener(
api.IdeConnection.EVENT_DISCONNECT,
handleDisconnect
);

return removerFn;
});

useEffect(
function listenForReconnect() {
if (connection == null) return;

// handles the reconnect event
function handleReconnect(event: CustomEvent): void {
const { detail } = event;
log.info('Reconnect', `${JSON.stringify(detail)}`);
setIsReconnecting(false);
}
const removerFn = connection.addEventListener(
api.CoreClient.EVENT_RECONNECT,
handleReconnect
);

return removerFn;
},
[api, connection]
);

useEffect(
function listenForShutdown() {
if (connection == null) return;

// handles the shutdown event
function handleShutdown(event: CustomEvent): void {
const { detail } = event;
log.info('Shutdown', `${JSON.stringify(detail)}`);
setError(`Server shutdown: ${detail ?? 'Unknown reason'}`);
setIsShutdown(true);
}

const removerFn = connection.addEventListener(
api.IdeConnection.EVENT_SHUTDOWN,
handleShutdown
);

return removerFn;
},
[api, connection]
);

useEffect(
function listenForAuthFailed() {
if (connection == null) return;

// handles the auth failed event
function handleAuthFailed(event: CustomEvent): void {
const { detail } = event;
log.warn(
'Reconnect authentication failed',
`${JSON.stringify(detail)}`
);
setError(
`Reconnect authentication failed: ${detail ?? 'Unknown reason'}`
);
setIsAuthFailed(true);
}
const removerFn = connection.addEventListener(
api.CoreClient.EVENT_RECONNECT_AUTH_FAILED,
handleAuthFailed
);

return removerFn;
},
[api, connection]
Expand All @@ -83,7 +160,34 @@ export function ConnectionBootstrap({
[connection]
);

if (connection == null || error != null) {
if (isReconnecting && !isShutdown) {
return (
<DebouncedModal isOpen={isReconnecting} debounceMs={1000}>
<InfoModal
icon={vsDebugDisconnect}
title={
<>
<LoadingSpinner /> Attempting to reconnect...
</>
}
subtitle="Please check your network connection."
/>
</DebouncedModal>
);
}

if (isAuthFailed) {
return (
<BasicModal
confirmButtonText="Refresh"
onConfirm={handleRefresh}
isOpen={isAuthFailed}
headerText="Authentication failed"
bodyText="Credentials are invalid. Please refresh your browser to try and reconnect."
/>
);
}
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
if (isShutdown) {
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
return (
<LoadingOverlay
data-testid="connection-bootstrap-loading"
Expand All @@ -93,8 +197,13 @@ export function ConnectionBootstrap({
);
}

function handleRefresh(): void {
log.info('Refreshing application');
window.location.reload();
}

return (
<ConnectionContext.Provider value={connection}>
<ConnectionContext.Provider value={connection ?? null}>
<ObjectFetcherContext.Provider value={objectFetcher}>
{children}
</ObjectFetcherContext.Provider>
Expand Down
98 changes: 4 additions & 94 deletions packages/code-studio/src/main/AppMainContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@ import {
Popper,
ContextAction,
Button,
InfoModal,
LoadingSpinner,
Logo,
BasicModal,
DebouncedModal,
NavTabList,
type NavTabItem,
SlideTransition,
Expand Down Expand Up @@ -140,8 +137,6 @@ interface AppMainContainerProps {

interface AppMainContainerState {
contextActions: ContextAction[];
isAuthFailed: boolean;
isDisconnected: boolean;
isPanelsMenuShown: boolean;
isResetLayoutPromptShown: boolean;
isSettingsMenuShown: boolean;
Expand Down Expand Up @@ -245,8 +240,6 @@ export class AppMainContainer extends Component<
isGlobal: true,
},
],
isAuthFailed: false,
isDisconnected: false,
isPanelsMenuShown: false,
isResetLayoutPromptShown: false,
isSettingsMenuShown: false,
Expand All @@ -266,7 +259,6 @@ export class AppMainContainer extends Component<
componentDidMount(): void {
this.initWidgets();
this.initDashboardData();
this.startListeningForDisconnect();

window.addEventListener(
'beforeunload',
Expand All @@ -286,7 +278,6 @@ export class AppMainContainer extends Component<

componentWillUnmount(): void {
this.deinitWidgets();
this.stopListeningForDisconnect();

this.dashboardLayouts.forEach(layout => {
stopListenForCreateDashboard(layout.eventHub, this.handleCreateDashboard);
Expand Down Expand Up @@ -637,21 +628,6 @@ export class AppMainContainer extends Component<
}
}

handleDisconnect(): void {
log.info('Disconnected from server');
this.setState({ isDisconnected: true });
}

handleReconnect(): void {
log.info('Reconnected to server');
this.setState({ isDisconnected: false });
}

handleReconnectAuthFailed(): void {
log.warn('Reconnect authentication failed');
this.setState({ isAuthFailed: true });
}

/**
* Import the provided file and set it in the workspace data (which should then load it in the dashboard)
* @param file JSON file to import
Expand Down Expand Up @@ -722,46 +698,6 @@ export class AppMainContainer extends Component<
}
}

startListeningForDisconnect(): void {
const { connection } = this.props;
if (connection == null) {
return;
}

connection.addEventListener(
dh.IdeConnection.EVENT_DISCONNECT,
this.handleDisconnect
);
connection.addEventListener(
dh.IdeConnection.EVENT_RECONNECT,
this.handleReconnect
);
connection.addEventListener(
dh.CoreClient.EVENT_RECONNECT_AUTH_FAILED,
this.handleReconnectAuthFailed
);
}

stopListeningForDisconnect(): void {
const { connection } = this.props;
if (connection == null) {
return;
}

connection.removeEventListener(
dh.IdeConnection.EVENT_DISCONNECT,
this.handleDisconnect
);
connection.removeEventListener(
dh.IdeConnection.EVENT_RECONNECT,
this.handleReconnect
);
connection.removeEventListener(
dh.CoreClient.EVENT_RECONNECT_AUTH_FAILED,
this.handleReconnectAuthFailed
);
}

/**
* Open a widget up, using a drag event if specified.
* @param widget The widget to open
Expand Down Expand Up @@ -851,13 +787,12 @@ export class AppMainContainer extends Component<
}

render(): ReactElement {
const { activeTool, plugins, user, serverConfigValues } = this.props;
const { activeTool, plugins, user, serverConfigValues, connection } =
this.props;
const { permissions } = user;
const { canUsePanels } = permissions;
const {
contextActions,
isAuthFailed,
isDisconnected,
isPanelsMenuShown,
isResetLayoutPromptShown,
isSettingsMenuShown,
Expand Down Expand Up @@ -950,7 +885,7 @@ export class AppMainContainer extends Component<
icon={
<span className="fa-layers">
<FontAwesomeIcon icon={vsGear} transform="grow-3" />
{isDisconnected && !isAuthFailed && (
{connection == null && (
<>
<FontAwesomeIcon
icon={dhSquareFilled}
Comment thread
AkshatJawne marked this conversation as resolved.
Outdated
Expand All @@ -966,11 +901,7 @@ export class AppMainContainer extends Component<
)}
</span>
}
tooltip={
isDisconnected && !isAuthFailed
? 'Server disconnected'
: 'User Settings'
}
tooltip="User Settings"
/>
</div>
</div>
Expand Down Expand Up @@ -1016,20 +947,6 @@ export class AppMainContainer extends Component<
onChange={this.handleImportLayoutFiles}
data-testid="input-import-layout"
/>
<DebouncedModal
isOpen={isDisconnected && !isAuthFailed}
debounceMs={1000}
>
<InfoModal
icon={vsDebugDisconnect}
title={
<>
<LoadingSpinner /> Attempting to reconnect...
</>
}
subtitle="Please check your network connection."
/>
</DebouncedModal>
<BasicModal
confirmButtonText="Reset"
onConfirm={this.handleConfirmResetLayoutPrompt}
Expand All @@ -1047,13 +964,6 @@ export class AppMainContainer extends Component<
: 'Do you want to reset your layout? Any unsaved notebooks will be lost.'
}
/>
<BasicModal
confirmButtonText="Refresh"
onConfirm={AppMainContainer.handleRefresh}
isOpen={isAuthFailed}
headerText="Authentication failed"
bodyText="Credentials are invalid. Please refresh your browser to try and reconnect."
/>
</div>
);
}
Expand Down
14 changes: 0 additions & 14 deletions packages/embed-widget/src/index.scss

This file was deleted.

Loading