diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bb6b60ab9e7..e1d674445e17a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ## v1.30.0 -- [core] Added support for moving webview-based views into a secondary window/tab for browser applications. Added new extension `secondary-window-ui` that contributes the UI integration to use this. [#11048](https://github.com/eclipse-theia/theia/pull/11048) - Contributed on behalf of ST Microelectronics and Ericsson and by ARM and EclipseSource +- [core] Added support for moving webview-based views into a secondary window for browser applications. Added new extension `secondary-window` that contributes the UI integration to use this. [#11048](https://github.com/eclipse-theia/theia/pull/11048) - Contributed on behalf of ST Microelectronics and Ericsson and by ARM and EclipseSource [Breaking Changes:](#breaking_changes_1.30.0) diff --git a/examples/browser/package.json b/examples/browser/package.json index 2b5c427881614..f7fea4d84f232 100644 --- a/examples/browser/package.json +++ b/examples/browser/package.json @@ -47,7 +47,7 @@ "@theia/scm": "1.29.0", "@theia/scm-extra": "1.29.0", "@theia/search-in-workspace": "1.29.0", - "@theia/secondary-window-ui": "1.29.0", + "@theia/secondary-window": "1.29.0", "@theia/task": "1.29.0", "@theia/terminal": "1.29.0", "@theia/timeline": "1.29.0", diff --git a/examples/browser/tsconfig.json b/examples/browser/tsconfig.json index de282d396c123..d4bcfc14426b9 100644 --- a/examples/browser/tsconfig.json +++ b/examples/browser/tsconfig.json @@ -105,7 +105,7 @@ "path": "../../packages/search-in-workspace" }, { - "path": "../../packages/secondary-window-ui" + "path": "../../packages/secondary-window" }, { "path": "../../packages/task" diff --git a/packages/core/i18n/nls.cs.json b/packages/core/i18n/nls.cs.json index 0daf47157a1d7..32b950463d2ac 100644 --- a/packages/core/i18n/nls.cs.json +++ b/packages/core/i18n/nls.cs.json @@ -409,7 +409,7 @@ "resultSubset": "Jedná se pouze o podmnožinu všech výsledků. Pro zúžení seznamu výsledků použijte konkrétnější vyhledávací výraz.", "searchOnEditorModification": "Prohledat aktivní editor při úpravě." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Přesunutí zobrazení do sekundárního okna" }, "task": { diff --git a/packages/core/i18n/nls.de.json b/packages/core/i18n/nls.de.json index b005093e09537..d8eaeb1bba782 100644 --- a/packages/core/i18n/nls.de.json +++ b/packages/core/i18n/nls.de.json @@ -409,7 +409,7 @@ "resultSubset": "Dies ist nur eine Teilmenge aller Ergebnisse. Verwenden Sie einen spezifischeren Suchbegriff, um die Ergebnisliste einzugrenzen.", "searchOnEditorModification": "Durchsucht den aktiven Editor nach Änderungen." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Ansicht in sekundäres Fenster verschieben" }, "task": { diff --git a/packages/core/i18n/nls.es.json b/packages/core/i18n/nls.es.json index ea81cbf3e6a3a..64f585e5f97e8 100644 --- a/packages/core/i18n/nls.es.json +++ b/packages/core/i18n/nls.es.json @@ -409,7 +409,7 @@ "resultSubset": "Esto es sólo un subconjunto de todos los resultados. Utilice un término de búsqueda más específico para reducir la lista de resultados.", "searchOnEditorModification": "Busca en el editor activo cuando se modifica." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Mover la vista a la ventana secundaria" }, "task": { diff --git a/packages/core/i18n/nls.fr.json b/packages/core/i18n/nls.fr.json index 019794e482920..2139137bba522 100644 --- a/packages/core/i18n/nls.fr.json +++ b/packages/core/i18n/nls.fr.json @@ -409,7 +409,7 @@ "resultSubset": "Il ne s'agit que d'un sous-ensemble de tous les résultats. Utilisez un terme de recherche plus spécifique pour réduire la liste des résultats.", "searchOnEditorModification": "Rechercher l'éditeur actif lorsqu'il est modifié." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Déplacer la vue vers une fenêtre secondaire" }, "task": { diff --git a/packages/core/i18n/nls.hu.json b/packages/core/i18n/nls.hu.json index ebafb0b38a77d..cbbd13fd7d61c 100644 --- a/packages/core/i18n/nls.hu.json +++ b/packages/core/i18n/nls.hu.json @@ -409,7 +409,7 @@ "resultSubset": "Ez csak egy részhalmaza az összes eredménynek. A találati lista szűkítéséhez használjon konkrétabb keresési kifejezést.", "searchOnEditorModification": "Keresés az aktív szerkesztőben, amikor módosítják." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Nézet áthelyezése másodlagos ablakba" }, "task": { diff --git a/packages/core/i18n/nls.it.json b/packages/core/i18n/nls.it.json index 4562a889cd006..0f2f596e32a8e 100644 --- a/packages/core/i18n/nls.it.json +++ b/packages/core/i18n/nls.it.json @@ -409,7 +409,7 @@ "resultSubset": "Questo è solo un sottoinsieme di tutti i risultati. Usa un termine di ricerca più specifico per restringere la lista dei risultati.", "searchOnEditorModification": "Cerca l'editor attivo quando viene modificato." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Sposta la vista nella finestra secondaria" }, "task": { diff --git a/packages/core/i18n/nls.ja.json b/packages/core/i18n/nls.ja.json index 9464b73689654..2e9e202751a6c 100644 --- a/packages/core/i18n/nls.ja.json +++ b/packages/core/i18n/nls.ja.json @@ -409,7 +409,7 @@ "resultSubset": "これは、すべての結果の一部に過ぎません。より具体的な検索用語を使って、結果リストを絞り込んでください。", "searchOnEditorModification": "修正されたときにアクティブなエディタを検索します。" }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "セカンダリーウィンドウへの表示移動" }, "task": { diff --git a/packages/core/i18n/nls.json b/packages/core/i18n/nls.json index 4be1ec58ad45d..57a4044029f04 100644 --- a/packages/core/i18n/nls.json +++ b/packages/core/i18n/nls.json @@ -409,7 +409,7 @@ "resultSubset": "This is only a subset of all results. Use a more specific search term to narrow down the result list.", "searchOnEditorModification": "Search the active editor when modified." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Move View to Secondary Window" }, "task": { diff --git a/packages/core/i18n/nls.pl.json b/packages/core/i18n/nls.pl.json index a406a1225bf8e..676ba8bf5e9fa 100644 --- a/packages/core/i18n/nls.pl.json +++ b/packages/core/i18n/nls.pl.json @@ -409,7 +409,7 @@ "resultSubset": "To jest tylko podzbiór wszystkich wyników. Użyj bardziej szczegółowego terminu wyszukiwania, aby zawęzić listę wyników.", "searchOnEditorModification": "Przeszukiwanie aktywnego edytora po modyfikacji." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Przenieś widok do okna podrzędnego" }, "task": { diff --git a/packages/core/i18n/nls.pt-br.json b/packages/core/i18n/nls.pt-br.json index 6cdfef0b350d8..182e4af4ebfcd 100644 --- a/packages/core/i18n/nls.pt-br.json +++ b/packages/core/i18n/nls.pt-br.json @@ -409,7 +409,7 @@ "resultSubset": "Este é apenas um subconjunto de todos os resultados. Use um termo de busca mais específico para restringir a lista de resultados.", "searchOnEditorModification": "Pesquise o editor ativo quando modificado." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Mover vista para a janela secundária" }, "task": { diff --git a/packages/core/i18n/nls.pt-pt.json b/packages/core/i18n/nls.pt-pt.json index 326d3fa052721..476d9b89a17e0 100644 --- a/packages/core/i18n/nls.pt-pt.json +++ b/packages/core/i18n/nls.pt-pt.json @@ -409,7 +409,7 @@ "resultSubset": "Este é apenas um subconjunto de todos os resultados. Use um termo de pesquisa mais específico para restringir a lista de resultados.", "searchOnEditorModification": "Pesquisar o editor activo quando modificado." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Mover vista para a janela secundária" }, "task": { diff --git a/packages/core/i18n/nls.ru.json b/packages/core/i18n/nls.ru.json index ffd791428eb60..42053bbdf8cff 100644 --- a/packages/core/i18n/nls.ru.json +++ b/packages/core/i18n/nls.ru.json @@ -409,7 +409,7 @@ "resultSubset": "Это только часть всех результатов. Используйте более конкретный поисковый запрос, чтобы сузить список результатов.", "searchOnEditorModification": "Поиск активного редактора при изменении." }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "Переместить вид в дополнительное окно" }, "task": { diff --git a/packages/core/i18n/nls.zh-cn.json b/packages/core/i18n/nls.zh-cn.json index 9d043783c0db9..be66788018ff0 100644 --- a/packages/core/i18n/nls.zh-cn.json +++ b/packages/core/i18n/nls.zh-cn.json @@ -409,7 +409,7 @@ "resultSubset": "这只是所有结果的一个子集。使用一个更具体的搜索词来缩小结果列表。", "searchOnEditorModification": "修改时搜索活动的编辑器。" }, - "secondary-window-ui": { + "secondary-window": { "extract-widget": "将视图移至第二窗口" }, "task": { diff --git a/packages/core/src/browser/secondary-window-handler.ts b/packages/core/src/browser/secondary-window-handler.ts index e8d551b4e1d13..2211181a4308f 100644 --- a/packages/core/src/browser/secondary-window-handler.ts +++ b/packages/core/src/browser/secondary-window-handler.ts @@ -44,8 +44,7 @@ class SecondaryWindowRootWidget extends Widget { * This handler manages the opened secondary windows and sets up messaging between them and the Theia main window. * In addition, it provides access to the extracted widgets and provides notifications when widgets are added to or removed from this handler. * - * _Note:_ This handler is used by the application shell and there should be no need for callers to directly interact with this class. - * Instead, consider using the application shell. + * @experimental The functionality provided by this handler is experimental and has known issues in Electron apps. */ @injectable() export class SecondaryWindowHandler { @@ -147,11 +146,12 @@ export class SecondaryWindowHandler { this.secondaryWindows.push(newWindow); + const mainWindowTitle = document.title; newWindow.onload = () => { // Use the widget's title as the window title // Even if the widget's label were malicious, this should be safe against XSS because the HTML standard defines this is inserted via a text node. // See https://html.spec.whatwg.org/multipage/dom.html#document.title - newWindow.document.title = widget.title.label; + newWindow.document.title = `${widget.title.label} — ${mainWindowTitle}`; const element = newWindow.document.getElementById('widget-host'); if (!element) { diff --git a/packages/core/src/browser/shell/application-shell.ts b/packages/core/src/browser/shell/application-shell.ts index 28ed92508ef7e..9fd0ae410dda2 100644 --- a/packages/core/src/browser/shell/application-shell.ts +++ b/packages/core/src/browser/shell/application-shell.ts @@ -34,7 +34,7 @@ import { FrontendApplicationStateService } from '../frontend-application-state'; import { TabBarToolbarRegistry, TabBarToolbarFactory } from './tab-bar-toolbar'; import { ContextKeyService } from '../context-key-service'; import { Emitter } from '../../common/event'; -import { ExtractableWidget, waitForRevealed, waitForClosed, PINNED_CLASS } from '../widgets'; +import { waitForRevealed, waitForClosed, PINNED_CLASS } from '../widgets'; import { CorePreferences } from '../core-preferences'; import { BreadcrumbsRendererFactory } from '../breadcrumbs/breadcrumbs-renderer'; import { Deferred } from '../../common/promise-util'; @@ -1946,9 +1946,6 @@ export class ApplicationShell extends Widget { } } - async moveWidgetToSecondaryWindow(widget: ExtractableWidget): Promise { - this.secondaryWindowHandler.moveWidgetToSecondaryWindow(widget); - } } /** diff --git a/packages/core/src/browser/window/secondary-window-service.ts b/packages/core/src/browser/window/secondary-window-service.ts index d314fab9ae63e..784e32bf974e2 100644 --- a/packages/core/src/browser/window/secondary-window-service.ts +++ b/packages/core/src/browser/window/secondary-window-service.ts @@ -16,7 +16,11 @@ export const SecondaryWindowService = Symbol('SecondaryWindowService'); -/** Service for opening new secondary windows to contain widgets extracted from the application shell. */ +/** + * Service for opening new secondary windows to contain widgets extracted from the application shell. + * + * @experimental The functionality provided by this service and its implementation is still under development. Use with caution. + */ export interface SecondaryWindowService { /** * Creates a new secondary window for a widget to be extracted from the application shell. diff --git a/packages/navigator/src/browser/open-editors-widget/navigator-open-editors-tree-model.ts b/packages/navigator/src/browser/open-editors-widget/navigator-open-editors-tree-model.ts index 6d6d326932f96..4ba20bcc97473 100644 --- a/packages/navigator/src/browser/open-editors-widget/navigator-open-editors-tree-model.ts +++ b/packages/navigator/src/browser/open-editors-widget/navigator-open-editors-tree-model.ts @@ -192,7 +192,7 @@ export class OpenEditorsModel extends FileTreeModel { const areaNode: CompositeTreeNode & ExpandableTreeNode = { id: `${OpenEditorsModel.AREA_NODE_ID_PREFIX}:${area}`, parent: rootNode, - name: area, + name: area === 'secondaryWindow' ? 'in secondary window' : area, expanded: true, children: [] }; diff --git a/packages/secondary-window-ui/.eslintrc.js b/packages/secondary-window/.eslintrc.js similarity index 100% rename from packages/secondary-window-ui/.eslintrc.js rename to packages/secondary-window/.eslintrc.js diff --git a/packages/secondary-window-ui/README.md b/packages/secondary-window/README.md similarity index 83% rename from packages/secondary-window-ui/README.md rename to packages/secondary-window/README.md index 4eba946554837..6cfb92c619a21 100644 --- a/packages/secondary-window-ui/README.md +++ b/packages/secondary-window/README.md @@ -4,7 +4,7 @@ theia-ext-logo -

