@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.
Files changed (180) hide show
  1. package/README.md +19 -9
  2. package/lib/browser/authentication-service.d.ts +2 -0
  3. package/lib/browser/authentication-service.d.ts.map +1 -1
  4. package/lib/browser/authentication-service.js +8 -2
  5. package/lib/browser/authentication-service.js.map +1 -1
  6. package/lib/browser/catalog.json +222 -66
  7. package/lib/browser/frontend-application.d.ts +2 -0
  8. package/lib/browser/frontend-application.d.ts.map +1 -1
  9. package/lib/browser/frontend-application.js +15 -9
  10. package/lib/browser/frontend-application.js.map +1 -1
  11. package/lib/browser/json-schema-store.d.ts +2 -0
  12. package/lib/browser/json-schema-store.d.ts.map +1 -1
  13. package/lib/browser/json-schema-store.js +8 -2
  14. package/lib/browser/json-schema-store.js.map +1 -1
  15. package/lib/browser/keybinding.js +2 -1
  16. package/lib/browser/keybinding.js.map +1 -1
  17. package/lib/browser/markdown-rendering/markdown.d.ts +1 -1
  18. package/lib/browser/markdown-rendering/markdown.d.ts.map +1 -1
  19. package/lib/browser/markdown-rendering/markdown.js +1 -1
  20. package/lib/browser/markdown-rendering/markdown.js.map +1 -1
  21. package/lib/browser/menu/composite-menu-node.js +4 -4
  22. package/lib/browser/menu/composite-menu-node.js.map +1 -1
  23. package/lib/browser/preferences/frontend-config-preference-contributions.d.ts +2 -0
  24. package/lib/browser/preferences/frontend-config-preference-contributions.d.ts.map +1 -1
  25. package/lib/browser/preferences/frontend-config-preference-contributions.js +7 -1
  26. package/lib/browser/preferences/frontend-config-preference-contributions.js.map +1 -1
  27. package/lib/browser/preferences/preference-proxy.spec.js +7 -0
  28. package/lib/browser/preferences/preference-proxy.spec.js.map +1 -1
  29. package/lib/browser/preferences/preference-schema-provider.spec.js +3 -0
  30. package/lib/browser/preferences/preference-schema-provider.spec.js.map +1 -1
  31. package/lib/browser/preferences/preference-validation-service.d.ts +2 -0
  32. package/lib/browser/preferences/preference-validation-service.d.ts.map +1 -1
  33. package/lib/browser/preferences/preference-validation-service.js +11 -5
  34. package/lib/browser/preferences/preference-validation-service.js.map +1 -1
  35. package/lib/browser/preferences/preference-validation-service.spec.js +2 -0
  36. package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
  37. package/lib/browser/quick-input/quick-view-service.d.ts +1 -0
  38. package/lib/browser/quick-input/quick-view-service.d.ts.map +1 -1
  39. package/lib/browser/quick-input/quick-view-service.js +6 -1
  40. package/lib/browser/quick-input/quick-view-service.js.map +1 -1
  41. package/lib/browser/quick-input/quick-view-service.spec.d.ts +2 -0
  42. package/lib/browser/quick-input/quick-view-service.spec.d.ts.map +1 -0
  43. package/lib/browser/quick-input/quick-view-service.spec.js +41 -0
  44. package/lib/browser/quick-input/quick-view-service.spec.js.map +1 -0
  45. package/lib/browser/secondary-window-handler.d.ts +2 -0
  46. package/lib/browser/secondary-window-handler.d.ts.map +1 -1
  47. package/lib/browser/secondary-window-handler.js +12 -6
  48. package/lib/browser/secondary-window-handler.js.map +1 -1
  49. package/lib/browser/shell/application-shell.d.ts +2 -0
  50. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  51. package/lib/browser/shell/application-shell.js +9 -3
  52. package/lib/browser/shell/application-shell.js.map +1 -1
  53. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +4 -4
  54. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
  55. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +2 -2
  56. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
  57. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js +131 -0
  58. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -1
  59. package/lib/browser/status-bar/status-bar.d.ts +2 -2
  60. package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
  61. package/lib/browser/status-bar/status-bar.js.map +1 -1
  62. package/lib/browser/test/jsdom.d.ts +4 -0
  63. package/lib/browser/test/jsdom.d.ts.map +1 -1
  64. package/lib/browser/test/jsdom.js +18 -0
  65. package/lib/browser/test/jsdom.js.map +1 -1
  66. package/lib/browser/tree/tree-container.spec.js +4 -0
  67. package/lib/browser/tree/tree-container.spec.js.map +1 -1
  68. package/lib/browser/tree/tree-widget.js +2 -2
  69. package/lib/browser/tree/tree-widget.js.map +1 -1
  70. package/lib/browser/tree/tree.d.ts +2 -0
  71. package/lib/browser/tree/tree.d.ts.map +1 -1
  72. package/lib/browser/tree/tree.js +7 -1
  73. package/lib/browser/tree/tree.js.map +1 -1
  74. package/lib/browser/window/default-window-service.d.ts +2 -1
  75. package/lib/browser/window/default-window-service.d.ts.map +1 -1
  76. package/lib/browser/window/default-window-service.js +10 -5
  77. package/lib/browser/window/default-window-service.js.map +1 -1
  78. package/lib/browser/window/default-window-service.spec.js +2 -0
  79. package/lib/browser/window/default-window-service.spec.js.map +1 -1
  80. package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts +2 -0
  81. package/lib/browser-only/messaging/frontend-only-service-connection-provider.d.ts.map +1 -1
  82. package/lib/browser-only/messaging/frontend-only-service-connection-provider.js +8 -2
  83. package/lib/browser-only/messaging/frontend-only-service-connection-provider.js.map +1 -1
  84. package/lib/common/command.d.ts +2 -0
  85. package/lib/common/command.d.ts.map +1 -1
  86. package/lib/common/command.js +10 -4
  87. package/lib/common/command.js.map +1 -1
  88. package/lib/common/preferences/injectable-preference-proxy.d.ts +3 -3
  89. package/lib/common/preferences/injectable-preference-proxy.d.ts.map +1 -1
  90. package/lib/common/preferences/injectable-preference-proxy.js +6 -1
  91. package/lib/common/preferences/injectable-preference-proxy.js.map +1 -1
  92. package/lib/common/preferences/preference-proxy.d.ts.map +1 -1
  93. package/lib/common/preferences/preference-proxy.js +6 -1
  94. package/lib/common/preferences/preference-proxy.js.map +1 -1
  95. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  96. package/lib/electron-main/electron-main-application.js +4 -2
  97. package/lib/electron-main/electron-main-application.js.map +1 -1
  98. package/lib/electron-node/request/electron-backend-request-service.d.ts +2 -0
  99. package/lib/electron-node/request/electron-backend-request-service.d.ts.map +1 -1
  100. package/lib/electron-node/request/electron-backend-request-service.js +7 -1
  101. package/lib/electron-node/request/electron-backend-request-service.js.map +1 -1
  102. package/lib/electron-node/token/electron-token-backend-contribution.d.ts +2 -0
  103. package/lib/electron-node/token/electron-token-backend-contribution.d.ts.map +1 -1
  104. package/lib/electron-node/token/electron-token-backend-contribution.js +7 -1
  105. package/lib/electron-node/token/electron-token-backend-contribution.js.map +1 -1
  106. package/lib/electron-node/token/electron-token-validator.d.ts +2 -0
  107. package/lib/electron-node/token/electron-token-validator.d.ts.map +1 -1
  108. package/lib/electron-node/token/electron-token-validator.js +7 -1
  109. package/lib/electron-node/token/electron-token-validator.js.map +1 -1
  110. package/lib/node/backend-application.d.ts +2 -0
  111. package/lib/node/backend-application.d.ts.map +1 -1
  112. package/lib/node/backend-application.js +17 -11
  113. package/lib/node/backend-application.js.map +1 -1
  114. package/lib/node/backend-application.spec.js +3 -2
  115. package/lib/node/backend-application.spec.js.map +1 -1
  116. package/lib/node/logger-cli-contribution.d.ts +6 -0
  117. package/lib/node/logger-cli-contribution.d.ts.map +1 -1
  118. package/lib/node/logger-cli-contribution.js +28 -5
  119. package/lib/node/logger-cli-contribution.js.map +1 -1
  120. package/lib/node/logger-cli-contribution.spec.js +54 -0
  121. package/lib/node/logger-cli-contribution.spec.js.map +1 -1
  122. package/lib/node/messaging/default-messaging-service.d.ts +2 -0
  123. package/lib/node/messaging/default-messaging-service.d.ts.map +1 -1
  124. package/lib/node/messaging/default-messaging-service.js +8 -2
  125. package/lib/node/messaging/default-messaging-service.js.map +1 -1
  126. package/lib/node/messaging/test/default-messaging-service.spec.js +2 -0
  127. package/lib/node/messaging/test/default-messaging-service.spec.js.map +1 -1
  128. package/lib/node/messaging/websocket-endpoint.d.ts +2 -0
  129. package/lib/node/messaging/websocket-endpoint.d.ts.map +1 -1
  130. package/lib/node/messaging/websocket-endpoint.js +7 -1
  131. package/lib/node/messaging/websocket-endpoint.js.map +1 -1
  132. package/lib/node/process-utils.d.ts +2 -0
  133. package/lib/node/process-utils.d.ts.map +1 -1
  134. package/lib/node/process-utils.js +8 -2
  135. package/lib/node/process-utils.js.map +1 -1
  136. package/lib/node/process-utils.spec.js +11 -9
  137. package/lib/node/process-utils.spec.js.map +1 -1
  138. package/package.json +26 -16
  139. package/src/browser/authentication-service.ts +6 -3
  140. package/src/browser/frontend-application.ts +13 -9
  141. package/src/browser/json-schema-store.ts +6 -2
  142. package/src/browser/keybinding.ts +2 -2
  143. package/src/browser/markdown-rendering/markdown.tsx +2 -2
  144. package/src/browser/menu/composite-menu-node.ts +4 -4
  145. package/src/browser/preferences/frontend-config-preference-contributions.ts +7 -2
  146. package/src/browser/preferences/preference-proxy.spec.ts +8 -0
  147. package/src/browser/preferences/preference-schema-provider.spec.ts +5 -0
  148. package/src/browser/preferences/preference-validation-service.spec.ts +3 -1
  149. package/src/browser/preferences/preference-validation-service.ts +9 -6
  150. package/src/browser/quick-input/quick-view-service.spec.ts +50 -0
  151. package/src/browser/quick-input/quick-view-service.ts +5 -0
  152. package/src/browser/secondary-window-handler.ts +11 -7
  153. package/src/browser/shell/application-shell.ts +8 -4
  154. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +4 -4
  155. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +2 -2
  156. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.ts +159 -1
  157. package/src/browser/status-bar/status-bar.tsx +3 -3
  158. package/src/browser/test/jsdom.ts +18 -0
  159. package/src/browser/tree/tree-container.spec.ts +6 -0
  160. package/src/browser/tree/tree-widget.tsx +2 -2
  161. package/src/browser/tree/tree.ts +6 -2
  162. package/src/browser/window/default-window-service.spec.ts +3 -1
  163. package/src/browser/window/default-window-service.ts +9 -6
  164. package/src/browser-only/messaging/frontend-only-service-connection-provider.ts +8 -3
  165. package/src/common/command.ts +8 -4
  166. package/src/common/preferences/injectable-preference-proxy.ts +10 -4
  167. package/src/common/preferences/preference-proxy.ts +10 -4
  168. package/src/electron-main/electron-main-application.ts +4 -2
  169. package/src/electron-node/request/electron-backend-request-service.ts +6 -2
  170. package/src/electron-node/token/electron-token-backend-contribution.ts +6 -2
  171. package/src/electron-node/token/electron-token-validator.ts +6 -2
  172. package/src/node/backend-application.spec.ts +3 -3
  173. package/src/node/backend-application.ts +15 -11
  174. package/src/node/logger-cli-contribution.spec.ts +65 -0
  175. package/src/node/logger-cli-contribution.ts +32 -5
  176. package/src/node/messaging/default-messaging-service.ts +6 -2
  177. package/src/node/messaging/test/default-messaging-service.spec.ts +3 -1
  178. package/src/node/messaging/websocket-endpoint.ts +6 -2
  179. package/src/node/process-utils.spec.ts +12 -9
  180. 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
