@theia/core 1.73.0-next.3 → 1.73.0-next.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -9
- package/lib/browser/authentication-service.d.ts +2 -0
- package/lib/browser/authentication-service.d.ts.map +1 -1
- package/lib/browser/authentication-service.js +8 -2
- package/lib/browser/authentication-service.js.map +1 -1
- package/lib/browser/catalog.json +222 -66
- package/lib/browser/frontend-application.d.ts +2 -0
- package/lib/browser/frontend-application.d.ts.map +1 -1
- package/lib/browser/frontend-application.js +15 -9
- package/lib/browser/frontend-application.js.map +1 -1
- package/lib/browser/json-schema-store.d.ts +2 -0
- package/lib/browser/json-schema-store.d.ts.map +1 -1
- package/lib/browser/json-schema-store.js +8 -2
- package/lib/browser/json-schema-store.js.map +1 -1
- package/lib/browser/keybinding.js +2 -1
- package/lib/browser/keybinding.js.map +1 -1
- package/lib/browser/markdown-rendering/markdown.d.ts +1 -1
- package/lib/browser/markdown-rendering/markdown.d.ts.map +1 -1
- package/lib/browser/markdown-rendering/markdown.js +1 -1
- package/lib/browser/markdown-rendering/markdown.js.map +1 -1
- package/lib/browser/menu/composite-menu-node.js +4 -4
- package/lib/browser/menu/composite-menu-node.js.map +1 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.d.ts +2 -0
- package/lib/browser/preferences/frontend-config-preference-contributions.d.ts.map +1 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.js +7 -1
- package/lib/browser/preferences/frontend-config-preference-contributions.js.map +1 -1
- package/lib/browser/preferences/preference-proxy.spec.js +7 -0
- package/lib/browser/preferences/preference-proxy.spec.js.map +1 -1
- package/lib/browser/preferences/preference-schema-provider.spec.js +3 -0
- package/lib/browser/preferences/preference-schema-provider.spec.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.d.ts +2 -0
- package/lib/browser/preferences/preference-validation-service.d.ts.map +1 -1
- package/lib/browser/preferences/preference-validation-service.js +11 -5
- package/lib/browser/preferences/preference-validation-service.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.spec.js +2 -0
- package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
- package/lib/browser/quick-input/quick-view-service.d.ts +1 -0
- package/lib/browser/quick-input/quick-view-service.d.ts.map +1 -1
- package/lib/browser/quick-input/quick-view-service.js +6 -1
- package/lib/browser/quick-input/quick-view-service.js.map +1 -1
- package/lib/browser/quick-input/quick-view-service.spec.d.ts +2 -0
- package/lib/browser/quick-input/quick-view-service.spec.d.ts.map +1 -0
- package/lib/browser/quick-input/quick-view-service.spec.js +41 -0
- package/lib/browser/quick-input/quick-view-service.spec.js.map +1 -0
- package/lib/browser/secondary-window-handler.d.ts +2 -0
- package/lib/browser/secondary-window-handler.d.ts.map +1 -1
- package/lib/browser/secondary-window-handler.js +12 -6
- package/lib/browser/secondary-window-handler.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +2 -0
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +9 -3
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +4 -4
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +2 -2
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js +131 -0
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -1
- package/lib/browser/status-bar/status-bar.d.ts +2 -2
- package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
- package/lib/browser/status-bar/status-bar.js.map +1 -1
- package/lib/browser/test/jsdom.d.ts +4 -0
- package/lib/browser/test/jsdom.d.ts.map +1 -1
- package/lib/browser/test/jsdom.js +18 -0
- package/lib/browser/test/jsdom.js.map +1 -1
- package/lib/browser/tree/tree-container.spec.js +4 -0
- package/lib/browser/tree/tree-container.spec.js.map +1 -1
- package/lib/browser/tree/tree-widget.js +2 -2
- package/lib/browser/tree/tree-widget.js.map +1 -1
- package/lib/browser/tree/tree.d.ts +2 -0
- package/lib/browser/tree/tree.d.ts.map +1 -1
- package/lib/browser/tree/tree.js +7 -1
- package/lib/browser/tree/tree.js.map +1 -1
- package/lib/browser/window/default-window-service.d.ts +2 -1
- package/lib/browser/window/default-window-service.d.ts.map +1 -1
- package/lib/browser/window/default-window-service.js +10 -5
- package/lib/browser/window/default-window-service.js.map +1 -1
- package/lib/browser/window/default-window-service.spec.js +2 -0
- package/lib/browser/window/default-window-service.spec.js.map +1 -1
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts +2 -0
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts.map +1 -1
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.js +8 -2
- package/lib/browser-only/messaging/frontend-only-service-connection-provider.js.map +1 -1
- package/lib/common/command.d.ts +2 -0
- package/lib/common/command.d.ts.map +1 -1
- package/lib/common/command.js +10 -4
- package/lib/common/command.js.map +1 -1
- package/lib/common/preferences/injectable-preference-proxy.d.ts +3 -3
- package/lib/common/preferences/injectable-preference-proxy.d.ts.map +1 -1
- package/lib/common/preferences/injectable-preference-proxy.js +6 -1
- package/lib/common/preferences/injectable-preference-proxy.js.map +1 -1
- package/lib/common/preferences/preference-proxy.d.ts.map +1 -1
- package/lib/common/preferences/preference-proxy.js +6 -1
- package/lib/common/preferences/preference-proxy.js.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +4 -2
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-node/request/electron-backend-request-service.d.ts +2 -0
- package/lib/electron-node/request/electron-backend-request-service.d.ts.map +1 -1
- package/lib/electron-node/request/electron-backend-request-service.js +7 -1
- package/lib/electron-node/request/electron-backend-request-service.js.map +1 -1
- package/lib/electron-node/token/electron-token-backend-contribution.d.ts +2 -0
- package/lib/electron-node/token/electron-token-backend-contribution.d.ts.map +1 -1
- package/lib/electron-node/token/electron-token-backend-contribution.js +7 -1
- package/lib/electron-node/token/electron-token-backend-contribution.js.map +1 -1
- package/lib/electron-node/token/electron-token-validator.d.ts +2 -0
- package/lib/electron-node/token/electron-token-validator.d.ts.map +1 -1
- package/lib/electron-node/token/electron-token-validator.js +7 -1
- package/lib/electron-node/token/electron-token-validator.js.map +1 -1
- package/lib/node/backend-application.d.ts +2 -0
- package/lib/node/backend-application.d.ts.map +1 -1
- package/lib/node/backend-application.js +17 -11
- package/lib/node/backend-application.js.map +1 -1
- package/lib/node/backend-application.spec.js +3 -2
- package/lib/node/backend-application.spec.js.map +1 -1
- package/lib/node/logger-cli-contribution.d.ts +6 -0
- package/lib/node/logger-cli-contribution.d.ts.map +1 -1
- package/lib/node/logger-cli-contribution.js +28 -5
- package/lib/node/logger-cli-contribution.js.map +1 -1
- package/lib/node/logger-cli-contribution.spec.js +54 -0
- package/lib/node/logger-cli-contribution.spec.js.map +1 -1
- package/lib/node/messaging/default-messaging-service.d.ts +2 -0
- package/lib/node/messaging/default-messaging-service.d.ts.map +1 -1
- package/lib/node/messaging/default-messaging-service.js +8 -2
- package/lib/node/messaging/default-messaging-service.js.map +1 -1
- package/lib/node/messaging/test/default-messaging-service.spec.js +2 -0
- package/lib/node/messaging/test/default-messaging-service.spec.js.map +1 -1
- package/lib/node/messaging/websocket-endpoint.d.ts +2 -0
- package/lib/node/messaging/websocket-endpoint.d.ts.map +1 -1
- package/lib/node/messaging/websocket-endpoint.js +7 -1
- package/lib/node/messaging/websocket-endpoint.js.map +1 -1
- package/lib/node/process-utils.d.ts +2 -0
- package/lib/node/process-utils.d.ts.map +1 -1
- package/lib/node/process-utils.js +8 -2
- package/lib/node/process-utils.js.map +1 -1
- package/lib/node/process-utils.spec.js +11 -9
- package/lib/node/process-utils.spec.js.map +1 -1
- package/package.json +26 -16
- package/src/browser/authentication-service.ts +6 -3
- package/src/browser/frontend-application.ts +13 -9
- package/src/browser/json-schema-store.ts +6 -2
- package/src/browser/keybinding.ts +2 -2
- package/src/browser/markdown-rendering/markdown.tsx +2 -2
- package/src/browser/menu/composite-menu-node.ts +4 -4
- package/src/browser/preferences/frontend-config-preference-contributions.ts +7 -2
- package/src/browser/preferences/preference-proxy.spec.ts +8 -0
- package/src/browser/preferences/preference-schema-provider.spec.ts +5 -0
- package/src/browser/preferences/preference-validation-service.spec.ts +3 -1
- package/src/browser/preferences/preference-validation-service.ts +9 -6
- package/src/browser/quick-input/quick-view-service.spec.ts +50 -0
- package/src/browser/quick-input/quick-view-service.ts +5 -0
- package/src/browser/secondary-window-handler.ts +11 -7
- package/src/browser/shell/application-shell.ts +8 -4
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +4 -4
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +2 -2
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.ts +159 -1
- package/src/browser/status-bar/status-bar.tsx +3 -3
- package/src/browser/test/jsdom.ts +18 -0
- package/src/browser/tree/tree-container.spec.ts +6 -0
- package/src/browser/tree/tree-widget.tsx +2 -2
- package/src/browser/tree/tree.ts +6 -2
- package/src/browser/window/default-window-service.spec.ts +3 -1
- package/src/browser/window/default-window-service.ts +9 -6
- package/src/browser-only/messaging/frontend-only-service-connection-provider.ts +8 -3
- package/src/common/command.ts +8 -4
- package/src/common/preferences/injectable-preference-proxy.ts +10 -4
- package/src/common/preferences/preference-proxy.ts +10 -4
- package/src/electron-main/electron-main-application.ts +4 -2
- package/src/electron-node/request/electron-backend-request-service.ts +6 -2
- package/src/electron-node/token/electron-token-backend-contribution.ts +6 -2
- package/src/electron-node/token/electron-token-validator.ts +6 -2
- package/src/node/backend-application.spec.ts +3 -3
- package/src/node/backend-application.ts +15 -11
- package/src/node/logger-cli-contribution.spec.ts +65 -0
- package/src/node/logger-cli-contribution.ts +32 -5
- package/src/node/messaging/default-messaging-service.ts +6 -2
- package/src/node/messaging/test/default-messaging-service.spec.ts +3 -1
- package/src/node/messaging/websocket-endpoint.ts +6 -2
- package/src/node/process-utils.spec.ts +12 -9
- package/src/node/process-utils.ts +7 -3
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { injectable, inject, optional, postConstruct } from 'inversify';
|
|
17
|
+
import { injectable, inject, optional, postConstruct, named } from 'inversify';
|
|
18
18
|
import { ArrayExt, find, toArray, each } from '@lumino/algorithm';
|
|
19
19
|
import {
|
|
20
20
|
BoxLayout, BoxPanel, DockLayout, DockPanel, FocusTracker, Layout, Panel, SplitLayout,
|
|
@@ -46,6 +46,7 @@ import { OpenerService } from '../opener-service';
|
|
|
46
46
|
import { PreviewableWidget } from '../widgets/previewable-widget';
|
|
47
47
|
import { WindowService } from '../window/window-service';
|
|
48
48
|
import { TheiaSplitPanel } from './theia-split-panel';
|
|
49
|
+
import { ILogger } from '../../common/logger';
|
|
49
50
|
|
|
50
51
|
/** The class name added to ApplicationShell instances. */
|
|
51
52
|
export const APPLICATION_SHELL_CLASS = 'theia-ApplicationShell';
|
|
@@ -242,6 +243,9 @@ export class ApplicationShell extends Widget {
|
|
|
242
243
|
@inject(UntitledResourceResolver)
|
|
243
244
|
protected readonly untitledResourceResolver: UntitledResourceResolver;
|
|
244
245
|
|
|
246
|
+
@inject(ILogger) @named('core:ApplicationShell')
|
|
247
|
+
protected readonly logger: ILogger;
|
|
248
|
+
|
|
245
249
|
protected readonly onDidAddWidgetEmitter = new Emitter<Widget>();
|
|
246
250
|
readonly onDidAddWidget = this.onDidAddWidgetEmitter.event;
|
|
247
251
|
protected fireDidAddWidget(widget: Widget): void {
|
|
@@ -595,7 +599,7 @@ export class ApplicationShell extends Widget {
|
|
|
595
599
|
const opener = await this.openerService.getOpener(fileUri);
|
|
596
600
|
opener.open(fileUri);
|
|
597
601
|
} catch (e) {
|
|
598
|
-
|
|
602
|
+
this.logger.info(`no opener found for '${fileUri}'`);
|
|
599
603
|
}
|
|
600
604
|
};
|
|
601
605
|
|
|
@@ -975,7 +979,7 @@ export class ApplicationShell extends Widget {
|
|
|
975
979
|
*/
|
|
976
980
|
async addWidget(widget: Widget, options?: Readonly<ApplicationShell.WidgetOptions>): Promise<void> {
|
|
977
981
|
if (!widget.id) {
|
|
978
|
-
|
|
982
|
+
this.logger.error('Widgets added to the application shell must have a unique id property.');
|
|
979
983
|
return;
|
|
980
984
|
}
|
|
981
985
|
const { area, addOptions } = this.getInsertionOptions(options);
|
|
@@ -1430,7 +1434,7 @@ export class ApplicationShell extends Widget {
|
|
|
1430
1434
|
if (delta < this.activationTimeout) {
|
|
1431
1435
|
request = setTimeout(step, 0);
|
|
1432
1436
|
} else {
|
|
1433
|
-
|
|
1437
|
+
this.logger.warn(`Widget was activated, but did not accept focus after ${this.activationTimeout}ms: ${widget.id}`);
|
|
1434
1438
|
}
|
|
1435
1439
|
};
|
|
1436
1440
|
let request = setTimeout(step, 0);
|
|
@@ -96,7 +96,7 @@ abstract class AbstractToolbarMenuWrapper {
|
|
|
96
96
|
const icon = this.icon || 'ellipsis';
|
|
97
97
|
const contextMatcher: ContextMatcher = this.contextKeyService;
|
|
98
98
|
const className = `${icon} ${ACTION_ITEM}`;
|
|
99
|
-
if (CompoundMenuNode.is(this.menuNode) && !this.menuNode.isEmpty(this.effectiveMenuPath, this.contextKeyService, widget.node)) {
|
|
99
|
+
if (CompoundMenuNode.is(this.menuNode) && !this.menuNode.isEmpty(this.effectiveMenuPath, this.contextKeyService, widget.node, widget)) {
|
|
100
100
|
return <div key={this.id} className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}>
|
|
101
101
|
<div className={className}
|
|
102
102
|
title={this.tooltip || this.text}
|
|
@@ -308,7 +308,7 @@ abstract class AbstractMenuNodeAsToolbarItemWrapper<T extends MenuNode> {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
isVisible<K>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<K>, context: K | undefined, ...args: unknown[]): boolean {
|
|
311
|
-
return this.menuNode!.isVisible(this.effectiveMenuPath, contextMatcher, context, args);
|
|
311
|
+
return this.menuNode!.isVisible(this.effectiveMenuPath, contextMatcher, context, ...args);
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -321,7 +321,7 @@ class ToolbarItemAsSubmenuWrapper extends AbstractMenuNodeAsToolbarItemWrapper<C
|
|
|
321
321
|
return this.menuNode.contextKeyOverlays;
|
|
322
322
|
}
|
|
323
323
|
isEmpty<T>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<T>, context: T | undefined, ...args: unknown[]): boolean {
|
|
324
|
-
return this.menuNode.isEmpty(this.effectiveMenuPath, contextMatcher, context, args);
|
|
324
|
+
return this.menuNode.isEmpty(this.effectiveMenuPath, contextMatcher, context, ...args);
|
|
325
325
|
}
|
|
326
326
|
get children(): MenuNode[] {
|
|
327
327
|
return this.menuNode.children;
|
|
@@ -340,7 +340,7 @@ class ToolbarItemAsCommandMenuWrapper extends AbstractMenuNodeAsToolbarItemWrapp
|
|
|
340
340
|
return this.menuNode.isToggled(this.effectiveMenuPath, ...args);
|
|
341
341
|
}
|
|
342
342
|
run(effectiveMenuPath: MenuPath, ...args: unknown[]): Promise<void> {
|
|
343
|
-
return this.menuNode.run(this.effectiveMenuPath, args);
|
|
343
|
+
return this.menuNode.run(this.effectiveMenuPath, ...args);
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
override get label(): string {
|
|
@@ -141,11 +141,11 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
141
141
|
const menu = this.menuRegistry.getMenu(delegate.menuPath);
|
|
142
142
|
if (menu) {
|
|
143
143
|
for (const child of menu.children) {
|
|
144
|
-
if (child.isVisible([...delegate.menuPath, child.id], this.contextKeyService, widget.node)) {
|
|
144
|
+
if (child.isVisible([...delegate.menuPath, child.id], this.contextKeyService, widget.node, widget)) {
|
|
145
145
|
if (CompoundMenuNode.is(child)) {
|
|
146
146
|
for (const grandchild of child.children) {
|
|
147
147
|
if (grandchild.isVisible([...delegate.menuPath, child.id, grandchild.id],
|
|
148
|
-
this.contextKeyService, widget.node) && RenderedMenuNode.is(grandchild)) {
|
|
148
|
+
this.contextKeyService, widget.node, widget) && RenderedMenuNode.is(grandchild)) {
|
|
149
149
|
if (CommandMenu.is(grandchild)) {
|
|
150
150
|
result.push(new CommandMenuAsToolbarItemWrapper([...delegate.menuPath, child.id, grandchild.id], this.commandRegistry,
|
|
151
151
|
this.menuRegistry, this.contextKeyService, this.contextMenuRenderer, grandchild, child.id));
|
|
@@ -18,7 +18,16 @@ import { enableJSDOM } from '../../test/jsdom';
|
|
|
18
18
|
|
|
19
19
|
let disableJSDOM = enableJSDOM();
|
|
20
20
|
import { expect } from 'chai';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
CommandMenu, CommandRegistry, CompoundMenuNode, Group, GroupImpl, MenuAction, MenuModelRegistry, MenuNode, MenuNodeFactory, MutableCompoundMenuNode,
|
|
23
|
+
Submenu, SubmenuImpl, SubMenuLink
|
|
24
|
+
} from '../../../common';
|
|
25
|
+
import { ContextKeyServiceDummyImpl } from '../../context-key-service';
|
|
26
|
+
import { ContextMenuRenderer } from '../../context-menu-renderer';
|
|
27
|
+
import { Widget } from '../../widgets';
|
|
28
|
+
import { TOOLBAR_WRAPPER_ID_SUFFIX } from './tab-bar-toolbar-menu-adapters';
|
|
29
|
+
import { TabBarToolbarRegistry } from './tab-bar-toolbar-registry';
|
|
30
|
+
import { TAB_BAR_TOOLBAR_CONTEXT_MENU, TabBarToolbarAction } from './tab-bar-toolbar-types';
|
|
22
31
|
|
|
23
32
|
disableJSDOM();
|
|
24
33
|
|
|
@@ -59,4 +68,153 @@ describe('tab-bar-toolbar', () => {
|
|
|
59
68
|
|
|
60
69
|
});
|
|
61
70
|
|
|
71
|
+
describe('menu delegates', () => {
|
|
72
|
+
|
|
73
|
+
const TEST_MENU_PATH = ['test-toolbar-delegate'];
|
|
74
|
+
const TEST_COMMAND = 'test.toolbar.command';
|
|
75
|
+
const TEST_SUBMENU_COMMAND = 'test.toolbar.submenu.command';
|
|
76
|
+
|
|
77
|
+
let contextKeyService: ContextKeyServiceDummyImpl;
|
|
78
|
+
|
|
79
|
+
before(() => {
|
|
80
|
+
disableJSDOM = enableJSDOM();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
beforeEach(() => {
|
|
84
|
+
contextKeyService = new ContextKeyServiceDummyImpl();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
after(() => {
|
|
88
|
+
disableJSDOM();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('passes the delegated widget to command visibility', () => {
|
|
92
|
+
const testWidget = new TestToolbarWidget();
|
|
93
|
+
const commands = createCommandRegistry();
|
|
94
|
+
commands.registerCommand({ id: TEST_COMMAND, label: 'Test Command' }, {
|
|
95
|
+
execute: () => { },
|
|
96
|
+
isVisible: widget => TestToolbarWidget.is(widget) && widget === testWidget
|
|
97
|
+
});
|
|
98
|
+
const menuRegistry = createMenuRegistry(commands);
|
|
99
|
+
menuRegistry.registerMenuAction([...TEST_MENU_PATH, 'other'], { commandId: TEST_COMMAND });
|
|
100
|
+
const registry = createToolbarRegistry(commands, menuRegistry, contextKeyService);
|
|
101
|
+
registry.registerMenuDelegate(TEST_MENU_PATH, TestToolbarWidget.is);
|
|
102
|
+
|
|
103
|
+
const commandItem = registry.visibleItems(testWidget).find(item => item.id === `${TEST_COMMAND}${TOOLBAR_WRAPPER_ID_SUFFIX}`);
|
|
104
|
+
|
|
105
|
+
expect(commandItem).to.exist;
|
|
106
|
+
testWidget.dispose();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('preserves the widget for wrapped command menu visibility, enablement, toggled state, and execution', async () => {
|
|
110
|
+
const testWidget = new TestToolbarWidget();
|
|
111
|
+
let executedWith: unknown;
|
|
112
|
+
const commands = createCommandRegistry();
|
|
113
|
+
commands.registerCommand({ id: TEST_COMMAND, label: 'Test Command' }, {
|
|
114
|
+
execute: widget => executedWith = widget,
|
|
115
|
+
isVisible: widget => TestToolbarWidget.is(widget) && widget === testWidget,
|
|
116
|
+
isEnabled: widget => TestToolbarWidget.is(widget) && widget === testWidget,
|
|
117
|
+
isToggled: widget => TestToolbarWidget.is(widget) && widget === testWidget
|
|
118
|
+
});
|
|
119
|
+
const menuRegistry = createMenuRegistry(commands);
|
|
120
|
+
menuRegistry.registerMenuAction([...TEST_MENU_PATH, 'other'], { commandId: TEST_COMMAND });
|
|
121
|
+
const registry = createToolbarRegistry(commands, menuRegistry, contextKeyService);
|
|
122
|
+
registry.registerMenuDelegate(TEST_MENU_PATH, TestToolbarWidget.is);
|
|
123
|
+
const commandItem = registry.visibleItems(testWidget).find(item => item.id === `${TEST_COMMAND}${TOOLBAR_WRAPPER_ID_SUFFIX}`);
|
|
124
|
+
const node = commandItem?.toMenuNode?.();
|
|
125
|
+
|
|
126
|
+
expect(CommandMenu.is(node)).to.be.true;
|
|
127
|
+
if (!CommandMenu.is(node)) {
|
|
128
|
+
throw new Error('Expected a command menu node.');
|
|
129
|
+
}
|
|
130
|
+
expect(node.isVisible(TAB_BAR_TOOLBAR_CONTEXT_MENU, contextKeyService, testWidget.node, testWidget)).to.be.true;
|
|
131
|
+
expect(node.isEnabled(TAB_BAR_TOOLBAR_CONTEXT_MENU, testWidget)).to.be.true;
|
|
132
|
+
expect(node.isToggled(TAB_BAR_TOOLBAR_CONTEXT_MENU, testWidget)).to.be.true;
|
|
133
|
+
await node.run(TAB_BAR_TOOLBAR_CONTEXT_MENU, testWidget);
|
|
134
|
+
expect(executedWith).to.equal(testWidget);
|
|
135
|
+
testWidget.dispose();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('preserves the widget for wrapped submenu emptiness checks', () => {
|
|
139
|
+
const testWidget = new TestToolbarWidget();
|
|
140
|
+
const commands = createCommandRegistry();
|
|
141
|
+
commands.registerCommand({ id: TEST_SUBMENU_COMMAND, label: 'Test Submenu Command' }, {
|
|
142
|
+
execute: () => { },
|
|
143
|
+
isVisible: widget => TestToolbarWidget.is(widget) && widget === testWidget
|
|
144
|
+
});
|
|
145
|
+
const menuRegistry = createMenuRegistry(commands);
|
|
146
|
+
menuRegistry.registerSubmenu([...TEST_MENU_PATH, 'other', 'test-submenu'], 'Test Submenu');
|
|
147
|
+
menuRegistry.registerMenuAction([...TEST_MENU_PATH, 'other', 'test-submenu'], { commandId: TEST_SUBMENU_COMMAND });
|
|
148
|
+
const registry = createToolbarRegistry(commands, menuRegistry, contextKeyService);
|
|
149
|
+
registry.registerMenuDelegate(TEST_MENU_PATH, TestToolbarWidget.is);
|
|
150
|
+
const submenuItem = registry.visibleItems(testWidget).find(item => item.id === `test-submenu${TOOLBAR_WRAPPER_ID_SUFFIX}`);
|
|
151
|
+
const node = submenuItem?.toMenuNode?.();
|
|
152
|
+
|
|
153
|
+
expect(CompoundMenuNode.is(node)).to.be.true;
|
|
154
|
+
if (!CompoundMenuNode.is(node)) {
|
|
155
|
+
throw new Error('Expected a compound menu node.');
|
|
156
|
+
}
|
|
157
|
+
expect(node.isEmpty(TAB_BAR_TOOLBAR_CONTEXT_MENU, contextKeyService, testWidget.node, testWidget)).to.be.false;
|
|
158
|
+
testWidget.dispose();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
});
|
|
162
|
+
|
|
62
163
|
});
|
|
164
|
+
|
|
165
|
+
class TestToolbarWidget extends Widget {
|
|
166
|
+
static is(candidate?: Widget): candidate is TestToolbarWidget {
|
|
167
|
+
return candidate instanceof TestToolbarWidget;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
class TestMenuNodeFactory implements MenuNodeFactory {
|
|
172
|
+
|
|
173
|
+
constructor(protected readonly commands: CommandRegistry) { }
|
|
174
|
+
|
|
175
|
+
createGroup(id: string, orderString?: string, when?: string): Group & MutableCompoundMenuNode {
|
|
176
|
+
return new GroupImpl(id, orderString, when);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
createSubmenu(id: string, label: string, contextKeyOverlays: Record<string, string> | undefined, orderString?: string, icon?: string, when?: string):
|
|
180
|
+
Submenu & MutableCompoundMenuNode {
|
|
181
|
+
return new SubmenuImpl(id, label, contextKeyOverlays, orderString, icon, when);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
createSubmenuLink(delegate: Submenu, sortString?: string, when?: string): MenuNode {
|
|
185
|
+
return new SubMenuLink(delegate, sortString, when);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
createCommandMenu(item: MenuAction): CommandMenu {
|
|
189
|
+
return {
|
|
190
|
+
isVisible: (_path, _contextMatcher, _context, ...args) => this.commands.isVisible(item.commandId, ...args),
|
|
191
|
+
isEnabled: (_path, ...args) => this.commands.isEnabled(item.commandId, ...args),
|
|
192
|
+
isToggled: (_path, ...args) => this.commands.isToggled(item.commandId, ...args),
|
|
193
|
+
id: item.commandId,
|
|
194
|
+
label: item.label || this.commands.getCommand(item.commandId)?.label || '',
|
|
195
|
+
icon: item.icon,
|
|
196
|
+
when: item.when,
|
|
197
|
+
sortString: item.order || '',
|
|
198
|
+
run: async (_path, ...args) => { await this.commands.executeCommand(item.commandId, ...args); }
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function createCommandRegistry(): CommandRegistry {
|
|
204
|
+
return new CommandRegistry({ getContributions: () => [] });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function createMenuRegistry(commands: CommandRegistry): MenuModelRegistry {
|
|
208
|
+
return new MenuModelRegistry({ getContributions: () => [] }, commands, new TestMenuNodeFactory(commands));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function createToolbarRegistry(commands: CommandRegistry, menuRegistry: MenuModelRegistry, contextKeyService: ContextKeyServiceDummyImpl): TabBarToolbarRegistry {
|
|
212
|
+
const registry = new TabBarToolbarRegistry();
|
|
213
|
+
Reflect.set(registry, 'commandRegistry', commands);
|
|
214
|
+
Reflect.set(registry, 'contextKeyService', contextKeyService);
|
|
215
|
+
Reflect.set(registry, 'menuRegistry', menuRegistry);
|
|
216
|
+
Reflect.set(registry, 'keybindingRegistry', {});
|
|
217
|
+
Reflect.set(registry, 'labelParser', {});
|
|
218
|
+
Reflect.set(registry, 'contextMenuRenderer', { render: () => undefined } as unknown as ContextMenuRenderer);
|
|
219
|
+
return registry;
|
|
220
|
+
}
|
|
@@ -99,7 +99,7 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
|
|
|
99
99
|
protected internalSetColor(color?: string): void {
|
|
100
100
|
this.color = color;
|
|
101
101
|
}
|
|
102
|
-
protected render(): JSX.Element {
|
|
102
|
+
protected render(): React.JSX.Element {
|
|
103
103
|
const leftEntries = Array.from(this.viewModel.getLeft(), entry => this.renderElement(entry));
|
|
104
104
|
const rightEntries = Array.from(this.viewModel.getRight(), entry => this.renderElement(entry));
|
|
105
105
|
|
|
@@ -192,9 +192,9 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
|
|
|
192
192
|
return attrs;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
protected renderElement(entry: StatusBarViewEntry): JSX.Element {
|
|
195
|
+
protected renderElement(entry: StatusBarViewEntry): React.JSX.Element {
|
|
196
196
|
const childStrings = this.entryService.parse(entry.entry.text);
|
|
197
|
-
const children: JSX.Element[] = [];
|
|
197
|
+
const children: React.JSX.Element[] = [];
|
|
198
198
|
|
|
199
199
|
childStrings.forEach((val, key) => {
|
|
200
200
|
if (LabelIcon.is(val)) {
|
|
@@ -72,3 +72,21 @@ export function enableJSDOM(): () => void {
|
|
|
72
72
|
};
|
|
73
73
|
return disableJSDOM;
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Enables React's act test environment and restores the previous value when disposed.
|
|
78
|
+
*/
|
|
79
|
+
export function enableReactActEnvironment(): () => void {
|
|
80
|
+
const reactActEnvironment = globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean };
|
|
81
|
+
const hadReactActEnvironment = Object.prototype.hasOwnProperty.call(reactActEnvironment, 'IS_REACT_ACT_ENVIRONMENT');
|
|
82
|
+
const previousReactActEnvironment = reactActEnvironment.IS_REACT_ACT_ENVIRONMENT;
|
|
83
|
+
reactActEnvironment.IS_REACT_ACT_ENVIRONMENT = true;
|
|
84
|
+
|
|
85
|
+
return () => {
|
|
86
|
+
if (hadReactActEnvironment) {
|
|
87
|
+
reactActEnvironment.IS_REACT_ACT_ENVIRONMENT = previousReactActEnvironment;
|
|
88
|
+
} else {
|
|
89
|
+
delete reactActEnvironment.IS_REACT_ACT_ENVIRONMENT;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -19,6 +19,8 @@ import { Container } from 'inversify';
|
|
|
19
19
|
import { createTreeContainer, isTreeServices } from './tree-container';
|
|
20
20
|
import { TreeSearch } from './tree-search';
|
|
21
21
|
import { defaultTreeProps, TreeProps } from './tree-widget';
|
|
22
|
+
import { ILogger } from '../../common/logger';
|
|
23
|
+
import { MockLogger } from '../../common/test/mock-logger';
|
|
22
24
|
|
|
23
25
|
describe('TreeContainer', () => {
|
|
24
26
|
describe('IsTreeServices should accurately distinguish TreeProps from TreeContainerProps', () => {
|
|
@@ -33,11 +35,15 @@ describe('TreeContainer', () => {
|
|
|
33
35
|
const nonDefault = { search: !defaultTreeProps.search, contextMenu: ['no-default-for-this'] };
|
|
34
36
|
it('should use props passed in as just props', () => {
|
|
35
37
|
const parent = new Container();
|
|
38
|
+
parent.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
39
|
+
|
|
36
40
|
const child = createTreeContainer(parent, nonDefault);
|
|
37
41
|
assert.deepStrictEqual(child.get(TreeProps), { ...defaultTreeProps, ...nonDefault });
|
|
38
42
|
});
|
|
39
43
|
it('should use props passed in as part of TreeContainerProps', () => {
|
|
40
44
|
const parent = new Container();
|
|
45
|
+
parent.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
46
|
+
|
|
41
47
|
const child = createTreeContainer(parent, { props: nonDefault });
|
|
42
48
|
assert.deepStrictEqual(child.get(TreeProps), { ...defaultTreeProps, ...nonDefault });
|
|
43
49
|
});
|
|
@@ -545,7 +545,7 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
|
|
|
545
545
|
return <this.ScrollingRowRenderer rows={rows} />;
|
|
546
546
|
}
|
|
547
547
|
return <TreeWidget.View
|
|
548
|
-
ref={view => this.view = (view || undefined)}
|
|
548
|
+
ref={view => { this.view = (view || undefined); }}
|
|
549
549
|
width={this.node.offsetWidth}
|
|
550
550
|
height={this.node.offsetHeight}
|
|
551
551
|
rows={rows}
|
|
@@ -1689,7 +1689,7 @@ export namespace TreeWidget {
|
|
|
1689
1689
|
override render(): React.ReactNode {
|
|
1690
1690
|
const { rows, width, height, scrollToRow, renderNodeRow, onScrollEmitter, ...other } = this.props;
|
|
1691
1691
|
return <Virtuoso
|
|
1692
|
-
ref={list => {
|
|
1692
|
+
ref={(list: VirtuosoHandle | null) => {
|
|
1693
1693
|
this.list = (list || undefined);
|
|
1694
1694
|
this.scrollIntoViewIfNeeded();
|
|
1695
1695
|
}}
|
package/src/browser/tree/tree.ts
CHANGED
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { injectable } from 'inversify';
|
|
17
|
+
import { injectable, inject, named } from 'inversify';
|
|
18
18
|
import { Event, Emitter, WaitUntilEvent } from '../../common/event';
|
|
19
19
|
import { Disposable, DisposableCollection } from '../../common/disposable';
|
|
20
20
|
import { CancellationToken, CancellationTokenSource } from '../../common/cancellation';
|
|
21
21
|
import { timeout } from '../../common/promise-util';
|
|
22
22
|
import { isObject, Mutable } from '../../common';
|
|
23
23
|
import { AccessibilityInformation } from '../../common/accessibility';
|
|
24
|
+
import { ILogger } from '../../common/logger';
|
|
24
25
|
|
|
25
26
|
export const Tree = Symbol('Tree');
|
|
26
27
|
|
|
@@ -250,6 +251,9 @@ export namespace CompositeTreeNode {
|
|
|
250
251
|
@injectable()
|
|
251
252
|
export class TreeImpl implements Tree {
|
|
252
253
|
|
|
254
|
+
@inject(ILogger) @named('core:TreeImpl')
|
|
255
|
+
protected readonly logger: ILogger;
|
|
256
|
+
|
|
253
257
|
protected _root: TreeNode | undefined;
|
|
254
258
|
protected readonly onChangedEmitter = new Emitter<void>();
|
|
255
259
|
protected readonly onNodeRefreshedEmitter = new Emitter<CompositeTreeNode & WaitUntilEvent>();
|
|
@@ -344,7 +348,7 @@ export class TreeImpl implements Tree {
|
|
|
344
348
|
protected async setChildren(parent: CompositeTreeNode, children: TreeNode[]): Promise<CompositeTreeNode | undefined> {
|
|
345
349
|
const root = this.getRootNode(parent);
|
|
346
350
|
if (this.nodes[root.id] && this.nodes[root.id] !== root) {
|
|
347
|
-
|
|
351
|
+
this.logger.error(`Child node '${parent.id}' does not belong to this '${root.id}' tree.`);
|
|
348
352
|
return undefined;
|
|
349
353
|
}
|
|
350
354
|
this.removeNode(parent);
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { Container } from 'inversify';
|
|
18
|
-
import { ContributionProvider } from '../../common';
|
|
18
|
+
import { ContributionProvider, ILogger } from '../../common';
|
|
19
19
|
import { CorePreferences } from '../../common/core-preferences';
|
|
20
20
|
import { FrontendApplicationContribution } from '../frontend-application-contribution';
|
|
21
21
|
import { DefaultWindowService } from './default-window-service';
|
|
22
22
|
import assert = require('assert');
|
|
23
|
+
import { MockLogger } from '../../common/test/mock-logger';
|
|
23
24
|
|
|
24
25
|
describe('DefaultWindowService', () => {
|
|
25
26
|
class TestFrontendApplicationContribution implements FrontendApplicationContribution {
|
|
@@ -42,6 +43,7 @@ describe('DefaultWindowService', () => {
|
|
|
42
43
|
.toConstantValue({
|
|
43
44
|
'application.confirmExit': confirmExit,
|
|
44
45
|
});
|
|
46
|
+
container.bind(ILogger).to(MockLogger).inSingletonScope();
|
|
45
47
|
return container.get(DefaultWindowService);
|
|
46
48
|
}
|
|
47
49
|
it('onWillStop should be called on every contribution (never)', () => {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { inject, injectable, named } from 'inversify';
|
|
18
|
-
import { Event, Emitter } from '../../common';
|
|
18
|
+
import { Event, Emitter, ILogger } from '../../common';
|
|
19
19
|
import { CorePreferences } from '../../common/core-preferences';
|
|
20
20
|
import { ContributionProvider } from '../../common/contribution-provider';
|
|
21
21
|
import { FrontendApplicationContribution, OnWillStopAction } from '../frontend-application-contribution';
|
|
@@ -43,6 +43,9 @@ export class DefaultWindowService implements WindowService, FrontendApplicationC
|
|
|
43
43
|
@named(FrontendApplicationContribution)
|
|
44
44
|
protected readonly contributions: ContributionProvider<FrontendApplicationContribution>;
|
|
45
45
|
|
|
46
|
+
@inject(ILogger) @named('core:DefaultWindowService')
|
|
47
|
+
protected readonly logger: ILogger;
|
|
48
|
+
|
|
46
49
|
onStart(app: FrontendApplication): void {
|
|
47
50
|
this.frontendApplication = app;
|
|
48
51
|
this.registerUnloadListeners();
|
|
@@ -114,7 +117,7 @@ export class DefaultWindowService implements WindowService, FrontendApplicationC
|
|
|
114
117
|
return true;
|
|
115
118
|
}
|
|
116
119
|
const preparedValues = await Promise.all(vetoes.map(e => e.prepare?.(stopReason)));
|
|
117
|
-
|
|
120
|
+
this.logger.debug('Shutdown prevented by', vetoes.map(({ reason }) => reason).join(', '));
|
|
118
121
|
for (let i = 0; i < vetoes.length; i++) {
|
|
119
122
|
try {
|
|
120
123
|
const result = await vetoes[i].action(preparedValues[i], stopReason);
|
|
@@ -122,10 +125,10 @@ export class DefaultWindowService implements WindowService, FrontendApplicationC
|
|
|
122
125
|
return false;
|
|
123
126
|
}
|
|
124
127
|
} catch (e) {
|
|
125
|
-
|
|
128
|
+
this.logger.error(e);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
|
-
|
|
131
|
+
this.logger.debug('OnWillStop actions resolved; allowing shutdown');
|
|
129
132
|
this.allowVetoes = false;
|
|
130
133
|
return true;
|
|
131
134
|
}
|
|
@@ -145,10 +148,10 @@ export class DefaultWindowService implements WindowService, FrontendApplicationC
|
|
|
145
148
|
const vetoes = this.collectContributionUnloadVetoes();
|
|
146
149
|
if (vetoes.length) {
|
|
147
150
|
// In the browser, we don't call the functions because this has to finish in a single tick, so we treat any desired action as a veto.
|
|
148
|
-
|
|
151
|
+
this.logger.debug('Shutdown prevented by', vetoes.map(({ reason }) => reason).join(', '));
|
|
149
152
|
return this.preventUnload(event);
|
|
150
153
|
}
|
|
151
|
-
|
|
154
|
+
this.logger.debug('Shutdown will proceed.');
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
/**
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
import { Event, RpcProxy, Channel, RpcProxyFactory, Emitter } from '../../common';
|
|
17
|
-
import { injectable } from 'inversify';
|
|
17
|
+
import { injectable, inject, named } from 'inversify';
|
|
18
18
|
import { ServiceConnectionProvider } from '../../browser/messaging/service-connection-provider';
|
|
19
|
+
import { ILogger } from '../../common/logger';
|
|
19
20
|
import { ConnectionSource } from '../../browser/messaging/connection-source';
|
|
20
21
|
|
|
21
22
|
@injectable()
|
|
@@ -25,15 +26,19 @@ export class FrontendOnlyConnectionSource implements ConnectionSource {
|
|
|
25
26
|
|
|
26
27
|
@injectable()
|
|
27
28
|
export class FrontendOnlyServiceConnectionProvider extends ServiceConnectionProvider {
|
|
29
|
+
|
|
30
|
+
@inject(ILogger) @named('core:FrontendOnlyServiceConnectionProvider')
|
|
31
|
+
protected readonly logger: ILogger;
|
|
32
|
+
|
|
28
33
|
onSocketDidOpen = Event.None;
|
|
29
34
|
onSocketDidClose = Event.None;
|
|
30
35
|
onIncomingMessageActivity = Event.None;
|
|
31
36
|
override createProxy<T extends object>(path: unknown, target?: unknown): RpcProxy<T> {
|
|
32
|
-
|
|
37
|
+
this.logger.debug(`[Frontend-Only Fallback] Created proxy connection for ${path}`);
|
|
33
38
|
const factory = target instanceof RpcProxyFactory ? target : new RpcProxyFactory<T>(target);
|
|
34
39
|
return factory.createProxy();
|
|
35
40
|
}
|
|
36
41
|
override listen(path: string, handler: ServiceConnectionProvider.ConnectionHandler, reconnect: boolean): void {
|
|
37
|
-
|
|
42
|
+
this.logger.debug('[Frontend-Only Fallback] Listen to websocket connection requested');
|
|
38
43
|
}
|
|
39
44
|
}
|
package/src/common/command.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { ContributionProvider } from './contribution-provider';
|
|
|
21
21
|
import { nls } from './nls';
|
|
22
22
|
import debounce = require('p-debounce');
|
|
23
23
|
import { isObject } from './types';
|
|
24
|
+
import { ILogger } from './logger';
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* A command is a unique identifier of a function
|
|
@@ -190,6 +191,9 @@ export interface CommandService {
|
|
|
190
191
|
@injectable()
|
|
191
192
|
export class CommandRegistry implements CommandService {
|
|
192
193
|
|
|
194
|
+
@inject(ILogger) @named('core:CommandRegistry')
|
|
195
|
+
protected readonly logger: ILogger;
|
|
196
|
+
|
|
193
197
|
protected readonly _commands: { [id: string]: Command } = {};
|
|
194
198
|
protected readonly _handlers: { [id: string]: CommandHandler[] } = {};
|
|
195
199
|
|
|
@@ -232,7 +236,7 @@ export class CommandRegistry implements CommandService {
|
|
|
232
236
|
*/
|
|
233
237
|
registerCommand(command: Command, handler?: CommandHandler): Disposable {
|
|
234
238
|
if (this._commands[command.id]) {
|
|
235
|
-
|
|
239
|
+
this.logger.warn(`A command ${command.id} is already registered.`);
|
|
236
240
|
return Disposable.NULL;
|
|
237
241
|
}
|
|
238
242
|
const toDispose = new DisposableCollection(this.doRegisterCommand(command));
|
|
@@ -363,7 +367,7 @@ export class CommandRegistry implements CommandService {
|
|
|
363
367
|
return handler;
|
|
364
368
|
}
|
|
365
369
|
} catch (error) {
|
|
366
|
-
|
|
370
|
+
this.logger.error(error);
|
|
367
371
|
}
|
|
368
372
|
}
|
|
369
373
|
}
|
|
@@ -383,7 +387,7 @@ export class CommandRegistry implements CommandService {
|
|
|
383
387
|
return handler;
|
|
384
388
|
}
|
|
385
389
|
} catch (error) {
|
|
386
|
-
|
|
390
|
+
this.logger.error(error);
|
|
387
391
|
}
|
|
388
392
|
}
|
|
389
393
|
}
|
|
@@ -403,7 +407,7 @@ export class CommandRegistry implements CommandService {
|
|
|
403
407
|
return handler;
|
|
404
408
|
}
|
|
405
409
|
} catch (error) {
|
|
406
|
-
|
|
410
|
+
this.logger.error(error);
|
|
407
411
|
}
|
|
408
412
|
}
|
|
409
413
|
}
|
|
@@ -106,7 +106,13 @@ export class InjectablePreferenceProxy<T extends Record<string, JSONValue>> impl
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
get(target: unknown, property: string, receiver: unknown): unknown {
|
|
109
|
+
get(target: unknown, property: string | symbol, receiver: unknown): unknown {
|
|
110
|
+
// React 19 dev mode calls Object.prototype.toString when handling prop diffs, which
|
|
111
|
+
// probes Symbol.toStringTag. Throwing should be avoided in this case, it crashes the React DOM.
|
|
112
|
+
if (property === Symbol.toStringTag) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
if (typeof property !== 'string') {
|
|
111
117
|
throw new Error(`Unexpected property: ${String(property)}`);
|
|
112
118
|
}
|
|
@@ -156,7 +162,7 @@ export class InjectablePreferenceProxy<T extends Record<string, JSONValue>> impl
|
|
|
156
162
|
}
|
|
157
163
|
}
|
|
158
164
|
|
|
159
|
-
set(target: unknown, property: string, value: unknown, receiver: unknown): boolean {
|
|
165
|
+
set(target: unknown, property: string | symbol, value: unknown, receiver: unknown): boolean {
|
|
160
166
|
if (typeof property !== 'string') {
|
|
161
167
|
throw new Error(`Unexpected property: ${String(property)}`);
|
|
162
168
|
}
|
|
@@ -212,8 +218,8 @@ export class InjectablePreferenceProxy<T extends Record<string, JSONValue>> impl
|
|
|
212
218
|
return properties;
|
|
213
219
|
}
|
|
214
220
|
|
|
215
|
-
getOwnPropertyDescriptor(target: unknown, property: string): PropertyDescriptor {
|
|
216
|
-
if (this.ownKeys().includes(property)) {
|
|
221
|
+
getOwnPropertyDescriptor(target: unknown, property: string | symbol): PropertyDescriptor {
|
|
222
|
+
if (typeof property === 'string' && this.ownKeys().includes(property)) {
|
|
217
223
|
return {
|
|
218
224
|
enumerable: true,
|
|
219
225
|
configurable: true
|
|
@@ -239,7 +239,7 @@ export function createPreferenceProxy<T>(preferences: PreferenceService, promise
|
|
|
239
239
|
return properties;
|
|
240
240
|
};
|
|
241
241
|
|
|
242
|
-
const set: (target: any, prop: string, value: any, receiver: any) => boolean = (_, property: string | symbol | number, value: any) => {
|
|
242
|
+
const set: (target: any, prop: string | symbol, value: any, receiver: any) => boolean = (_, property: string | symbol | number, value: any) => {
|
|
243
243
|
if (typeof property !== 'string') {
|
|
244
244
|
throw new Error(`unexpected property: ${String(property)}`);
|
|
245
245
|
}
|
|
@@ -270,7 +270,13 @@ export function createPreferenceProxy<T>(preferences: PreferenceService, promise
|
|
|
270
270
|
return false;
|
|
271
271
|
};
|
|
272
272
|
|
|
273
|
-
const get: (target: any, prop: string) => any = (_, property: string | symbol | number) => {
|
|
273
|
+
const get: (target: any, prop: string | symbol) => any = (_, property: string | symbol | number) => {
|
|
274
|
+
// React 19 dev mode calls Object.prototype.toString when handling prop diffs, which
|
|
275
|
+
// probes Symbol.toStringTag. Throwing should be avoided in this case, it crashes the React DOM.
|
|
276
|
+
if (property === Symbol.toStringTag) {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
|
|
274
280
|
if (typeof property !== 'string') {
|
|
275
281
|
throw new Error(`unexpected property: ${String(property)}`);
|
|
276
282
|
}
|
|
@@ -347,8 +353,8 @@ export function createPreferenceProxy<T>(preferences: PreferenceService, promise
|
|
|
347
353
|
return new Proxy({}, {
|
|
348
354
|
get,
|
|
349
355
|
ownKeys,
|
|
350
|
-
getOwnPropertyDescriptor: (_, property: string) => {
|
|
351
|
-
if (ownKeys().indexOf(property) !== -1) {
|
|
356
|
+
getOwnPropertyDescriptor: (_, property: string | symbol) => {
|
|
357
|
+
if (typeof property === 'string' && ownKeys().indexOf(property) !== -1) {
|
|
352
358
|
return {
|
|
353
359
|
enumerable: true,
|
|
354
360
|
configurable: true
|
|
@@ -394,6 +394,8 @@ export class ElectronMainApplication {
|
|
|
394
394
|
const cancelTokenSource = new CancellationTokenSource();
|
|
395
395
|
const minTime = timeout(splashScreenOptions.minDuration ?? 0, cancelTokenSource.token);
|
|
396
396
|
const maxTime = timeout(splashScreenOptions.maxDuration ?? 30000, cancelTokenSource.token);
|
|
397
|
+
// Swallow rejections that occur when the cancellation token is cancelled after one of the timers wins.
|
|
398
|
+
const ignoreCancellation = () => { /* timer was cancelled, intentionally ignored */ };
|
|
397
399
|
|
|
398
400
|
const showWindowAndCloseSplashScreen = () => {
|
|
399
401
|
cancelTokenSource.cancel();
|
|
@@ -404,10 +406,10 @@ export class ElectronMainApplication {
|
|
|
404
406
|
};
|
|
405
407
|
TheiaRendererAPI.onApplicationStateChanged(mainWindow.webContents, state => {
|
|
406
408
|
if (state === 'ready') {
|
|
407
|
-
minTime.then(() => showWindowAndCloseSplashScreen());
|
|
409
|
+
minTime.then(() => showWindowAndCloseSplashScreen(), ignoreCancellation);
|
|
408
410
|
}
|
|
409
411
|
});
|
|
410
|
-
maxTime.then(() => showWindowAndCloseSplashScreen());
|
|
412
|
+
maxTime.then(() => showWindowAndCloseSplashScreen(), ignoreCancellation);
|
|
411
413
|
return splashScreenWindow;
|
|
412
414
|
}
|
|
413
415
|
|