From 00c1c69c6d7cce3d2369ce0f57d935aea2584aa0 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Mon, 26 Feb 2024 09:06:28 -0800 Subject: [PATCH 1/7] introduce UI modes --- src/main/config/settings.ts | 15 ++++- src/main/labview/labview.ts | 83 +++++++++++++++++++++++++ src/main/sessionwindow/sessionwindow.ts | 60 ++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/src/main/config/settings.ts b/src/main/config/settings.ts index 1eb31bd5..a8176242 100644 --- a/src/main/config/settings.ts +++ b/src/main/config/settings.ts @@ -35,6 +35,13 @@ export enum CtrlWBehavior { DoNotClose = 'do-not-close' } +export enum UIMode { + Custom = 'custom', + MultiDocument = 'multi-document', + SingleDocument = 'single-document', + SingleDocumentZen = 'single-document-zen' +} + export type KeyValueMap = { [key: string]: string }; export enum SettingType { @@ -62,7 +69,9 @@ export enum SettingType { condaPath = 'condaPath', systemPythonPath = 'systemPythonPath', pythonEnvsPath = 'pythonEnvsPath', - condaChannels = 'condaChannels' + condaChannels = 'condaChannels', + + uiMode = 'uiMode' } export const serverLaunchArgsFixed = [ @@ -159,7 +168,9 @@ export class UserSettings { condaPath: new Setting(''), systemPythonPath: new Setting(''), pythonEnvsPath: new Setting(''), - condaChannels: new Setting(['conda-forge']) + condaChannels: new Setting(['conda-forge']), + + uiMode: new Setting(UIMode.MultiDocument, { wsOverridable: true }) }; if (readSettings) { diff --git a/src/main/labview/labview.ts b/src/main/labview/labview.ts index af58689a..eb1f1b2c 100644 --- a/src/main/labview/labview.ts +++ b/src/main/labview/labview.ts @@ -21,6 +21,7 @@ import { SessionWindow } from '../sessionwindow/sessionwindow'; import { CtrlWBehavior, SettingType, + UIMode, userSettings, WorkspaceSettings } from '../config/settings'; @@ -222,6 +223,87 @@ export class LabView implements IDisposable { } } + get uiMode(): UIMode { + return this._uiMode; + } + + async setUIMode(uiMode: UIMode) { + if (uiMode === UIMode.Custom) { + this._uiMode = uiMode; + return; + } + + await this._setUIMode(uiMode); + } + + async _setUIMode(uiMode: UIMode) { + this._uiMode = uiMode; + + await this._view.webContents.executeJavaScript(` + executeJSResult_currentLayout = {}; + { + const lab = window.jupyterapp || window.jupyterlab; + + if (lab) { + const labShell = lab.shell; + const statusBar = labShell.widgets('bottom').find(widget => widget.id === 'jp-main-statusbar'); + const currentState = { + leftTabBarVisible: labShell.isSideTabBarVisible('left'), + leftCollapsed: labShell.leftCollapsed, + rightTabBarVisible: labShell.isSideTabBarVisible('right'), + rightCollapsed: labShell.rightCollapsed, + isSimpleInterface: labShell.mode === 'single-document', + statusBarVisible: statusBar && statusBar.isVisible, + }; + + console.log('CURRENT STATE', currentState); + + if ('${this._uiMode}' === '${UIMode.MultiDocument}' || '${this._uiMode}' === '${UIMode.SingleDocument}') { + console.log('UI MODE', '${this._uiMode}'); + labShell.mode = '${this._uiMode}' === '${UIMode.MultiDocument}' ? 'multiple-document' : 'single-document'; + if (currentState.leftCollapsed) { + labShell.expandLeft(); + } + if (!currentState.leftTabBarVisible) { + labShell.toggleSideTabBarVisibility('left'); + } + if (!currentState.rightCollapsed) { + labShell.collapseRight(); + } + if (!currentState.rightTabBarVisible) { + labShell.toggleSideTabBarVisibility('right'); + } + if (statusBar) { + statusBar.setHidden(false); + } + } else if ('${this._uiMode}' === '${UIMode.SingleDocumentZen}') { + if (!currentState.leftCollapsed) { + labShell.collapseLeft(); + } + if (currentState.leftTabBarVisible) { + labShell.toggleSideTabBarVisibility('left'); + } + if (!currentState.rightCollapsed) { + labShell.collapseRight(); + } + if (currentState.rightTabBarVisible) { + labShell.toggleSideTabBarVisibility('right'); + } + if (!currentState.isSimpleInterface) { + labShell.mode = 'single-document'; + } + if (currentState.statusBarVisible) { + if (statusBar) { + statusBar.setHidden(true); + } + } + } + executeJSResult_currentLayout = currentState; + } + } + `); + } + get labUIReady(): Promise { return new Promise(resolve => { const checkIfReady = () => { @@ -410,6 +492,7 @@ export class LabView implements IDisposable { private _wsSettings: WorkspaceSettings; private _labUIReady = false; private _evm = new EventManager(); + private _uiMode: UIMode = UIMode.Custom; } export namespace LabView { diff --git a/src/main/sessionwindow/sessionwindow.ts b/src/main/sessionwindow/sessionwindow.ts index 7dc5089e..9cc54c72 100644 --- a/src/main/sessionwindow/sessionwindow.ts +++ b/src/main/sessionwindow/sessionwindow.ts @@ -17,6 +17,7 @@ import { DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH, SettingType, + UIMode, userSettings, WorkspaceSettings } from '../config/settings'; @@ -420,6 +421,8 @@ export class SessionWindow implements IDisposable { showServerNotificationBadge ); } + + this._setUIMode(this._wsSettings.getValue(SettingType.uiMode)); } get titleBarView(): TitleBarView { @@ -861,6 +864,56 @@ export class SessionWindow implements IDisposable { this._newWindow(); } }, + { + label: 'UI Mode', + visible: + this._contentViewType === ContentViewType.Lab && + !this._progressViewVisible, + type: 'submenu', + submenu: [ + { + label: 'Zen Mode', + click: () => { + this._setUIMode(UIMode.SingleDocumentZen); + }, + type: 'checkbox', + checked: + this._contentViewType === ContentViewType.Lab && + this._labView.uiMode === UIMode.SingleDocumentZen + }, + { + label: 'Single document IDE', + click: () => { + this._setUIMode(UIMode.SingleDocument); + }, + type: 'checkbox', + checked: + this._contentViewType === ContentViewType.Lab && + this._labView.uiMode === UIMode.SingleDocument + }, + { + label: 'Multi document IDE', + click: () => { + this._setUIMode(UIMode.MultiDocument); + }, + type: 'checkbox', + checked: + this._contentViewType === ContentViewType.Lab && + this._labView.uiMode === UIMode.MultiDocument + }, + { + label: 'Custom', + click: () => { + this._setUIMode(UIMode.Custom); + }, + type: 'checkbox', + checked: + this._contentViewType === ContentViewType.Lab && + this._labView.uiMode === UIMode.Custom + } + ] + }, + { type: 'separator' }, { label: 'Close Session', visible: @@ -1564,6 +1617,13 @@ export class SessionWindow implements IDisposable { this._updateContentView(); } + private async _setUIMode(uiMode: UIMode) { + await this._labView.labUIReady; + this._wsSettings.setValue(SettingType.uiMode, uiMode); + this._wsSettings.save(); + this._labView.setUIMode(uiMode); + } + private _newWindow() { this._app.createNewEmptySession(); // keep a free server up From bb19dc325275c8112ae63ec54d74145fb2349385 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Tue, 27 Feb 2024 20:11:18 -0800 Subject: [PATCH 2/7] open single files in zen mode --- src/main/config/settings.ts | 6 +- src/main/labview/labview.ts | 155 +++++++++++++++++++++--------------- 2 files changed, 95 insertions(+), 66 deletions(-) diff --git a/src/main/config/settings.ts b/src/main/config/settings.ts index a8176242..f30a812f 100644 --- a/src/main/config/settings.ts +++ b/src/main/config/settings.ts @@ -71,7 +71,8 @@ export enum SettingType { pythonEnvsPath = 'pythonEnvsPath', condaChannels = 'condaChannels', - uiMode = 'uiMode' + uiMode = 'uiMode', + uiModeForSingleFileOpen = 'uiModeForSingleFileOpen' } export const serverLaunchArgsFixed = [ @@ -170,7 +171,8 @@ export class UserSettings { pythonEnvsPath: new Setting(''), condaChannels: new Setting(['conda-forge']), - uiMode: new Setting(UIMode.MultiDocument, { wsOverridable: true }) + uiMode: new Setting(UIMode.Custom, { wsOverridable: true }), + uiModeForSingleFileOpen: new Setting(UIMode.SingleDocumentZen) }; if (readSettings) { diff --git a/src/main/labview/labview.ts b/src/main/labview/labview.ts index eb1f1b2c..88780faa 100644 --- a/src/main/labview/labview.ts +++ b/src/main/labview/labview.ts @@ -165,7 +165,25 @@ export class LabView implements IDisposable { return path.normalize(path.join(__dirname, '../../../')); } + private _willOpenSingleFile(): boolean { + const labDir = this._sessionConfig.resolvedWorkingDirectory; + + const filesToOpen = this._sessionConfig.filesToOpen; + if (filesToOpen.length === 1) { + const filePath = path.resolve(labDir, this._sessionConfig.filesToOpen[0]); + if (fs.lstatSync(filePath)?.isFile()) { + return true; + } + } + + return false; + } + async openFiles() { + if (this._willOpenSingleFile()) { + this._setUIMode(UIMode.SingleDocumentZen); + } + const filesToOpen = this._sessionConfig.filesToOpen; filesToOpen.forEach(async (relPath: string) => { if (relPath === '') { @@ -240,66 +258,8 @@ export class LabView implements IDisposable { this._uiMode = uiMode; await this._view.webContents.executeJavaScript(` - executeJSResult_currentLayout = {}; { - const lab = window.jupyterapp || window.jupyterlab; - - if (lab) { - const labShell = lab.shell; - const statusBar = labShell.widgets('bottom').find(widget => widget.id === 'jp-main-statusbar'); - const currentState = { - leftTabBarVisible: labShell.isSideTabBarVisible('left'), - leftCollapsed: labShell.leftCollapsed, - rightTabBarVisible: labShell.isSideTabBarVisible('right'), - rightCollapsed: labShell.rightCollapsed, - isSimpleInterface: labShell.mode === 'single-document', - statusBarVisible: statusBar && statusBar.isVisible, - }; - - console.log('CURRENT STATE', currentState); - - if ('${this._uiMode}' === '${UIMode.MultiDocument}' || '${this._uiMode}' === '${UIMode.SingleDocument}') { - console.log('UI MODE', '${this._uiMode}'); - labShell.mode = '${this._uiMode}' === '${UIMode.MultiDocument}' ? 'multiple-document' : 'single-document'; - if (currentState.leftCollapsed) { - labShell.expandLeft(); - } - if (!currentState.leftTabBarVisible) { - labShell.toggleSideTabBarVisibility('left'); - } - if (!currentState.rightCollapsed) { - labShell.collapseRight(); - } - if (!currentState.rightTabBarVisible) { - labShell.toggleSideTabBarVisibility('right'); - } - if (statusBar) { - statusBar.setHidden(false); - } - } else if ('${this._uiMode}' === '${UIMode.SingleDocumentZen}') { - if (!currentState.leftCollapsed) { - labShell.collapseLeft(); - } - if (currentState.leftTabBarVisible) { - labShell.toggleSideTabBarVisibility('left'); - } - if (!currentState.rightCollapsed) { - labShell.collapseRight(); - } - if (currentState.rightTabBarVisible) { - labShell.toggleSideTabBarVisibility('right'); - } - if (!currentState.isSimpleInterface) { - labShell.mode = 'single-document'; - } - if (currentState.statusBarVisible) { - if (statusBar) { - statusBar.setHidden(true); - } - } - } - executeJSResult_currentLayout = currentState; - } + jlabDesktop_setUIMode('${this._uiMode}'); } `); } @@ -450,13 +410,17 @@ export class LabView implements IDisposable { private _registerWebAppFrontEndHandlers() { this._view.webContents.on('dom-ready', () => { + const openingSingleFile = this._willOpenSingleFile(); + this._view.webContents.executeJavaScript(` // disable splash animation - const style = document.createElement('style'); - style.textContent = '#jupyterlab-splash { display: none !important; }'; - document.head.append(style); + { + const style = document.createElement('style'); + style.textContent = '#jupyterlab-splash * { display: none; }'; + document.head.append(style); + } - async function getLab() { + async function jlabDesktop_getLab() { return new Promise((resolve) => { const checkLab = () => { return window.jupyterapp || window.jupyterlab; @@ -476,7 +440,70 @@ export class LabView implements IDisposable { }); } - getLab().then((lab) => { + async function jlabDesktop_setUIMode(uiMode) { + const lab = await jlabDesktop_getLab(); + const labShell = lab.shell; + const statusBar = labShell.widgets('bottom').find(widget => widget.id === 'jp-main-statusbar'); + const currentState = { + leftTabBarVisible: labShell.isSideTabBarVisible('left'), + leftCollapsed: labShell.leftCollapsed, + rightTabBarVisible: labShell.isSideTabBarVisible('right'), + rightCollapsed: labShell.rightCollapsed, + isSimpleInterface: labShell.mode === 'single-document', + statusBarVisible: statusBar && statusBar.isVisible, + }; + + if (uiMode === '${UIMode.MultiDocument}' || uiMode === '${ + UIMode.SingleDocument + }') { + labShell.mode = uiMode === '${ + UIMode.MultiDocument + }' ? 'multiple-document' : 'single-document'; + if (currentState.leftCollapsed) { + labShell.expandLeft(); + } + if (!currentState.leftTabBarVisible) { + labShell.toggleSideTabBarVisibility('left'); + } + if (!currentState.rightCollapsed) { + labShell.collapseRight(); + } + if (!currentState.rightTabBarVisible) { + labShell.toggleSideTabBarVisibility('right'); + } + if (statusBar) { + statusBar.setHidden(false); + } + } else if (uiMode === '${UIMode.SingleDocumentZen}') { + if (!currentState.leftCollapsed) { + labShell.collapseLeft(); + } + if (currentState.leftTabBarVisible) { + labShell.toggleSideTabBarVisibility('left'); + } + if (!currentState.rightCollapsed) { + labShell.collapseRight(); + } + if (currentState.rightTabBarVisible) { + labShell.toggleSideTabBarVisibility('right'); + } + if (!currentState.isSimpleInterface) { + labShell.mode = 'single-document'; + } + if (currentState.statusBarVisible) { + if (statusBar) { + statusBar.setHidden(true); + } + } + } + } + + jlabDesktop_getLab().then((lab) => { + ${ + openingSingleFile + ? `jlabDesktop_setUIMode('${UIMode.SingleDocumentZen}');` + : '' + } lab.restored.then(() => { window.electronAPI.broadcastLabUIReady(); }); From 233af4dadd00eed09f8018d03c416ad837b31662 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Tue, 27 Feb 2024 20:42:23 -0800 Subject: [PATCH 3/7] UI modes on settings dialog --- src/main/config/settings.ts | 4 +- src/main/labview/labview.ts | 10 +++-- src/main/sessionwindow/sessionwindow.ts | 4 +- src/main/settingsdialog/settingsdialog.ts | 53 +++++++++++++++++++++-- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/config/settings.ts b/src/main/config/settings.ts index f30a812f..75e92355 100644 --- a/src/main/config/settings.ts +++ b/src/main/config/settings.ts @@ -39,7 +39,7 @@ export enum UIMode { Custom = 'custom', MultiDocument = 'multi-document', SingleDocument = 'single-document', - SingleDocumentZen = 'single-document-zen' + Zen = 'zen' } export type KeyValueMap = { [key: string]: string }; @@ -172,7 +172,7 @@ export class UserSettings { condaChannels: new Setting(['conda-forge']), uiMode: new Setting(UIMode.Custom, { wsOverridable: true }), - uiModeForSingleFileOpen: new Setting(UIMode.SingleDocumentZen) + uiModeForSingleFileOpen: new Setting(UIMode.Zen) }; if (readSettings) { diff --git a/src/main/labview/labview.ts b/src/main/labview/labview.ts index 88780faa..6c29766b 100644 --- a/src/main/labview/labview.ts +++ b/src/main/labview/labview.ts @@ -181,7 +181,9 @@ export class LabView implements IDisposable { async openFiles() { if (this._willOpenSingleFile()) { - this._setUIMode(UIMode.SingleDocumentZen); + this._setUIMode( + userSettings.getValue(SettingType.uiModeForSingleFileOpen) + ); } const filesToOpen = this._sessionConfig.filesToOpen; @@ -474,7 +476,7 @@ export class LabView implements IDisposable { if (statusBar) { statusBar.setHidden(false); } - } else if (uiMode === '${UIMode.SingleDocumentZen}') { + } else if (uiMode === '${UIMode.Zen}') { if (!currentState.leftCollapsed) { labShell.collapseLeft(); } @@ -501,7 +503,9 @@ export class LabView implements IDisposable { jlabDesktop_getLab().then((lab) => { ${ openingSingleFile - ? `jlabDesktop_setUIMode('${UIMode.SingleDocumentZen}');` + ? `jlabDesktop_setUIMode('${userSettings.getValue( + SettingType.uiModeForSingleFileOpen + )}');` : '' } lab.restored.then(() => { diff --git a/src/main/sessionwindow/sessionwindow.ts b/src/main/sessionwindow/sessionwindow.ts index 9cc54c72..fd175561 100644 --- a/src/main/sessionwindow/sessionwindow.ts +++ b/src/main/sessionwindow/sessionwindow.ts @@ -874,12 +874,12 @@ export class SessionWindow implements IDisposable { { label: 'Zen Mode', click: () => { - this._setUIMode(UIMode.SingleDocumentZen); + this._setUIMode(UIMode.Zen); }, type: 'checkbox', checked: this._contentViewType === ContentViewType.Lab && - this._labView.uiMode === UIMode.SingleDocumentZen + this._labView.uiMode === UIMode.Zen }, { label: 'Single document IDE', diff --git a/src/main/settingsdialog/settingsdialog.ts b/src/main/settingsdialog/settingsdialog.ts index f92efe85..e97dfb29 100644 --- a/src/main/settingsdialog/settingsdialog.ts +++ b/src/main/settingsdialog/settingsdialog.ts @@ -13,7 +13,8 @@ import { serverLaunchArgsDefault, serverLaunchArgsFixed, StartupMode, - ThemeType + ThemeType, + UIMode } from '../config/settings'; import { IRegistry } from '../registry'; import { jlabCLICommandIsSetup } from '../utils'; @@ -41,7 +42,9 @@ export class SettingsDialog { serverArgs, overrideDefaultServerArgs, serverEnvVars, - ctrlWBehavior + ctrlWBehavior, + uiMode, + uiModeForSingleFileOpen } = options; const installUpdatesAutomaticallyEnabled = process.platform === 'darwin'; const installUpdatesAutomatically = @@ -94,6 +97,10 @@ export class SettingsDialog { justify-content: flex-end; align-items: center; } + .column { + display: flex; + flex-direction: column; + } .progress-message { margin-right: 5px; line-height: 24px; visibility: hidden; } @@ -155,6 +162,40 @@ export class SettingsDialog { >Start new session >Restore last sessions + +
+
+
+
+ +
+ +
+ + Zen Mode + Single document IDE + Multi document IDE + Custom + +
+
+ +
+
+ +
+ +
+ + Zen Mode + Single document IDE + Multi document IDE + Custom + +
+
+
+
@@ -476,6 +517,8 @@ export class SettingsDialog { window.electronAPI.setSettings({ notifyOnBundledEnvUpdates: notifyOnBundledEnvUpdatesCheckbox.checked, updateBundledEnvAutomatically: updateBundledEnvAutomaticallyCheckbox.checked, + uiMode: document.getElementById('ui-mode').value, + uiModeForSingleFileOpen: document.getElementById('ui-mode-for-single-file-open').value, }); window.electronAPI.setDefaultWorkingDirectory(workingDirectoryInput.value); @@ -517,7 +560,9 @@ export class SettingsDialog { overrideDefaultServerArgs, serverEnvVars: strServerEnvVars, ctrlWBehavior, - cliCommandIsSetup + cliCommandIsSetup, + uiMode, + uiModeForSingleFileOpen }); } @@ -557,5 +602,7 @@ export namespace SettingsDialog { overrideDefaultServerArgs: boolean; serverEnvVars: KeyValueMap; ctrlWBehavior: CtrlWBehavior; + uiMode: UIMode; + uiModeForSingleFileOpen: UIMode; } } From c72e31f2a2cdc231fd333d6ff005776c0989cf08 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Tue, 27 Feb 2024 20:49:19 -0800 Subject: [PATCH 4/7] Update app.ts --- src/main/app.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/app.ts b/src/main/app.ts index 43d1ea20..7cc5dbad 100644 --- a/src/main/app.ts +++ b/src/main/app.ts @@ -410,7 +410,11 @@ export class JupyterApplication implements IApplication, IDisposable { SettingType.overrideDefaultServerArgs ), serverEnvVars: userSettings.getValue(SettingType.serverEnvVars), - ctrlWBehavior: userSettings.getValue(SettingType.ctrlWBehavior) + ctrlWBehavior: userSettings.getValue(SettingType.ctrlWBehavior), + uiMode: userSettings.getValue(SettingType.uiMode), + uiModeForSingleFileOpen: userSettings.getValue( + SettingType.uiModeForSingleFileOpen + ) }, this._registry ); From 8621eabfd71dbe16313231445ea02a5926f7cfe8 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Tue, 27 Feb 2024 21:34:52 -0800 Subject: [PATCH 5/7] compose menu based on session type --- src/main/sessionwindow/sessionwindow.ts | 34 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/sessionwindow/sessionwindow.ts b/src/main/sessionwindow/sessionwindow.ts index fd175561..9d1c9b9c 100644 --- a/src/main/sessionwindow/sessionwindow.ts +++ b/src/main/sessionwindow/sessionwindow.ts @@ -857,13 +857,12 @@ export class SessionWindow implements IDisposable { return; } - const template: MenuItemConstructorOptions[] = [ - { - label: 'New Window', - click: () => { - this._newWindow(); - } - }, + const inSession = + this._contentViewType === ContentViewType.Lab && + !this._progressViewVisible; + const inLocalSession = inSession && !this._sessionConfig?.remoteURL; + + const uiModeSubmenu: MenuItemConstructorOptions[] = [ { label: 'UI Mode', visible: @@ -912,18 +911,29 @@ export class SessionWindow implements IDisposable { this._labView.uiMode === UIMode.Custom } ] - }, - { type: 'separator' }, + } + ]; + + const closeSessionMenuItem: MenuItemConstructorOptions[] = [ { label: 'Close Session', - visible: - this._contentViewType === ContentViewType.Lab && - !this._progressViewVisible, click: () => { this._closeSession(); } }, + { type: 'separator' } + ]; + + const template: MenuItemConstructorOptions[] = [ + { + label: 'New Window', + click: () => { + this._newWindow(); + } + }, + ...(inLocalSession ? uiModeSubmenu : []), { type: 'separator' }, + ...(inSession ? closeSessionMenuItem : []), { label: 'Settings', click: () => { From 2fa9fd82e3437f1b6d6bf841a47daebaf57a4e26 Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Thu, 29 Feb 2024 09:07:14 -0800 Subject: [PATCH 6/7] handle reverting back to web app managed, refactoring --- src/main/config/settings.ts | 18 +++++++--- src/main/labview/labview.ts | 35 ++++++++++++++++--- src/main/sessionwindow/sessionwindow.ts | 41 ++++++++++++++++++----- src/main/settingsdialog/settingsdialog.ts | 10 +++--- 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/main/config/settings.ts b/src/main/config/settings.ts index 75e92355..0d2957be 100644 --- a/src/main/config/settings.ts +++ b/src/main/config/settings.ts @@ -36,10 +36,11 @@ export enum CtrlWBehavior { } export enum UIMode { - Custom = 'custom', + Default = 'default', // Desktop app defaults for new session or single file MultiDocument = 'multi-document', SingleDocument = 'single-document', - Zen = 'zen' + Zen = 'zen', + ManagedByWebApp = 'managed-by-web-app' // let JupyterLab web app manage the layout } export type KeyValueMap = { [key: string]: string }; @@ -171,7 +172,9 @@ export class UserSettings { pythonEnvsPath: new Setting(''), condaChannels: new Setting(['conda-forge']), - uiMode: new Setting(UIMode.Custom, { wsOverridable: true }), + uiMode: new Setting(UIMode.ManagedByWebApp, { + wsOverridable: true + }), uiModeForSingleFileOpen: new Setting(UIMode.Zen) }; @@ -252,6 +255,10 @@ export class WorkspaceSettings extends UserSettings { return this._wsSettings; } + hasValue(setting: SettingType) { + return setting in this._wsSettings; + } + getValue(setting: SettingType) { if (setting in this._wsSettings) { return this._wsSettings[setting].value; @@ -301,12 +308,15 @@ export class WorkspaceSettings extends UserSettings { ); const wsSettings: { [key: string]: any } = {}; + // uiMode needs special handling, it needs to be saved even if same as global default. + // this is due to automatically setting uiMode to Zen for default for opening single file for (let key in SettingType) { const setting = this._wsSettings[key]; if ( setting && this._settings[key].wsOverridable && - this._isDifferentThanUserSetting(key as SettingType) + (key === SettingType.uiMode || + this._isDifferentThanUserSetting(key as SettingType)) ) { wsSettings[key] = setting.value; } diff --git a/src/main/labview/labview.ts b/src/main/labview/labview.ts index 6c29766b..d3c9b053 100644 --- a/src/main/labview/labview.ts +++ b/src/main/labview/labview.ts @@ -165,6 +165,30 @@ export class LabView implements IDisposable { return path.normalize(path.join(__dirname, '../../../')); } + /** + * if opening a single file and no workspace setting exists + */ + shouldSetToSingleFileUIMode(): boolean { + let setToSingleFileUIMode = false; + this._reloadWSSettings(); + const wsUIModeSet = this._wsSettings.hasValue(SettingType.uiMode); + // if UI mode not specified for project directory, or set to Default + if ( + !wsUIModeSet || + this._wsSettings.getValue(SettingType.uiMode) === UIMode.Default + ) { + setToSingleFileUIMode = this._willOpenSingleFile(); + } + + return setToSingleFileUIMode; + } + + private _reloadWSSettings() { + this._wsSettings = new WorkspaceSettings( + this._sessionConfig.workingDirectory + ); + } + private _willOpenSingleFile(): boolean { const labDir = this._sessionConfig.resolvedWorkingDirectory; @@ -180,7 +204,7 @@ export class LabView implements IDisposable { } async openFiles() { - if (this._willOpenSingleFile()) { + if (this.shouldSetToSingleFileUIMode()) { this._setUIMode( userSettings.getValue(SettingType.uiModeForSingleFileOpen) ); @@ -248,8 +272,9 @@ export class LabView implements IDisposable { } async setUIMode(uiMode: UIMode) { - if (uiMode === UIMode.Custom) { + if (uiMode === UIMode.ManagedByWebApp) { this._uiMode = uiMode; + // let web app control the layout return; } @@ -412,7 +437,7 @@ export class LabView implements IDisposable { private _registerWebAppFrontEndHandlers() { this._view.webContents.on('dom-ready', () => { - const openingSingleFile = this._willOpenSingleFile(); + const setToSingleFileUIMode = this.shouldSetToSingleFileUIMode(); this._view.webContents.executeJavaScript(` // disable splash animation @@ -502,7 +527,7 @@ export class LabView implements IDisposable { jlabDesktop_getLab().then((lab) => { ${ - openingSingleFile + setToSingleFileUIMode ? `jlabDesktop_setUIMode('${userSettings.getValue( SettingType.uiModeForSingleFileOpen )}');` @@ -523,7 +548,7 @@ export class LabView implements IDisposable { private _wsSettings: WorkspaceSettings; private _labUIReady = false; private _evm = new EventManager(); - private _uiMode: UIMode = UIMode.Custom; + private _uiMode: UIMode = UIMode.Default; } export namespace LabView { diff --git a/src/main/sessionwindow/sessionwindow.ts b/src/main/sessionwindow/sessionwindow.ts index 9d1c9b9c..c20770d5 100644 --- a/src/main/sessionwindow/sessionwindow.ts +++ b/src/main/sessionwindow/sessionwindow.ts @@ -422,7 +422,12 @@ export class SessionWindow implements IDisposable { ); } - this._setUIMode(this._wsSettings.getValue(SettingType.uiMode)); + // initialize UI mode to workspace default or app default + const uiMode = this._labView.shouldSetToSingleFileUIMode() + ? userSettings.getValue(SettingType.uiModeForSingleFileOpen) + : this._wsSettings.getValue(SettingType.uiMode); + + this._setUIMode(uiMode, false); } get titleBarView(): TitleBarView { @@ -901,14 +906,21 @@ export class SessionWindow implements IDisposable { this._labView.uiMode === UIMode.MultiDocument }, { - label: 'Custom', + label: 'Managed by web app', click: () => { - this._setUIMode(UIMode.Custom); + this._setUIMode(UIMode.ManagedByWebApp); }, type: 'checkbox', checked: this._contentViewType === ContentViewType.Lab && - this._labView.uiMode === UIMode.Custom + this._labView.uiMode === UIMode.ManagedByWebApp + }, + { type: 'separator' }, + { + label: 'Reset to session default', + click: () => { + this._setUIMode(UIMode.Default); + } } ] } @@ -1627,11 +1639,24 @@ export class SessionWindow implements IDisposable { this._updateContentView(); } - private async _setUIMode(uiMode: UIMode) { + private async _setUIMode(uiMode: UIMode, save: boolean = true) { await this._labView.labUIReady; - this._wsSettings.setValue(SettingType.uiMode, uiMode); - this._wsSettings.save(); - this._labView.setUIMode(uiMode); + if (uiMode === UIMode.Default) { + this._wsSettings.unsetValue(SettingType.uiMode); + this._wsSettings.save(); + let defaultUIMode = userSettings.getValue( + this._labView.shouldSetToSingleFileUIMode() + ? SettingType.uiModeForSingleFileOpen + : SettingType.uiMode + ); + this._labView.setUIMode(defaultUIMode); + } else { + if (save) { + this._wsSettings.setValue(SettingType.uiMode, uiMode); + this._wsSettings.save(); + } + this._labView.setUIMode(uiMode); + } } private _newWindow() { diff --git a/src/main/settingsdialog/settingsdialog.ts b/src/main/settingsdialog/settingsdialog.ts index e97dfb29..8d27640f 100644 --- a/src/main/settingsdialog/settingsdialog.ts +++ b/src/main/settingsdialog/settingsdialog.ts @@ -175,7 +175,7 @@ export class SettingsDialog { Zen Mode Single document IDE Multi document IDE - Custom + Managed by web app @@ -187,10 +187,10 @@ export class SettingsDialog {
- Zen Mode - Single document IDE - Multi document IDE - Custom + Zen Mode + Single document IDE + Multi document IDE + Managed by web app
From 65ef5c268fe2e08608031b9894c445ea82dd04fa Mon Sep 17 00:00:00 2001 From: Mehmet Bektas Date: Thu, 29 Feb 2024 09:21:36 -0800 Subject: [PATCH 7/7] simplify and remove use of Default UI mode enum --- src/main/config/settings.ts | 1 - src/main/labview/labview.ts | 16 +++++------- src/main/sessionwindow/sessionwindow.ts | 33 ++++++++++++++----------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/main/config/settings.ts b/src/main/config/settings.ts index 0d2957be..866e338f 100644 --- a/src/main/config/settings.ts +++ b/src/main/config/settings.ts @@ -36,7 +36,6 @@ export enum CtrlWBehavior { } export enum UIMode { - Default = 'default', // Desktop app defaults for new session or single file MultiDocument = 'multi-document', SingleDocument = 'single-document', Zen = 'zen', diff --git a/src/main/labview/labview.ts b/src/main/labview/labview.ts index d3c9b053..f8eecf0f 100644 --- a/src/main/labview/labview.ts +++ b/src/main/labview/labview.ts @@ -169,18 +169,14 @@ export class LabView implements IDisposable { * if opening a single file and no workspace setting exists */ shouldSetToSingleFileUIMode(): boolean { - let setToSingleFileUIMode = false; this._reloadWSSettings(); - const wsUIModeSet = this._wsSettings.hasValue(SettingType.uiMode); - // if UI mode not specified for project directory, or set to Default - if ( - !wsUIModeSet || - this._wsSettings.getValue(SettingType.uiMode) === UIMode.Default - ) { - setToSingleFileUIMode = this._willOpenSingleFile(); + + // if UI mode not specified for project directory + if (!this._wsSettings.hasValue(SettingType.uiMode)) { + return this._willOpenSingleFile(); } - return setToSingleFileUIMode; + return false; } private _reloadWSSettings() { @@ -548,7 +544,7 @@ export class LabView implements IDisposable { private _wsSettings: WorkspaceSettings; private _labUIReady = false; private _evm = new EventManager(); - private _uiMode: UIMode = UIMode.Default; + private _uiMode: UIMode = UIMode.ManagedByWebApp; } export namespace LabView { diff --git a/src/main/sessionwindow/sessionwindow.ts b/src/main/sessionwindow/sessionwindow.ts index c20770d5..7462f800 100644 --- a/src/main/sessionwindow/sessionwindow.ts +++ b/src/main/sessionwindow/sessionwindow.ts @@ -919,7 +919,7 @@ export class SessionWindow implements IDisposable { { label: 'Reset to session default', click: () => { - this._setUIMode(UIMode.Default); + this._resetUIModeToSessionDefault(); } } ] @@ -1639,24 +1639,27 @@ export class SessionWindow implements IDisposable { this._updateContentView(); } + private async _resetUIModeToSessionDefault() { + await this._labView.labUIReady; + + this._wsSettings.unsetValue(SettingType.uiMode); + this._wsSettings.save(); + + const defaultUIMode = userSettings.getValue( + this._labView.shouldSetToSingleFileUIMode() + ? SettingType.uiModeForSingleFileOpen + : SettingType.uiMode + ); + this._labView.setUIMode(defaultUIMode); + } + private async _setUIMode(uiMode: UIMode, save: boolean = true) { await this._labView.labUIReady; - if (uiMode === UIMode.Default) { - this._wsSettings.unsetValue(SettingType.uiMode); + if (save) { + this._wsSettings.setValue(SettingType.uiMode, uiMode); this._wsSettings.save(); - let defaultUIMode = userSettings.getValue( - this._labView.shouldSetToSingleFileUIMode() - ? SettingType.uiModeForSingleFileOpen - : SettingType.uiMode - ); - this._labView.setUIMode(defaultUIMode); - } else { - if (save) { - this._wsSettings.setValue(SettingType.uiMode, uiMode); - this._wsSettings.save(); - } - this._labView.setUIMode(uiMode); } + this._labView.setUIMode(uiMode); } private _newWindow() {