mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-26 08:51:22 -06:00
SDA-2547 (Upgrade electron version to 14.0.1) (#1267)
* SDA-2547 - Upgrade electron version to 14.0.1
* SDA-2547 - refactor and fix unit tests
* SDA-2555 - Move custom title bar away from remote module
* SDA-2555 - Update API new-window to setWindowOpenHandler and fix issues
* SDA-2555 - Arrange imports
* SDA-2555 - Fix unit tests
* SDA-3387 - Fixed reload, native notification issues & finally removed the SFE CSS injection 🎉
* SDA-2547 - Fix fullscreen state on Windows
* SDA-2552 - Update version info
* SDA-2548 - Fix media permission
* SDA-2547 - Get app name from package.json
This commit is contained in:
parent
962eb0886c
commit
e7f4470d9c
@ -1,7 +1,7 @@
|
||||
## Prerequisites
|
||||
|
||||
### Windows
|
||||
- NodeJS version >= 12.x.y (corresponds to electron 9.x.y)
|
||||
- NodeJS version >= 14.x.y (corresponds to electron 14.x.y)
|
||||
- Microsoft Visual Studio 2017 Community or Paid (C++ and .NET/C# development tools)
|
||||
- Python >= 2.7.1
|
||||
- Dot Net 3.5 SP1 or later
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
### Mac
|
||||
- Xcode command line tools. Or better, Xcode latest version
|
||||
- NodeJS version >= 12.x.y (corresponds to electron 9.x.y)
|
||||
- NodeJS version >= 14.x.y (corresponds to electron 14.x.y)
|
||||
- [Sudre Packages](http://s.sudre.free.fr/Software/Packages/about.html)
|
||||
|
||||
#### Notes
|
||||
@ -35,7 +35,7 @@ npm install
|
||||
npm run prebuild
|
||||
|
||||
# Run against a POD
|
||||
cross-env ELECTRON_DEV=true electron . --url=https://corporate.symphony.com
|
||||
npm run dev -- --url=https://corporate.symphony.com
|
||||
|
||||
# Run the demo app
|
||||
npm run demo
|
||||
|
476
package-lock.json
generated
476
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "symphony",
|
||||
"version": "9.3.0",
|
||||
"version": "14.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -1163,9 +1163,9 @@
|
||||
}
|
||||
},
|
||||
"@electron/get": {
|
||||
"version": "1.12.4",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@electron/get/-/get-1.12.4.tgz",
|
||||
"integrity": "sha1-pZcRE/wb+PoSqHidwgFSpzWfBqs=",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@electron/get/-/get-1.13.0.tgz",
|
||||
"integrity": "sha1-lca8r/T5pQXqRnkkJPRR7+qJIow=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
@ -1179,6 +1179,12 @@
|
||||
"sumchecker": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"@electron/remote": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@electron/remote/-/remote-1.2.2.tgz",
|
||||
"integrity": "sha1-TDkKLmad9Hr5c8Ce7BBhYqKWwyM=",
|
||||
"dev": true
|
||||
},
|
||||
"@felixrieseberg/spellchecker": {
|
||||
"version": "4.0.12",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@felixrieseberg/spellchecker/-/spellchecker-4.0.12.tgz",
|
||||
@ -1673,9 +1679,9 @@
|
||||
}
|
||||
},
|
||||
"@types/cacheable-request": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
|
||||
"integrity": "sha1-XSLz3e0f06hMC761A5p0GcLJGXY=",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/cacheable-request/-/cacheable-request-6.0.2.tgz",
|
||||
"integrity": "sha1-wyTaAZfeCpiiMSFWU2riYkKf9rk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/http-cache-semantics": "*",
|
||||
@ -1755,9 +1761,9 @@
|
||||
}
|
||||
},
|
||||
"@types/http-cache-semantics": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
|
||||
"integrity": "sha1-kUB3lzaqJlVjXudW4kZ9eHz+iio=",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
|
||||
"integrity": "sha1-Dqe2FJaQK5WJDcTDoRa2DLja6BI=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/istanbul-lib-coverage": {
|
||||
@ -1792,9 +1798,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/keyv": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/keyv/-/keyv-3.1.1.tgz",
|
||||
"integrity": "sha1-5FpFMk/KnatxarEjDuJJyftSz6c=",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/keyv/-/keyv-3.1.3.tgz",
|
||||
"integrity": "sha1-HJquMocuwfINza7omp87qI9GXkE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
@ -1851,9 +1857,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/puppeteer": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/puppeteer/-/puppeteer-5.4.3.tgz",
|
||||
"integrity": "sha1-zcqEqndR13RI2KR32/oK8fEUhfI=",
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/puppeteer/-/puppeteer-5.4.4.tgz",
|
||||
"integrity": "sha1-6Sq+zMT0YgfD4bOJNKEka+CAzNA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
@ -1959,9 +1965,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/yauzl": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/yauzl/-/yauzl-2.9.1.tgz",
|
||||
"integrity": "sha1-0Q9p+fUi7vPPmOMK+2hKHh7JI68=",
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/yauzl/-/yauzl-2.9.2.tgz",
|
||||
"integrity": "sha1-xI5dVq/xREQJ45+hZLC01FUqe3o=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -1992,15 +1998,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@ -2008,12 +2014,12 @@
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
"ansi-regex": "^5.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3525,9 +3531,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"boolean": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/boolean/-/boolean-3.0.2.tgz",
|
||||
"integrity": "sha1-3xuqGLaisOcIQEdeHZPsj+dbJXA=",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/boolean/-/boolean-3.1.4.tgz",
|
||||
"integrity": "sha1-9RovtYOKmeBvm27B7bZ03mcCZDU=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -4121,9 +4127,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001203",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001203.tgz",
|
||||
"integrity": "sha1-p6NN8ho4fZ3v/NVsAAuM9atUBYA=",
|
||||
"version": "1.0.30001265",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
|
||||
"integrity": "sha1-BhPJ5ski5CJ5Lm/O/fmjr+7k+MM=",
|
||||
"dev": true
|
||||
},
|
||||
"capture-exit": {
|
||||
@ -4732,9 +4738,9 @@
|
||||
}
|
||||
},
|
||||
"config-chain": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/config-chain/-/config-chain-1.1.12.tgz",
|
||||
"integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/config-chain/-/config-chain-1.1.13.tgz",
|
||||
"integrity": "sha1-+tB5Wqamza/57Rto6d/5Q3LCMvQ=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -5566,9 +5572,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"detect-node": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/detect-node/-/detect-node-2.0.5.tgz",
|
||||
"integrity": "sha1-nScKp+qlrwtyxMnZuBTn9M5zi3k=",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/detect-node/-/detect-node-2.1.0.tgz",
|
||||
"integrity": "sha1-yccHdaScPQO8LAbZpzvlUPl4+LE=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -5930,14 +5936,22 @@
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/electron/-/electron-9.4.1.tgz",
|
||||
"integrity": "sha1-YqKq5M2T8bVteUpHVBUFpxZUF3o=",
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/electron/-/electron-14.1.1.tgz",
|
||||
"integrity": "sha1-ZDcm/h/UrXf7s6dbIRAF7QE1dIU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
"@types/node": "^12.0.12",
|
||||
"@types/node": "^14.6.2",
|
||||
"extract-zip": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.17.19",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@types/node/-/node-14.17.19.tgz",
|
||||
"integrity": "sha1-c0HprBtddI16PdwEM27VNqb5HDE=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-builder": {
|
||||
@ -6235,12 +6249,12 @@
|
||||
}
|
||||
},
|
||||
"electron-chromedriver": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/electron-chromedriver/-/electron-chromedriver-9.0.0.tgz",
|
||||
"integrity": "sha1-x2Kf5rlyEUDzo4AUT5mWDCvDtcE=",
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/electron-chromedriver/-/electron-chromedriver-13.0.0.tgz",
|
||||
"integrity": "sha1-pVOvd0MhWsRj4eQODbFNSlQu92I=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.12.2",
|
||||
"@electron/get": "^1.12.4",
|
||||
"extract-zip": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -6480,6 +6494,15 @@
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-abi/-/node-abi-2.30.1.tgz",
|
||||
"integrity": "sha1-xDfUsf4OKFqvKQ1FtF1Nev7axM8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/p-locate/-/p-locate-3.0.0.tgz",
|
||||
@ -6504,6 +6527,12 @@
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=",
|
||||
"dev": true
|
||||
},
|
||||
"spawn-rx": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/spawn-rx/-/spawn-rx-3.0.0.tgz",
|
||||
@ -6589,8 +6618,8 @@
|
||||
}
|
||||
},
|
||||
"electron-spellchecker": {
|
||||
"version": "git+https://github.com/symphonyoss/electron-spellchecker.git#8628a0e62660bc23da969fc19c9e9b39eb54be5a",
|
||||
"from": "git+https://github.com/symphonyoss/electron-spellchecker.git#v2.3.2",
|
||||
"version": "git+ssh://git@github.com/symphonyoss/electron-spellchecker.git#8628a0e62660bc23da969fc19c9e9b39eb54be5a",
|
||||
"from": "electron-spellchecker@git+https://github.com/symphonyoss/electron-spellchecker.git#v2.3.2",
|
||||
"requires": {
|
||||
"@aabuhijleh/electron-remote": "^1.4.0",
|
||||
"@felixrieseberg/spellchecker": "^4.0.12",
|
||||
@ -8415,9 +8444,9 @@
|
||||
}
|
||||
},
|
||||
"global-agent": {
|
||||
"version": "2.1.12",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/global-agent/-/global-agent-2.1.12.tgz",
|
||||
"integrity": "sha1-5K44Ercxqegcv4Jfk3fvRQqOQZU=",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/global-agent/-/global-agent-2.2.0.tgz",
|
||||
"integrity": "sha1-VmMxsGRua/eUKaFod2hcSh+/dtw=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -8431,9 +8460,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/core-js/-/core-js-3.9.1.tgz",
|
||||
"integrity": "sha1-zsjeWT246yqF/7Db3rMSy25UYK4=",
|
||||
"version": "3.18.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/core-js/-/core-js-3.18.1.tgz",
|
||||
"integrity": "sha1-KJ1L4s4AhdQPwSRMCxpUwARUYi8=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -8465,9 +8494,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-7.3.4.tgz",
|
||||
"integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -11414,13 +11443,13 @@
|
||||
}
|
||||
},
|
||||
"lighthouse-logger": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz",
|
||||
"integrity": "sha1-t21Wk16cE36GoEdB9rubJ3bohso=",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/lighthouse-logger/-/lighthouse-logger-1.3.0.tgz",
|
||||
"integrity": "sha1-umMD5zkwfE7uGPCCSVJOfa/VENs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^2.6.8",
|
||||
"marky": "^1.2.0"
|
||||
"debug": "^2.6.9",
|
||||
"marky": "^1.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@ -11755,9 +11784,9 @@
|
||||
}
|
||||
},
|
||||
"marky": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/marky/-/marky-1.2.1.tgz",
|
||||
"integrity": "sha1-o/z4L/01d1a4uK/+yf2/OjDcGwI=",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/marky/-/marky-1.2.2.tgz",
|
||||
"integrity": "sha1-RFZ2W03jB6E9JjppsMeb8ibmgyM=",
|
||||
"dev": true
|
||||
},
|
||||
"matchdep": {
|
||||
@ -12348,18 +12377,36 @@
|
||||
}
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-abi/-/node-abi-2.21.0.tgz",
|
||||
"integrity": "sha1-wtyeutb09T1uqbUx57j6rYEEHUg=",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-abi/-/node-abi-3.2.0.tgz",
|
||||
"integrity": "sha1-yOxodPgItNpfvVbpUGOQzmWxUqI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -12370,10 +12417,37 @@
|
||||
"integrity": "sha1-gTJeCiEXeJwBKNq2Xn448HzroWE="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=",
|
||||
"dev": true
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-fetch/-/node-fetch-2.6.5.tgz",
|
||||
"integrity": "sha1-QnNVN9fwgKfl94tsVJtxRr4XQv0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"dev": true
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"dev": true
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "6.1.0",
|
||||
@ -13584,6 +13658,23 @@
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"which-pm-runs": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-abi": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-abi/-/node-abi-2.30.1.tgz",
|
||||
"integrity": "sha1-xDfUsf4OKFqvKQ1FtF1Nev7axM8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"prelude-ls": {
|
||||
@ -14593,9 +14684,9 @@
|
||||
}
|
||||
},
|
||||
"resolve-alpn": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/resolve-alpn/-/resolve-alpn-1.0.0.tgz",
|
||||
"integrity": "sha1-dFrWCz1q/0tKSOAbjAvccJWeDow=",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||
"integrity": "sha1-t629rDVGqq7CC0Xn2CZZJwcnJvk=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-cwd": {
|
||||
@ -14648,9 +14739,9 @@
|
||||
}
|
||||
},
|
||||
"resq": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/resq/-/resq-1.10.0.tgz",
|
||||
"integrity": "sha1-QLXjUV/5hGaOa2t8JAHygrCAQuo=",
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/resq/-/resq-1.10.1.tgz",
|
||||
"integrity": "sha1-wF0bOAgBbM7sTUhc6zday0lWX1M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^2.0.1"
|
||||
@ -14752,6 +14843,23 @@
|
||||
"nan": "^2.14.0",
|
||||
"node-abi": "^2.13.0",
|
||||
"prebuild-install": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-abi": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/node-abi/-/node-abi-2.30.1.tgz",
|
||||
"integrity": "sha1-xDfUsf4OKFqvKQ1FtF1Nev7axM8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"rst-selector-parser": {
|
||||
@ -15042,16 +15150,16 @@
|
||||
}
|
||||
},
|
||||
"screen-share-indicator-frame": {
|
||||
"version": "git+https://github.com/symphonyoss/ScreenShareIndicatorFrame.git#e943ec141899d8cf7301f4bd3f91a1434e1ceb10",
|
||||
"from": "screen-share-indicator-frame@git+https://github.com/symphonyoss/ScreenShareIndicatorFrame.git#e943ec141899d8cf7301f4bd3f91a1434e1ceb10",
|
||||
"version": "git+ssh://git@github.com/symphonyoss/ScreenShareIndicatorFrame.git#e943ec141899d8cf7301f4bd3f91a1434e1ceb10",
|
||||
"from": "screen-share-indicator-frame@git+https://github.com/symphonyoss/ScreenShareIndicatorFrame.git#v1.4.10",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"run-script-os": "1.0.7"
|
||||
}
|
||||
},
|
||||
"screen-snippet": {
|
||||
"version": "git+https://github.com/symphonyoss/ScreenSnippet2.git#889aedbd3ecf16320a387967aaee0e7ca992d717",
|
||||
"from": "screen-snippet@git+https://github.com/symphonyoss/ScreenSnippet2.git#889aedbd3ecf16320a387967aaee0e7ca992d717",
|
||||
"version": "git+ssh://git@github.com/symphonyoss/ScreenSnippet2.git#889aedbd3ecf16320a387967aaee0e7ca992d717",
|
||||
"from": "screen-snippet@git+https://github.com/symphonyoss/ScreenSnippet2.git#v2.4.0",
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
@ -15527,16 +15635,140 @@
|
||||
"dev": true
|
||||
},
|
||||
"spectron": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/spectron/-/spectron-11.1.0.tgz",
|
||||
"integrity": "sha1-7k8RyQV/bXkJTy1ETrpVXMvmOWU=",
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/spectron/-/spectron-15.0.0.tgz",
|
||||
"integrity": "sha1-nA4lSyvj8HJagbg0MJK50BCEOcc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/remote": "^1.1.0",
|
||||
"dev-null": "^0.1.1",
|
||||
"electron-chromedriver": "^9.0.0",
|
||||
"request": "^2.87.0",
|
||||
"split": "^1.0.0",
|
||||
"webdriverio": "^6.1.20"
|
||||
"electron-chromedriver": "^13.0.0",
|
||||
"got": "^11.8.0",
|
||||
"split": "^1.0.1",
|
||||
"webdriverio": "^6.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@sindresorhus/is/-/is-4.2.0.tgz",
|
||||
"integrity": "sha1-Znv8YYaufJ4LRaCJYMVRQ3F24co=",
|
||||
"dev": true
|
||||
},
|
||||
"@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha1-tKkUu2LnwnLU5Zif5EQPgSqx2Ac=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"cacheable-request": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/cacheable-request/-/cacheable-request-7.0.2.tgz",
|
||||
"integrity": "sha1-6g0LiJNkolhUdXMByhKy2nf5HSc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone-response": "^1.0.2",
|
||||
"get-stream": "^5.1.0",
|
||||
"http-cache-semantics": "^4.0.0",
|
||||
"keyv": "^4.0.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"normalize-url": "^6.0.1",
|
||||
"responselike": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha1-yjh2Et234QS9FthaqwDV7PCcZvw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-response": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"defer-to-connect": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||
"integrity": "sha1-gBa9tBQ+RjK3ejRJxiNid95SBYc=",
|
||||
"dev": true
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"got": {
|
||||
"version": "11.8.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/got/-/got-11.8.2.tgz",
|
||||
"integrity": "sha1-ers5Weoowx81dvFXbB7/ziPzNZk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
"@types/cacheable-request": "^6.0.1",
|
||||
"@types/responselike": "^1.0.0",
|
||||
"cacheable-lookup": "^5.0.3",
|
||||
"cacheable-request": "^7.0.1",
|
||||
"decompress-response": "^6.0.0",
|
||||
"http2-wrapper": "^1.0.0-beta.5.2",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"responselike": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha1-kziAKjDTtmBfvgYT4JQAjKjAWhM=",
|
||||
"dev": true
|
||||
},
|
||||
"keyv": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/keyv/-/keyv-4.0.3.tgz",
|
||||
"integrity": "sha1-TzqpjeJUgDyvzSiWc0EI2qNeQlQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||
"integrity": "sha1-JgPni3tLAAbLyi+8yKMgJVislHk=",
|
||||
"dev": true
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha1-LR1Zr5wbEpgVrMwsRqAipc4fo8k=",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-url": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo=",
|
||||
"dev": true
|
||||
},
|
||||
"p-cancelable": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha1-qrf71BZYL6MqPbSYWcEiSHxe0s8=",
|
||||
"dev": true
|
||||
},
|
||||
"responselike": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/responselike/-/responselike-2.0.0.tgz",
|
||||
"integrity": "sha1-JjkbzDF091D5p56sxAoSpcQtdyM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lowercase-keys": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"split": {
|
||||
@ -16853,9 +17085,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.24",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/ua-parser-js/-/ua-parser-js-0.7.24.tgz",
|
||||
"integrity": "sha1-jT7OpG7U8fHWPsJfF9hWgQXcAnw=",
|
||||
"version": "0.7.28",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/ua-parser-js/-/ua-parser-js-0.7.28.tgz",
|
||||
"integrity": "sha1-i6BOZT81ziECOcZGYWhb+RId7DE=",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
@ -17447,24 +17679,24 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@sindresorhus/is/-/is-4.0.0.tgz",
|
||||
"integrity": "sha1-L/Z06WEbRbUoiW2CDT16gS3i8OQ=",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@sindresorhus/is/-/is-4.2.0.tgz",
|
||||
"integrity": "sha1-Znv8YYaufJ4LRaCJYMVRQ3F24co=",
|
||||
"dev": true
|
||||
},
|
||||
"@szmarczak/http-timer": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
|
||||
"integrity": "sha1-v71QIR6d+lG6B9pYoUzf0zMgUVI=",
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha1-tKkUu2LnwnLU5Zif5EQPgSqx2Ac=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"cacheable-request": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/cacheable-request/-/cacheable-request-7.0.1.tgz",
|
||||
"integrity": "sha1-BiAxwoViMngu1pSiV/o12pOUKlg=",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/cacheable-request/-/cacheable-request-7.0.2.tgz",
|
||||
"integrity": "sha1-6g0LiJNkolhUdXMByhKy2nf5HSc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone-response": "^1.0.2",
|
||||
@ -17472,7 +17704,7 @@
|
||||
"http-cache-semantics": "^4.0.0",
|
||||
"keyv": "^4.0.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"normalize-url": "^4.1.0",
|
||||
"normalize-url": "^6.0.1",
|
||||
"responselike": "^2.0.0"
|
||||
}
|
||||
},
|
||||
@ -17546,10 +17778,16 @@
|
||||
"integrity": "sha1-LR1Zr5wbEpgVrMwsRqAipc4fo8k=",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-url": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo=",
|
||||
"dev": true
|
||||
},
|
||||
"p-cancelable": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/p-cancelable/-/p-cancelable-2.1.0.tgz",
|
||||
"integrity": "sha1-TVHDuR9IPQKg0wB2UyH8o5PXWN0=",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha1-qrf71BZYL6MqPbSYWcEiSHxe0s8=",
|
||||
"dev": true
|
||||
},
|
||||
"responselike": {
|
||||
@ -17610,19 +17848,19 @@
|
||||
}
|
||||
},
|
||||
"async": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/async/-/async-3.2.0.tgz",
|
||||
"integrity": "sha1-s6JoXF67ZB094C0WEALGD8n4VyA=",
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/async/-/async-3.2.1.tgz",
|
||||
"integrity": "sha1-0ydOxm0QekdHakxJE2qs2wBmX8g=",
|
||||
"dev": true
|
||||
},
|
||||
"compress-commons": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/compress-commons/-/compress-commons-4.1.0.tgz",
|
||||
"integrity": "sha1-Jex6RSiFLM0dRBp9Q1PNDs4RNxs=",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://repo.symphony.com/artifactory/api/npm/npm-virtual-dev/compress-commons/-/compress-commons-4.1.1.tgz",
|
||||
"integrity": "sha1-3yoJp+0XRHZCutEKhcyaGeXEKn0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-crc32": "^0.2.13",
|
||||
"crc32-stream": "^4.0.1",
|
||||
"crc32-stream": "^4.0.2",
|
||||
"normalize-path": "^3.0.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
}
|
||||
|
@ -126,7 +126,7 @@
|
||||
"browserify": "16.5.1",
|
||||
"cross-env": "5.2.0",
|
||||
"del": "3.0.0",
|
||||
"electron": "9.4.1",
|
||||
"electron": "14.1.1",
|
||||
"electron-builder": "22.7.0",
|
||||
"electron-builder-squirrel-windows": "20.38.3",
|
||||
"electron-icon-maker": "0.0.4",
|
||||
@ -144,13 +144,13 @@
|
||||
"jest-html-reporter": "3.0.0",
|
||||
"less": "3.8.1",
|
||||
"ncp": "2.0.0",
|
||||
"node-abi": "^2.17.0",
|
||||
"node-abi": "^3.2.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.2.1",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"robotjs": "0.6.0",
|
||||
"run-script-os": "1.0.7",
|
||||
"spectron": "^11.0.0",
|
||||
"spectron": "^15.0.0",
|
||||
"ts-jest": "25.3.0",
|
||||
"tslint": "5.11.0",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
|
@ -31,6 +31,7 @@ interface ILoginItemSettings {
|
||||
}
|
||||
interface IIpcMain {
|
||||
on(event: any, cb: any): void;
|
||||
handle(event: any, cb: any): Promise<void>;
|
||||
send(event: any, cb: any): void;
|
||||
}
|
||||
interface IIpcRenderer {
|
||||
@ -40,6 +41,14 @@ interface IIpcRenderer {
|
||||
removeListener(eventName: any, cb: any): void;
|
||||
once(eventName: any, cb: any): void;
|
||||
}
|
||||
interface IWebContents {
|
||||
setWindowOpenHandler(details: any): any;
|
||||
sendSync(event: any, cb: any): any;
|
||||
on(eventName: any, cb: any): void;
|
||||
send(event: any, ...cb: any[]): void;
|
||||
removeListener(eventName: any, cb: any): void;
|
||||
once(eventName: any, cb: any): void;
|
||||
}
|
||||
interface IPowerMonitor {
|
||||
getSystemIdleTime(): void;
|
||||
}
|
||||
@ -92,6 +101,10 @@ export const ipcMain: IIpcMain = {
|
||||
on: (event, cb) => {
|
||||
ipcEmitter.on(event, cb);
|
||||
},
|
||||
handle: (event, cb) => {
|
||||
ipcEmitter.on(event, cb);
|
||||
return Promise.resolve();
|
||||
},
|
||||
send: (event, args) => {
|
||||
const senderEvent = {
|
||||
sender: {
|
||||
@ -141,6 +154,42 @@ export const ipcRenderer: IIpcRenderer = {
|
||||
},
|
||||
};
|
||||
|
||||
export const webContents: IWebContents = {
|
||||
setWindowOpenHandler: (_details: {}) => {
|
||||
return { action: 'allow' };
|
||||
},
|
||||
sendSync: (event, args) => {
|
||||
const listeners = ipcEmitter.listeners(event);
|
||||
if (listeners.length > 0) {
|
||||
const listener = listeners[0];
|
||||
const eventArg = {};
|
||||
listener(eventArg, args);
|
||||
return eventArg;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
send: (event, ...args) => {
|
||||
const senderEvent = {
|
||||
sender: {
|
||||
send: (eventSend, ...arg) => {
|
||||
ipcEmitter.emit(eventSend, ...arg);
|
||||
},
|
||||
},
|
||||
preventDefault: jest.fn(),
|
||||
};
|
||||
ipcEmitter.emit(event, senderEvent, ...args);
|
||||
},
|
||||
on: (eventName, cb) => {
|
||||
ipcEmitter.on(eventName, cb);
|
||||
},
|
||||
removeListener: (eventName, cb) => {
|
||||
ipcEmitter.removeListener(eventName, cb);
|
||||
},
|
||||
once: (eventName, cb) => {
|
||||
ipcEmitter.on(eventName, cb);
|
||||
},
|
||||
};
|
||||
|
||||
export const shell = {
|
||||
openExternal: jest.fn(),
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ exports[`windows title bar should render correctly 1`] = `
|
||||
onClick={[Function]}
|
||||
onContextMenu={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
title="Maximize"
|
||||
title="Restore"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 14 10.2"
|
||||
@ -127,7 +127,7 @@ exports[`windows title bar should render correctly 1`] = `
|
||||
y="0px"
|
||||
>
|
||||
<path
|
||||
d="M0,0v10.1h10.2V0H0z M9.2,9.2H1.1V1h8.1V9.2z"
|
||||
d="M2.1,0v2H0v8.1h8.2v-2h2V0H2.1z M7.2,9.2H1.1V3h6.1V9.2z M9.2,7.1h-1V2H3.1V1h6.1V7.1z"
|
||||
fill="rgba(255, 255, 255, 0.9)"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
import { apiCmds } from '../src/common/api-interface';
|
||||
import AboutApp from '../src/renderer/components/about-app';
|
||||
import { ipcRenderer, remote } from './__mocks__/electron';
|
||||
import { ipcRenderer } from './__mocks__/electron';
|
||||
|
||||
describe('about app', () => {
|
||||
const aboutAppDataLabel = 'about-app-data';
|
||||
@ -32,6 +33,7 @@ describe('about app', () => {
|
||||
swiftSearchSupportedVersion: 'N/A',
|
||||
};
|
||||
const onLabelEvent = 'on';
|
||||
const ipcSendEvent = 'send';
|
||||
const removeListenerLabelEvent = 'removeListener';
|
||||
|
||||
it('should render correctly', () => {
|
||||
@ -62,12 +64,16 @@ describe('about app', () => {
|
||||
});
|
||||
|
||||
it('should copy the correct data on to clipboard', () => {
|
||||
const spyMount = jest.spyOn(remote.clipboard, 'write');
|
||||
const spyIpc = jest.spyOn(ipcRenderer, ipcSendEvent);
|
||||
const wrapper = shallow(React.createElement(AboutApp));
|
||||
ipcRenderer.send('about-app-data', aboutDataMock);
|
||||
const copyButtonSelector = `button.AboutApp-copy-button[title="Copy all the version information in this page"]`;
|
||||
wrapper.find(copyButtonSelector).simulate('click');
|
||||
const expectedData = { text: JSON.stringify(aboutDataMock, null, 4) };
|
||||
expect(spyMount).toBeCalledWith(expectedData, 'clipboard');
|
||||
const expectedData = {
|
||||
cmd: apiCmds.aboutAppClipBoardData,
|
||||
clipboard: aboutDataMock,
|
||||
clipboardType: 'clipboard',
|
||||
};
|
||||
expect(spyIpc).toBeCalledWith('symphony-api', expectedData);
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { handleChildWindow } from '../src/app/child-window-handler';
|
||||
import { config } from '../src/app/config-handler';
|
||||
import { windowHandler } from '../src/app/window-handler';
|
||||
import { injectStyles } from '../src/app/window-utils';
|
||||
import { ipcRenderer } from './__mocks__/electron';
|
||||
import { webContents } from './__mocks__/electron';
|
||||
import anything = jasmine.anything;
|
||||
|
||||
const getMainWindow = {
|
||||
isDestroyed: jest.fn(() => false),
|
||||
@ -69,52 +67,16 @@ jest.mock('../src/common/logger', () => {
|
||||
});
|
||||
|
||||
describe('child window handle', () => {
|
||||
const frameName = {};
|
||||
const disposition = 'new-window';
|
||||
const newWinOptions = {
|
||||
webPreferences: jest.fn(),
|
||||
webContents: { ...ipcRenderer, ...getMainWindow, webContents: ipcRenderer },
|
||||
};
|
||||
it('should set open window handler', () => {
|
||||
const spy = jest.spyOn(webContents, 'setWindowOpenHandler');
|
||||
|
||||
it('should call `did-start-loading` correctly on WindowOS', () => {
|
||||
const newWinUrl = 'about:blank';
|
||||
const args = [newWinUrl, frameName, disposition, newWinOptions];
|
||||
const spy = jest.spyOn(getMainWindow, 'setMenuBarVisibility');
|
||||
handleChildWindow(ipcRenderer as any);
|
||||
ipcRenderer.send('new-window', ...args);
|
||||
ipcRenderer.send('did-start-loading');
|
||||
expect(spy).toBeCalledWith(false);
|
||||
handleChildWindow(webContents as any);
|
||||
expect(spy).toBeCalledWith(expect.any(Function));
|
||||
});
|
||||
|
||||
it('should call `did-finish-load` correctly on WindowOS', () => {
|
||||
config.getGlobalConfigFields = jest.fn(() => {
|
||||
return {
|
||||
url: 'https://foundation-dev.symphony.com',
|
||||
};
|
||||
});
|
||||
const newWinUrl = 'about:blank';
|
||||
const args = [newWinUrl, frameName, disposition, newWinOptions];
|
||||
const spy = jest.spyOn(newWinOptions.webContents.webContents, 'send');
|
||||
handleChildWindow(ipcRenderer as any);
|
||||
ipcRenderer.send('new-window', ...args);
|
||||
ipcRenderer.send('did-finish-load');
|
||||
expect(spy).lastCalledWith('page-load', {
|
||||
enableCustomTitleBar: false,
|
||||
isMainWindow: false,
|
||||
isWindowsOS: true,
|
||||
locale: 'en-US',
|
||||
origin: 'https://foundation-dev.symphony.com',
|
||||
resources: {},
|
||||
});
|
||||
expect(injectStyles).toBeCalled();
|
||||
});
|
||||
|
||||
it('should call `windowHandler.openUrlInDefaultBrowser` when url in invalid', () => {
|
||||
const newWinUrl = 'invalid';
|
||||
const args = [newWinUrl, frameName, disposition, newWinOptions];
|
||||
const spy = jest.spyOn(windowHandler, 'openUrlInDefaultBrowser');
|
||||
handleChildWindow(ipcRenderer as any);
|
||||
ipcRenderer.send('new-window', ...args);
|
||||
expect(spy).not.toBeCalledWith('invalid');
|
||||
it('should trigger did-create-window', () => {
|
||||
const spy = jest.spyOn(webContents, 'on');
|
||||
handleChildWindow(webContents as any);
|
||||
expect(spy).toBeCalledWith('did-create-window', anything());
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
import { apiCmds } from '../src/common/api-interface';
|
||||
import WindowsTitleBar from '../src/renderer/components/windows-title-bar';
|
||||
import { ipcRenderer, remote } from './__mocks__/electron';
|
||||
import { ipcRenderer } from './__mocks__/electron';
|
||||
|
||||
// @ts-ignore
|
||||
global.MutationObserver = jest.fn().mockImplementation(() => ({
|
||||
@ -9,33 +10,11 @@ global.MutationObserver = jest.fn().mockImplementation(() => ({
|
||||
disconnect: jest.fn(),
|
||||
}));
|
||||
|
||||
// TODO: Fix tests
|
||||
describe('windows title bar', () => {
|
||||
beforeEach(() => {
|
||||
// state initial
|
||||
jest.spyOn(remote, 'getCurrentWindow').mockImplementation(() => {
|
||||
return {
|
||||
isFullScreen: jest.fn(() => {
|
||||
return false;
|
||||
}),
|
||||
isMaximized: jest.fn(() => {
|
||||
return false;
|
||||
}),
|
||||
on: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
isDestroyed: jest.fn(() => {
|
||||
return false;
|
||||
}),
|
||||
close: jest.fn(),
|
||||
maximize: jest.fn(),
|
||||
minimize: jest.fn(),
|
||||
unmaximize: jest.fn(),
|
||||
setFullScreen: jest.fn(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const getCurrentWindowFnLabel = 'getCurrentWindow';
|
||||
const onEventLabel = 'on';
|
||||
const sendEventLabel = 'send';
|
||||
const apiName = 'symphony-api';
|
||||
const maximizeEventLabel = 'maximize';
|
||||
const unmaximizeEventLabel = 'unmaximize';
|
||||
const enterFullScreenEventLabel = 'enter-full-screen';
|
||||
@ -47,28 +26,19 @@ describe('windows title bar', () => {
|
||||
});
|
||||
|
||||
it('should mount correctly', () => {
|
||||
const spy = jest.spyOn(ipcRenderer, onEventLabel);
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spy = jest.spyOn(remote, getCurrentWindowFnLabel);
|
||||
const spyWindow = jest.spyOn(window, onEventLabel);
|
||||
instance.updateState({ isMaximized: false });
|
||||
expect(spy).toBeCalled();
|
||||
expect(spyWindow).nthCalledWith(
|
||||
1,
|
||||
maximizeEventLabel,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(spyWindow).nthCalledWith(
|
||||
2,
|
||||
unmaximizeEventLabel,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(spyWindow).nthCalledWith(
|
||||
expect(spy).nthCalledWith(1, maximizeEventLabel, expect.any(Function));
|
||||
expect(spy).nthCalledWith(2, unmaximizeEventLabel, expect.any(Function));
|
||||
expect(spy).nthCalledWith(
|
||||
3,
|
||||
enterFullScreenEventLabel,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(spyWindow).nthCalledWith(
|
||||
expect(spy).nthCalledWith(
|
||||
4,
|
||||
leaveFullScreenEventLabel,
|
||||
expect.any(Function),
|
||||
@ -76,27 +46,27 @@ describe('windows title bar', () => {
|
||||
});
|
||||
|
||||
it('should call `close` correctly', () => {
|
||||
const fnLabel = 'close';
|
||||
const titleLabel = 'Close';
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const customSelector = `button.title-bar-button[title="${titleLabel}"]`;
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spy = jest.spyOn(window, fnLabel);
|
||||
const cmd = {
|
||||
cmd: apiCmds.closeMainWindow,
|
||||
};
|
||||
const spy = jest.spyOn(ipcRenderer, sendEventLabel);
|
||||
wrapper.find(customSelector).simulate('click');
|
||||
expect(spy).toBeCalled();
|
||||
expect(spy).toBeCalledWith(apiName, cmd);
|
||||
});
|
||||
|
||||
it('should call `minimize` correctly', () => {
|
||||
const fnLabel = 'minimize';
|
||||
const titleLabel = 'Minimize';
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const customSelector = `button.title-bar-button[title="${titleLabel}"]`;
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spy = jest.spyOn(window, fnLabel);
|
||||
const spy = jest.spyOn(ipcRenderer, sendEventLabel);
|
||||
const cmd = {
|
||||
cmd: apiCmds.minimizeMainWindow,
|
||||
};
|
||||
wrapper.find(customSelector).simulate('click');
|
||||
expect(spy).toBeCalled();
|
||||
expect(spy).toBeCalledWith(apiName, cmd);
|
||||
});
|
||||
|
||||
it('should call `showMenu` correctly', () => {
|
||||
@ -132,82 +102,47 @@ describe('windows title bar', () => {
|
||||
expect(spy).lastCalledWith(expect.any(Function));
|
||||
});
|
||||
|
||||
describe('componentDidMount event', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div id="content-wrapper"></div>`;
|
||||
});
|
||||
|
||||
it('should call `componentDidMount` when isFullScreen', () => {
|
||||
const spy = jest.spyOn(document.body.style, 'removeProperty');
|
||||
const expectedValue = 'margin-top';
|
||||
// changing state before componentDidMount
|
||||
jest.spyOn(remote, 'getCurrentWindow').mockImplementation(() => {
|
||||
return {
|
||||
isFullScreen: jest.fn(() => {
|
||||
return true;
|
||||
}),
|
||||
isMaximized: jest.fn(() => {
|
||||
return false;
|
||||
}),
|
||||
on: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
isDestroyed: jest.fn(() => {
|
||||
return false;
|
||||
}),
|
||||
close: jest.fn(),
|
||||
maximize: jest.fn(),
|
||||
minimize: jest.fn(),
|
||||
unmaximize: jest.fn(),
|
||||
setFullScreen: jest.fn(),
|
||||
};
|
||||
});
|
||||
shallow(React.createElement(WindowsTitleBar));
|
||||
expect(spy).toBeCalledWith(expectedValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maximize functions', () => {
|
||||
it('should call `unmaximize` correctly when is not full screen', () => {
|
||||
const titleLabel = 'Restore';
|
||||
const unmaximizeFn = 'unmaximize';
|
||||
const cmd = {
|
||||
cmd: apiCmds.unmaximizeMainWindow,
|
||||
};
|
||||
const customSelector = `button.title-bar-button[title="${titleLabel}"]`;
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spy = jest.spyOn(window, unmaximizeFn);
|
||||
const spy = jest.spyOn(ipcRenderer, sendEventLabel);
|
||||
wrapper.setState({ isMaximized: true });
|
||||
wrapper.find(customSelector).simulate('click');
|
||||
expect(spy).toBeCalled();
|
||||
expect(spy).toBeCalledWith(apiName, cmd);
|
||||
});
|
||||
|
||||
it('should call `unmaximize` correctly when is full screen', () => {
|
||||
const windowSpyFn = 'setFullScreen';
|
||||
const titleLabel = 'Restore';
|
||||
const customSelector = `button.title-bar-button[title="${titleLabel}"]`;
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spy = jest.spyOn(window, windowSpyFn);
|
||||
window.isFullScreen = jest.fn(() => {
|
||||
return true;
|
||||
});
|
||||
const cmd = {
|
||||
cmd: apiCmds.unmaximizeMainWindow,
|
||||
};
|
||||
const spy = jest.spyOn(ipcRenderer, sendEventLabel);
|
||||
wrapper.setState({ isMaximized: true });
|
||||
wrapper.find(customSelector).simulate('click');
|
||||
expect(spy).toBeCalledWith(false);
|
||||
expect(spy).toBeCalledWith(apiName, cmd);
|
||||
});
|
||||
|
||||
it('should call maximize correctly when it is not in full screen', () => {
|
||||
const titleLabel = 'Maximize';
|
||||
const maximizeFn = 'maximize';
|
||||
const expectedState = { isMaximized: true };
|
||||
const customSelector = `button.title-bar-button[title="${titleLabel}"]`;
|
||||
const wrapper = shallow(React.createElement(WindowsTitleBar));
|
||||
const instance: any = wrapper.instance();
|
||||
const window = instance.window;
|
||||
const spyWindow = jest.spyOn(window, maximizeFn);
|
||||
wrapper.setState({ isMaximized: false });
|
||||
const spy = jest.spyOn(ipcRenderer, sendEventLabel);
|
||||
const spyState = jest.spyOn(wrapper, 'setState');
|
||||
wrapper.find(customSelector).simulate('click');
|
||||
expect(spyWindow).toBeCalled();
|
||||
const cmd = {
|
||||
cmd: apiCmds.maximizeMainWindow,
|
||||
};
|
||||
expect(spy).toBeCalled();
|
||||
expect(spy).toBeCalledWith(apiName, cmd);
|
||||
expect(spyState).lastCalledWith(expectedState);
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { BrowserWindow, crashReporter, WebContents } from 'electron';
|
||||
import {
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
crashReporter,
|
||||
DidCreateWindowDetails,
|
||||
HandlerDetails,
|
||||
WebContents,
|
||||
} from 'electron';
|
||||
|
||||
import { parse as parseQuerystring } from 'querystring';
|
||||
import { format, parse, Url } from 'url';
|
||||
@ -9,6 +16,7 @@ import { getGuid } from '../common/utils';
|
||||
import { whitelistHandler } from '../common/whitelist-handler';
|
||||
import { config } from './config-handler';
|
||||
import crashHandler from './crash-handler';
|
||||
import { mainEvents } from './main-event-handler';
|
||||
import {
|
||||
handlePermissionRequests,
|
||||
monitorWindowActions,
|
||||
@ -16,10 +24,13 @@ import {
|
||||
removeWindowEventListener,
|
||||
sendInitialBoundChanges,
|
||||
} from './window-actions';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import {
|
||||
ICustomBrowserWindow,
|
||||
ICustomBrowserWindowConstructorOpts,
|
||||
windowHandler,
|
||||
} from './window-handler';
|
||||
import {
|
||||
getBounds,
|
||||
// handleCertificateProxyVerification,
|
||||
injectStyles,
|
||||
preventWindowNavigation,
|
||||
} from './window-utils';
|
||||
@ -30,6 +41,8 @@ const DEFAULT_POP_OUT_HEIGHT = 600;
|
||||
const MIN_WIDTH = 300;
|
||||
const MIN_HEIGHT = 300;
|
||||
|
||||
const CHILD_WINDOW_EVENTS = ['enter-full-screen', 'leave-full-screen'];
|
||||
|
||||
/**
|
||||
* Verifies protocol for a new url to check if it is http or https
|
||||
* @param url URL to be verified
|
||||
@ -82,38 +95,39 @@ const getParsedUrl = (url: string): Url => {
|
||||
|
||||
export const handleChildWindow = (webContents: WebContents): void => {
|
||||
const childWindow = (
|
||||
event,
|
||||
newWinUrl,
|
||||
frameName,
|
||||
disposition,
|
||||
newWinOptions,
|
||||
): void => {
|
||||
logger.info(`child-window-handler: trying to create new child window for url: ${newWinUrl},
|
||||
frame name: ${frameName || undefined}, disposition: ${disposition}`);
|
||||
details: HandlerDetails,
|
||||
):
|
||||
| { action: 'deny' }
|
||||
| {
|
||||
action: 'allow';
|
||||
overrideBrowserWindowOptions?: BrowserWindowConstructorOptions;
|
||||
} => {
|
||||
logger.info(`child-window-handler: trying to create new child window for url: ${
|
||||
details.url
|
||||
},
|
||||
frame name: ${details.frameName || undefined}, disposition: ${
|
||||
details.disposition
|
||||
}`);
|
||||
const mainWindow = windowHandler.getMainWindow();
|
||||
if (!mainWindow || mainWindow.isDestroyed()) {
|
||||
logger.info(
|
||||
`child-window-handler: main window is not available / destroyed, not creating child window!`,
|
||||
);
|
||||
return;
|
||||
return {
|
||||
action: 'deny',
|
||||
};
|
||||
}
|
||||
if (!windowHandler.url) {
|
||||
logger.info(
|
||||
`child-window-handler: we don't have a valid url, not creating child window!`,
|
||||
);
|
||||
return;
|
||||
return {
|
||||
action: 'deny',
|
||||
};
|
||||
}
|
||||
|
||||
if (!newWinOptions.webPreferences) {
|
||||
newWinOptions.webPreferences = {};
|
||||
}
|
||||
|
||||
Object.assign(newWinOptions.webPreferences, webContents);
|
||||
|
||||
// need this to extract other parameters
|
||||
const newWinParsedUrl = getParsedUrl(newWinUrl);
|
||||
|
||||
const newWinUrlData = whitelistHandler.parseDomain(newWinUrl);
|
||||
const newWinOptions = windowHandler.getMainWindowOpts();
|
||||
const newWinUrlData = whitelistHandler.parseDomain(details.url);
|
||||
const mainWinUrlData = whitelistHandler.parseDomain(windowHandler.url);
|
||||
|
||||
const newWinDomainName = `${newWinUrlData.domain}${newWinUrlData.tld}`;
|
||||
@ -130,24 +144,70 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
// otherwise open in default browser.
|
||||
if (
|
||||
(newWinDomainName === mainWinDomainName ||
|
||||
emptyUrlString.includes(newWinUrl)) &&
|
||||
frameName !== '' &&
|
||||
dispositionWhitelist.includes(disposition)
|
||||
emptyUrlString.includes(details.url)) &&
|
||||
details.frameName !== '' &&
|
||||
dispositionWhitelist.includes(details.disposition)
|
||||
) {
|
||||
logger.info(
|
||||
`child-window-handler: opening pop-out window for ${newWinUrl}`,
|
||||
`child-window-handler: opening pop-out window for ${details.url}`,
|
||||
);
|
||||
|
||||
const newWinKey = getGuid();
|
||||
if (!frameName) {
|
||||
if (!details.frameName) {
|
||||
logger.info(
|
||||
`child-window-handler: frame name missing! not opening the url ${newWinUrl}`,
|
||||
`child-window-handler: frame name missing! not opening the url ${details.url}`,
|
||||
);
|
||||
return {
|
||||
action: 'deny',
|
||||
};
|
||||
}
|
||||
return {
|
||||
action: 'allow',
|
||||
// override child window options
|
||||
overrideBrowserWindowOptions: { ...newWinOptions, ...{ frame: true } },
|
||||
};
|
||||
} else {
|
||||
if (details.url && details.url.length > 2083) {
|
||||
logger.info(
|
||||
`child-window-handler: new window url length is greater than 2083, not performing any action!`,
|
||||
);
|
||||
return {
|
||||
action: 'deny',
|
||||
};
|
||||
}
|
||||
if (!verifyProtocolForNewUrl(details.url)) {
|
||||
logger.info(
|
||||
`child-window-handler: new window url protocol is not valid, not performing any action!`,
|
||||
);
|
||||
return {
|
||||
action: 'deny',
|
||||
};
|
||||
}
|
||||
logger.info(`child-window-handler: new window url is ${details.url} which is not of the same host / protocol,
|
||||
so opening it in the default app!`);
|
||||
windowHandler.openUrlInDefaultBrowser(details.url);
|
||||
return { action: 'deny' };
|
||||
}
|
||||
};
|
||||
|
||||
webContents.setWindowOpenHandler(childWindow);
|
||||
|
||||
webContents.on(
|
||||
'did-create-window',
|
||||
(browserWindow: BrowserWindow, details: DidCreateWindowDetails) => {
|
||||
const newWinOptions = details.options as ICustomBrowserWindowConstructorOpts;
|
||||
const width = newWinOptions.width || DEFAULT_POP_OUT_WIDTH;
|
||||
const height = newWinOptions.height || DEFAULT_POP_OUT_HEIGHT;
|
||||
const newWinKey = getGuid();
|
||||
|
||||
const mainWindow = windowHandler.getMainWindow();
|
||||
if (!mainWindow || mainWindow.isDestroyed()) {
|
||||
logger.info(
|
||||
'child-window-handler: main window is not available / destroyed, not creating child window!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const width = newWinOptions.width || DEFAULT_POP_OUT_WIDTH;
|
||||
const height = newWinOptions.height || DEFAULT_POP_OUT_HEIGHT;
|
||||
// need this to extract other parameters
|
||||
const newWinParsedUrl = getParsedUrl(details.url);
|
||||
|
||||
// try getting x and y position from query parameters
|
||||
const query =
|
||||
@ -184,8 +244,9 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
newWinOptions.frame = true;
|
||||
newWinOptions.winKey = newWinKey;
|
||||
newWinOptions.fullscreen = false;
|
||||
newWinOptions.fullscreenable = true;
|
||||
|
||||
const childWebContents: WebContents = newWinOptions.webContents;
|
||||
const childWebContents: WebContents = browserWindow.webContents;
|
||||
// Event needed to hide native menu bar
|
||||
childWebContents.once('did-start-loading', () => {
|
||||
const browserWin = BrowserWindow.fromWebContents(
|
||||
@ -203,7 +264,7 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
|
||||
childWebContents.once('did-finish-load', async () => {
|
||||
logger.info(
|
||||
`child-window-handler: child window content loaded for url ${newWinUrl}!`,
|
||||
`child-window-handler: child window content loaded for url ${details.url}!`,
|
||||
);
|
||||
const browserWin: ICustomBrowserWindow = BrowserWindow.fromWebContents(
|
||||
childWebContents,
|
||||
@ -221,12 +282,11 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
origin: url,
|
||||
enableCustomTitleBar: false,
|
||||
isMainWindow: false,
|
||||
});
|
||||
// Inserts css on to the window
|
||||
await injectStyles(browserWin, false);
|
||||
browserWin.winName = frameName;
|
||||
await injectStyles(browserWin.webContents, false);
|
||||
browserWin.winName = details.frameName;
|
||||
browserWin.setAlwaysOnTop(mainWindow.isAlwaysOnTop());
|
||||
logger.info(
|
||||
`child-window-handler: setting always on top for child window? ${mainWindow.isAlwaysOnTop()}!`,
|
||||
@ -251,7 +311,12 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
// Remove all attached event listeners
|
||||
browserWin.on('close', () => {
|
||||
logger.info(
|
||||
`child-window-handler: close event occurred for window with url ${newWinUrl}!`,
|
||||
`child-window-handler: close event occurred for window with url ${details.url}!`,
|
||||
);
|
||||
// Subscribe events for main view - snack bar
|
||||
mainEvents.unsubscribeMultipleEvents(
|
||||
CHILD_WINDOW_EVENTS,
|
||||
browserWin.webContents,
|
||||
);
|
||||
removeWindowEventListener(browserWin);
|
||||
});
|
||||
@ -268,11 +333,6 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
// validate link and create a child window or open in browser
|
||||
handleChildWindow(browserWin.webContents);
|
||||
|
||||
// Certificate verification proxy
|
||||
// if (!isDevEnv) {
|
||||
// browserWin.webContents.session.setCertificateVerifyProc(handleCertificateProxyVerification);
|
||||
// }
|
||||
|
||||
// Updates media permissions for preload context
|
||||
const { permissions } = config.getConfigFields(['permissions']);
|
||||
browserWin.webContents.send(
|
||||
@ -280,25 +340,13 @@ export const handleChildWindow = (webContents: WebContents): void => {
|
||||
permissions.media,
|
||||
);
|
||||
}
|
||||
|
||||
// Subscribe events for main view - snack bar
|
||||
mainEvents.subscribeMultipleEvents(
|
||||
CHILD_WINDOW_EVENTS,
|
||||
browserWin.webContents,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
event.preventDefault();
|
||||
if (newWinUrl && newWinUrl.length > 2083) {
|
||||
logger.info(
|
||||
`child-window-handler: new window url length is greater than 2083, not performing any action!`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!verifyProtocolForNewUrl(newWinUrl)) {
|
||||
logger.info(
|
||||
`child-window-handler: new window url protocol is not valid, not performing any action!`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
logger.info(`child-window-handler: new window url is ${newWinUrl} which is not of the same host / protocol,
|
||||
so opening it in the default app!`);
|
||||
windowHandler.openUrlInDefaultBrowser(newWinUrl);
|
||||
}
|
||||
};
|
||||
webContents.on('new-window', childWindow);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { app, crashReporter, Details, dialog } from 'electron';
|
||||
import { app, crashReporter, dialog, RenderProcessGoneDetails } from 'electron';
|
||||
import { i18n } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import {
|
||||
@ -89,7 +89,7 @@ class CrashHandler {
|
||||
public handleRendererCrash(browserWindow: ICustomBrowserWindow) {
|
||||
browserWindow.webContents.on(
|
||||
'render-process-gone',
|
||||
async (_event: Event, details: Details) => {
|
||||
async (_event: Event, details: RenderProcessGoneDetails) => {
|
||||
logger.info(`crash-handler: Renderer process for ${browserWindow.winName} crashed.
|
||||
Reason is ${details.reason}`);
|
||||
const eventData: ICrashData = {
|
||||
|
@ -1,11 +1,17 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
import {
|
||||
BrowserWindow,
|
||||
clipboard,
|
||||
dialog,
|
||||
ipcMain,
|
||||
systemPreferences,
|
||||
} from 'electron';
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
IApiArgs,
|
||||
INotificationData,
|
||||
} from '../common/api-interface';
|
||||
import { LocaleType } from '../common/i18n';
|
||||
import { i18n, LocaleType } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { activityDetection } from './activity-detection';
|
||||
import { analytics } from './analytics-handler';
|
||||
@ -22,6 +28,7 @@ import { activate, handleKeyPress } from './window-actions';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import {
|
||||
downloadManagerAction,
|
||||
isValidView,
|
||||
isValidWindow,
|
||||
sanitize,
|
||||
setDataUrl,
|
||||
@ -40,7 +47,12 @@ import {
|
||||
ipcMain.on(
|
||||
apiName.symphonyApi,
|
||||
async (event: Electron.IpcMainEvent, arg: IApiArgs) => {
|
||||
if (!isValidWindow(BrowserWindow.fromWebContents(event.sender))) {
|
||||
if (
|
||||
!(
|
||||
isValidWindow(BrowserWindow.fromWebContents(event.sender)) ||
|
||||
isValidView(event.sender)
|
||||
)
|
||||
) {
|
||||
logger.error(
|
||||
`main-api-handler: invalid window try to perform action, ignoring action`,
|
||||
arg.cmd,
|
||||
@ -295,8 +307,89 @@ ipcMain.on(
|
||||
case apiCmds.autoUpdate:
|
||||
autoUpdate.update(arg.filename);
|
||||
break;
|
||||
case apiCmds.aboutAppClipBoardData:
|
||||
if (arg.clipboard && arg.clipboardType) {
|
||||
clipboard.write(
|
||||
{ text: JSON.stringify(arg.clipboard, null, 4) },
|
||||
arg.clipboardType,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case apiCmds.closeMainWindow:
|
||||
windowHandler.getMainWindow()?.close();
|
||||
break;
|
||||
case apiCmds.minimizeMainWindow:
|
||||
windowHandler.getMainWindow()?.minimize();
|
||||
break;
|
||||
case apiCmds.maximizeMainWindow:
|
||||
windowHandler.getMainWindow()?.maximize();
|
||||
break;
|
||||
case apiCmds.unmaximizeMainWindow:
|
||||
const mainWindow = windowHandler.getMainWindow();
|
||||
if (mainWindow && windowExists(mainWindow)) {
|
||||
mainWindow.isFullScreen()
|
||||
? mainWindow.setFullScreen(false)
|
||||
: mainWindow.unmaximize();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
apiName.symphonyApi,
|
||||
async (event: Electron.IpcMainInvokeEvent, arg: IApiArgs) => {
|
||||
if (
|
||||
!(
|
||||
isValidWindow(BrowserWindow.fromWebContents(event.sender)) ||
|
||||
isValidView(event.sender)
|
||||
)
|
||||
) {
|
||||
logger.error(
|
||||
`main-api-handler: invalid window try to perform action, ignoring action`,
|
||||
arg.cmd,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg.cmd) {
|
||||
case apiCmds.getCurrentOriginUrl:
|
||||
return windowHandler.getMainWindow()?.origin;
|
||||
case apiCmds.isAeroGlassEnabled:
|
||||
return systemPreferences.isAeroGlassEnabled();
|
||||
case apiCmds.showScreenSharePermissionDialog: {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow && !focusedWindow.isDestroyed()) {
|
||||
await dialog.showMessageBox(focusedWindow, {
|
||||
message: `${i18n.t(
|
||||
'Your administrator has disabled sharing your screen. Please contact your admin for help',
|
||||
'Permissions',
|
||||
)()}`,
|
||||
title: `${i18n.t('Permission Denied')()}!`,
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case apiCmds.getMediaAccessStatus:
|
||||
const camera = systemPreferences.getMediaAccessStatus('camera');
|
||||
const microphone = systemPreferences.getMediaAccessStatus('microphone');
|
||||
const screen = systemPreferences.getMediaAccessStatus('screen');
|
||||
return {
|
||||
camera,
|
||||
microphone,
|
||||
screen,
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
},
|
||||
);
|
||||
|
92
src/app/main-event-handler.ts
Normal file
92
src/app/main-event-handler.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { WebContents } from 'electron';
|
||||
|
||||
export class MainProcessEvents {
|
||||
private registeredWebContents: Map<string, Set<WebContents>> = new Map<
|
||||
string,
|
||||
Set<Electron.WebContents>
|
||||
>();
|
||||
|
||||
/**
|
||||
* Broadcasts events to all the registered webContents
|
||||
* @param eventName
|
||||
* @param args
|
||||
*/
|
||||
public publish(eventName: string, args?: any[]) {
|
||||
const allWebContests = this.registeredWebContents.get(eventName);
|
||||
if (!allWebContests) {
|
||||
return;
|
||||
}
|
||||
allWebContests.forEach((w) => {
|
||||
if (w && !w.isDestroyed()) {
|
||||
w.send(eventName, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe multiple events for the webContents
|
||||
* @param eventNames
|
||||
* @param webContents
|
||||
*/
|
||||
public subscribeMultipleEvents(
|
||||
eventNames: string[],
|
||||
webContents: WebContents,
|
||||
) {
|
||||
eventNames.forEach((e) => this.subscribe(e, webContents));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe multiple events for the webContents
|
||||
* @param eventNames
|
||||
* @param webContents
|
||||
*/
|
||||
public unsubscribeMultipleEvents(
|
||||
eventNames: string[],
|
||||
webContents: WebContents,
|
||||
) {
|
||||
eventNames.forEach((e) => this.unsubscribe(e, webContents));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe event for the webContents
|
||||
* @param eventName
|
||||
* @param webContents
|
||||
*/
|
||||
public subscribe(eventName: string, webContents: WebContents) {
|
||||
if (!webContents || webContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
const registeredWebContents = this.registeredWebContents.get(eventName);
|
||||
if (registeredWebContents) {
|
||||
const isRegistered = registeredWebContents.has(webContents);
|
||||
if (isRegistered) {
|
||||
return;
|
||||
}
|
||||
registeredWebContents.add(webContents);
|
||||
return;
|
||||
}
|
||||
this.registeredWebContents.set(eventName, new Set<WebContents>());
|
||||
this.registeredWebContents.get(eventName)!.add(webContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe an event from a specific webContents
|
||||
* @param eventName
|
||||
* @param webContents
|
||||
*/
|
||||
public unsubscribe(eventName: string, webContents: WebContents) {
|
||||
if (!webContents || webContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
const registeredWebContents = this.registeredWebContents.get(eventName);
|
||||
if (registeredWebContents) {
|
||||
if (registeredWebContents.has(webContents)) {
|
||||
registeredWebContents.delete(webContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mainEvents = new MainProcessEvents();
|
||||
|
||||
export { mainEvents };
|
@ -2,7 +2,7 @@ import { app, systemPreferences } from 'electron';
|
||||
import * as electronDownloader from 'electron-dl';
|
||||
import * as shellPath from 'shell-path';
|
||||
|
||||
import { isDevEnv, isElectronQA, isLinux, isMac } from '../common/env';
|
||||
import { isDevEnv, isLinux, isMac } from '../common/env';
|
||||
import { logger } from '../common/logger';
|
||||
import { getCommandLineArgs } from '../common/utils';
|
||||
import { cleanUpAppCache, createAppCacheFile } from './app-cache-handler';
|
||||
@ -60,12 +60,6 @@ electronDownloader();
|
||||
handlePerformanceSettings();
|
||||
setChromeFlags();
|
||||
|
||||
// Need this to prevent blank pop-out from 8.x versions
|
||||
// Refer - SDA-1877 - https://github.com/electron/electron/issues/18397
|
||||
if (!isElectronQA) {
|
||||
app.allowRendererProcessReuse = true;
|
||||
}
|
||||
|
||||
// Electron sets the default protocol
|
||||
if (!isDevEnv) {
|
||||
const { userDataPath } = config.getConfigFields(['userDataPath']);
|
||||
|
@ -19,26 +19,11 @@ export class ElectronNotification extends Notification {
|
||||
this.callback = callback;
|
||||
this.options = options;
|
||||
|
||||
this.once('click', this.onClick);
|
||||
this.once('reply', this.onReply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification on click handler
|
||||
* @param _event
|
||||
* @private
|
||||
*/
|
||||
private onClick(_event: Event) {
|
||||
this.callback(NotificationActions.notificationClicked, this.options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification reply handler
|
||||
* @param _event
|
||||
* @param reply
|
||||
* @private
|
||||
*/
|
||||
private onReply(_event: Event, reply: string) {
|
||||
this.callback(NotificationActions.notificationReply, this.options, reply);
|
||||
this.once('click', (_event) => {
|
||||
this.callback(NotificationActions.notificationClicked, this.options);
|
||||
});
|
||||
this.once('reply', (_event, reply) => {
|
||||
this.callback(NotificationActions.notificationReply, this.options, reply);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
import { isWindowsOS } from '../../common/env';
|
||||
import { notification } from '../../renderer/notification';
|
||||
import { windowHandler } from '../window-handler';
|
||||
import { windowExists } from '../window-utils';
|
||||
import { ElectronNotification } from './electron-notification';
|
||||
|
||||
class NotificationHelper {
|
||||
@ -80,9 +79,9 @@ class NotificationHelper {
|
||||
data: ElectronNotificationData,
|
||||
notificationData: ElectronNotificationData,
|
||||
) {
|
||||
const mainWindow = windowHandler.getMainWindow();
|
||||
if (mainWindow && windowExists(mainWindow) && mainWindow.webContents) {
|
||||
mainWindow.webContents.send('notification-actions', {
|
||||
const mainWebContents = windowHandler.getMainWebContents();
|
||||
if (mainWebContents && !mainWebContents.isDestroyed()) {
|
||||
mainWebContents.send('notification-actions', {
|
||||
event,
|
||||
data,
|
||||
notificationData,
|
||||
|
@ -12,6 +12,7 @@ import { logger } from '../common/logger';
|
||||
import { throttle } from '../common/utils';
|
||||
import { notification } from '../renderer/notification';
|
||||
import { CloudConfigDataTypes, config } from './config-handler';
|
||||
import { mainEvents } from './main-event-handler';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import { showPopupMenu, windowExists } from './window-utils';
|
||||
|
||||
@ -97,10 +98,11 @@ const windowMaximized = async (): Promise<void> => {
|
||||
}
|
||||
};
|
||||
|
||||
const throttledWindowChanges = throttle(async () => {
|
||||
const throttledWindowChanges = throttle(async (eventName) => {
|
||||
await saveWindowSettings();
|
||||
await windowMaximized();
|
||||
notification.moveNotificationToTop();
|
||||
mainEvents.publish(eventName);
|
||||
}, 1000);
|
||||
|
||||
const throttledWindowRestore = throttle(async () => {
|
||||
@ -303,14 +305,18 @@ export const monitorWindowActions = (window: BrowserWindow): void => {
|
||||
eventNames.forEach((event: string) => {
|
||||
if (window) {
|
||||
// @ts-ignore
|
||||
window.on(event, throttledWindowChanges);
|
||||
window.on(event, () => throttledWindowChanges(event));
|
||||
}
|
||||
});
|
||||
window.on('enter-full-screen', throttledWindowChanges);
|
||||
window.on('maximize', throttledWindowChanges);
|
||||
window.on('enter-full-screen', () =>
|
||||
throttledWindowChanges('enter-full-screen'),
|
||||
);
|
||||
window.on('maximize', () => throttledWindowChanges('maximize'));
|
||||
|
||||
window.on('leave-full-screen', throttledWindowChanges);
|
||||
window.on('unmaximize', throttledWindowChanges);
|
||||
window.on('leave-full-screen', () =>
|
||||
throttledWindowChanges('leave-full-screen'),
|
||||
);
|
||||
window.on('unmaximize', () => throttledWindowChanges('unmaximize'));
|
||||
|
||||
if ((window as ICustomBrowserWindow).winName === apiName.mainWindowName) {
|
||||
window.on('restore', throttledWindowRestore);
|
||||
|
@ -8,8 +8,10 @@ import {
|
||||
dialog,
|
||||
globalShortcut,
|
||||
ipcMain,
|
||||
RenderProcessGoneDetails,
|
||||
screen,
|
||||
shell,
|
||||
WebContents,
|
||||
} from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
@ -41,6 +43,7 @@ import {
|
||||
IGlobalConfig,
|
||||
} from './config-handler';
|
||||
import crashHandler from './crash-handler';
|
||||
import { mainEvents } from './main-event-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
import { checkIfBuildExpired } from './ttl-handler';
|
||||
import { versionHandler } from './version-handler';
|
||||
@ -58,10 +61,12 @@ import {
|
||||
handleDownloadManager,
|
||||
injectStyles,
|
||||
isSymphonyReachable,
|
||||
loadBrowserViews,
|
||||
monitorNetworkInterception,
|
||||
preventWindowNavigation,
|
||||
reloadWindow,
|
||||
resetZoomLevel,
|
||||
viewExists,
|
||||
windowExists,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
@ -79,7 +84,9 @@ enum ClientSwitchType {
|
||||
CLIENT_2_0_DAILY = 'CLIENT_2_0_DAILY',
|
||||
}
|
||||
|
||||
interface ICustomBrowserWindowConstructorOpts
|
||||
const MAIN_WEB_CONTENTS_EVENTS = ['enter-full-screen', 'leave-full-screen'];
|
||||
|
||||
export interface ICustomBrowserWindowConstructorOpts
|
||||
extends Electron.BrowserWindowConstructorOptions {
|
||||
winKey: string;
|
||||
}
|
||||
@ -90,9 +97,15 @@ export interface ICustomBrowserWindow extends Electron.BrowserWindow {
|
||||
origin?: string;
|
||||
}
|
||||
|
||||
export interface ICustomBrowserView extends Electron.BrowserView {
|
||||
winName: string;
|
||||
notificationData?: object;
|
||||
origin?: string;
|
||||
}
|
||||
|
||||
// Default window width & height
|
||||
let DEFAULT_WIDTH: number = 900;
|
||||
let DEFAULT_HEIGHT: number = 900;
|
||||
export let DEFAULT_WIDTH: number = 900;
|
||||
export let DEFAULT_HEIGHT: number = 900;
|
||||
|
||||
// Timeout on restarting SDA in case it's stuck
|
||||
const LISTEN_TIMEOUT: number = 25 * 1000;
|
||||
@ -113,6 +126,9 @@ export class WindowHandler {
|
||||
}
|
||||
return format(parsedUrl);
|
||||
}
|
||||
public mainView: ICustomBrowserView | null;
|
||||
public titleBarView: ICustomBrowserView | null;
|
||||
public mainWebContents: WebContents | undefined;
|
||||
public appMenu: AppMenu | null;
|
||||
public isAutoReload: boolean;
|
||||
public isOnline: boolean;
|
||||
@ -233,6 +249,8 @@ export class WindowHandler {
|
||||
}
|
||||
|
||||
this.appMenu = null;
|
||||
this.mainView = null;
|
||||
this.titleBarView = null;
|
||||
const locale: LocaleType = (this.config.locale ||
|
||||
app.getLocale()) as LocaleType;
|
||||
i18n.setLocale(locale);
|
||||
@ -387,8 +405,24 @@ export class WindowHandler {
|
||||
cleanAppCacheOnCrash(this.mainWindow);
|
||||
// loads the main window with url from config/cmd line
|
||||
logger.info(`Loading main window with url ${this.url}`);
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
this.mainWindow.loadURL(this.url, { userAgent });
|
||||
const userAgent = this.getUserAgent(this.mainWindow.webContents);
|
||||
|
||||
if (
|
||||
this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED &&
|
||||
isWindowsOS &&
|
||||
this.mainWindow &&
|
||||
windowExists(this.mainWindow)
|
||||
) {
|
||||
this.mainWebContents = await loadBrowserViews(
|
||||
this.mainWindow,
|
||||
this.url,
|
||||
userAgent,
|
||||
);
|
||||
} else {
|
||||
await this.mainWindow.loadURL(this.url, { userAgent });
|
||||
this.mainWebContents = this.mainWindow.webContents;
|
||||
}
|
||||
|
||||
// check for build expiry in case of test builds
|
||||
this.checkExpiry(this.mainWindow);
|
||||
// update version info from server
|
||||
@ -397,20 +431,12 @@ export class WindowHandler {
|
||||
this.mainWindow.origin = this.globalConfig.contextOriginUrl || this.url;
|
||||
|
||||
// Event needed to hide native menu bar on Windows 10 as we use custom menu bar
|
||||
this.mainWindow.webContents.once('did-start-loading', () => {
|
||||
this.mainView?.webContents.once('did-start-loading', () => {
|
||||
logger.info(
|
||||
`window-handler: main window web contents started loading for url ${this.mainWindow?.webContents.getURL()}!`,
|
||||
`window-handler: main window web contents started loading for url ${this.mainView?.webContents.getURL()}!`,
|
||||
);
|
||||
this.finishedLoading = false;
|
||||
this.listenForLoad();
|
||||
if (
|
||||
this.config.isCustomTitleBar === CloudConfigDataTypes.ENABLED &&
|
||||
isWindowsOS &&
|
||||
this.mainWindow &&
|
||||
windowExists(this.mainWindow)
|
||||
) {
|
||||
this.mainWindow.setMenuBarVisibility(false);
|
||||
}
|
||||
// monitors network connection and
|
||||
// displays error banner on failure
|
||||
monitorNetworkInterception(
|
||||
@ -441,50 +467,55 @@ export class WindowHandler {
|
||||
logger.info(`window-handler: Main Window ready to show: ${event}`);
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.on('did-finish-load', async () => {
|
||||
this.mainWebContents.on('did-finish-load', async () => {
|
||||
// reset to false when the client reloads
|
||||
this.isMana = false;
|
||||
logger.info(`window-handler: main window web contents finished loading!`);
|
||||
// early exit if the window has already been destroyed
|
||||
if (!this.mainWindow || !windowExists(this.mainWindow)) {
|
||||
if (!this.mainWebContents || this.mainWebContents.isDestroyed()) {
|
||||
logger.info(
|
||||
`window-handler: main window web contents destroyed already! exiting`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.finishedLoading = true;
|
||||
this.url = this.mainWindow.webContents.getURL();
|
||||
if (this.url.indexOf('about:blank') === 0) {
|
||||
this.url = this.mainWebContents?.getURL();
|
||||
if (this.url?.indexOf('about:blank') === 0) {
|
||||
logger.info(
|
||||
`Looks like about:blank got loaded which may lead to blank screen`,
|
||||
);
|
||||
logger.info(`Reloading the app to check if it resolves the issue`);
|
||||
const url = this.userConfig.url || this.globalConfig.url;
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
await this.mainWindow.loadURL(url, { userAgent });
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents?.loadURL(url, { userAgent });
|
||||
return;
|
||||
}
|
||||
logger.info('window-handler: did-finish-load, url: ' + this.url);
|
||||
|
||||
// Injects custom title bar and snack bar css into the webContents
|
||||
await injectStyles(this.mainWindow, this.isCustomTitleBar);
|
||||
if (this.mainWebContents && !this.mainWebContents.isDestroyed()) {
|
||||
// Injects custom title bar and snack bar css into the webContents
|
||||
await injectStyles(this.mainWebContents, this.isCustomTitleBar);
|
||||
this.mainWebContents.send('page-load', {
|
||||
isWindowsOS,
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
isMainWindow: true,
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.send('page-load', {
|
||||
isWindowsOS,
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
enableCustomTitleBar: this.isCustomTitleBar,
|
||||
isMainWindow: true,
|
||||
});
|
||||
this.appMenu = new AppMenu();
|
||||
const { permissions } = config.getConfigFields(['permissions']);
|
||||
this.mainWindow.webContents.send(
|
||||
'is-screen-share-enabled',
|
||||
permissions.media,
|
||||
);
|
||||
this.appMenu = new AppMenu();
|
||||
|
||||
const { permissions } = config.getConfigFields(['permissions']);
|
||||
this.mainWebContents.send('is-screen-share-enabled', permissions.media);
|
||||
|
||||
// Subscribe events for main view - snack bar
|
||||
mainEvents.subscribeMultipleEvents(
|
||||
MAIN_WEB_CONTENTS_EVENTS,
|
||||
this.mainWebContents,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.on(
|
||||
this.mainWebContents.on(
|
||||
'did-fail-load',
|
||||
(_event, errorCode, errorDesc, validatedURL) => {
|
||||
logger.error(
|
||||
@ -494,13 +525,13 @@ export class WindowHandler {
|
||||
},
|
||||
);
|
||||
|
||||
this.mainWindow.webContents.on('did-stop-loading', async () => {
|
||||
this.mainWebContents.on('did-stop-loading', async () => {
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
this.mainWindow.webContents.send('page-load-failed', {
|
||||
this.mainWebContents?.send('page-load-failed', {
|
||||
locale: i18n.getLocale(),
|
||||
resources: i18n.loadedResources,
|
||||
});
|
||||
const href = await this.mainWindow.webContents.executeJavaScript(
|
||||
const href = await this.mainWebContents?.executeJavaScript(
|
||||
'document.location.href',
|
||||
);
|
||||
try {
|
||||
@ -509,7 +540,7 @@ export class WindowHandler {
|
||||
href === 'chrome-error://chromewebdata/'
|
||||
) {
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
this.mainWindow.webContents.insertCSS(
|
||||
this.mainWebContents?.insertCSS(
|
||||
fs
|
||||
.readFileSync(
|
||||
path.join(
|
||||
@ -521,7 +552,7 @@ export class WindowHandler {
|
||||
)
|
||||
.toString(),
|
||||
);
|
||||
this.mainWindow.webContents.send('network-error', {
|
||||
this.mainWebContents?.send('network-error', {
|
||||
error: this.loadFailError,
|
||||
});
|
||||
isSymphonyReachable(
|
||||
@ -537,12 +568,14 @@ export class WindowHandler {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Register dev tools on initial launch
|
||||
this.registerGlobalShortcuts();
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.on(
|
||||
'crashed',
|
||||
async (_event: Event, killed: boolean) => {
|
||||
if (killed) {
|
||||
this.mainWebContents.on(
|
||||
'render-process-gone',
|
||||
async (_event: Event, details: RenderProcessGoneDetails) => {
|
||||
if (details.reason === 'killed') {
|
||||
logger.info(`window-handler: main window crashed (killed)!`);
|
||||
return;
|
||||
}
|
||||
@ -581,8 +614,12 @@ export class WindowHandler {
|
||||
|
||||
if (this.willQuitApp) {
|
||||
logger.info(`window-handler: app is quitting, destroying all windows!`);
|
||||
if (this.mainWindow && this.mainWindow.webContents.isDevToolsOpened()) {
|
||||
this.mainWindow.webContents.closeDevTools();
|
||||
if (
|
||||
this.mainWindow &&
|
||||
!this.mainWebContents?.isDestroyed() &&
|
||||
this.mainWebContents?.isDevToolsOpened()
|
||||
) {
|
||||
this.mainWebContents?.closeDevTools();
|
||||
}
|
||||
return this.destroyAllWindows();
|
||||
}
|
||||
@ -629,7 +666,7 @@ export class WindowHandler {
|
||||
|
||||
// Certificate verification proxy
|
||||
if (!isDevEnv) {
|
||||
this.mainWindow.webContents.session.setCertificateVerifyProc(
|
||||
this.mainWebContents.session.setCertificateVerifyProc(
|
||||
handleCertificateProxyVerification,
|
||||
);
|
||||
}
|
||||
@ -646,25 +683,22 @@ export class WindowHandler {
|
||||
preventWindowNavigation(this.mainWindow, false);
|
||||
|
||||
// Handle media/other permissions
|
||||
handlePermissionRequests(this.mainWindow.webContents);
|
||||
handlePermissionRequests(this.mainWebContents);
|
||||
|
||||
// Start monitoring window actions
|
||||
monitorWindowActions(this.mainWindow);
|
||||
|
||||
// Download manager
|
||||
this.mainWindow.webContents.session.on(
|
||||
'will-download',
|
||||
handleDownloadManager,
|
||||
);
|
||||
this.mainWebContents.session.on('will-download', handleDownloadManager);
|
||||
|
||||
// store window ref
|
||||
this.addWindow(this.windowOpts.winKey, this.mainWindow);
|
||||
|
||||
// Handle pop-outs window
|
||||
handleChildWindow(this.mainWindow.webContents);
|
||||
handleChildWindow(this.mainWebContents);
|
||||
|
||||
if (this.config.enableRendererLogs) {
|
||||
this.mainWindow.webContents.on('console-message', onConsoleMessages);
|
||||
this.mainWebContents.on('console-message', onConsoleMessages);
|
||||
}
|
||||
|
||||
return this.mainWindow;
|
||||
@ -697,13 +731,12 @@ export class WindowHandler {
|
||||
}
|
||||
logger.info(`finished loading welcome screen.`);
|
||||
if (this.url.indexOf('welcome')) {
|
||||
const ssoValue =
|
||||
const ssoValue = !!(
|
||||
this.userConfig.url &&
|
||||
this.userConfig.url.indexOf('/login/sso/initsso') > -1
|
||||
? true
|
||||
: false;
|
||||
);
|
||||
|
||||
this.mainWindow.webContents.send('page-load-welcome', {
|
||||
this.mainWindow.webContents?.send('page-load-welcome', {
|
||||
locale: i18n.getLocale(),
|
||||
resource: i18n.loadedResources,
|
||||
});
|
||||
@ -716,7 +749,7 @@ export class WindowHandler {
|
||||
)
|
||||
: this.userConfig.url;
|
||||
|
||||
this.mainWindow.webContents.send('welcome', {
|
||||
this.mainWindow.webContents?.send('welcome', {
|
||||
url: userConfigUrl || this.startUrl,
|
||||
message: '',
|
||||
urlValid: !!userConfigUrl,
|
||||
@ -739,6 +772,20 @@ export class WindowHandler {
|
||||
return this.mainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the main browser webContents
|
||||
*/
|
||||
public getMainWebContents(): WebContents | undefined {
|
||||
return this.mainWebContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the main browser view
|
||||
*/
|
||||
public getMainView(): ICustomBrowserView | null {
|
||||
return this.mainView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the window that we have created
|
||||
*
|
||||
@ -749,6 +796,33 @@ export class WindowHandler {
|
||||
return this.windows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the main window opts
|
||||
*
|
||||
* @return ICustomBrowserWindowConstructorOpts
|
||||
*/
|
||||
public getMainWindowOpts(): ICustomBrowserWindowConstructorOpts {
|
||||
return this.windowOpts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title bar view
|
||||
*
|
||||
* @param mainView
|
||||
*/
|
||||
public setMainView(mainView: ICustomBrowserView): void {
|
||||
this.mainView = mainView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title bar view
|
||||
*
|
||||
* @param titleBarView
|
||||
*/
|
||||
public setTitleBarView(titleBarView: ICustomBrowserView): void {
|
||||
this.titleBarView = titleBarView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the window from an event emitted by the render processes
|
||||
*
|
||||
@ -837,12 +911,27 @@ export class WindowHandler {
|
||||
/**
|
||||
* Checks if the window and a key has a window
|
||||
*
|
||||
* @param key {string}
|
||||
* @param window {Electron.BrowserWindow}
|
||||
*/
|
||||
public hasWindow(key: string, window: Electron.BrowserWindow): boolean {
|
||||
const browserWindow = this.windows[key];
|
||||
return browserWindow && window === browserWindow;
|
||||
public hasWindow(window: Electron.BrowserWindow): boolean {
|
||||
for (const key in this.windows) {
|
||||
if (this.windows[key] === window) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.aboutAppWindow === window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the window and a key has a window
|
||||
*
|
||||
* @param webContents {Electron.webContents}
|
||||
*/
|
||||
public hasView(webContents: Electron.webContents): boolean {
|
||||
return (
|
||||
webContents === this.mainView?.webContents ||
|
||||
webContents === this.titleBarView?.webContents
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1756,15 +1845,15 @@ export class WindowHandler {
|
||||
/**
|
||||
* Reloads symphony in case of network failures
|
||||
*/
|
||||
public reloadSymphony() {
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
public async reloadSymphony() {
|
||||
if (this.mainWebContents && !this.mainWebContents.isDestroyed()) {
|
||||
// If the client is fully loaded, upon network interruption, load that
|
||||
if (this.isLoggedIn) {
|
||||
logger.info(
|
||||
`window-utils: user has logged in, getting back to Symphony app`,
|
||||
);
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
this.mainWindow.loadURL(
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(
|
||||
this.url || this.userConfig.url || this.globalConfig.url,
|
||||
{ userAgent },
|
||||
);
|
||||
@ -1774,10 +1863,13 @@ export class WindowHandler {
|
||||
logger.info(
|
||||
`window-utils: user hasn't logged in yet, loading login page again`,
|
||||
);
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
this.mainWindow.loadURL(this.userConfig.url || this.globalConfig.url, {
|
||||
userAgent,
|
||||
});
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(
|
||||
this.userConfig.url || this.globalConfig.url,
|
||||
{
|
||||
userAgent,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1788,16 +1880,16 @@ export class WindowHandler {
|
||||
setTimeout(async () => {
|
||||
if (!this.finishedLoading) {
|
||||
logger.info(`window-handler: Pod load failed on launch`);
|
||||
if (this.mainWindow && windowExists(this.mainWindow)) {
|
||||
const webContentsUrl = this.mainWindow.webContents.getURL();
|
||||
if (this.mainWebContents && !this.mainWebContents.isDestroyed()) {
|
||||
const webContentsUrl = this.mainWebContents?.getURL();
|
||||
logger.info(
|
||||
`window-handler: Current main window url is ${webContentsUrl}.`,
|
||||
);
|
||||
const reloadUrl =
|
||||
webContentsUrl || this.userConfig.url || this.globalConfig.url;
|
||||
logger.info(`window-handler: Trying to reload ${reloadUrl}.`);
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
await this.mainWindow.loadURL(reloadUrl, { userAgent });
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(reloadUrl, { userAgent });
|
||||
return;
|
||||
}
|
||||
logger.error(
|
||||
@ -1829,9 +1921,8 @@ export class WindowHandler {
|
||||
*/
|
||||
private registerGlobalShortcuts(): void {
|
||||
logger.info('window-handler: register global shortcuts!');
|
||||
globalShortcut.register(
|
||||
isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I',
|
||||
this.onRegisterDevtools,
|
||||
globalShortcut.register(isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I', () =>
|
||||
this.onRegisterDevtools(),
|
||||
);
|
||||
globalShortcut.register('CmdOrCtrl+R', this.onReload);
|
||||
|
||||
@ -1895,6 +1986,16 @@ export class WindowHandler {
|
||||
}
|
||||
const { devToolsEnabled } = config.getConfigFields(['devToolsEnabled']);
|
||||
if (devToolsEnabled) {
|
||||
if (
|
||||
this.mainWindow &&
|
||||
windowExists(this.mainWindow) &&
|
||||
focusedWindow === this.mainWindow
|
||||
) {
|
||||
if (this.mainView && viewExists(this.mainView)) {
|
||||
this.mainWebContents?.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
}
|
||||
focusedWindow.webContents.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
@ -1922,7 +2023,7 @@ export class WindowHandler {
|
||||
private async switchClient(clientSwitch: ClientSwitchType): Promise<void> {
|
||||
logger.info(`window handler: switch to client ${clientSwitch}`);
|
||||
|
||||
if (!this.mainWindow || !windowExists(this.mainWindow)) {
|
||||
if (!this.mainWebContents || this.mainWebContents.isDestroyed()) {
|
||||
logger.info(
|
||||
`window-handler: switch client - main window web contents destroyed already! exiting`,
|
||||
);
|
||||
@ -1933,7 +2034,7 @@ export class WindowHandler {
|
||||
this.url = this.globalConfig.url;
|
||||
}
|
||||
const parsedUrl = parse(this.url);
|
||||
const csrfToken = await this.mainWindow.webContents.executeJavaScript(
|
||||
const csrfToken = await this.mainWebContents?.executeJavaScript(
|
||||
`localStorage.getItem('x-km-csrf-token')`,
|
||||
);
|
||||
switch (clientSwitch) {
|
||||
@ -1949,9 +2050,9 @@ export class WindowHandler {
|
||||
default:
|
||||
this.url = this.globalConfig.url + `?x-km-csrf-token=${csrfToken}`;
|
||||
}
|
||||
this.execCmd(this.screenShareIndicatorFrameUtil, []);
|
||||
const userAgent = this.getUserAgent(this.mainWindow);
|
||||
await this.mainWindow.loadURL(this.url, { userAgent });
|
||||
await this.execCmd(this.screenShareIndicatorFrameUtil, []);
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(this.url, { userAgent });
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`window-handler: failed to switch client because of error ${e}`,
|
||||
@ -2038,12 +2139,12 @@ export class WindowHandler {
|
||||
* getUserAgent retrieves current window user-agent and updates it
|
||||
* depending on global config setup
|
||||
* Electron user-agent is removed due to Microsoft Azure not supporting SSO if found - cf SDA-3201
|
||||
* @param mainWindow
|
||||
* @param webContents
|
||||
* @returns updated user-agents
|
||||
*/
|
||||
private getUserAgent(mainWindow: ICustomBrowserWindow): string {
|
||||
private getUserAgent(webContents: WebContents): string {
|
||||
const doOverrideUserAgents = !!this.globalConfig.overrideUserAgent;
|
||||
let userAgent = mainWindow.webContents.getUserAgent();
|
||||
let userAgent = webContents.getUserAgent();
|
||||
if (doOverrideUserAgents) {
|
||||
const electronUserAgentRegex = /Electron/;
|
||||
userAgent = userAgent.replace(electronUserAgentRegex, 'ElectronSymphony');
|
||||
|
@ -1,10 +1,12 @@
|
||||
import {
|
||||
app,
|
||||
BrowserView,
|
||||
BrowserWindow,
|
||||
dialog,
|
||||
nativeImage,
|
||||
screen,
|
||||
shell,
|
||||
WebContents,
|
||||
} from 'electron';
|
||||
import electron = require('electron');
|
||||
import fetch from 'electron-fetch';
|
||||
@ -14,7 +16,13 @@ import * as path from 'path';
|
||||
import { format, parse } from 'url';
|
||||
import { apiName } from '../common/api-interface';
|
||||
|
||||
import { isDevEnv, isLinux, isMac, isNodeEnv } from '../common/env';
|
||||
import {
|
||||
isDevEnv,
|
||||
isLinux,
|
||||
isMac,
|
||||
isNodeEnv,
|
||||
isWindowsOS,
|
||||
} from '../common/env';
|
||||
import { i18n, LocaleType } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { getGuid } from '../common/utils';
|
||||
@ -30,9 +38,16 @@ import { downloadHandler, IDownloadItem } from './download-handler';
|
||||
import { memoryMonitor } from './memory-monitor';
|
||||
import { screenSnippet } from './screen-snippet-handler';
|
||||
import { updateAlwaysOnTop } from './window-actions';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import {
|
||||
DEFAULT_HEIGHT,
|
||||
DEFAULT_WIDTH,
|
||||
ICustomBrowserView,
|
||||
ICustomBrowserWindow,
|
||||
windowHandler,
|
||||
} from './window-handler';
|
||||
|
||||
import { notification } from '../renderer/notification';
|
||||
import { mainEvents } from './main-event-handler';
|
||||
interface IStyles {
|
||||
name: styleNames;
|
||||
content: string;
|
||||
@ -45,7 +60,10 @@ enum styleNames {
|
||||
}
|
||||
|
||||
const checkValidWindow = true;
|
||||
const { ctWhitelist } = config.getConfigFields(['ctWhitelist']);
|
||||
const { ctWhitelist, mainWinPos } = config.getConfigFields([
|
||||
'ctWhitelist',
|
||||
'mainWinPos',
|
||||
]);
|
||||
|
||||
// Network status check variables
|
||||
const networkStatusCheckInterval = 10 * 1000;
|
||||
@ -55,6 +73,13 @@ let isNetworkMonitorInitialized = false;
|
||||
const styles: IStyles[] = [];
|
||||
const DOWNLOAD_MANAGER_NAMESPACE = 'DownloadManager';
|
||||
|
||||
const TITLE_BAR_EVENTS = [
|
||||
'maximize',
|
||||
'unmaximize',
|
||||
'enter-full-screen',
|
||||
'leave-full-screen',
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if window is valid and exists
|
||||
*
|
||||
@ -64,6 +89,17 @@ const DOWNLOAD_MANAGER_NAMESPACE = 'DownloadManager';
|
||||
export const windowExists = (window: BrowserWindow): boolean =>
|
||||
!!window && typeof window.isDestroyed === 'function' && !window.isDestroyed();
|
||||
|
||||
/**
|
||||
* Checks if view is valid and exists
|
||||
*
|
||||
* @param view {BrowserView}
|
||||
* @return boolean
|
||||
*/
|
||||
export const viewExists = (view: BrowserView): boolean =>
|
||||
!!view &&
|
||||
typeof view.webContents.isDestroyed === 'function' &&
|
||||
!view.webContents.isDestroyed();
|
||||
|
||||
/**
|
||||
* Prevents window from navigating
|
||||
*
|
||||
@ -265,9 +301,31 @@ export const isValidWindow = (
|
||||
}
|
||||
let result: boolean = false;
|
||||
if (browserWin && !browserWin.isDestroyed()) {
|
||||
// @ts-ignore
|
||||
const winKey = browserWin.webContents.browserWindowOptions.winKey;
|
||||
result = windowHandler.hasWindow(winKey, browserWin);
|
||||
result = windowHandler.hasWindow(browserWin);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
logger.warn(
|
||||
`window-utils: invalid window try to perform action, ignoring action`,
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure events comes from a view that we have created.
|
||||
*
|
||||
* @return {Boolean} returns true if exists otherwise false
|
||||
* @param webContents
|
||||
*/
|
||||
export const isValidView = (webContents: Electron.webContents): boolean => {
|
||||
if (!checkValidWindow) {
|
||||
return true;
|
||||
}
|
||||
let result: boolean = false;
|
||||
if (webContents && !webContents.isDestroyed()) {
|
||||
result = windowHandler.hasView(webContents);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
@ -502,22 +560,22 @@ export const handleDownloadManager = (
|
||||
/**
|
||||
* Inserts css in to the window
|
||||
*
|
||||
* @param window {BrowserWindow}
|
||||
* @param mainWebContents {WebContents}
|
||||
*/
|
||||
const readAndInsertCSS = async (window): Promise<IStyles[] | void> => {
|
||||
if (window && windowExists(window)) {
|
||||
return styles.map(({ content }) => window.webContents.insertCSS(content));
|
||||
const readAndInsertCSS = async (mainWebContents): Promise<IStyles[] | void> => {
|
||||
if (mainWebContents && !mainWebContents.isDestroyed()) {
|
||||
return styles.map(({ content }) => mainWebContents.insertCSS(content));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts all the required css on to the specified windows
|
||||
*
|
||||
* @param mainWindow {BrowserWindow}
|
||||
* @param mainView {WebContents}
|
||||
* @param isCustomTitleBar {boolean} - whether custom title bar enabled
|
||||
*/
|
||||
export const injectStyles = async (
|
||||
mainWindow: BrowserWindow,
|
||||
mainView: WebContents,
|
||||
isCustomTitleBar: boolean,
|
||||
): Promise<IStyles[] | void> => {
|
||||
if (isCustomTitleBar) {
|
||||
@ -578,7 +636,7 @@ export const injectStyles = async (
|
||||
});
|
||||
}
|
||||
|
||||
await readAndInsertCSS(mainWindow);
|
||||
await readAndInsertCSS(mainView);
|
||||
return;
|
||||
};
|
||||
|
||||
@ -638,12 +696,12 @@ export const isSymphonyReachable = (
|
||||
const podUrl = `${protocol}//${hostname}`;
|
||||
logger.info(`window-utils: checking to see if pod ${podUrl} is reachable!`);
|
||||
fetch(podUrl, { method: 'GET' })
|
||||
.then((rsp) => {
|
||||
.then(async (rsp) => {
|
||||
if (rsp.status === 200 && windowHandler.isOnline) {
|
||||
logger.info(
|
||||
`window-utils: pod ${podUrl} is reachable, loading main window!`,
|
||||
);
|
||||
windowHandler.reloadSymphony();
|
||||
await windowHandler.reloadSymphony();
|
||||
if (networkStatusCheckIntervalId) {
|
||||
clearInterval(networkStatusCheckIntervalId);
|
||||
networkStatusCheckIntervalId = null;
|
||||
@ -673,11 +731,15 @@ export const reloadWindow = (browserWindow: ICustomBrowserWindow) => {
|
||||
}
|
||||
|
||||
const windowName = browserWindow.winName;
|
||||
const mainWindow = windowHandler.getMainWindow();
|
||||
const mainWebContents = windowHandler.getMainWebContents();
|
||||
// reload the main window
|
||||
if (windowName === apiName.mainWindowName) {
|
||||
if (
|
||||
windowName === apiName.mainWindowName &&
|
||||
mainWebContents &&
|
||||
!mainWebContents.isDestroyed()
|
||||
) {
|
||||
logger.info(`window-utils: reloading the main window`);
|
||||
browserWindow.reload();
|
||||
mainWebContents.reload();
|
||||
|
||||
windowHandler.closeAllWindows();
|
||||
|
||||
@ -685,11 +747,12 @@ export const reloadWindow = (browserWindow: ICustomBrowserWindow) => {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Send an event to SFE that restarts the pop-out window
|
||||
if (mainWindow && windowExists(mainWindow)) {
|
||||
if (mainWebContents && !mainWebContents.isDestroyed()) {
|
||||
logger.info(`window-handler: reloading the window`, { windowName });
|
||||
const bounds = browserWindow.getBounds();
|
||||
mainWindow.webContents.send('restart-floater', { windowName, bounds });
|
||||
mainWebContents.send('restart-floater', { windowName, bounds });
|
||||
}
|
||||
};
|
||||
|
||||
@ -903,3 +966,131 @@ export const monitorNetworkInterception = (url: string) => {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const loadBrowserViews = async (
|
||||
mainWindow: BrowserWindow,
|
||||
url: string,
|
||||
userAgent: string,
|
||||
): Promise<WebContents> => {
|
||||
mainWindow.setMenuBarVisibility(false);
|
||||
|
||||
const titleBarView = new BrowserView({
|
||||
webPreferences: {
|
||||
sandbox: !isNodeEnv,
|
||||
nodeIntegration: isNodeEnv,
|
||||
preload: path.join(__dirname, '../renderer/_preload-component.js'),
|
||||
devTools: isDevEnv,
|
||||
},
|
||||
}) as ICustomBrowserView;
|
||||
const mainView = new BrowserView({
|
||||
...windowHandler.getMainWindowOpts(),
|
||||
...getBounds(mainWinPos, DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
||||
}) as ICustomBrowserView;
|
||||
|
||||
mainWindow.addBrowserView(titleBarView);
|
||||
mainWindow.addBrowserView(mainView);
|
||||
|
||||
const titleBarWindowUrl = format({
|
||||
pathname: require.resolve('../renderer/react-window.html'),
|
||||
protocol: 'file',
|
||||
query: {
|
||||
componentName: 'title-bar',
|
||||
locale: i18n.getLocale(),
|
||||
},
|
||||
slashes: true,
|
||||
});
|
||||
titleBarView.webContents.once('did-finish-load', () => {
|
||||
if (!titleBarView || titleBarView.webContents.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
titleBarView?.webContents.send('page-load', {
|
||||
isWindowsOS,
|
||||
locale: i18n.getLocale(),
|
||||
resource: i18n.loadedResources,
|
||||
isMainWindow: true,
|
||||
});
|
||||
mainEvents.subscribeMultipleEvents(
|
||||
TITLE_BAR_EVENTS,
|
||||
titleBarView.webContents,
|
||||
);
|
||||
|
||||
mainWindow?.on('enter-full-screen', () => {
|
||||
if (!titleBarView || !viewExists(titleBarView)) {
|
||||
return;
|
||||
}
|
||||
const titleBarBounds = titleBarView.getBounds();
|
||||
titleBarView.setBounds({ ...titleBarBounds, ...{ height: 0 } });
|
||||
|
||||
if (
|
||||
!mainView ||
|
||||
!viewExists(mainView) ||
|
||||
!mainWindow ||
|
||||
!windowExists(mainWindow)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const mainWindowBounds = mainWindow.getBounds();
|
||||
const mainViewBounds = mainView.getBounds();
|
||||
mainView.setBounds({
|
||||
width: mainWindowBounds.width,
|
||||
height: mainViewBounds.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
});
|
||||
mainWindow?.on('leave-full-screen', () => {
|
||||
if (!titleBarView || !viewExists(titleBarView)) {
|
||||
return;
|
||||
}
|
||||
const titleBarBounds = titleBarView.getBounds();
|
||||
titleBarView.setBounds({ ...titleBarBounds, ...{ height: 32 } });
|
||||
|
||||
if (
|
||||
!mainView ||
|
||||
!viewExists(mainView) ||
|
||||
!mainWindow ||
|
||||
!windowExists(mainWindow)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const mainWindowBounds = mainWindow.getBounds();
|
||||
mainView.setBounds({
|
||||
width: mainWindowBounds.width,
|
||||
height: mainWindowBounds.height,
|
||||
x: mainWindowBounds.x,
|
||||
y: 32,
|
||||
});
|
||||
});
|
||||
if (mainWindow?.isMaximized()) {
|
||||
mainEvents.publish('maximize');
|
||||
}
|
||||
if (mainWindow?.isFullScreen()) {
|
||||
mainEvents.publish('enter-full-screen');
|
||||
}
|
||||
});
|
||||
await titleBarView.webContents.loadURL(titleBarWindowUrl);
|
||||
titleBarView.setBounds({
|
||||
...mainWindow.getBounds(),
|
||||
...{ x: 0, y: 0, height: 32 },
|
||||
});
|
||||
titleBarView.setAutoResize({
|
||||
vertical: false,
|
||||
horizontal: true,
|
||||
width: true,
|
||||
height: false,
|
||||
});
|
||||
|
||||
await mainView.webContents.loadURL(url, { userAgent });
|
||||
mainView.setBounds({ ...mainWindow.getBounds(), ...{ y: 32 } });
|
||||
mainView.setAutoResize({
|
||||
horizontal: true,
|
||||
vertical: false,
|
||||
width: true,
|
||||
height: false,
|
||||
});
|
||||
|
||||
windowHandler.setMainView(mainView);
|
||||
windowHandler.setTitleBarView(mainView);
|
||||
|
||||
return mainView.webContents;
|
||||
};
|
||||
|
@ -48,6 +48,15 @@ export enum apiCmds {
|
||||
closeAllWrapperWindows = 'close-all-windows',
|
||||
setZoomLevel = 'set-zoom-level',
|
||||
autoUpdate = 'auto-update',
|
||||
aboutAppClipBoardData = 'about-app-clip-board-data',
|
||||
closeMainWindow = 'close-main-window',
|
||||
minimizeMainWindow = 'minimize-main-window',
|
||||
maximizeMainWindow = 'maximize-main-window',
|
||||
unmaximizeMainWindow = 'unmaximize-main-window',
|
||||
getCurrentOriginUrl = 'get-current-origin-url',
|
||||
isAeroGlassEnabled = 'is-aero-glass-enabled',
|
||||
showScreenSharePermissionDialog = 'show-screen-share-permission-dialog',
|
||||
getMediaAccessStatus = 'get-media-access-status',
|
||||
}
|
||||
|
||||
export enum apiName {
|
||||
@ -89,6 +98,10 @@ export interface IApiArgs {
|
||||
theme: Themes;
|
||||
zoomLevel: number;
|
||||
filename: string;
|
||||
clipboard: string;
|
||||
clipboardType: 'clipboard' | 'selection';
|
||||
requestId: number;
|
||||
mediaStatus: IMediaPermission;
|
||||
}
|
||||
|
||||
export type Themes = 'light' | 'dark';
|
||||
@ -195,9 +208,14 @@ export interface IDownloadManager {
|
||||
}
|
||||
|
||||
export interface IMediaPermission {
|
||||
camera: string;
|
||||
microphone: string;
|
||||
screen: string;
|
||||
camera: 'not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown';
|
||||
microphone:
|
||||
| 'not-determined'
|
||||
| 'granted'
|
||||
| 'denied'
|
||||
| 'restricted'
|
||||
| 'unknown';
|
||||
screen: 'not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown';
|
||||
}
|
||||
|
||||
export interface ILogMsg {
|
||||
|
@ -45,7 +45,7 @@
|
||||
</style>
|
||||
<link rel="stylesheet" href="download-manager.css" />
|
||||
</head>
|
||||
<body>
|
||||
<body style="background-color: white">
|
||||
<h1>Symphony Electron API Demo</h1>
|
||||
<div class="origin-reminder">
|
||||
<p>
|
||||
@ -331,6 +331,8 @@
|
||||
openConfigWin.addEventListener('click', function () {
|
||||
if (window.ssf) {
|
||||
ssf.showNotificationSettings();
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.showNotificationSettings();
|
||||
} else {
|
||||
postMessage(apiCmds.showNotificationSettings);
|
||||
}
|
||||
@ -431,6 +433,8 @@
|
||||
badgeCount++;
|
||||
if (window.ssf) {
|
||||
ssf.setBadgeCount(badgeCount);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.setBadgeCount(badgeCount);
|
||||
} else {
|
||||
postMessage(apiCmds.setBadgeCount, badgeCount);
|
||||
}
|
||||
@ -441,6 +445,8 @@
|
||||
badgeCount = 0;
|
||||
if (window.ssf) {
|
||||
ssf.setBadgeCount(0);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.setBadgeCount(0);
|
||||
} else {
|
||||
postMessage(apiCmds.setBadgeCount, 0);
|
||||
}
|
||||
@ -448,21 +454,23 @@
|
||||
|
||||
const snippetButton = document.getElementById('snippet');
|
||||
snippetButton.addEventListener('click', () => {
|
||||
if (window.ssf) {
|
||||
const gotSnippet = (rsp) => {
|
||||
if (rsp) {
|
||||
if (rsp.type && rsp.type === 'ERROR') {
|
||||
// called when some error occurs during capture
|
||||
alert('error getting snippet' + rsp.message);
|
||||
} else if (rsp.data && rsp.type === 'image/png;base64') {
|
||||
const dataUrl = 'data:' + rsp.type + ',' + rsp.data;
|
||||
const img = document.getElementById('snippet-img');
|
||||
img.src = dataUrl;
|
||||
}
|
||||
const gotSnippet = (rsp) => {
|
||||
if (rsp) {
|
||||
if (rsp.type && rsp.type === 'ERROR') {
|
||||
// called when some error occurs during capture
|
||||
alert('error getting snippet' + rsp.message);
|
||||
} else if (rsp.data && rsp.type === 'image/png;base64') {
|
||||
const dataUrl = 'data:' + rsp.type + ',' + rsp.data;
|
||||
const img = document.getElementById('snippet-img');
|
||||
img.src = dataUrl;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
if (window.ssf) {
|
||||
const screenSnippet = new window.ssf.ScreenSnippet();
|
||||
screenSnippet.capture().then(gotSnippet).catch(gotSnippet);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.openScreenSnippet(gotSnippet);
|
||||
} else {
|
||||
postMessage(apiCmds.openScreenSnippet);
|
||||
}
|
||||
@ -473,6 +481,8 @@
|
||||
if (window.ssf) {
|
||||
const screenSnippet = new window.ssf.ScreenSnippet();
|
||||
screenSnippet.cancelCapture();
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.closeScreenSnippet();
|
||||
} else {
|
||||
postMessage(apiCmds.closeScreenSnippet);
|
||||
}
|
||||
@ -504,6 +514,8 @@
|
||||
front.addEventListener('click', () => {
|
||||
if (window.ssf) {
|
||||
window.ssf.activate(win.name);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.activate(win.name);
|
||||
} else {
|
||||
postMessage(apiCmds.activate, win.name);
|
||||
}
|
||||
@ -515,6 +527,8 @@
|
||||
frontWithoutFocus.addEventListener('click', () => {
|
||||
if (window.ssf) {
|
||||
window.ssf.bringToFront(win.name, 'notification');
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.bringToFront(win.name, 'notification');
|
||||
} else {
|
||||
postMessage(apiCmds.bringToFront, {
|
||||
windowName: win.name,
|
||||
@ -540,6 +554,15 @@
|
||||
searchApiVer.innerText = versionInfo.searchApiVer;
|
||||
cpuArch.innerText = versionInfo.cpuArch;
|
||||
});
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.getVersionInfo().then((versionInfo) => {
|
||||
apiVersionInfo.innerText = versionInfo.apiVer;
|
||||
containerIdentifier.innerText = versionInfo.containerIdentifier;
|
||||
version.innerText = versionInfo.containerVer;
|
||||
buildNumber.innerText = versionInfo.buildNumber;
|
||||
searchApiVer.innerText = versionInfo.searchApiVer;
|
||||
cpuArch.innerText = versionInfo.cpuArch;
|
||||
});
|
||||
} else {
|
||||
postRequest(apiCmds.getVersionInfo, null, {
|
||||
successCallback: (versionInfo) => {
|
||||
@ -767,6 +790,8 @@
|
||||
*/
|
||||
if (window.ssf) {
|
||||
window.ssf.registerRestartFloater(onRestartFloater);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.registerRestartFloater(onRestartFloater);
|
||||
} else {
|
||||
postMessage(apiCmds.registerRestartFloater);
|
||||
}
|
||||
@ -780,6 +805,9 @@
|
||||
if (window.ssf) {
|
||||
window.ssf.registerActivityDetection(5000, activityCallback);
|
||||
startActivityInterval();
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.registerActivityDetection(5000, activityCallback);
|
||||
startActivityInterval();
|
||||
} else {
|
||||
postMessage(apiCmds.registerActivityDetection, 5000);
|
||||
startActivityInterval();
|
||||
@ -850,6 +878,16 @@
|
||||
microphonePermission.innerText = mediaPermission.microphone;
|
||||
screenPermission.innerText = mediaPermission.screen;
|
||||
});
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.checkMediaPermission().then((mediaPermission) => {
|
||||
console.log(
|
||||
'check-media-permission, mediaPermission: ' +
|
||||
JSON.stringify(mediaPermission),
|
||||
);
|
||||
cameraPermission.innerText = mediaPermission.camera;
|
||||
microphonePermission.innerText = mediaPermission.microphone;
|
||||
screenPermission.innerText = mediaPermission.screen;
|
||||
});
|
||||
} else {
|
||||
postRequest(apiCmds.checkMediaPermission, null, {
|
||||
successCallback: (mediaPermission) => {
|
||||
@ -902,6 +940,32 @@
|
||||
);
|
||||
},
|
||||
);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.getMediaSource(
|
||||
{ types: ['window', 'screen'] },
|
||||
function (error, source) {
|
||||
if (error) throw error;
|
||||
navigator.webkitGetUserMedia(
|
||||
{
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: source.id,
|
||||
minWidth: 1280,
|
||||
maxWidth: 1280,
|
||||
minHeight: 720,
|
||||
maxHeight: 720,
|
||||
},
|
||||
},
|
||||
},
|
||||
(stream) => {
|
||||
handleStream(stream, source.display_id);
|
||||
},
|
||||
handleError,
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const successHandler = (data) => {
|
||||
const constraints = {
|
||||
@ -956,6 +1020,21 @@
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.showScreenSharingIndicator(
|
||||
{
|
||||
stream,
|
||||
displayId,
|
||||
},
|
||||
(event) => {
|
||||
console.log('screen-sharing-indicator callback', event);
|
||||
if (event.type === 'stopRequested') {
|
||||
stream.getVideoTracks().forEach((t) => t.stop());
|
||||
document.getElementById('video').srcObject = null;
|
||||
window.manaSSF.closeScreenSharingIndicator(stream.id);
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const success = (data) => {
|
||||
if (data.error) {
|
||||
@ -1052,6 +1131,8 @@
|
||||
const id = downloadedItem.id;
|
||||
if (window.ssf) {
|
||||
window.ssf.openDownloadedItem(id);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.openDownloadedItem(id);
|
||||
} else {
|
||||
postMessage(apiCmds.openDownloadedItem, id);
|
||||
}
|
||||
@ -1066,6 +1147,8 @@
|
||||
const id = downloadedItem.id;
|
||||
if (window.ssf) {
|
||||
window.ssf.showDownloadedItem(id);
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.showDownloadedItem(id);
|
||||
} else {
|
||||
postMessage(apiCmds.showDownloadedItem, id);
|
||||
}
|
||||
@ -1077,6 +1160,8 @@
|
||||
downloadedItem = undefined;
|
||||
if (window.ssf) {
|
||||
window.ssf.clearDownloadedItems();
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.clearDownloadedItems();
|
||||
} else {
|
||||
postMessage(apiCmds.clearDownloadedItems);
|
||||
}
|
||||
@ -1085,6 +1170,8 @@
|
||||
document.getElementById('restart-app').addEventListener('click', () => {
|
||||
if (window.ssf) {
|
||||
window.ssf.restartApp();
|
||||
} else if (window.manaSSF) {
|
||||
window.manaSSF.restartApp();
|
||||
} else {
|
||||
postMessage(apiCmds.restartApp);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { remote } from 'electron';
|
||||
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { IAnalyticsData } from '../app/analytics-handler';
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
IBoundsChange,
|
||||
ILogMsg,
|
||||
INotificationData,
|
||||
@ -20,12 +20,12 @@ import {
|
||||
import { SSFApi } from './ssf-api';
|
||||
|
||||
const ssf = new SSFApi();
|
||||
const notification = remote.require('../renderer/notification').notification;
|
||||
let ssInstance: any;
|
||||
|
||||
try {
|
||||
const SSAPIBridge = remote.require('swift-search').SSAPIBridge;
|
||||
ssInstance = new SSAPIBridge();
|
||||
// TODO: remove remote module
|
||||
/*const SSAPIBridge = remote.require('swift-search').SSAPIBridge;
|
||||
ssInstance = new SSAPIBridge();*/
|
||||
} catch (e) {
|
||||
ssInstance = null;
|
||||
console.warn(
|
||||
@ -47,7 +47,7 @@ export class AppBridge {
|
||||
return event.source && event.source === window;
|
||||
}
|
||||
|
||||
public origin: string;
|
||||
public origin: string = '';
|
||||
|
||||
private readonly callbackHandlers = {
|
||||
onMessage: (event) => this.handleMessage(event),
|
||||
@ -80,14 +80,22 @@ export class AppBridge {
|
||||
constructor() {
|
||||
// starts with corporate pod and
|
||||
// will be updated with the global config url
|
||||
const currentWindow = remote.getCurrentWindow();
|
||||
// @ts-ignore
|
||||
this.origin = currentWindow.origin || '';
|
||||
// this.origin = '*'; // DEMO-APP: Comment this line back in only to test demo-app - DO NOT COMMIT
|
||||
if (ssInstance && typeof ssInstance.setBroadcastMessage === 'function') {
|
||||
ssInstance.setBroadcastMessage(this.broadcastMessage);
|
||||
}
|
||||
window.addEventListener('message', this.callbackHandlers.onMessage);
|
||||
ipcRenderer
|
||||
.invoke(apiName.symphonyApi, {
|
||||
cmd: apiCmds.getCurrentOriginUrl,
|
||||
})
|
||||
.then((origin) => {
|
||||
this.origin = origin;
|
||||
// this.origin = '*'; // DEMO-APP: Comment this line back in only to test demo-app - DO NOT COMMIT
|
||||
if (
|
||||
ssInstance &&
|
||||
typeof ssInstance.setBroadcastMessage === 'function'
|
||||
) {
|
||||
ssInstance.setBroadcastMessage(this.broadcastMessage);
|
||||
}
|
||||
window.addEventListener('message', this.callbackHandlers.onMessage);
|
||||
}) // tslint:disable-next-line:no-console
|
||||
.catch((reason) => console.error(reason));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,13 +208,13 @@ export class AppBridge {
|
||||
);
|
||||
break;
|
||||
case apiCmds.notification:
|
||||
notification.showNotification(
|
||||
ssf.showNotification(
|
||||
data as INotificationData,
|
||||
this.callbackHandlers.onNotificationCallback,
|
||||
);
|
||||
break;
|
||||
case apiCmds.closeNotification:
|
||||
await notification.hideNotification(data as number);
|
||||
await ssf.closeNotification(data as number);
|
||||
break;
|
||||
case apiCmds.showNotificationSettings:
|
||||
ssf.showNotificationSettings(data);
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { ipcRenderer, remote } from 'electron';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
import { productName } from '../../../package.json';
|
||||
import { apiCmds, apiName } from '../../common/api-interface';
|
||||
import { i18n } from '../../common/i18n-preload';
|
||||
interface IState {
|
||||
userConfig: object;
|
||||
@ -86,7 +88,7 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
client,
|
||||
} = this.state;
|
||||
|
||||
const appName = remote.app.getName() || 'Symphony';
|
||||
const appName = productName || 'Symphony';
|
||||
const copyright = `\xA9 ${new Date().getFullYear()} ${appName}`;
|
||||
const podVersion = `${clientVersion} (${buildNumber})`;
|
||||
const sdaVersionBuild = `${sdaVersion} (${sdaBuildNumber})`;
|
||||
@ -165,10 +167,11 @@ export default class AboutApp extends React.Component<{}, IState> {
|
||||
const { clientVersion, ...rest } = this.state;
|
||||
const data = { ...{ sbeVersion: clientVersion }, ...rest };
|
||||
if (data) {
|
||||
remote.clipboard.write(
|
||||
{ text: JSON.stringify(data, null, 4) },
|
||||
'clipboard',
|
||||
);
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.aboutAppClipBoardData,
|
||||
clipboard: data,
|
||||
clipboardType: 'clipboard',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ipcRenderer, remote } from 'electron';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
|
||||
import { i18n } from '../../common/i18n-preload';
|
||||
@ -47,7 +47,7 @@ export default class LoadingScreen extends React.Component<{}, IState> {
|
||||
*/
|
||||
public render(): JSX.Element {
|
||||
const { error } = this.state;
|
||||
const appName = remote.app.getName() || 'Symphony';
|
||||
const appName = 'Symphony';
|
||||
|
||||
if (error) {
|
||||
return this.renderErrorContent(error);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
import { ipcRenderer, remote } from 'electron';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
import { productName } from '../../../package.json';
|
||||
|
||||
import { apiCmds, apiName } from '../../common/api-interface';
|
||||
import { isMac } from '../../common/env';
|
||||
@ -40,6 +41,7 @@ export default class ScreenSharingIndicator extends React.Component<
|
||||
public render(): JSX.Element {
|
||||
const { id } = this.state;
|
||||
const namespace = 'ScreenSharingIndicator';
|
||||
const appName = productName || 'Symphony';
|
||||
|
||||
return (
|
||||
<div className={classNames('ScreenSharingIndicator', { mac: isMac })}>
|
||||
@ -48,9 +50,9 @@ export default class ScreenSharingIndicator extends React.Component<
|
||||
.t(
|
||||
`You are sharing your screen on {appName}`,
|
||||
namespace,
|
||||
)({ appName: remote.app.getName() })
|
||||
.replace(remote.app.getName(), '')}
|
||||
<span className='text-label2'> {remote.app.getName()}</span>
|
||||
)({ appName })
|
||||
.replace(appName, '')}
|
||||
<span className='text-label2'> {appName}</span>
|
||||
</span>
|
||||
<span className='buttons'>
|
||||
<button
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { remote } from 'electron';
|
||||
import Timer = NodeJS.Timer;
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import { i18n } from '../../common/i18n-preload';
|
||||
|
||||
@ -17,18 +17,8 @@ export default class SnackBar {
|
||||
private snackBar: HTMLElement | null = null;
|
||||
|
||||
constructor() {
|
||||
const browserWindow = remote.getCurrentWindow();
|
||||
if (
|
||||
browserWindow &&
|
||||
typeof browserWindow.isDestroyed === 'function' &&
|
||||
!browserWindow.isDestroyed()
|
||||
) {
|
||||
browserWindow.on('enter-full-screen', this.eventHandlers.onShowSnackBar);
|
||||
browserWindow.on(
|
||||
'leave-full-screen',
|
||||
this.eventHandlers.onRemoveSnackBar,
|
||||
);
|
||||
}
|
||||
ipcRenderer.on('enter-full-screen', this.eventHandlers.onShowSnackBar);
|
||||
ipcRenderer.on('leave-full-screen', this.eventHandlers.onRemoveSnackBar);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ipcRenderer, remote } from 'electron';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as React from 'react';
|
||||
|
||||
import { apiCmds, apiName } from '../../common/api-interface';
|
||||
@ -8,12 +8,10 @@ interface IState {
|
||||
title: string;
|
||||
isMaximized: boolean;
|
||||
isFullScreen: boolean;
|
||||
titleBarHeight: string;
|
||||
}
|
||||
const TITLE_BAR_NAMESPACE = 'TitleBar';
|
||||
|
||||
export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
private readonly window: Electron.BrowserWindow;
|
||||
private readonly eventHandlers = {
|
||||
onClose: () => this.close(),
|
||||
onMaximize: () => this.maximize(),
|
||||
@ -26,26 +24,24 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.window = remote.getCurrentWindow();
|
||||
this.state = {
|
||||
title: document.title || 'Symphony',
|
||||
isFullScreen: this.window.isFullScreen(),
|
||||
isMaximized: this.window.isMaximized(),
|
||||
titleBarHeight: '32px',
|
||||
isFullScreen: false,
|
||||
isMaximized: true,
|
||||
};
|
||||
// Adds borders to the window
|
||||
this.addWindowBorders();
|
||||
|
||||
this.renderMaximizeButtons = this.renderMaximizeButtons.bind(this);
|
||||
// Event to capture and update icons
|
||||
this.window.on('maximize', () => this.updateState({ isMaximized: true }));
|
||||
this.window.on('unmaximize', () =>
|
||||
ipcRenderer.on('maximize', () => this.updateState({ isMaximized: true }));
|
||||
ipcRenderer.on('unmaximize', () =>
|
||||
this.updateState({ isMaximized: false }),
|
||||
);
|
||||
this.window.on('enter-full-screen', () =>
|
||||
ipcRenderer.on('enter-full-screen', () =>
|
||||
this.updateState({ isFullScreen: true }),
|
||||
);
|
||||
this.window.on('leave-full-screen', () =>
|
||||
ipcRenderer.on('leave-full-screen', () =>
|
||||
this.updateState({ isFullScreen: false }),
|
||||
);
|
||||
}
|
||||
@ -69,10 +65,6 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
characterData: true,
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.updateTitleBar();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +82,6 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
public render(): JSX.Element | null {
|
||||
const { title, isFullScreen } = this.state;
|
||||
const style = { display: isFullScreen ? 'none' : 'flex' };
|
||||
this.updateTitleBar();
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -214,57 +205,46 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
* Method that closes the browser window
|
||||
*/
|
||||
public close(): void {
|
||||
if (this.isValidWindow()) {
|
||||
this.window.close();
|
||||
}
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.closeMainWindow,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that minimizes the browser window
|
||||
*/
|
||||
public minimize(): void {
|
||||
if (this.isValidWindow()) {
|
||||
this.window.minimize();
|
||||
}
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.minimizeMainWindow,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that maximize the browser window
|
||||
*/
|
||||
public maximize(): void {
|
||||
if (this.isValidWindow()) {
|
||||
this.window.maximize();
|
||||
this.setState({ isMaximized: true });
|
||||
}
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.maximizeMainWindow,
|
||||
});
|
||||
this.setState({ isMaximized: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that unmaximize the browser window
|
||||
*/
|
||||
public unmaximize(): void {
|
||||
if (this.isValidWindow()) {
|
||||
this.window.isFullScreen()
|
||||
? this.window.setFullScreen(false)
|
||||
: this.window.unmaximize();
|
||||
}
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.unmaximizeMainWindow,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that popup the application menu
|
||||
*/
|
||||
public showMenu(): void {
|
||||
if (this.isValidWindow()) {
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.popupMenu,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies if the this.window is valid and is not destroyed
|
||||
*/
|
||||
public isValidWindow(): boolean {
|
||||
return this.window && !this.window.isDestroyed();
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.popupMenu,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,61 +266,6 @@ export default class WindowsTitleBar extends React.Component<{}, IState> {
|
||||
document.body.classList.add('window-border');
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the client's DOM content
|
||||
*/
|
||||
private updateTitleBar(): void {
|
||||
const { isFullScreen, titleBarHeight } = this.state;
|
||||
const contentWrapper = document.getElementById('content-wrapper');
|
||||
const appView = document.getElementsByClassName('jss1')[0] as HTMLElement;
|
||||
const root = document.getElementById('root');
|
||||
const railContainer = document.getElementsByClassName(
|
||||
'ReactRail-container-2',
|
||||
)[0] as HTMLElement;
|
||||
const railList = document.getElementsByClassName(
|
||||
'railList',
|
||||
)[0] as HTMLElement;
|
||||
if (railContainer) {
|
||||
railContainer.style.height = isFullScreen
|
||||
? '100vh'
|
||||
: `calc(100vh - ${titleBarHeight})`;
|
||||
} else if (railList) {
|
||||
railList.style.height = isFullScreen
|
||||
? '100vh'
|
||||
: `calc(100vh - ${titleBarHeight})`;
|
||||
}
|
||||
if (!contentWrapper && !root) {
|
||||
document.body.style.marginTop = isFullScreen ? '0px' : titleBarHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
if (root) {
|
||||
const rootChild = root.firstElementChild as HTMLElement;
|
||||
if (rootChild && rootChild.style && rootChild.style.height === '100vh') {
|
||||
rootChild.style.height = isFullScreen
|
||||
? '100vh'
|
||||
: `calc(100vh - ${titleBarHeight})`;
|
||||
}
|
||||
root.style.height = isFullScreen
|
||||
? '100vh'
|
||||
: `calc(100vh - ${titleBarHeight})`;
|
||||
root.style.marginTop = isFullScreen ? '0px' : titleBarHeight;
|
||||
} else if (contentWrapper) {
|
||||
contentWrapper.style.marginTop = isFullScreen ? '0px' : titleBarHeight;
|
||||
}
|
||||
|
||||
if (appView) {
|
||||
appView.style.height = isFullScreen
|
||||
? '100vh'
|
||||
: `calc(100vh - ${titleBarHeight})`;
|
||||
}
|
||||
if (isFullScreen) {
|
||||
document.body.style.removeProperty('margin-top');
|
||||
}
|
||||
|
||||
document.body.classList.add('sda-title-bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title bar logo
|
||||
*/
|
||||
|
@ -2,7 +2,6 @@ import {
|
||||
desktopCapturer,
|
||||
DesktopCapturerSource,
|
||||
ipcRenderer,
|
||||
remote,
|
||||
SourcesOptions,
|
||||
} from 'electron';
|
||||
|
||||
@ -12,7 +11,6 @@ import {
|
||||
NOTIFICATION_WINDOW_TITLE,
|
||||
} from '../common/api-interface';
|
||||
import { isWindowsOS } from '../common/env';
|
||||
import { i18n } from '../common/i18n-preload';
|
||||
|
||||
const includes = [''].includes;
|
||||
|
||||
@ -94,7 +92,9 @@ export const getSource = async (
|
||||
* Setting captureWindow to false returns only screen sources
|
||||
* @type {boolean}
|
||||
*/
|
||||
captureWindow = remote.systemPreferences.isAeroGlassEnabled();
|
||||
captureWindow = await ipcRenderer.invoke(apiName.symphonyApi, {
|
||||
cmd: apiCmds.isAeroGlassEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
if (captureWindow) {
|
||||
@ -106,23 +106,15 @@ export const getSource = async (
|
||||
|
||||
// displays a dialog if media permissions are disable
|
||||
if (!isScreenShareEnabled) {
|
||||
const focusedWindow = remote.BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow && !focusedWindow.isDestroyed()) {
|
||||
remote.dialog.showMessageBox(focusedWindow, {
|
||||
message: `${i18n.t(
|
||||
'Your administrator has disabled sharing your screen. Please contact your admin for help',
|
||||
'Permissions',
|
||||
)()}`,
|
||||
title: `${i18n.t('Permission Denied')()}!`,
|
||||
type: 'error',
|
||||
});
|
||||
callback({
|
||||
name: 'Permission Denied',
|
||||
message: 'Permission Denied',
|
||||
requestId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
await ipcRenderer.invoke(apiName.symphonyApi, {
|
||||
cmd: apiCmds.showScreenSharePermissionDialog,
|
||||
});
|
||||
callback({
|
||||
name: 'Permission Denied',
|
||||
message: 'Permission Denied',
|
||||
requestId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
id = getNextId();
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { remote } from 'electron';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
INotificationData,
|
||||
NotificationActions,
|
||||
} from '../common/api-interface';
|
||||
const notification = remote.require('../renderer/notification').notification;
|
||||
|
||||
let latestID = 0;
|
||||
|
||||
@ -16,20 +17,47 @@ export default class SSFNotificationHandler {
|
||||
public _data: INotificationData;
|
||||
|
||||
private readonly id: number;
|
||||
private readonly eventHandlers = {
|
||||
onClick: (event: NotificationActions, _data: INotificationData) =>
|
||||
this.notificationClicked(event),
|
||||
};
|
||||
private notificationClickCallback: (({ target }) => {}) | undefined;
|
||||
private notificationCloseCallback: (({ target }) => {}) | undefined;
|
||||
|
||||
constructor(title, options) {
|
||||
this.id = latestID;
|
||||
latestID++;
|
||||
notification.showNotification(
|
||||
{ ...options, title, id: this.id },
|
||||
this.eventHandlers.onClick,
|
||||
);
|
||||
const notificationOpts = { ...options, title, id: this.id };
|
||||
// ipc does not support sending Functions, Promises, Symbols, WeakMaps,
|
||||
// or WeakSets will throw an exception
|
||||
if (notificationOpts.callback) {
|
||||
delete notificationOpts.callback;
|
||||
}
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.showNotification,
|
||||
notificationOpts,
|
||||
});
|
||||
|
||||
ipcRenderer.once('notification-actions', (_event, args) => {
|
||||
if (args.id === this.id) {
|
||||
switch (args.event) {
|
||||
case NotificationActions.notificationClicked:
|
||||
if (
|
||||
this.notificationClickCallback &&
|
||||
typeof this.notificationClickCallback === 'function'
|
||||
) {
|
||||
this.notificationClickCallback({ target: this });
|
||||
}
|
||||
break;
|
||||
case NotificationActions.notificationClosed:
|
||||
if (
|
||||
this.notificationCloseCallback &&
|
||||
typeof this.notificationCloseCallback === 'function'
|
||||
) {
|
||||
this.notificationCloseCallback({ target: this });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
this._data = options.data;
|
||||
}
|
||||
|
||||
@ -37,7 +65,10 @@ export default class SSFNotificationHandler {
|
||||
* Closes notification
|
||||
*/
|
||||
public close(): void {
|
||||
notification.hideNotification(this.id);
|
||||
ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.closeNotification,
|
||||
notificationId: this.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,29 +104,4 @@ export default class SSFNotificationHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the callback based on the event name
|
||||
*
|
||||
* @param event {NotificationActions}
|
||||
*/
|
||||
private notificationClicked(event: NotificationActions): void {
|
||||
switch (event) {
|
||||
case NotificationActions.notificationClicked:
|
||||
if (
|
||||
this.notificationClickCallback &&
|
||||
typeof this.notificationClickCallback === 'function'
|
||||
) {
|
||||
this.notificationClickCallback({ target: this });
|
||||
}
|
||||
break;
|
||||
case NotificationActions.notificationClosed:
|
||||
if (
|
||||
this.notificationCloseCallback &&
|
||||
typeof this.notificationCloseCallback === 'function'
|
||||
) {
|
||||
this.notificationCloseCallback({ target: this });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import ScreenSharingFrame from './components/screen-sharing-frame';
|
||||
import ScreenSharingIndicator from './components/screen-sharing-indicator';
|
||||
import SnippingTool from './components/snipping-tool';
|
||||
import Welcome from './components/welcome';
|
||||
import WindowsTitleBar from './components/windows-title-bar';
|
||||
|
||||
const enum components {
|
||||
aboutApp = 'about-app',
|
||||
@ -23,6 +24,7 @@ const enum components {
|
||||
notificationSettings = 'notification-settings',
|
||||
welcome = 'welcome',
|
||||
snippingTool = 'snipping-tool',
|
||||
titleBar = 'title-bar',
|
||||
}
|
||||
|
||||
const loadStyle = (style) => {
|
||||
@ -89,6 +91,10 @@ const load = () => {
|
||||
loadStyle(components.welcome);
|
||||
component = Welcome;
|
||||
break;
|
||||
case components.titleBar:
|
||||
loadStyle(components.titleBar);
|
||||
component = WindowsTitleBar;
|
||||
break;
|
||||
}
|
||||
const element = React.createElement(component);
|
||||
ReactDOM.render(element, document.getElementById('Root'));
|
||||
|
@ -10,7 +10,6 @@ import MessageBanner from './components/message-banner';
|
||||
import NetworkError from './components/network-error';
|
||||
import SnackBar from './components/snack-bar';
|
||||
import Welcome from './components/welcome';
|
||||
import WindowsTitleBar from './components/windows-title-bar';
|
||||
import { SSFApi } from './ssf-api';
|
||||
|
||||
interface ISSFWindow extends Window {
|
||||
@ -126,45 +125,32 @@ const monitorMemory = (time) => {
|
||||
};
|
||||
|
||||
// When the window is completely loaded
|
||||
ipcRenderer.on(
|
||||
'page-load',
|
||||
(_event, { locale, resources, enableCustomTitleBar }) => {
|
||||
i18n.setResource(locale, resources);
|
||||
ipcRenderer.on('page-load', (_event, { locale, resources }) => {
|
||||
i18n.setResource(locale, resources);
|
||||
|
||||
if (enableCustomTitleBar) {
|
||||
// injects custom title bar
|
||||
const element = React.createElement(WindowsTitleBar);
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
ReactDOM.render(element, div);
|
||||
|
||||
document.body.classList.add('sda-title-bar');
|
||||
}
|
||||
|
||||
webFrame.setSpellCheckProvider('en-US', {
|
||||
spellCheck(words, callback) {
|
||||
const misspelled = words.filter((word) => {
|
||||
return ipcRenderer.sendSync(apiName.symphonyApi, {
|
||||
cmd: apiCmds.isMisspelled,
|
||||
word,
|
||||
});
|
||||
webFrame.setSpellCheckProvider('en-US', {
|
||||
spellCheck(words, callback) {
|
||||
const misspelled = words.filter((word) => {
|
||||
return ipcRenderer.sendSync(apiName.symphonyApi, {
|
||||
cmd: apiCmds.isMisspelled,
|
||||
word,
|
||||
});
|
||||
callback(misspelled);
|
||||
},
|
||||
});
|
||||
});
|
||||
callback(misspelled);
|
||||
},
|
||||
});
|
||||
|
||||
// injects snack bar
|
||||
snackBar.initSnackBar();
|
||||
// injects snack bar
|
||||
snackBar.initSnackBar();
|
||||
|
||||
// injects download manager contents
|
||||
const downloadManager = new DownloadManager();
|
||||
downloadManager.initDownloadManager();
|
||||
// injects download manager contents
|
||||
const downloadManager = new DownloadManager();
|
||||
downloadManager.initDownloadManager();
|
||||
|
||||
// initialize red banner
|
||||
banner.initBanner();
|
||||
banner.showBanner(false, 'error');
|
||||
},
|
||||
);
|
||||
// initialize red banner
|
||||
banner.initBanner();
|
||||
banner.showBanner(false, 'error');
|
||||
});
|
||||
|
||||
ipcRenderer.on('page-load-welcome', (_event, data) => {
|
||||
const { locale, resource } = data;
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { ipcRenderer, remote, webFrame } from 'electron';
|
||||
import { buildNumber, searchAPIVersion } from '../../package.json';
|
||||
import { ipcRenderer, webFrame } from 'electron';
|
||||
import {
|
||||
buildNumber,
|
||||
name,
|
||||
searchAPIVersion,
|
||||
version,
|
||||
} from '../../package.json';
|
||||
import { IDownloadItem } from '../app/download-handler';
|
||||
import { ICustomBrowserWindow } from '../app/window-handler';
|
||||
import {
|
||||
apiCmds,
|
||||
apiName,
|
||||
@ -23,12 +27,11 @@ import {
|
||||
import { i18n, LocaleType } from '../common/i18n-preload';
|
||||
import { throttle } from '../common/utils';
|
||||
import { getSource } from './desktop-capturer';
|
||||
import SSFNotificationHandler from './notification-ssf-hendler';
|
||||
import SSFNotificationHandler from './notification-ssf-handler';
|
||||
import { ScreenSnippetBcHandler } from './screen-snippet-bc-handler';
|
||||
|
||||
const SUPPORTED_SETTINGS = ['flashing-notifications'];
|
||||
|
||||
const os = remote.require('os');
|
||||
const MAIN_WINDOW_NAME = 'main';
|
||||
|
||||
let isAltKey: boolean = false;
|
||||
let isMenuOpen: boolean = false;
|
||||
@ -161,7 +164,7 @@ const throttledSetZoomLevel = throttle((zoomLevel) => {
|
||||
|
||||
let cryptoLib: ICryptoLib | null;
|
||||
try {
|
||||
cryptoLib = remote.require('../app/crypto-handler.js').cryptoLibrary;
|
||||
// cryptoLib = remote.require('../app/crypto-handler.js').cryptoLibrary;
|
||||
} catch (e) {
|
||||
cryptoLib = null;
|
||||
// tslint:disable-next-line
|
||||
@ -172,7 +175,7 @@ try {
|
||||
|
||||
let swiftSearch: any;
|
||||
try {
|
||||
swiftSearch = remote.require('swift-search').Search;
|
||||
// swiftSearch = remote.require('swift-search').Search;
|
||||
} catch (e) {
|
||||
swiftSearch = null;
|
||||
// tslint:disable-next-line
|
||||
@ -183,7 +186,7 @@ try {
|
||||
|
||||
let swiftSearchUtils: any;
|
||||
try {
|
||||
swiftSearchUtils = remote.require('swift-search').SearchUtils;
|
||||
// swiftSearchUtils = remote.require('swift-search').SearchUtils;
|
||||
} catch (e) {
|
||||
swiftSearchUtils = null;
|
||||
// tslint:disable-next-line
|
||||
@ -244,9 +247,9 @@ export class SSFApi {
|
||||
* Method that returns various version info
|
||||
*/
|
||||
public getVersionInfo(): Promise<IVersionInfo> {
|
||||
const appName = remote.app.getName();
|
||||
const appVer = remote.app.getVersion();
|
||||
const cpuArch = os.arch() || '';
|
||||
const appName = name;
|
||||
const appVer = version;
|
||||
const cpuArch = process.arch || '';
|
||||
|
||||
return Promise.resolve({
|
||||
containerIdentifier: appName,
|
||||
@ -481,11 +484,9 @@ export class SSFApi {
|
||||
* Opens a modal window to configure notification preference.
|
||||
*/
|
||||
public showNotificationSettings(data: string): void {
|
||||
const windowName = (remote.getCurrentWindow() as ICustomBrowserWindow)
|
||||
.winName;
|
||||
local.ipcRenderer.send(apiName.symphonyApi, {
|
||||
cmd: apiCmds.showNotificationSettings,
|
||||
windowName,
|
||||
windowName: MAIN_WINDOW_NAME,
|
||||
theme: data,
|
||||
});
|
||||
}
|
||||
@ -631,10 +632,13 @@ export class SSFApi {
|
||||
* Check media permission
|
||||
*/
|
||||
public async checkMediaPermission(): Promise<IMediaPermission> {
|
||||
const mediaStatus = (await ipcRenderer.invoke(apiName.symphonyApi, {
|
||||
cmd: apiCmds.getMediaAccessStatus,
|
||||
})) as IMediaPermission;
|
||||
return Promise.resolve({
|
||||
camera: remote.systemPreferences.getMediaAccessStatus('camera'),
|
||||
microphone: remote.systemPreferences.getMediaAccessStatus('microphone'),
|
||||
screen: remote.systemPreferences.getMediaAccessStatus('screen'),
|
||||
camera: mediaStatus.camera,
|
||||
microphone: mediaStatus.microphone,
|
||||
screen: mediaStatus.screen,
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user