diff --git a/CHANGELOG.md b/CHANGELOG.md index 94ddd5a42..b75d7a5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Added - [main] Added npm script to watch and auto-restart the main process in PR [1450](https://github.com/Microsoft/BotFramework-Emulator/pull/1450) +- [main] Added a splash screen to app startup in PR [1451](https://github.com/Microsoft/BotFramework-Emulator/pull/1451) ## Fixed - [luis / client] Fixed several styling issues within the LUIS inspector, and enabled log deep link to configure missing LUIS service in PR [#1399](https://github.com/Microsoft/BotFramework-Emulator/pull/1399) diff --git a/packages/app/client/src/splash.html b/packages/app/client/src/splash.html new file mode 100644 index 000000000..a71d76bbb --- /dev/null +++ b/packages/app/client/src/splash.html @@ -0,0 +1,196 @@ + + +
+ + + + + + diff --git a/packages/app/client/webpack.config.js b/packages/app/client/webpack.config.js index 1e97e516e..f56964168 100644 --- a/packages/app/client/webpack.config.js +++ b/packages/app/client/webpack.config.js @@ -143,6 +143,7 @@ const defaultConfig = { new HardSourceWebpackPlugin(), new CopyWebpackPlugin([ { from: './src/inspector-preload.js', to: './' }, + { from: './src/splash.html', to: './splash.html' }, { from: './src/index.html', to: './index.html' }, { from: './src/ui/styles/themes/light.css', to: 'themes/light.css' }, { from: './src/ui/styles/themes/dark.css', to: 'themes/dark.css' }, diff --git a/packages/app/main/src/main.ts b/packages/app/main/src/main.ts index c99f65a1d..36ddf6438 100644 --- a/packages/app/main/src/main.ts +++ b/packages/app/main/src/main.ts @@ -61,6 +61,7 @@ import { WindowManager } from './windowManager'; export let mainWindow: Window; export let windowManager: WindowManager; +let splashWindow: Window; // start app startup timer const beginStartupTime = Date.now(); @@ -264,33 +265,10 @@ const windowIsOffScreen = function(windowBounds: Rectangle): boolean { }; const createMainWindow = async () => { - /* - // TODO: Read window size AFTER store is initialized (how did this ever work?) - const settings = getSettings(); - let initBounds: Rectangle = { - width: settings.windowState.width || 0, - height: settings.windowState.height || 0, - x: settings.windowState.left || 0, - y: settings.windowState.top || 0, - } - if (windowIsOffScreen(initBounds)) { - let display = screen.getAllDisplays().find(display => display.id === settings.windowState.displayId); - display = display || screen.getDisplayMatching(initBounds); - initBounds.x = display.workArea.x; - initBounds.y = display.workArea.y; - } - */ - mainWindow = new Window( new BrowserWindow({ show: false, backgroundColor: '#f7f7f7', - /* - width: initBounds.width, - height: initBounds.height, - x: initBounds.x, - y: initBounds.y - */ width: 1400, height: 920, }) @@ -380,6 +358,7 @@ const createMainWindow = async () => { settingsStore.dispatch(rememberTheme(isHighContrast ? 'high-contrast' : themeInfo.name)); } mainWindow.webContents.setZoomLevel(zoomLevel); + splashWindow.browserWindow.close(); mainWindow.browserWindow.show(); // Start auto-updater @@ -449,12 +428,42 @@ function loadMainPage() { mainWindow.browserWindow.loadURL(page); } +function createSplashScreen(): void { + // create the splash window + splashWindow = new Window( + new BrowserWindow({ + show: false, + width: 400, + height: 300, + center: true, + frame: false, + }) + ); + // dereference on close + splashWindow.browserWindow.once('closed', () => { + splashWindow = null; + }); + const splashPage = process.env.ELECTRON_TARGET_URL + ? `${process.env.ELECTRON_TARGET_URL}splash.html` + : url.format({ + protocol: 'file', + slashes: true, + pathname: require.resolve('@bfemulator/client/public/splash.html'), + }); + splashWindow.browserWindow.loadURL(splashPage); + splashWindow.browserWindow.once('ready-to-show', () => { + // only show if the main window still hasn't loaded + const showSplashScreen = !mainWindow || (mainWindow.browserWindow && !mainWindow.browserWindow.isVisible()); + showSplashScreen && splashWindow.browserWindow.show(); + }); +} + app.on('ready', function() { if (!mainWindow) { + createSplashScreen(); if (process.argv.find(val => val.includes('--vscode-debugger'))) { // workaround for delay in vscode debugger attach setTimeout(createMainWindow, 5000); - // createMainWindow(); } else { createMainWindow(); } diff --git a/packages/app/main/src/settingsData/actions/azureAuthActions.spec.ts b/packages/app/main/src/settingsData/actions/azureAuthActions.spec.ts new file mode 100644 index 000000000..180b91d55 --- /dev/null +++ b/packages/app/main/src/settingsData/actions/azureAuthActions.spec.ts @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as azureAuthActions from './azureAuthActions'; + +describe('Azure auth actions', () => { + test('azurePersistLoginChanged action', () => { + expect(azureAuthActions.azurePersistLoginChanged(true)).toEqual({ + type: azureAuthActions.AZURE_PERSIST_LOGIN_CHANGED, + payload: true, + }); + }); + + test('azureLoggedInUserChanged action', () => { + expect(azureAuthActions.azureLoggedInUserChanged('someUser')).toEqual({ + type: azureAuthActions.AZURE_LOGGED_IN_USER_CHANGED, + payload: 'someUser', + }); + }); +}); diff --git a/packages/app/main/src/settingsData/actions/botActions.spec.ts b/packages/app/main/src/settingsData/actions/botActions.spec.ts new file mode 100644 index 000000000..4f809831a --- /dev/null +++ b/packages/app/main/src/settingsData/actions/botActions.spec.ts @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as botActions from './botActions'; + +describe('Bot actions', () => { + test('addOrUpdateBots action', () => { + const bots = [{ botId: 'someBotId', botUrl: 'someBotUrl' }]; + expect(botActions.addOrUpdateBots(bots)).toEqual({ + type: botActions.ADD_OR_UPDATE_BOT, + state: { bots }, + }); + }); +}); diff --git a/packages/app/main/src/settingsData/actions/frameworkActions.spec.ts b/packages/app/main/src/settingsData/actions/frameworkActions.spec.ts new file mode 100644 index 000000000..807e01b79 --- /dev/null +++ b/packages/app/main/src/settingsData/actions/frameworkActions.spec.ts @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as frameworkActions from './frameworkActions'; + +describe('Framework actions', () => { + test('setFramework action', () => { + const frameworkSettings = { + autoUpdate: true, + }; + expect(frameworkActions.setFramework(frameworkSettings)).toEqual({ + type: frameworkActions.SET_FRAMEWORK, + state: frameworkSettings, + }); + }); + + test('pushClientAwareSettings action', () => { + expect(frameworkActions.pushClientAwareSettings()).toEqual({ + type: frameworkActions.PUSH_CLIENT_AWARE_SETTINGS, + state: void 0, + }); + }); +}); diff --git a/packages/app/main/src/settingsData/actions/userActions.spec.ts b/packages/app/main/src/settingsData/actions/userActions.spec.ts new file mode 100644 index 000000000..1051d8195 --- /dev/null +++ b/packages/app/main/src/settingsData/actions/userActions.spec.ts @@ -0,0 +1,65 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { User } from '@bfemulator/sdk-shared'; + +import * as userActions from './userActions'; + +describe('User actions', () => { + const user: User = { + id: 'someId', + name: 'someName', + }; + const users = [user]; + + test('addUsers action', () => { + expect(userActions.addUsers(users)).toEqual({ + type: userActions.ADD_USERS, + state: { users }, + }); + }); + + test('removeUsers action', () => { + expect(userActions.removeUsers(users)).toEqual({ + type: userActions.REMOVE_USERS, + state: { users }, + }); + }); + + test('setCurrentUser action', () => { + expect(userActions.setCurrentUser(user)).toEqual({ + type: userActions.SET_CURRENT_USER, + state: { user }, + }); + }); +}); diff --git a/packages/app/main/src/settingsData/actions/windowStateActions.spec.ts b/packages/app/main/src/settingsData/actions/windowStateActions.spec.ts new file mode 100644 index 000000000..c1c50a4ec --- /dev/null +++ b/packages/app/main/src/settingsData/actions/windowStateActions.spec.ts @@ -0,0 +1,78 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { DebugMode } from '@bfemulator/app-shared'; + +import * as windowStateActions from './windowStateActions'; + +describe('Window state actions', () => { + test('rememberTheme action', () => { + expect(windowStateActions.rememberTheme('light')).toEqual({ + type: windowStateActions.REMEMBER_THEME, + payload: { + theme: 'light', + }, + }); + }); + + test('rememberBounds action', () => { + const boundsState = { + displayId: 123, + top: 0, + left: 0, + width: 300, + height: 300, + }; + expect(windowStateActions.rememberBounds(boundsState)).toEqual({ + type: windowStateActions.REMEMBER_BOUNDS, + state: boundsState, + }); + }); + + test('rememberZoomLevel action', () => { + const zoomState = { zoomLevel: 200 }; + expect(windowStateActions.rememberZoomLevel(zoomState)).toEqual({ + type: windowStateActions.REMEMBER_ZOOM_LEVEL, + state: zoomState, + }); + }); + + test('debugModeChanged action', () => { + expect(windowStateActions.debugModeChanged(DebugMode.Normal)).toEqual({ + type: windowStateActions.DEBUG_MODE_CHANGED, + payload: { + debugMode: DebugMode.Normal, + }, + }); + }); +});