- console.info(`no opener found for '${fileUri}'`);
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
- console.error('Widgets added to the application shell must have a unique id property.');
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
- console.warn(`Widget was activated, but did not accept focus after ${this.activationTimeout}ms: ${widget.id}`);
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 { TabBarToolbarAction } from './tab-bar-toolbar-types';
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
  }}
@@ -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
- console.error(`Child node '${parent.id}' does not belong to this '${root.id}' tree.`);
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
- console.debug('Shutdown prevented by', vetoes.map(({ reason }) => reason).join(', '));
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
- console.error(e);
128
+ this.logger.error(e);
126
129
  }
127
130
  }
128
- console.debug('OnWillStop actions resolved; allowing shutdown');
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
- console.debug('Shutdown prevented by', vetoes.map(({ reason }) => reason).join(', '));
151
+ this.logger.debug('Shutdown prevented by', vetoes.map(({ reason }) => reason).join(', '));
149
152
  return this.preventUnload(event);
150
153
  }
151
- console.debug('Shutdown will proceed.');
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
- console.debug(`[Frontend-Only Fallback] Created proxy connection for ${path}`);
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
- console.debug('[Frontend-Only Fallback] Listen to websocket connection requested');
42
+ this.logger.debug('[Frontend-Only Fallback] Listen to websocket connection requested');
38
43
  }
39
44
  }
@@ -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
- console.warn(`A command ${command.id} is already registered.`);
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
- console.error(error);
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
- console.error(error);
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
- console.error(error);
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