ECLIPSE THEIA - WIDGET-EXTRACTION-UI EXTENSION

+

ECLIPSE THEIA - SECONDARY WINDOW EXTENSION


@@ -12,7 +12,7 @@ ## Description -The `@theia/secondary-window-ui` extension contributes UI integration that allows moving widgets to secondary windows. +The `@theia/secondary-window` extension contributes UI integration that allows moving widgets to secondary windows. ### Limitations diff --git a/packages/secondary-window-ui/package.json b/packages/secondary-window/package.json similarity index 89% rename from packages/secondary-window-ui/package.json rename to packages/secondary-window/package.json index ffde35054c3f2..d8e5b700effab 100644 --- a/packages/secondary-window-ui/package.json +++ b/packages/secondary-window/package.json @@ -1,5 +1,5 @@ { - "name": "@theia/secondary-window-ui", + "name": "@theia/secondary-window", "version": "1.29.0", "description": "Theia - Secondary window UI contributions", "dependencies": { @@ -10,7 +10,7 @@ }, "theiaExtensions": [ { - "frontend": "lib/browser/secondary-window-ui-frontend-module" + "frontend": "lib/browser/secondary-window-frontend-module" } ], "keywords": [ diff --git a/packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-contribution.ts b/packages/secondary-window/src/browser/secondary-window-frontend-contribution.ts similarity index 81% rename from packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-contribution.ts rename to packages/secondary-window/src/browser/secondary-window-frontend-contribution.ts index 31ad13442a5dc..15c43dc002e6c 100644 --- a/packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-contribution.ts +++ b/packages/secondary-window/src/browser/secondary-window-frontend-contribution.ts @@ -15,26 +15,26 @@ // ***************************************************************************** import { inject, injectable } from '@theia/core/shared/inversify'; -import { ApplicationShell } from '@theia/core/lib/browser/shell'; import { CommandRegistry, CommandContribution, Command } from '@theia/core/lib/common/command'; import { codicon, ExtractableWidget } from '@theia/core/lib/browser/widgets'; import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { SecondaryWindowHandler } from '@theia/core/lib/browser/secondary-window-handler'; export const EXTRACT_WIDGET = Command.toLocalizedCommand({ id: 'extract-widget', label: 'Move View to Secondary Window' -}, 'theia/secondary-window-ui/extract-widget'); +}, 'theia/secondary-window/extract-widget'); /** Contributes the widget extraction command and registers it in the toolbar of extractable widgets. */ @injectable() -export class SecondaryWindowUiContribution implements CommandContribution, TabBarToolbarContribution { +export class SecondaryWindowContribution implements CommandContribution, TabBarToolbarContribution { - @inject(ApplicationShell) - protected readonly shell: ApplicationShell; + @inject(SecondaryWindowHandler) + protected readonly secondaryWindowHandler: SecondaryWindowHandler; registerCommands(commands: CommandRegistry): void { commands.registerCommand(EXTRACT_WIDGET, { - execute: async widget => this.shell.moveWidgetToSecondaryWindow(widget), + execute: async widget => this.secondaryWindowHandler.moveWidgetToSecondaryWindow(widget), isVisible: widget => ExtractableWidget.is(widget), isEnabled: widget => ExtractableWidget.is(widget) }); diff --git a/packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-module.ts b/packages/secondary-window/src/browser/secondary-window-frontend-module.ts similarity index 78% rename from packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-module.ts rename to packages/secondary-window/src/browser/secondary-window-frontend-module.ts index 0326a8d8647a9..474730cb970ed 100644 --- a/packages/secondary-window-ui/src/browser/secondary-window-ui-frontend-module.ts +++ b/packages/secondary-window/src/browser/secondary-window-frontend-module.ts @@ -15,13 +15,13 @@ // ***************************************************************************** import { ContainerModule } from '@theia/core/shared/inversify'; -import { SecondaryWindowUiContribution } from './secondary-window-ui-frontend-contribution'; +import { SecondaryWindowContribution } from './secondary-window-frontend-contribution'; import { CommandContribution } from '@theia/core/lib/common/command'; import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; export default new ContainerModule(bind => { - bind(SecondaryWindowUiContribution).toSelf().inSingletonScope(); - bind(CommandContribution).toService(SecondaryWindowUiContribution); - bind(TabBarToolbarContribution).toService(SecondaryWindowUiContribution); + bind(SecondaryWindowContribution).toSelf().inSingletonScope(); + bind(CommandContribution).toService(SecondaryWindowContribution); + bind(TabBarToolbarContribution).toService(SecondaryWindowContribution); }); diff --git a/packages/secondary-window-ui/src/package.spec.ts b/packages/secondary-window/src/package.spec.ts similarity index 95% rename from packages/secondary-window-ui/src/package.spec.ts rename to packages/secondary-window/src/package.spec.ts index 230369d996150..dc03411b1269d 100644 --- a/packages/secondary-window-ui/src/package.spec.ts +++ b/packages/secondary-window/src/package.spec.ts @@ -14,6 +14,6 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** -describe('secondary-window-ui package', () => { +describe('secondary-window package', () => { it('supports code coverage statistics', () => true); }); diff --git a/packages/secondary-window-ui/tsconfig.json b/packages/secondary-window/tsconfig.json similarity index 100% rename from packages/secondary-window-ui/tsconfig.json rename to packages/secondary-window/tsconfig.json diff --git a/tsconfig.json b/tsconfig.json index 2839e74fe8d6d..bcdceef63de0c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -148,7 +148,7 @@ "path": "packages/search-in-workspace" }, { - "path": "packages/secondary-window-ui" + "path": "packages/secondary-window" }, { "path": "packages/task"