Skip to content

Commit 6e813fd

Browse files
ericllnmofojed
andauthored
feat: Add global shortcut to export logs (#2336)
- Added `Ctrl+Alt+Shift+L/Cmd-Option-Shift-L` as a global shortcut for exporting support logs - When pressed in code-studio, it will download logs with the same contents as logs produced by pressing the 'Export Logs' button in the settings menu - When pressed in other contexts: when not logged in, on a reconnect error, or in embed-widgets, the logs are exported without the plugin and server info - Tested by E2E tests that navigate to the various contexts, presses the shortcut, and checks if a file was downloaded. Can further inspect the file downloaded in the tests but unsure if that's necessary Closes #1963 --------- Co-authored-by: Mike Bender <mikebender@deephaven.io>
1 parent 7e35751 commit 6e813fd

14 files changed

Lines changed: 134 additions & 18 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"lint:packages": "eslint \"packages/*/src/**/*.{ts,tsx,js,jsx}\"",
3535
"preview": "lerna run --scope=@deephaven/{code-studio,embed-widget} preview --stream",
3636
"preview:app": "lerna run --scope=@deephaven/code-studio preview --stream",
37+
"preview:embed-widget": "lerna run --scope=@deephaven/embed-widget preview --stream",
3738
"prestart": "npm run build:necessary",
3839
"start": "run-p watch:types start:*",
3940
"start:app": "lerna run start --scope=@deephaven/code-studio --stream",

packages/app-utils/src/components/AppBootstrap.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import '@deephaven/components/scss/BaseStyleSheet.scss';
55
import { ClientBootstrap } from '@deephaven/jsapi-bootstrap';
66
import { useBroadcastLoginListener } from '@deephaven/jsapi-components';
77
import { type Plugin } from '@deephaven/plugin';
8+
import { ContextActions, ContextMenuRoot } from '@deephaven/components';
89
import FontBootstrap from './FontBootstrap';
910
import PluginsBootstrap from './PluginsBootstrap';
1011
import AuthBootstrap from './AuthBootstrap';
1112
import ConnectionBootstrap from './ConnectionBootstrap';
12-
import { getConnectOptions } from '../utils';
13+
import { getConnectOptions, createExportLogsContextAction } from '../utils';
1314
import FontsLoaded from './FontsLoaded';
1415
import UserBootstrap from './UserBootstrap';
1516
import ServerConfigBootstrap from './ServerConfigBootstrap';
@@ -19,6 +20,9 @@ export type AppBootstrapProps = {
1920
/** URL of the server. */
2021
serverUrl: string;
2122

23+
/** Properties included in support logs. */
24+
logMetadata?: Record<string, unknown>;
25+
2226
/** URL of the plugins to load. */
2327
pluginsUrl: string;
2428

@@ -43,6 +47,7 @@ export function AppBootstrap({
4347
pluginsUrl,
4448
getCorePlugins,
4549
serverUrl,
50+
logMetadata,
4651
children,
4752
}: AppBootstrapProps): JSX.Element {
4853
const clientOptions = useMemo(() => getConnectOptions(), []);
@@ -56,6 +61,12 @@ export function AppBootstrap({
5661
});
5762
}, []);
5863
useBroadcastLoginListener(onLogin, onLogout);
64+
65+
const contextActions = useMemo(
66+
() => [createExportLogsContextAction(logMetadata, true)],
67+
[logMetadata]
68+
);
69+
5970
return (
6071
<Provider store={store}>
6172
<FontBootstrap fontClassNames={fontClassNames}>
@@ -78,10 +89,12 @@ export function AppBootstrap({
7889
</UserBootstrap>
7990
</ServerConfigBootstrap>
8091
</AuthBootstrap>
92+
<ContextActions actions={contextActions} />
8193
</ClientBootstrap>
8294
</ThemeBootstrap>
8395
</PluginsBootstrap>
8496
</FontBootstrap>
97+
<ContextMenuRoot />
8598
</Provider>
8699
);
87100
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { type ContextAction, GLOBAL_SHORTCUTS } from '@deephaven/components';
2+
import { exportLogs, logHistory } from '@deephaven/log';
3+
import { store } from '@deephaven/redux';
4+
5+
export function createExportLogsContextAction(
6+
metadata?: Record<string, unknown>,
7+
isGlobal = false
8+
): ContextAction {
9+
return {
10+
action: () => {
11+
exportLogs(
12+
logHistory,
13+
{
14+
...metadata,
15+
userAgent: navigator.userAgent,
16+
},
17+
store.getState()
18+
);
19+
},
20+
shortcut: GLOBAL_SHORTCUTS.EXPORT_LOGS,
21+
isGlobal,
22+
};
23+
}
24+
25+
export default createExportLogsContextAction;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './ConnectUtils';
2+
export * from './createExportLogsContextAction';

packages/code-studio/src/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ const pluginsURL = new URL(
3434
document.baseURI
3535
);
3636

37+
const logMetadata: Record<string, unknown> = {
38+
uiVersion: import.meta.env.npm_package_version,
39+
};
40+
3741
// Lazy load the configs because it breaks initial page loads otherwise
3842
async function getCorePlugins() {
3943
const dashboardCorePlugins = await import(
@@ -69,6 +73,7 @@ ReactDOM.render(
6973
getCorePlugins={getCorePlugins}
7074
serverUrl={apiURL.origin}
7175
pluginsUrl={pluginsURL.href}
76+
logMetadata={logMetadata}
7277
>
7378
<AppRoot />
7479
</AppBootstrap>

packages/code-studio/src/main/App.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import React, { type ReactElement } from 'react';
2-
import { ContextMenuRoot, ToastContainer } from '@deephaven/components';
2+
import { ToastContainer } from '@deephaven/components';
33
import AppMainContainer from './AppMainContainer';
44

55
function App(): ReactElement {
66
return (
77
<div className="app">
88
<AppMainContainer />
9-
<ContextMenuRoot />
109
<ToastContainer />
1110
</div>
1211
);

packages/code-studio/src/main/AppMainContainer.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function renderAppMainContainer({
6969
setActiveTool = jest.fn(),
7070
setDashboardIsolatedLinkerPanelId = jest.fn(),
7171
client = new (dh as any).Client({}),
72-
serverConfigValues = {},
72+
serverConfigValues = new Map<string, string>(),
7373
dashboardOpenedPanelMaps = {},
7474
connection = makeConnection(),
7575
session = makeSession(),

packages/code-studio/src/main/AppMainContainer.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,18 @@ import {
8585
AppDashboards,
8686
type LayoutStorage,
8787
UserLayoutUtils,
88+
createExportLogsContextAction,
8889
} from '@deephaven/app-utils';
8990
import JSZip from 'jszip';
9091
import SettingsMenu from '../settings/SettingsMenu';
9192
import AppControlsMenu from './AppControlsMenu';
9293
import { getLayoutStorage, getServerConfigValues } from '../redux';
9394
import './AppMainContainer.scss';
9495
import WidgetList, { type WindowMouseEvent } from './WidgetList';
95-
import { getFormattedVersionInfo } from '../settings/SettingsUtils';
96+
import {
97+
getFormattedPluginInfo,
98+
getFormattedVersionInfo,
99+
} from '../settings/SettingsUtils';
96100
import EmptyDashboard from './EmptyDashboard';
97101

98102
const log = Log.module('AppMainContainer');
@@ -186,18 +190,26 @@ export class AppMainContainer extends Component<
186190

187191
this.importElement = React.createRef();
188192

189-
const { allDashboardData } = this.props;
193+
const { allDashboardData, serverConfigValues, plugins } = this.props;
190194

191195
this.dashboardLayouts = new Map();
192196
this.createDashboardListenerRemovers = new Map();
193197
this.closeDashboardListenerRemovers = new Map();
194198

195199
this.state = {
196200
contextActions: [
201+
createExportLogsContextAction(
202+
{
203+
uiVersion: import.meta.env.npm_package_version,
204+
userAgent: navigator.userAgent,
205+
...Object.fromEntries(serverConfigValues),
206+
pluginInfo: getFormattedPluginInfo(plugins),
207+
},
208+
false // Not global to prevent conflict with export logs action with same shortcut in AppBootstrap.tsx
209+
),
197210
{
198211
action: () => {
199212
// Copies the version info to the clipboard for easy pasting into a ticket
200-
const { serverConfigValues } = this.props;
201213
const versionInfo = getFormattedVersionInfo(serverConfigValues);
202214
const versionInfoText = Object.entries(versionInfo)
203215
.map(([key, value]) => `${key}: ${value}`)

packages/components/src/shortcuts/GlobalShortcuts.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ const GLOBAL_SHORTCUTS = {
5858
macShortcut: [MODIFIER.CMD, MODIFIER.SHIFT, KEY.I],
5959
isEditable: true,
6060
}),
61+
EXPORT_LOGS: ShortcutRegistry.createAndAdd({
62+
id: 'GLOBAL.EXPORT_LOGS',
63+
name: 'Export Logs',
64+
shortcut: [MODIFIER.CTRL, MODIFIER.ALT, MODIFIER.SHIFT, KEY.L],
65+
macShortcut: [MODIFIER.CMD, MODIFIER.OPTION, MODIFIER.SHIFT, KEY.L],
66+
isEditable: true,
67+
}),
6168
NEXT: ShortcutRegistry.createAndAdd({
6269
id: 'GLOBAL.NEXT',
6370
name: 'Next',

packages/embed-widget/src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import type GoldenLayout from '@deephaven/golden-layout';
1313
import type { ItemConfig } from '@deephaven/golden-layout';
1414
import {
15-
ContextMenuRoot,
1615
ErrorBoundary,
1716
LoadingOverlay,
1817
Shortcut,
@@ -241,7 +240,6 @@ function App(): JSX.Element {
241240
errorMessage={error ?? null}
242241
/>
243242
)}
244-
<ContextMenuRoot />
245243
<ToastContainer />
246244
</div>
247245
);

0 commit comments

Comments
 (0)