Compare commits

..

1 Commits

Author SHA1 Message Date
Eugene Pankov
39732908a3 ivy test 2019-12-19 01:45:12 +01:00
211 changed files with 4085 additions and 7735 deletions

View File

@@ -225,52 +225,6 @@
"contributions": [
"code"
]
},
{
"login": "LeSeulArtichaut",
"name": "LeSeulArtichaut",
"avatar_url": "https://avatars1.githubusercontent.com/u/38361244?v=4",
"profile": "https://github.com/LeSeulArtichaut",
"contributions": [
"code"
]
},
{
"login": "CyrilTaylor",
"name": "Cyril Taylor",
"avatar_url": "https://avatars0.githubusercontent.com/u/12631466?v=4",
"profile": "https://github.com/CyrilTaylor",
"contributions": [
"code"
]
},
{
"login": "nstefanou",
"name": "nstefanou",
"avatar_url": "https://avatars3.githubusercontent.com/u/51129173?v=4",
"profile": "https://github.com/nstefanou",
"contributions": [
"code",
"plugin"
]
},
{
"login": "orin220444",
"name": "orin220444",
"avatar_url": "https://avatars3.githubusercontent.com/u/30747229?v=4",
"profile": "https://github.com/orin220444",
"contributions": [
"code"
]
},
{
"login": "Goobles",
"name": "Gobius Dolhain",
"avatar_url": "https://avatars3.githubusercontent.com/u/8776771?v=4",
"profile": "https://github.com/Goobles",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
@@ -278,6 +232,5 @@
"projectOwner": "Eugeny",
"repoType": "github",
"repoHost": "https://github.com",
"commitConvention": "none",
"skipCi": true
"commitConvention": "none"
}

View File

@@ -79,7 +79,6 @@ rules:
args: after-used
argsIgnorePattern: ^_
no-undef: error
no-var: error
object-curly-spacing:
- error
- always
@@ -99,8 +98,3 @@ rules:
'@typescript-eslint/restrict-template-expressions': off
'@typescript-eslint/no-dynamic-delete': off
'@typescript-eslint/prefer-nullish-coalescing': off
'@typescript-eslint/prefer-readonly-parameter-types': off
'@typescript-eslint/no-unsafe-member-access': off
'@typescript-eslint/no-unsafe-call': off
'@typescript-eslint/no-unsafe-return': off
'@typescript-eslint/no-base-to-string': off # broken in typescript-eslint

View File

@@ -11,7 +11,7 @@ jobs:
- name: Installing Node
uses: actions/setup-node@v1
with:
node-version: 10
version: 10
- name: Build
run: |

View File

@@ -11,7 +11,7 @@ jobs:
- name: Installing Node
uses: actions/setup-node@v1
with:
node-version: 10
version: 10
- name: Install deps
run: |

View File

@@ -11,7 +11,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v1
with:
node-version: 10
version: 10
- name: Install deps
run: |
@@ -25,6 +25,9 @@ jobs:
- name: Build native deps
run: scripts/build-native.js
- name: Build typings
run: yarn run build:typings
- name: Webpack
run: yarn run build

View File

@@ -11,7 +11,7 @@ jobs:
- name: Installing Node
uses: actions/setup-node@v1
with:
node-version: 10
version: 10
- name: Install deps
run: |
@@ -25,24 +25,23 @@ jobs:
- name: Build native deps
run: scripts/build-native.js
- name: Build typings
run: yarn run build:typings
- name: Webpack
run: yarn run build
- name: Prepackage plugins
run: scripts/prepackage-plugins.js
- run: sed -i '' 's/updateInfo = await/\/\/updateInfo = await/g' node_modules/app-builder-lib/out/targets/ArchiveTarget.js
- name: Build and sign packages
run: scripts/build-macos.js
if: github.repository == 'Eugeny/terminus' && github.event_name == 'push'
env:
#DEBUG: electron-builder,electron-builder:*
DEBUG: electron-builder,electron-builder:*
GH_TOKEN: ${{ secrets.GH_TOKEN }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
- name: Build packages without signing
run: scripts/build-macos.js

View File

@@ -11,7 +11,7 @@ jobs:
- name: Installing Node
uses: actions/setup-node@v1
with:
node-version: 10
version: 10
- name: Build
shell: powershell
@@ -39,7 +39,7 @@ jobs:
mkdir artifact-setup
mv dist/*-setup.exe artifact-setup/
mkdir artifact-portable
mv dist/*-portable.zip artifact-portable/
mv dist/*-portable.exe artifact-portable/
- uses: actions/upload-artifact@master
name: Upload installer

View File

@@ -13,13 +13,12 @@
**Terminus** is a highly configurable terminal emulator for Windows, macOS and Linux
* Integrated SSH client and connection manager
* Theming and color schemes
* Fully configurable shortcuts
* Split panes
* Remembers your tabs
* PowerShell (and PS Core), WSL, Git-Bash, Cygwin, Cmder and CMD support
* Direct file transfer from/to SSH sessions via Zmodem
* Integrated SSH client and connection manager
* Full Unicode support including double-width characters
* Doesn't choke on fast-flowing outputs
* Proper shell experience on Windows including tab completion (via Clink)
@@ -35,15 +34,12 @@
---
# Portable
For portable in windows, user can create folder `data` at the same directory as `Terminal.exe` to save the settings.
# Plugins
Plugins and themes can be installed directly from the Settings view inside Terminus.
* [clickable-links](https://github.com/Eugeny/terminus-clickable-links) - makes paths and URLs in the terminal clickable
* [shell-selector](https://github.com/Eugeny/terminus-shell-selector) - a quick shell selector pane
* [title-control](https://github.com/kbjr/terminus-title-control) - allows modifying the title of the terminal tabs by providing a prefix, suffix, and/or strings to be removed
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - quickly send commands to one or all terminal tabs
* [save-output](https://github.com/Eugeny/terminus-save-output) - record terminal output into a file
@@ -70,52 +66,42 @@ See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) and
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- prettier-ignore -->
<table>
<tr>
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt="Russell Myers"/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt="Austin Warren"/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt="Felicia Hummel"/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt="Mike MacCana"/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt="Yacine Kanzari"/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt="BBJip"/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt="Futagirl"/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt="Levin Rickert"/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt="OJ Kwon"/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt="domain"/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt="James Brumond"/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt="Daniel Imms"/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt="Florian Bachmann"/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt="Michael Kühnel"/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt="Tilmann Meyer"/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt="PM Extra"/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt="Jonathan"/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt="Hans Koch"/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt="Dak Smyth"/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt="Wang Zhi"/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt="jack1142"/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt="Howie Douglas"/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt="Chris Kaczor"/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt="Johannes Kadak"/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -8,15 +8,17 @@ html
window.nodeRequire = require
script(src='./preload.js')
script(src='./bundle.js', defer)
style#custom-css
style.
body { transition: 0.5s background; }
body
style#custom-css
app-root
.preload-logo
div
.terminus-logo
h1.terminus-title Terminus
sup α
sup α
.progress
.bar(style='width: 0%')

View File

@@ -1,5 +1,4 @@
import { app, ipcMain, Menu, Tray, shell, globalShortcut } from 'electron'
// eslint-disable-next-line no-duplicate-imports
import { app, ipcMain, Menu, Tray, shell } from 'electron'
import * as electron from 'electron'
import { loadConfig } from './config'
import { Window, WindowOptions } from './window'
@@ -9,38 +8,25 @@ export class Application {
private windows: Window[] = []
constructor () {
ipcMain.on('app:config-change', (_event, config) => {
this.broadcast('host:config-change', config)
})
ipcMain.on('app:register-global-hotkey', (_event, specs) => {
globalShortcut.unregisterAll()
for (let spec of specs) {
globalShortcut.register(spec, () => {
this.onGlobalHotkey()
})
}
ipcMain.on('app:config-change', () => {
this.broadcast('host:config-change')
})
const configData = loadConfig()
if (process.platform === 'linux') {
app.commandLine.appendSwitch('no-sandbox')
if (((configData.appearance || {}).opacity || 1) !== 1) {
app.commandLine.appendSwitch('enable-transparent-visuals')
app.disableHardwareAcceleration()
}
if (process.platform === 'linux' && ((configData.appearance || {}).opacity || 1) !== 1) {
app.commandLine.appendSwitch('enable-transparent-visuals')
app.disableHardwareAcceleration()
}
app.commandLine.appendSwitch('disable-http-cache')
app.commandLine.appendSwitch('lang', 'EN')
app.allowRendererProcessReuse = false
for (const flag of configData.flags || [['force_discrete_gpu', '0']]) {
app.commandLine.appendSwitch(flag[0], flag[1])
}
}
init (): void {
init () {
electron.screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
}
@@ -54,9 +40,6 @@ export class Application {
this.enableTray()
}
})
window.closed$.subscribe(() => {
this.windows = this.windows.filter(x => x !== window)
})
if (process.platform === 'darwin') {
this.setupMenu()
}
@@ -64,38 +47,20 @@ export class Application {
return window
}
onGlobalHotkey (): void {
if (this.windows.some(x => x.isFocused())) {
for (let window of this.windows) {
window.hide()
}
} else {
for (let window of this.windows) {
window.present()
}
}
}
presentAllWindows (): void {
broadcast (event, ...args) {
for (let window of this.windows) {
window.present()
}
}
broadcast (event: string, ...args): void {
for (const window of this.windows) {
window.send(event, ...args)
}
}
async send (event: string, ...args): Promise<void> {
async send (event, ...args) {
if (!this.hasWindows()) {
await this.newWindow()
}
this.windows.filter(w => !w.isDestroyed())[0].send(event, ...args)
}
enableTray (): void {
enableTray () {
if (this.tray) {
return
}
@@ -106,7 +71,7 @@ export class Application {
this.tray = new Tray(`${app.getAppPath()}/assets/tray.png`)
}
this.tray.on('click', () => setTimeout(() => this.focus()))
this.tray.on('click', () => setTimeout(() => this.focus()));
const contextMenu = Menu.buildFromTemplate([{
label: 'Show',
@@ -120,30 +85,23 @@ export class Application {
this.tray.setToolTip(`Terminus ${app.getVersion()}`)
}
disableTray (): void {
disableTray () {
if (this.tray) {
this.tray.destroy()
this.tray = null
}
}
hasWindows (): boolean {
hasWindows () {
return !!this.windows.length
}
focus (): void {
focus () {
for (let window of this.windows) {
window.show()
}
}
handleSecondInstance (argv: string[], cwd: string): void {
this.presentAllWindows()
for (let window of this.windows) {
window.handleSecondInstance(argv, cwd)
}
}
private setupMenu () {
let template: Electron.MenuItemConstructorOptions[] = [
{
@@ -224,7 +182,7 @@ export class Application {
},
},
],
},
}
]
Menu.setApplicationMenu(Menu.buildFromTemplate(template))

View File

@@ -1,6 +1,6 @@
import { app } from 'electron'
export function parseArgs (argv: string[], cwd: string): any {
export function parseArgs (argv, cwd) {
if (argv[0].includes('node')) {
argv = argv.slice(1)
}
@@ -20,25 +20,25 @@ export function parseArgs (argv: string[], cwd: string): any {
return yargs.option('escape', {
alias: 'e',
type: 'boolean',
describe: 'Perform shell escaping',
describe: 'Perform shell escaping'
}).positional('text', {
type: 'string',
type: 'string'
})
})
.version('version', '', app.getVersion())
.option('debug', {
alias: 'd',
describe: 'Show DevTools on start',
type: 'boolean',
type: 'boolean'
})
.option('hidden', {
describe: 'Start minimized',
type: 'boolean',
type: 'boolean'
})
.option('version', {
alias: 'v',
describe: 'Show version and exit',
type: 'boolean',
type: 'boolean'
})
.help('help')
.parse(argv.slice(1))

View File

@@ -1,10 +1,9 @@
import './portable'
import './sentry'
import './lru'
import { app, ipcMain, Menu } from 'electron'
import { parseArgs } from './cli'
import { Application } from './app'
import electronDebug = require('electron-debug')
import * as electronDebug from 'electron-debug'
if (!process.env.TERMINUS_PLUGINS) {
process.env.TERMINUS_PLUGINS = ''
@@ -34,7 +33,7 @@ process.on('uncaughtException' as any, err => {
})
app.on('second-instance', (_event, argv, cwd) => {
application.handleSecondInstance(argv, cwd)
application.send('host:second-instance', parseArgs(argv, cwd), cwd)
})
const argv = parseArgs(process.argv, process.cwd())
@@ -59,8 +58,8 @@ app.on('ready', () => {
label: 'New window',
click () {
this.app.newWindow()
},
},
}
}
]))
}
application.init()

View File

@@ -1,15 +1,13 @@
import * as createLRU from 'lru-cache'
import * as fs from 'fs'
const lru = createLRU({ max: 256, maxAge: 250 })
const origLstat = fs.realpathSync.bind(fs)
let lru = require('lru-cache')({ max: 256, maxAge: 250 })
let fs = require('fs')
let origLstat = fs.realpathSync.bind(fs)
// NB: The biggest offender of thrashing realpathSync is the node module system
// itself, which we can't get into via any sane means.
require('fs').realpathSync = function (p) {
let r = lru.get(p)
if (r) {
return r
}
if (r) return r
r = origLstat(p)
lru.set(p, r)

View File

@@ -1,24 +0,0 @@
import * as path from 'path'
import * as fs from 'fs'
let appPath: string | null = null
try {
appPath = path.dirname(require('electron').app.getPath('exe'))
} catch {
appPath = path.dirname(require('electron').remote.app.getPath('exe'))
}
if (null != appPath) {
if(fs.existsSync(path.join(appPath, 'terminus-data'))) {
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
}
const portableData = path.join(appPath, 'data')
if (fs.existsSync(portableData)) {
console.log('reset user data to ' + portableData)
try {
require('electron').app.setPath('userData', portableData)
} catch {
require('electron').remote.app.setPath('userData', portableData)
}
}
}

17
app/lib/sentry.ts Executable file → Normal file
View File

@@ -1,5 +1,4 @@
const { init } = process.type === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
import * as isDev from 'electron-is-dev'
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
@@ -10,12 +9,10 @@ try {
release = require('electron').remote.app.getVersion()
}
if (!isDev) {
init({
dsn: SENTRY_DSN,
release,
integrations (integrations) {
return integrations.filter(integration => integration.name !== 'Breadcrumbs')
},
})
}
init({
dsn: SENTRY_DSN,
release,
integrations (integrations) {
return integrations.filter(integration => integration.name !== 'Breadcrumbs')
},
})

View File

@@ -1,11 +1,10 @@
import { Subject, Observable } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen } from 'electron'
import ElectronConfig = require('electron-config')
import { BrowserWindow, app, ipcMain, Rectangle, screen } from 'electron'
import * as ElectronConfig from 'electron-config'
import * as os from 'os'
import * as path from 'path'
import { parseArgs } from './cli'
import { loadConfig } from './config'
let SetWindowCompositionAttribute: any
@@ -24,20 +23,15 @@ export interface WindowOptions {
export class Window {
ready: Promise<void>
private visible = new Subject<boolean>()
private closed = new Subject<void>()
private window: BrowserWindow
private windowConfig: ElectronConfig
private windowBounds: Rectangle
private closing = false
private lastVibrancy: {enabled: boolean, type?: string} | null = null
private disableVibrancyWhileDragging = false
private configStore: any
get visible$ (): Observable<boolean> { return this.visible }
get closed$ (): Observable<void> { return this.closed }
constructor (options?: WindowOptions) {
this.configStore = loadConfig()
let configData = loadConfig()
options = options || {}
@@ -54,7 +48,6 @@ export class Window {
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'sentry.js'),
backgroundThrottling: false,
},
frame: false,
show: false,
@@ -63,18 +56,18 @@ export class Window {
if (this.windowBounds) {
Object.assign(bwOptions, this.windowBounds)
const closestDisplay = screen.getDisplayNearestPoint( { x: this.windowBounds.x, y: this.windowBounds.y } )
const closestDisplay = screen.getDisplayNearestPoint( {x: this.windowBounds.x, y: this.windowBounds.y} )
const [left1, top1, right1, bottom1] = [this.windowBounds.x, this.windowBounds.y, this.windowBounds.x + this.windowBounds.width, this.windowBounds.y + this.windowBounds.height]
const [left2, top2, right2, bottom2] = [closestDisplay.bounds.x, closestDisplay.bounds.y, closestDisplay.bounds.x + closestDisplay.bounds.width, closestDisplay.bounds.y + closestDisplay.bounds.height]
const [left1, top1, right1, bottom1] = [this.windowBounds.x, this.windowBounds.y, this.windowBounds.x + this.windowBounds.width, this.windowBounds.y + this.windowBounds.height];
const [left2, top2, right2, bottom2] = [closestDisplay.bounds.x, closestDisplay.bounds.y, closestDisplay.bounds.x + closestDisplay.bounds.width, closestDisplay.bounds.y + closestDisplay.bounds.height];
if ((left2 > right1 || right2 < left1 || top2 > bottom1 || bottom2 < top1) && !maximized) {
bwOptions.x = closestDisplay.bounds.width / 2 - bwOptions.width / 2
bwOptions.y = closestDisplay.bounds.height / 2 - bwOptions.height / 2
bwOptions.x = closestDisplay.bounds.width / 2 - bwOptions.width / 2;
bwOptions.y = closestDisplay.bounds.height / 2 - bwOptions.height / 2;
}
}
if ((this.configStore.appearance || {}).frame === 'native') {
if ((configData.appearance || {}).frame === 'native') {
bwOptions.frame = true
} else {
if (process.platform === 'darwin') {
@@ -90,7 +83,7 @@ export class Window {
this.window.once('ready-to-show', () => {
if (process.platform === 'darwin') {
this.window.setVibrancy('window')
} else if (process.platform === 'win32' && (this.configStore.appearance || {}).vibrancy) {
} else if (process.platform === 'win32' && (configData.appearance || {}).vibrancy) {
this.setVibrancy(true)
}
@@ -101,13 +94,6 @@ export class Window {
this.window.show()
}
this.window.focus()
this.window.moveTop()
}
})
this.window.on('blur', () => {
if (this.configStore.appearance?.dockHideOnBlur) {
this.hide()
}
})
@@ -130,13 +116,12 @@ export class Window {
})
}
setVibrancy (enabled: boolean, type?: string): void {
this.lastVibrancy = { enabled, type }
setVibrancy (enabled: boolean, type?: string) {
if (process.platform === 'win32') {
if (parseFloat(os.release()) >= 10) {
let attribValue = AccentState.ACCENT_DISABLED
if (enabled) {
if (type === 'fluent') {
if (parseInt(os.release().split('.')[2]) >= 17063 && type === 'fluent') {
attribValue = AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND
} else {
attribValue = AccentState.ACCENT_ENABLE_BLURBEHIND
@@ -146,77 +131,26 @@ export class Window {
} else {
DwmEnableBlurBehindWindow(this.window, enabled)
}
} else {
this.window.setVibrancy(enabled ? 'dark' : null as any) // electron issue 20269
}
}
show (): void {
show () {
this.window.show()
this.window.moveTop()
}
focus (): void {
focus () {
this.window.focus()
}
send (event: string, ...args): void {
send (event, ...args) {
if (!this.window) {
return
}
this.window.webContents.send(event, ...args)
if (event === 'host:config-change') {
this.configStore = args[0]
}
}
isDestroyed (): boolean {
return !this.window || this.window.isDestroyed()
}
isFocused (): boolean {
return this.window.isFocused()
}
hide (): void {
if (process.platform === 'darwin') {
// Lose focus
Menu.sendActionToFirstResponder('hide:')
}
this.window.blur()
if (process.platform !== 'darwin') {
this.window.hide()
}
}
present (): void {
if (!this.window.isVisible()) {
// unfocused, invisible
this.window.show()
this.window.focus()
} else {
if (!this.configStore.appearance?.dock || this.configStore.appearance?.dock === 'off') {
// not docked, visible
setTimeout(() => {
this.window.show()
this.window.focus()
})
} else {
if (this.configStore.appearance?.dockAlwaysOnTop) {
// docked, visible, on top
this.window.hide()
} else {
// docked, visible, not on top
this.window.focus()
}
}
}
}
handleSecondInstance (argv: string[], cwd: string): void {
if (!this.configStore.appearance?.dock) {
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
}
isDestroyed () {
return !this.window || this.window.isDestroyed();
}
private setupWindowManagement () {
@@ -268,10 +202,6 @@ export class Window {
}
})
this.window.on('focus', () => {
this.send('host:window-focused')
})
ipcMain.on('window-focus', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
@@ -359,35 +289,10 @@ export class Window {
})
this.window.webContents.on('new-window', event => event.preventDefault())
ipcMain.on('window-set-disable-vibrancy-while-dragging', (_event, value) => {
this.disableVibrancyWhileDragging = value
})
this.window.on('will-move', () => {
if (!this.lastVibrancy?.enabled || !this.disableVibrancyWhileDragging) {
return
}
let timeout: number|null = null
const oldVibrancy = this.lastVibrancy
this.setVibrancy(false)
const onMove = () => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
this.window.off('move', onMove)
this.setVibrancy(oldVibrancy.enabled, oldVibrancy.type)
}, 500)
}
this.window.on('move', onMove)
})
}
private destroy () {
this.window = null
this.closed.next()
this.visible.complete()
this.closed.complete()
}
}

View File

@@ -13,43 +13,43 @@
"watch": "webpack --progress --color --watch"
},
"dependencies": {
"@angular/animations": "9.1.9",
"@angular/common": "9.1.9",
"@angular/compiler": "9.1.9",
"@angular/core": "9.1.9",
"@angular/forms": "9.1.9",
"@angular/platform-browser": "9.1.9",
"@angular/platform-browser-dynamic": "9.1.9",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@angular/animations": "9.0.0-rc.5",
"@angular/common": "9.0.0-rc.5",
"@angular/compiler": "9.0.0-rc.5",
"@angular/core": "9.0.0-rc.5",
"@angular/forms": "9.0.0-rc.5",
"@angular/platform-browser": "9.0.0-rc.5",
"@angular/platform-browser-dynamic": "9.0.0-rc.5",
"@ng-bootstrap/ng-bootstrap": "^5.1.4",
"devtron": "1.4.0",
"electron-config": "2.0.0",
"electron-debug": "^3.0.1",
"electron-is-dev": "1.1.0",
"electron-updater": "^4.3.1",
"electron-updater": "^4.2.0",
"fontmanager-redux": "0.4.0",
"js-yaml": "3.14.0",
"keytar": "^5.6.0",
"js-yaml": "3.13.1",
"keytar": "^5.0.0",
"mz": "^2.7.0",
"ngx-toastr": "^12.0.1",
"node-pty": "^0.10.0-beta9",
"ngx-toastr": "^11.2.1",
"node-pty": "^0.10.0-beta2",
"npm": "6.9.0",
"path": "0.12.7",
"rxjs": "^6.5.5",
"rxjs-compat": "^6.5.5",
"yargs": "^15.3.1",
"zone.js": "^0.10.3"
"rxjs": "^6.5.3",
"rxjs-compat": "^6.5.3",
"yargs": "^15.0.2",
"zone.js": "^0.10.2"
},
"optionalDependencies": {
"macos-native-processlist": "^1.0.2",
"serialport": "^9.0.0",
"windows-blurbehind": "^1.0.1",
"windows-native-registry": "^1.0.17",
"windows-native-registry": "^1.0.16",
"windows-process-tree": "^0.2.4",
"windows-swca": "^2.0.2"
},
"devDependencies": {
"@angular/localize": "^9.0.0-rc.7",
"@types/mz": "0.0.32",
"@types/node": "12.7.12",
"node-abi": "^2.17.0"
"node-abi": "^2.13.0"
}
}

View File

@@ -1,13 +1,14 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { NgModule } from '@angular/core'
import { NgModule, Compiler, Inject, Injector, ɵcreateInjector as createInjector } from '@angular/core'
import '@angular/localize/init'
import { CommonModule } from '@angular/common'
import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr'
export function getRootModule (plugins: any[]) {
const imports = [
@NgModule({
imports: [
BrowserModule,
...plugins,
CommonModule,
NgbModule,
ToastrModule.forRoot({
positionClass: 'toast-bottom-center',
@@ -15,7 +16,33 @@ export function getRootModule (plugins: any[]) {
preventDuplicates: true,
extendedTimeOut: 5000,
}),
]
],
})
export class RootModule {
constructor (
private compiler: Compiler,
private injector: Injector,
@Inject('plugins') private plugins: any[],
) { }
async ngDoBootstrap (app) {
console.log('bootstrap', app)
for (let plugin of this.plugins) {
console.log(plugin)
// try {
const injector = createInjector(plugin, this.injector)
console.log(injector)
const module = await this.compiler.compileModuleAsync(plugin)
console.log(module)
// } catch (e) {
// console.error('Failed loading', plugin, e)
// }
}
}
}
export function setupRootModule (plugins: any[]) {
const bootstrap = [
...plugins.filter(x => x.bootstrap).map(x => x.bootstrap),
]
@@ -23,11 +50,4 @@ export function getRootModule (plugins: any[]) {
if (bootstrap.length === 0) {
throw new Error('Did not find any bootstrap components. Are there any plugins installed?')
}
@NgModule({
imports,
bootstrap,
}) class RootModule { } // eslint-disable-line @typescript-eslint/no-extraneous-class
return RootModule
}

View File

@@ -1,4 +1,5 @@
import '../lib/lru'
import 'core-js/proposals/reflect-metadata'
import 'source-sans-pro/source-sans-pro.css'
import 'source-code-pro/source-code-pro.css'
import '@fortawesome/fontawesome-free/css/solid.css'
@@ -6,3 +7,71 @@ import '@fortawesome/fontawesome-free/css/brands.css'
import '@fortawesome/fontawesome-free/css/fontawesome.css'
import 'ngx-toastr/toastr.css'
import './preload.scss'
import * as path from 'path'
const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
const nodeRequire = (global as any).require
const builtinModules = [
'@angular/animations',
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/forms',
'@angular/localize',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@ng-bootstrap/ng-bootstrap',
'ngx-toastr',
'rxjs',
'rxjs/operators',
'rxjs/internal/observable/fromEvent',
'rxjs/internal/observable/merge',
'rxjs-compat/Subject',
'zone.js/dist/zone.js',
'terminus-core',
// 'terminus-settings',
// 'terminus-terminal',
]
const cachedBuiltinModules = {}
if (process.env.TERMINUS_DEV) {
console.info(path.dirname(require('electron').remote.app.getAppPath()))
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
nodeModule.globalPaths.unshift(path.join(require('electron').remote.app.getAppPath(), 'node_modules'))
}
const originalRequire = (global as any).require
;(global as any).require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalRequire.apply(this, arguments)
}
const originalModuleRequire = nodeModule.prototype.require
nodeModule.prototype.require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalModuleRequire.call(this, query)
}
global['require'].resolve = originalRequire.resolve
nodeModule.prototype.require.resolve = originalModuleRequire.resolve
builtinModules.forEach(m => {
const label = 'Caching ' + m
console.time(label)
try {
console.log(m + '/__ivy_ngcc__/fesm5/' + m.split('/')[1] + '.js')
cachedBuiltinModules[m] = nodeRequire(m + '/__ivy_ngcc__/fesm5/' + m.split('/')[1] + '.js')
console.log('loaded ivy')
} catch (e) {
console.error(e)
cachedBuiltinModules[m] = nodeRequire(m)
}
console.timeEnd(label)
})

View File

@@ -1,17 +1,12 @@
import 'zone.js'
import 'core-js/proposals/reflect-metadata'
import 'rxjs'
import * as isDev from 'electron-is-dev'
import './global.scss'
import './toastr.scss'
import { enableProdMode, NgModuleRef, ApplicationRef } from '@angular/core'
import { enableDebugTools } from '@angular/platform-browser'
import { enableProdMode, NgModuleRef } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { getRootModule } from './app.module'
import { setupRootModule, RootModule } from './app.module'
import { findPlugins, loadPlugins, PluginInfo } from './plugins'
// Always land on the start view
@@ -33,19 +28,14 @@ async function bootstrap (plugins: PluginInfo[], safeMode = false): Promise<NgMo
if (safeMode) {
plugins = plugins.filter(x => x.isBuiltin)
}
const pluginsModules = await loadPlugins(plugins, (current, total) => {
const pluginModules = await loadPlugins(plugins, (current, total) => {
(document.querySelector('.progress .bar') as HTMLElement).style.width = `${100 * current / total}%` // eslint-disable-line
})
const module = getRootModule(pluginsModules)
window['rootModule'] = module
return platformBrowserDynamic().bootstrapModule(module).then(moduleRef => {
if (isDev) {
const applicationRef = moduleRef.injector.get(ApplicationRef)
const componentRef = applicationRef.components[0]
enableDebugTools(componentRef)
}
return moduleRef
})
setupRootModule(pluginModules)
window['rootModule'] = RootModule
return platformBrowserDynamic([
{ provide: 'plugins', useValue: pluginModules },
]).bootstrapModule(RootModule)
}
findPlugins().then(async plugins => {

View File

@@ -14,14 +14,12 @@ function normalizePath (path: string): string {
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
if (process.env.TERMINUS_DEV) {
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
}
const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(require('electron').remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
const userPluginsPath = path.join(
require('electron').remote.app.getPath('userData'),
require('electron').remote.app.getPath('appData'),
'terminus',
'plugins',
)
@@ -51,49 +49,6 @@ export interface PluginInfo {
info?: any
}
const builtinModules = [
'@angular/animations',
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/forms',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@ng-bootstrap/ng-bootstrap',
'ngx-toastr',
'rxjs',
'rxjs/operators',
'rxjs-compat/Subject',
'terminus-core',
'terminus-settings',
'terminus-terminal',
'zone.js/dist/zone.js',
]
const cachedBuiltinModules = {}
builtinModules.forEach(m => {
const label = 'Caching ' + m
console.time(label)
cachedBuiltinModules[m] = nodeRequire(m)
console.timeEnd(label)
})
const originalRequire = (global as any).require
;(global as any).require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalRequire.apply(this, arguments)
}
const originalModuleRequire = nodeModule.prototype.require
nodeModule.prototype.require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalModuleRequire.call(this, query)
}
export async function findPlugins (): Promise<PluginInfo[]> {
const paths = nodeModule.globalPaths
let foundPlugins: PluginInfo[] = []
@@ -166,6 +121,7 @@ export async function loadPlugins (foundPlugins: PluginInfo[], progress: Progres
progress(0, 1)
let index = 0
for (const foundPlugin of foundPlugins) {
if (foundPlugin.name !== 'core') continue
console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`)
progress(index, foundPlugins.length)
try {

View File

@@ -1,6 +0,0 @@
import { Component } from '@angular/core'
@Component({
template: '<app-root></app-root>',
})
export class RootComponent { } // eslint-disable-line @typescript-eslint/no-extraneous-class

View File

@@ -1,7 +1,8 @@
{
"compilerOptions": {
"baseUrl": "./src",
"module": "commonjs",
"module": "es2015",
"moduleResolution": "node",
"target": "es2015",
"declaration": false,
"noImplicitAny": false,
@@ -19,7 +20,10 @@
"es2015.iterable",
"es2017",
"es7"
]
],
"paths": {
"*": ["../../app/node_modules/*"]
}
},
"compileOnSave": false,
"exclude": [
@@ -28,5 +32,9 @@
"*/node_modules",
"terminus*",
"platforms"
]
],
"angularCompilerOptions": {
"enableIvy": true,
"disableTypeScriptVersionCheck": true
}
}

View File

@@ -1,5 +1,6 @@
const path = require('path')
const webpack = require('webpack')
const { AngularCompilerPlugin } = require('@ngtools/webpack')
module.exports = {
name: 'terminus',
@@ -28,13 +29,8 @@ module.exports = {
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.json'),
},
},
test: /(?:\.ngfactory\.js|\.ngfactory|\.ngstyle\.js|\.ts)$/,
loader: '@ngtools/webpack',
},
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
@@ -82,5 +78,10 @@ module.exports = {
new webpack.DefinePlugin({
'process.type': '"renderer"'
}),
new AngularCompilerPlugin({
tsConfigPath: path.resolve(__dirname, 'tsconfig.json'),
entryModule: 'src/index#default',
sourceMap: true,
}),
],
}

View File

@@ -2,111 +2,172 @@
# yarn lockfile v1
"@angular/animations@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.1.9.tgz#de54334ea195189402487855c9a98f5618605da4"
integrity sha512-qWVi0TxmU6HeXAgEsfpQvFFygh+a0kH2kGe6bWij4XvG6dWfV3xZjlaFwSIYGk+yK4yL0+9+PAXH+ENfxNw+Cw==
"@angular/animations@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.0.0-rc.5.tgz#8ed3fa2f5d16c16d1ea013ec71e46365c8336622"
integrity sha512-pb1QJjBaBOenSIdKB9h1Ts8yQwdAjjTuH9ckVycjYH3yKDc1cQuaGy4NxEx7TJF8ADo4iKkCvKTyh0dW42TOvg==
"@angular/common@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.1.9.tgz#16e77b2db675b80e32f1788a20c538150fd09294"
integrity sha512-y/tJtkuOJhV2kcaXZyrLZH84i4uQ1r+vaaEHvXj+JZYfYfcMMd/TDqMiPcIkUb3RxqghtZ+q0ZNW5D1Nlru3Pw==
"@angular/common@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.0.0-rc.5.tgz#05c6cfeef03d55757bf131c8171fb3bf35daa59f"
integrity sha512-Gg24S8dMUwVrmIvVHIz2rWCU+q+4Su41s4oipJWJIW1bCBMWqb2oGtaWMhy7RbUkFq2TeL7tC3dS2FOqvgj9sg==
"@angular/compiler@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.9.tgz#cbf678ee28a0811a8ef3ee7be565d4911ff28ec7"
integrity sha512-kjFgaTB2ckr9lgmkS1dOGRT7kmzpQueydxsxXSHWgICNVE6F/u1PHyeSOyJRpxW0GnrkLq3QM2EUFnQGGga5bg==
"@angular/compiler@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0-rc.5.tgz#4771e04d8a4c25cfe195232b194dd8ac61bdce42"
integrity sha512-0CWPDbpHoWm/ZN40/Y+iPikRQbhd50keoE4xSAYM2SS1pnomJaF2ytIL9xfc3BMGGKgiX3aIk57B0m4yDYTiBw==
"@angular/core@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.9.tgz#db4241f867d6e14b81ed6e7c50334813c6ebfc10"
integrity sha512-q/DERgVU6vK2LtTcdVCGGBcoO424WsEfImh3Vcuy+P/ZVmthlDUC/+q+tSKt8MMf4hLpxFDQJE8vUSkktj7QEw==
"@angular/core@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.0-rc.5.tgz#4d6140e3bf14b7be86e2045bf6a657ec7b4ef211"
integrity sha512-g9IhWc5znQGNj056Qtk1OnNYDQAIT8ti++xgcAYJ2Z1Yp0Bkb8gL7WexiuwKxmilHmZxnZiRHsPfSlKl0Hxp5g==
"@angular/forms@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.1.9.tgz#20c9a79d1dcb2cace45df9e2f304b658e02c1687"
integrity sha512-r675yImnb/0pY7K5W3V2ITa7YETu1I2AS+bRfII6UQ6gthyeFFOHb5noa7YneC2yqQiM6E4DQmF5ig3daPuFNg==
"@angular/forms@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.0.0-rc.5.tgz#ab8886d865d968ab23b7680e80061c16fef0a5d8"
integrity sha512-+K4MHD7EmSbxljKd/+vugyGWUROSy8PAcqV160gCQQbxW9MuYsHJM/BBPaq2H07gE5YHJ/HOSQoepNdXJ3PUSw==
"@angular/platform-browser-dynamic@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.9.tgz#12f8b05d3c9ef0844df88f3833e29ea1e49ec5e0"
integrity sha512-b9MG5MWne+IuL3uLm8jwPhlJzqYaGBGk/qibOqb17T24j1iyrlO7T5bZ8zO6pUy5iT/TahVfHPnPJC1qTK5OmA==
"@angular/platform-browser@9.1.9":
version "9.1.9"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.1.9.tgz#c2fcc50aebfdc268521b407e32dc0d967cb40411"
integrity sha512-V861X3MxJp1AlMTnkUPldpBLIJbApXF3ka0A5Dq2nVJCyOFeteGkaRWSBgqe2jxmq+LVpJbzcNvtDFXw6mQ0jA==
"@ng-bootstrap/ng-bootstrap@^6.1.0":
version "6.1.0"
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-6.1.0.tgz#fce7550a095aeac42108f76ac1ebd63caf8304e9"
integrity sha512-2GzkNJBKdeHkaUqaCAqSILPft0IzzHjMfAlAuGY6/ZLlVQ0glt5MTbIXtIhSbjR+OvlrljoXFLrvzs1LGdmE+A==
"@serialport/binding-abstract@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz#78e6d7995a95c46d480445303e6f32ca4d53edcd"
integrity sha512-1swwUVoRyQ9ubxrkJ8JPppykohUpTAP4jkGr36e9NjbVocSPfqeX6tFZFwl/IdUlwJwxGdbKDqq7FvXniCQUMw==
"@angular/localize@^9.0.0-rc.7":
version "9.0.0-rc.7"
resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.0.0-rc.7.tgz#8819a32309d44a631c102d3c8d064302cfc23f3c"
integrity sha512-y03uNKoZSsedY5W2X7NUNcmxm6rsL6dMs2g1NRw0jOmveXjk8N0g7uUgcBQhXJ7LiHtaRcIK+bOq+2JvvTtZlQ==
dependencies:
debug "^4.1.1"
"@babel/core" "^7.5.5"
glob "7.1.2"
yargs "13.1.0"
"@serialport/binding-mock@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/binding-mock/-/binding-mock-8.0.6.tgz#41a8f827269c6a0e58546513a274e12023134155"
integrity sha512-BIbY5/PsDDo0QWDNCCxDgpowAdks+aZR8BOsEtK2GoASTTcJCy1fBwPIfH870o7rnbH901wY3C+yuTfdOvSO9A==
"@angular/platform-browser-dynamic@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.0-rc.5.tgz#6beb6e5f625df5939b757b80f7f39134e95769f0"
integrity sha512-MCDIuwcFlXo4f/ro9NiYcV1t8SBdt22dXjQWWSij+ABlVqrW7Xwl8oNq0q2+HJQIlg+a37Y2svJouUN1kLvZ3A==
"@angular/platform-browser@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.0.0-rc.5.tgz#b10dcd5df71c33e7bff48154ae3876de5236eb5e"
integrity sha512-omnc9GnVU8THx2YSnJUzrR2Lk2alzao9AhR+I05GOlYgL3HsuttTtTBEzVfvecGLwSBKrdtbPUwWG4NTuuxGTA==
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==
dependencies:
"@serialport/binding-abstract" "^8.0.6"
debug "^4.1.1"
"@babel/highlight" "^7.0.0"
"@serialport/bindings@^8.0.7":
version "8.0.7"
resolved "https://registry.yarnpkg.com/@serialport/bindings/-/bindings-8.0.7.tgz#2a58f60f1e24ee4549be6f9e0e37b3359d038a1c"
integrity sha512-IqudDL8ne2Y2S0W5fKA6wdgHCIA2e2OIaPVYhGy6duE6legNHFY+05CLicHAyAeTocXmHU7rVNxzVQrOG5tM4g==
"@babel/core@^7.5.5":
version "7.7.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.5.tgz#ae1323cd035b5160293307f50647e83f8ba62f7e"
integrity sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==
dependencies:
"@serialport/binding-abstract" "^8.0.6"
"@serialport/parser-readline" "^8.0.6"
bindings "^1.5.0"
debug "^4.1.1"
nan "^2.14.0"
prebuild-install "^5.3.0"
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.4"
"@babel/helpers" "^7.7.4"
"@babel/parser" "^7.7.5"
"@babel/template" "^7.7.4"
"@babel/traverse" "^7.7.4"
"@babel/types" "^7.7.4"
convert-source-map "^1.7.0"
debug "^4.1.0"
json5 "^2.1.0"
lodash "^4.17.13"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
"@serialport/parser-byte-length@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-byte-length/-/parser-byte-length-8.0.6.tgz#efb6195692b1088e6c095fd43bae196fc30674d0"
integrity sha512-92mrFxFEvq3gRvSM7ANK/jfbmHslz91a5oYJy/nbSn4H/MCRXjxR2YOkQgVXuN+zLt+iyDoW3pcOP4Sc1nWdqQ==
"@serialport/parser-cctalk@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-cctalk/-/parser-cctalk-8.0.6.tgz#4134a3c479d465df3b152a21e16b8ecf1bc818c3"
integrity sha512-pqtCYQPgxnxHygiXUPCfgX7sEx+fdR/ObjpscidynEULUq2fFrC5kBkrxRbTfHRtTaU2ii9DyjFq0JVRCbhI0Q==
"@serialport/parser-delimiter@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-delimiter/-/parser-delimiter-8.0.6.tgz#0e467cb07a40bd3006835c48e488666bd7de22cc"
integrity sha512-ogKOcPisPMlVtirkuDu3SFTF0+xT0ijxoH7XjpZiYL41EVi367MwuCnEmXG+dEKKnF0j9EPqOyD2LGSJxaFmhQ==
"@serialport/parser-readline@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-readline/-/parser-readline-8.0.6.tgz#8a6a296a1bec08a4855bf7a62bc6335d52972e4a"
integrity sha512-OYBT2mpczh9QUI3MTw8j0A0tIlPVjpVipvuVnjRkYwxrxPeq04RaLFhaDpuRzua5rTKMt89c1y3btYeoDXMjAA==
"@babel/generator@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369"
integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==
dependencies:
"@serialport/parser-delimiter" "^8.0.6"
"@babel/types" "^7.7.4"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
"@serialport/parser-ready@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-ready/-/parser-ready-8.0.6.tgz#d6e95e53ee70d298ae0b4147995007f4ba62651c"
integrity sha512-xcEqv4rc119WR5JzAuu8UeJOlAwET2PTdNb6aIrrLlmTxhvuBbuRFcsnF3BpH9jUL30Kh7a6QiNXIwVG+WR/1Q==
"@serialport/parser-regex@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/parser-regex/-/parser-regex-8.0.6.tgz#70aa1abe31899d1b986f44cfb6777a76e26755bf"
integrity sha512-J8KY75Azz5ZyExmyM5YfUxbXOWBkZCytKgCCmZ966ttwZS0bUZOuoCaZj2Zp4VILJAiLuxHoqc0foi67Fri5+g==
"@serialport/stream@^8.0.6":
version "8.0.6"
resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-8.0.6.tgz#3395dbac788c00797c2435c61c2ecb4e99fbf41d"
integrity sha512-ym1PwM0rwLrj90vRBB66I1hwMXbuMw9wGTxqns75U3N/tuNFOH85mxXaYVF2TpI66aM849NoI1jMm50fl9equg==
"@babel/helper-function-name@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e"
integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==
dependencies:
debug "^4.1.1"
"@babel/helper-get-function-arity" "^7.7.4"
"@babel/template" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/helper-get-function-arity@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0"
integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==
dependencies:
"@babel/types" "^7.7.4"
"@babel/helper-split-export-declaration@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8"
integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==
dependencies:
"@babel/types" "^7.7.4"
"@babel/helpers@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302"
integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==
dependencies:
"@babel/template" "^7.7.4"
"@babel/traverse" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/highlight@^7.0.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
dependencies:
chalk "^2.0.0"
esutils "^2.0.2"
js-tokens "^4.0.0"
"@babel/parser@^7.7.4", "@babel/parser@^7.7.5":
version "7.7.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71"
integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==
"@babel/template@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b"
integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/parser" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/traverse@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558"
integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.4"
"@babel/helper-function-name" "^7.7.4"
"@babel/helper-split-export-declaration" "^7.7.4"
"@babel/parser" "^7.7.4"
"@babel/types" "^7.7.4"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
"@babel/types@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193"
integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==
dependencies:
esutils "^2.0.2"
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@ng-bootstrap/ng-bootstrap@^5.1.4":
version "5.1.4"
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-5.1.4.tgz#1ace4d4a7b80017fb1c55547a5569993b4742b5d"
integrity sha512-UtL9GBkAMy0O/0Rkc4DG1WoFDWhAnAdvsQuJ1IFLmlN2v6HAX+E84tgUK0n15WLBhYBXXuhRx0dIW2jafjg1xQ==
dependencies:
tslib "^1.9.0"
"@types/color-name@^1.1.1":
version "1.1.1"
@@ -130,12 +191,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/semver@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
dependencies:
"@types/node" "*"
"@types/semver@^6.0.2":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
JSONStream@^1.3.4, JSONStream@^1.3.5:
version "1.3.5"
@@ -203,6 +262,11 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
@@ -290,11 +354,6 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@@ -328,13 +387,6 @@ bin-links@^1.1.2:
graceful-fs "^4.1.11"
write-file-atomic "^2.3.0"
bindings@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
dependencies:
file-uri-to-path "1.0.0"
bl@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
@@ -380,10 +432,10 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
builder-util-runtime@8.7.0:
version "8.7.0"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d"
integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==
builder-util-runtime@8.4.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.4.0.tgz#3163fffc078e6b8f3dd5b6eb12a8345573590682"
integrity sha512-CJB/eKfPf2vHrkmirF5eicVnbDCkMBbwd5tRYlTlgud16zFeqD7QmrVUAOEXdnsrcNkiLg9dbuUsQKtl/AwsYQ==
dependencies:
debug "^4.1.1"
sax "^1.2.4"
@@ -448,7 +500,7 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^2.0.1:
chalk@^2.0.0, chalk@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -633,6 +685,13 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
dependencies:
safe-buffer "~5.1.1"
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@@ -666,6 +725,17 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
@@ -704,7 +774,7 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"
debug@^4.1.1:
debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@@ -862,18 +932,24 @@ electron-localshortcut@^3.1.0:
keyboardevent-from-electron-accelerator "^1.1.0"
keyboardevents-areequal "^0.2.1"
electron-updater@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.1.tgz#9d485b6262bc56fcf7ee62b1dc1b3b105a3e96a7"
integrity sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==
electron-updater@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.2.0.tgz#f9ecfc657f65ead737d42b9efecf628d3756b550"
integrity sha512-GuS3g7HDh17x/SaFjxjswlWUaKHczksYkV2Xc5CKj/bZH0YCvTSHtOmnBAdAmCk99u/71p3zP8f0jIqDfGcjww==
dependencies:
"@types/semver" "^7.1.0"
builder-util-runtime "8.7.0"
fs-extra "^9.0.0"
"@types/semver" "^6.0.2"
builder-util-runtime "8.4.0"
fs-extra "^8.1.0"
js-yaml "^3.13.1"
lazy-val "^1.0.4"
lodash.isequal "^4.5.0"
semver "^7.1.3"
pako "^1.0.10"
semver "^6.3.0"
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0:
version "8.0.0"
@@ -940,6 +1016,11 @@ esprima@^4.0.0:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@@ -953,6 +1034,19 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
expand-template@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
@@ -988,11 +1082,6 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
find-npm-prefix@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
@@ -1068,15 +1157,14 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-extra@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^1.0.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^1.2.5:
version "1.2.6"
@@ -1186,6 +1274,18 @@ github-from-package@0.0.0:
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.3, glob@^7.1.1, glob@^7.1.3:
version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
@@ -1205,6 +1305,11 @@ global-dirs@^0.1.0:
dependencies:
ini "^1.3.4"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
got@^6.7.1:
version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -1383,6 +1488,11 @@ invert-kv@^1.0.0:
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
ip-regex@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -1489,10 +1599,15 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
js-yaml@3.14.0, js-yaml@^3.13.1:
version "3.14.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@3.13.1, js-yaml@^3.13.1:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -1502,6 +1617,11 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -1522,12 +1642,17 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsonfile@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
json5@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
dependencies:
universalify "^1.0.0"
minimist "^1.2.0"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
@@ -1556,12 +1681,12 @@ keyboardevents-areequal@^0.2.1:
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
keytar@^5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.6.0.tgz#7b5d4bd043d17211163640be6c4a27a49b12bb39"
integrity sha512-ueulhshHSGoryfRXaIvTj0BV1yB0KddBGhGoqCxSN9LR1Ks1GKuuCdVhF+2/YOs5fMl6MlTI9On1a4DHDXoTow==
keytar@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.0.0.tgz#c89b6b7a4608fd7af633d9f8474b1a7eb97cbe6f"
integrity sha512-a5UheK59YOlJf9i+2Osaj/kkH6mK0RCHVMtJ84u6ZfbfRIbOJ/H4b5VlOF/LgNHF6s78dRSBzZnvIuPiBKv6wg==
dependencies:
nan "2.14.1"
nan "2.14.0"
prebuild-install "5.3.3"
latest-version@^3.0.0:
@@ -1588,6 +1713,13 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
dependencies:
invert-kv "^2.0.0"
libcipm@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-3.0.3.tgz#2e764effe0b90d458790dab3165794c804075ed3"
@@ -1803,6 +1935,11 @@ lodash.without@~4.4.0:
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
lodash@^4.17.13:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
lowercase-keys@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
@@ -1854,6 +1991,13 @@ make-fetch-happen@^4.0.1:
socks-proxy-agent "^4.0.0"
ssri "^6.0.0"
map-age-cleaner@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
dependencies:
p-defer "^1.0.0"
meant@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
@@ -1866,6 +2010,15 @@ mem@^1.1.0:
dependencies:
mimic-fn "^1.0.0"
mem@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
dependencies:
map-age-cleaner "^0.1.1"
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
mime-db@1.40.0:
version "1.40.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
@@ -1883,6 +2036,11 @@ mimic-fn@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
@@ -1979,25 +2137,32 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@2.14.1, nan@^2.13.2, nan@^2.14.0:
version "2.14.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nan@2.14.0, nan@^2.13.2, nan@^2.14.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
napi-build-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
ngx-toastr@^12.0.1:
version "12.0.1"
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-12.0.1.tgz#288c8ef505f1216aa4952cd2a8c6fa7c57a54ccc"
integrity sha512-PABtbn2dyHweVSbo/py1W3veXzcmZO7uVItfTW9AykSSeAUju3gOCgauAw89km0aJ9EBcPOieaoI+9tAR7Pfug==
ngx-toastr@^11.2.1:
version "11.2.1"
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-11.2.1.tgz#130dcb416499f4419b18c39ad9cfea2e7790c7c4"
integrity sha512-qLZA+h1lIGLQ1HAJpx5JJ8i87PAZPAN6MnexmrWipSONqrK4fRh+nUKIxqmcckIiD16dgu2O5SNloSJymTKUAw==
dependencies:
tslib "^1.9.0"
node-abi@^2.16.0, node-abi@^2.7.0:
version "2.16.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.16.0.tgz#7df94e9c0a7a189f4197ab84bac8089ef5894992"
integrity sha512-+sa0XNlWDA6T+bDLmkCUYn6W5k5W6BPRL6mqzSCs6H/xUgtl4D5x2fORKDzopKiU6wsyn/+wXlRXwXeSp+mtoA==
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-abi@^2.13.0, node-abi@^2.7.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.13.0.tgz#e2f2ec444d0aca3ea1b3874b6de41d1665828f63"
integrity sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==
dependencies:
semver "^5.4.1"
@@ -2045,10 +2210,10 @@ node-gyp@^4.0.0:
tar "^4.4.8"
which "1"
node-pty@^0.10.0-beta9:
version "0.10.0-beta9"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta9.tgz#e5a795f9b53948346803cb71bac4ffc02e7909f0"
integrity sha512-Qm6uSH30FUcAhJ9s76C+lgvTsOW2cHUbkIGjCdOVCL0c7S4DxsmKBRgjcr+guUK9d9KwfuZHeSjXYWjpJFPe4w==
node-pty@^0.10.0-beta2:
version "0.10.0-beta3"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta3.tgz#a33c9fc67c9e4d4f124111e1da2a72b0783008e7"
integrity sha512-j7MoJ3K999jrT9gAVs7JvM/skAQXQITrZK/PhL9B4W4GAPkANKwdu9uEtNvYionQ9dV8gRGte7lg9D2cRDdAiA==
dependencies:
nan "^2.14.0"
@@ -2351,6 +2516,15 @@ os-locale@^2.0.0:
lcid "^1.0.0"
mem "^1.1.0"
os-locale@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
dependencies:
execa "^1.0.0"
lcid "^2.0.0"
mem "^4.0.0"
os-tmpdir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -2364,11 +2538,21 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-is-promise@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
p-limit@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@@ -2464,6 +2648,11 @@ pacote@^9.1.0, pacote@^9.2.3, pacote@^9.5.0:
unique-filename "^1.1.1"
which "^1.3.1"
pako@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
parallel-transform@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
@@ -2493,7 +2682,7 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2:
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
path-key@^2.0.0:
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
@@ -2528,7 +2717,7 @@ pkg-up@^2.0.0:
dependencies:
find-up "^2.1.0"
prebuild-install@5.3.3, prebuild-install@^5.3.0:
prebuild-install@5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e"
integrity sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==
@@ -2841,6 +3030,13 @@ resolve@^1.10.0:
dependencies:
path-parse "^1.0.6"
resolve@^1.3.2:
version "1.14.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.0.tgz#6d14c6f9db9f8002071332b600039abf82053f64"
integrity sha512-uviWSi5N67j3t3UKFxej1loCH0VZn5XuqdNxoLShPcYPw6cUZn74K1VRj+9myynRX03bxIBEkwlkob/ujLsJVw==
dependencies:
path-parse "^1.0.6"
retry@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
@@ -2865,15 +3061,15 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs-compat@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.5.tgz#073c40510f29c45a2a5fc02dde87f8c3ad75f2c2"
integrity sha512-F42sssVbUyWH4vJswEo6m+Eh02xHv3q93n8S7nUJO58R7sbc3CvJIOts605zdaBhWa1xMB9aVSyqPqhQ5q3eXg==
rxjs-compat@^6.5.3:
version "6.5.3"
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.3.tgz#18440949b2678bf87a78a754009676b2c49183dc"
integrity sha512-BIJX2yovz3TBpjJoAZyls2QYuU6ZiCaZ+U96SmxQpuSP/qDUfiXPKOVLbThBB2WZijNHkdTTJXKRwvv5Y48H7g==
rxjs@^6.5.5:
version "6.5.5"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec"
integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==
rxjs@^6.5.3:
version "6.5.3"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
dependencies:
tslib "^1.9.0"
@@ -2904,32 +3100,16 @@ semver-diff@^2.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
serialport@^8.0.7:
version "8.0.7"
resolved "https://registry.yarnpkg.com/serialport/-/serialport-8.0.7.tgz#9f28b1b7c47333a0962f5505a1c3feb1d90f89a9"
integrity sha512-R9bfNebs2dblYf5sD/Aaa7j8+siP4X7TGT02lqHM9DF5fyjlrPGXmsLw9+LKOz1AvjGjkxf2NzBVnDpqRX7clQ==
dependencies:
"@serialport/binding-mock" "^8.0.6"
"@serialport/bindings" "^8.0.7"
"@serialport/parser-byte-length" "^8.0.6"
"@serialport/parser-cctalk" "^8.0.6"
"@serialport/parser-delimiter" "^8.0.6"
"@serialport/parser-readline" "^8.0.6"
"@serialport/parser-ready" "^8.0.6"
"@serialport/parser-regex" "^8.0.6"
"@serialport/stream" "^8.0.6"
debug "^4.1.1"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -3018,6 +3198,11 @@ sorted-union-stream@~2.1.3:
from2 "^1.3.0"
stream-iterate "^1.1.0"
source-map@^0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
spdx-correct@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@@ -3119,6 +3304,15 @@ string-width@^1.0.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string-width@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string-width@^4.1.0, string-width@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
@@ -3166,6 +3360,13 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"
strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
@@ -3282,6 +3483,11 @@ tiny-relative-date@^1.3.0:
resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
@@ -3343,10 +3549,10 @@ unique-string@^1.0.0:
dependencies:
crypto-random-string "^1.0.0"
universalify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
unpipe@~1.0.0:
version "1.0.0"
@@ -3477,10 +3683,10 @@ windows-blurbehind@^1.0.1:
resolved "https://registry.yarnpkg.com/windows-blurbehind/-/windows-blurbehind-1.0.1.tgz#ff098713873304e38330b2c54cc41bb369b587b9"
integrity sha512-1HzHfCiM1ayrbACJu5qE9zELV24uX/tINT6kxaZwLY3rtQAoeav6x9z7LFHWoLaGDN/sYbnK+9Vk0cz7fsk5HQ==
windows-native-registry@^1.0.17:
version "1.0.17"
resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.17.tgz#d8cce48b364703a55c226690431b325114405022"
integrity sha512-u9Fp9TyDo5dvhlW6hYBOdHPETtAahXKxo3jeW5EXwNK7qa+nSNopQycN1drtBVWe3jpJXvyKpt9zrjiDd+u4JQ==
windows-native-registry@^1.0.16:
version "1.0.16"
resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.16.tgz#761f21b7dfa6cdb28479cf9bc66b705592e3ae6a"
integrity sha512-RROB5VPEafEJLK93vdttfq4BGWaMWI/OHjAE2cqA31eMjmPShD2KaerlhEfUgqa5THsaAbYUK0LQKc4UQTjIMg==
dependencies:
nan "^2.14.0"
@@ -3566,10 +3772,18 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yargs-parser@^18.1.1:
version "18.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.1.tgz#bf7407b915427fc760fcbbccc6c82b4f0ffcbd37"
integrity sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA==
yargs-parser@^13.0.0:
version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^16.1.0:
version "16.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1"
integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
@@ -3581,6 +3795,23 @@ yargs-parser@^9.0.2:
dependencies:
camelcase "^4.1.0"
yargs@13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301"
integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==
dependencies:
cliui "^4.0.0"
find-up "^3.0.0"
get-caller-file "^2.0.1"
os-locale "^3.1.0"
require-directory "^2.1.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^3.0.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^13.0.0"
yargs@^11.0.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"
@@ -3599,10 +3830,10 @@ yargs@^11.0.0:
y18n "^3.2.1"
yargs-parser "^9.0.2"
yargs@^15.3.1:
version "15.3.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b"
integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==
yargs@^15.0.2:
version "15.0.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.0.2.tgz#4248bf218ef050385c4f7e14ebdf425653d13bd3"
integrity sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==
dependencies:
cliui "^6.0.0"
decamelize "^1.2.0"
@@ -3614,9 +3845,9 @@ yargs@^15.3.1:
string-width "^4.2.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^18.1.1"
yargs-parser "^16.1.0"
zone.js@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16"
integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==
zone.js@^0.10.2:
version "0.10.2"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.2.tgz#67ca084b3116fc33fc40435e0d5ea40a207e392e"
integrity sha512-UAYfiuvxLN4oyuqhJwd21Uxb4CNawrq6fPS/05Su5L4G+1TN+HVDJMUHNMobVQDFJRir2cLAODXwluaOKB7HFg==

View File

@@ -1,7 +1,4 @@
#!/bin/bash
cat > '/usr/bin/${executable}' << END
#!/bin/sh
'/opt/${productFilename}/${executable}' --no-sandbox $@
END
chmod +x '/usr/bin/${executable}'
# Link to the binary
ln -sf '/opt/${productFilename}/${executable}' '/usr/bin/${executable}'

View File

@@ -1,16 +0,0 @@
const fs = require('fs')
const signHook = require('./afterSignHook')
module.exports = async function (params) {
// notarize the app on Mac OS only.
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
return
}
console.log('afterBuild hook triggered')
let pkgName = fs.readdirSync('dist').find(x => x.endsWith('.pkg'))
signHook({
appOutDir: 'dist',
_pathOverride: pkgName,
})
}

View File

@@ -6,14 +6,14 @@ const notarizer = require('electron-notarize')
module.exports = async function (params) {
// notarize the app on Mac OS only.
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
if (process.platform !== 'darwin' || process.env.GITHUB_REF !== 'refs/heads/master' || process.env.GITHUB_REF && !process.env.GITHUB_REF.startsWith('refs/tags/')) {
return
}
console.log('afterSign hook triggered', params)
let appId = 'org.terminus'
let appPath = path.join(params.appOutDir, params._pathOverride || `${params.packager.appInfo.productFilename}.app`)
let appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`)
if (!fs.existsSync(appPath)) {
throw new Error(`Cannot find application at: ${appPath}`)
}

View File

@@ -1,62 +0,0 @@
---
appId: org.terminus
productName: Terminus
compression: normal
afterSign: "./build/mac/afterSignHook.js"
afterAllArtifactBuild: "./build/mac/afterBuildHook.js"
files:
- "**/*"
- dist
extraResources:
- builtin-plugins
- extras
publish:
- provider: github
win:
icon: "./build/windows/icon.ico"
artifactName: terminus-${version}-portable.${ext}
rfc3161TimeStampServer: http://sha256timestamp.ws.symantec.com/sha256/timestamp
nsis:
oneClick: false
artifactName: terminus-${version}-setup.${ext}
installerIcon: "./build/windows/icon.ico"
mac:
category: public.app-category.video
icon: "./build/mac/icon.icns"
artifactName: terminus-${version}-macos.${ext}
hardenedRuntime: true
entitlements: "./build/mac/entitlements.plist"
entitlementsInherit: "./build/mac/entitlements.plist"
extendInfo:
NSRequiresAquaSystemAppearance: false
pkg:
artifactName: terminus-${version}-macos.pkg
linux:
category: Utilities
icon: "./build/icons"
artifactName: terminus-${version}-linux.${ext}
executableArgs:
- "--no-sandbox"
snap:
plugs:
- default
- system-files
- system-observe
deb:
depends:
- gconf2
- gconf-service
- gnome-keyring
- libnotify4
- libsecret-1-0
- libappindicator1
- libxtst6
- libnss3
afterInstall: build/linux/after-install.tpl
rpm:
depends:
- screen
- gnome-keyring

Binary file not shown.

Binary file not shown.

View File

@@ -1,35 +1,39 @@
{
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.13.0",
"@sentry/cli": "^1.52.3",
"@sentry/electron": "^1.2.1",
"@angular/compiler": "9.0.0-rc.5",
"@angular/compiler-cli": "9.0.0-rc.5",
"@angular/core": "9.0.0-rc.5",
"@fortawesome/fontawesome-free": "^5.11.2",
"@ngtools/webpack": "9.0.0-rc.5",
"@sentry/cli": "^1.49.0",
"@sentry/electron": "^1.0.0",
"@types/electron-config": "^3.2.2",
"@types/electron-debug": "^2.1.0",
"@types/js-yaml": "^3.12.4",
"@types/js-yaml": "^3.12.1",
"@types/node": "12.7.12",
"@types/webpack-env": "^1.15.2",
"@typescript-eslint/eslint-plugin": "^2.26.0",
"@typescript-eslint/parser": "^2.34.0",
"@types/webpack-env": "1.14.1",
"@typescript-eslint/eslint-plugin": "^2.9.0",
"@typescript-eslint/parser": "^2.10.0",
"apply-loader": "2.0.0",
"awesome-typescript-loader": "^5.0.0",
"core-js": "^3.6.5",
"cross-env": "7.0.2",
"css-loader": "3.4.2",
"electron": "^8.2.5",
"electron-builder": "22.6.1",
"core-js": "^3.4.2",
"cross-env": "6.0.3",
"css-loader": "3.4.0",
"electron": "^7.1.3",
"electron-builder": "22.1.0",
"electron-download": "^4.1.1",
"electron-installer-snap": "^5.0.0",
"electron-installer-snap": "^4.1.0",
"electron-notarize": "^0.1.1",
"electron-rebuild": "^1.10.1",
"eslint": "^6.8.0",
"eslint-plugin-import": "^2.20.2",
"electron-rebuild": "^1.8.5",
"eslint": "^6.7.1",
"eslint-plugin-import": "^2.18.2",
"file-loader": "^5.0.2",
"graceful-fs": "^4.2.4",
"graceful-fs": "^4.2.2",
"html-loader": "0.5.5",
"json-loader": "0.5.7",
"node-abi": "^2.16.0",
"node-gyp": "^6.1.0",
"node-sass": "^4.14.1",
"node-abi": "^2.12.0",
"node-gyp": "^6.0.1",
"node-sass": "^4.13.0",
"npmlog": "4.1.2",
"npx": "^10.2.0",
"pug": "^2.0.4",
@@ -37,37 +41,104 @@
"pug-lint": "^2.6.0",
"pug-loader": "^2.4.0",
"pug-static-loader": "2.0.0",
"raw-loader": "4.0.1",
"raw-loader": "4.0.0",
"sass-loader": "^8.0.0",
"shelljs": "0.8.4",
"shelljs": "0.8.3",
"source-code-pro": "^2.30.2",
"source-sans-pro": "3.6.0",
"style-loader": "^1.1.4",
"style-loader": "^1.0.1",
"svg-inline-loader": "^0.8.0",
"to-string-loader": "1.1.6",
"tslib": "^2.0.0",
"typedoc": "^0.17.6",
"typescript": "^3.9.3",
"tslib": "^1.10.0",
"typedoc": "^0.15.3",
"typescript": "^3.7.3",
"url-loader": "^3.0.0",
"val-loader": "2.1.1",
"webpack": "^5.0.0-beta.16",
"val-loader": "2.1.0",
"webpack": "4",
"webpack-cli": "^3.3.10",
"yaml-loader": "0.6.0"
"yaml-loader": "0.5.0"
},
"resolutions": {
"*/node-abi": "^2.14.0"
"*/node-abi": "^2.8.0"
},
"build": {
"appId": "org.terminus",
"productName": "Terminus",
"compression": "normal",
"afterSign": "./build/mac/afterSignHook.js",
"files": [
"**/*",
"dist"
],
"extraResources": [
"builtin-plugins",
"extras"
],
"win": {
"icon": "./build/windows/icon.ico",
"artifactName": "terminus-${version}-setup.exe",
"rfc3161TimeStampServer": "http://sha256timestamp.ws.symantec.com/sha256/timestamp"
},
"nsis": {
"oneClick": false,
"artifactName": "terminus-${version}-setup.${ext}",
"installerIcon": "./build/windows/icon.ico"
},
"publish": [
{
"provider": "github"
}
],
"portable": {
"artifactName": "terminus-${version}-portable.exe"
},
"mac": {
"category": "public.app-category.video",
"icon": "./build/mac/icon.icns",
"artifactName": "terminus-${version}-macos.${ext}",
"hardenedRuntime": true,
"entitlements": "./build/mac/entitlements.plist",
"entitlementsInherit": "./build/mac/entitlements.plist",
"extendInfo": {
"NSRequiresAquaSystemAppearance": false
}
},
"pkg": {
"artifactName": "terminus-${version}-macos.pkg"
},
"linux": {
"category": "Utilities",
"icon": "./build/icons",
"artifactName": "terminus-${version}-linux.${ext}"
},
"deb": {
"depends": [
"gconf2",
"gconf-service",
"libnotify4",
"libsecret-1-0",
"libappindicator1",
"libxtst6",
"libnss3"
],
"afterInstall": "build/linux/after-install.tpl"
},
"rpm": {
"depends": [
"screen",
"gnome-python2-gnomekeyring"
]
}
},
"scripts": {
"build": "npm run build:typings && webpack --color --config app/webpack.main.config.js && webpack --color --config app/webpack.config.js && webpack --color --config terminus-core/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-terminal/webpack.config.js && webpack --color --config terminus-plugin-manager/webpack.config.js && webpack --color --config terminus-community-color-schemes/webpack.config.js && webpack --color --config terminus-ssh/webpack.config.js && webpack --color --config terminus-serial/webpack.config.js",
"build:typings": "node scripts/build-typings.js",
"build": "npm run build:typings && webpack --color --config app/webpack.main.config.js && webpack --color --config app/webpack.config.js && webpack --color --config terminus-core/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-terminal/webpack.config.js && webpack --color --config terminus-plugin-manager/webpack.config.js && webpack --color --config terminus-community-color-schemes/webpack.config.js && webpack --color --config terminus-ssh/webpack.config.js",
"build:typings": "tsc --project terminus-core/tsconfig.typings.json && tsc --project terminus-settings/tsconfig.typings.json && tsc --project terminus-terminal/tsconfig.typings.json && tsc --project terminus-plugin-manager/tsconfig.typings.json && tsc --project terminus-ssh/tsconfig.typings.json",
"watch": "cross-env TERMINUS_DEV=1 webpack --progress --color --watch",
"start": "cross-env TERMINUS_DEV=1 electron app --debug",
"prod": "cross-env TERMINUS_DEV=1 electron app",
"docs": "typedoc --out docs/api terminus-core/src && typedoc --out docs/api/terminal --tsconfig terminus-terminal/tsconfig.typings.json terminus-terminal/src && typedoc --out docs/api/settings --tsconfig terminus-settings/tsconfig.typings.json terminus-settings/src",
"lint": "eslint --ext ts */src */lib",
"lint": "eslint --ext ts */src",
"postinstall": "node ./scripts/install-deps.js"
},
"repository": "eugeny/terminus",
"author": "Eugene Pankov",
"license": "MIT"
"repository": "eugeny/terminus"
}

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env node
const builder = require('electron-builder').build
const vars = require('./vars')
const fs = require('fs')
const signHook = require('../build/mac/afterSignHook')
const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
const isCI = !!process.env.GITHUB_REF
builder({
dir: true,
@@ -15,7 +14,4 @@ builder({
},
},
publish: isTag ? 'always' : 'onTag',
}).catch(e => {
console.error(e)
process.exit(1)
})
}).catch(() => process.exit(1))

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env node
const sh = require('shelljs')
const vars = require('./vars')
const log = require('npmlog')
vars.builtinPlugins.forEach(plugin => {
log.info('typings', plugin)
sh.exec(`npx tsc --project ${plugin}/tsconfig.typings.json`)
})

View File

@@ -7,7 +7,7 @@ const isCI = !!process.env.GITHUB_REF
builder({
dir: true,
win: ['nsis', 'zip'],
win: ['nsis', 'portable'],
config: {
extraMetadata: {
version: vars.version,

View File

@@ -21,10 +21,5 @@ exports.builtinPlugins = [
'terminus-community-color-schemes',
'terminus-plugin-manager',
'terminus-ssh',
'terminus-serial',
]
exports.bundledModules = [
'@angular',
'@ng-bootstrap',
]
exports.electronVersion = electronInfo.version

View File

@@ -1,6 +1,6 @@
{
"name": "terminus-community-color-schemes",
"version": "1.0.104-nightly.0",
"version": "1.0.98-nightly.0",
"description": "Community color schemes for Terminus",
"keywords": [
"terminus-builtin-plugin"

View File

@@ -1,14 +0,0 @@
{
"extends": "../tsconfig.json",
"exclude": ["node_modules", "dist", "typings"],
"compilerOptions": {
"baseUrl": "src",
"emitDeclarationOnly": true,
"declaration": true,
"declarationDir": "./typings",
"paths": {
"terminus-*": ["../../terminus-*"],
"*": ["../../app/node_modules/*"]
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "terminus-core",
"version": "1.0.104-nightly.0",
"version": "1.0.98-nightly.0",
"description": "Terminus core",
"keywords": [
"terminus-builtin-plugin"
@@ -30,7 +30,7 @@
"ng2-dnd": "^5.0.2",
"ngx-perfect-scrollbar": "^8.0.0",
"shell-escape": "^0.2.0",
"uuid": "^8.0.0",
"uuid": "^3.3.2",
"winston": "^3.2.1"
},
"peerDependencies": {

View File

@@ -1,13 +1,11 @@
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
export { TabHeaderComponent } from '../components/tabHeader.component'
export { SplitTabComponent, SplitContainer } from '../components/splitTab.component'
export { TabRecoveryProvider, RecoveredTab, RecoveryToken } from './tabRecovery'
export { TabRecoveryProvider, RecoveredTab } from './tabRecovery'
export { ToolbarButtonProvider, ToolbarButton } from './toolbarButtonProvider'
export { ConfigProvider } from './configProvider'
export { HotkeyProvider, HotkeyDescription } from './hotkeyProvider'
export { Theme } from './theme'
export { TabContextMenuItemProvider } from './tabContextMenuProvider'
export { SelectorOption } from './selector'
export { AppService } from '../services/app.service'
export { ConfigService } from '../services/config.service'
@@ -20,4 +18,3 @@ export { HostAppService, Platform } from '../services/hostApp.service'
export { ShellIntegrationService } from '../services/shellIntegration.service'
export { ThemesService } from '../services/themes.service'
export { TabsService } from '../services/tabs.service'
export * from '../utils'

View File

@@ -1,8 +0,0 @@
export interface SelectorOption<T> {
name: string
description?: string
result?: T
icon?: string
freeInputPattern?: string
callback?: (string?) => void
}

View File

@@ -12,12 +12,6 @@ export interface RecoveredTab {
options?: any
}
export interface RecoveryToken {
[_: string]: any
type: string
tabColor?: string|null
}
/**
* Extend to enable recovery for your custom tab.
* This works in conjunction with [[getRecoveryToken()]]
@@ -40,5 +34,5 @@ export abstract class TabRecoveryProvider {
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
* or `null` if this token is from a different tab type or is not supported
*/
abstract async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null>
abstract async recover (recoveryToken: any): Promise<RecoveredTab|null>
}

View File

@@ -10,8 +10,8 @@ title-bar(
.inset.background(*ngIf='hostApp.platform == Platform.macOS && config.store.appearance.frame == "thin" && config.store.appearance.tabsLocation == "top"')
.tabs(
dnd-sortable-container,
[sortableData]='app.tabs',
)
//- [sortableData]='app.tabs',
tab-header(
*ngFor='let tab of app.tabs; let idx = index',
dnd-sortable,
@@ -38,7 +38,7 @@ title-bar(
button.btn.btn-secondary.btn-tab-bar(
[title]='button.title',
(click)='button.click && button.click()',
[fastHtmlBind]='button.icon',
[innerHTML]='sanitizeIcon(button.icon)',
ngbDropdownToggle,
)
div(*ngIf='button.submenu', ngbDropdownMenu)
@@ -49,7 +49,7 @@ title-bar(
)
.icon-wrapper(
*ngIf='hasIcons(button.submenuItems)',
[fastHtmlBind]='item.icon'
[innerHTML]='sanitizeIcon(item.icon)'
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
@@ -64,7 +64,7 @@ title-bar(
button.btn.btn-secondary.btn-tab-bar(
[title]='button.title',
(click)='button.click && button.click()',
[fastHtmlBind]='button.icon',
[innerHTML]='sanitizeIcon(button.icon)',
ngbDropdownToggle,
)
div(*ngIf='button.submenu', ngbDropdownMenu)
@@ -75,7 +75,7 @@ title-bar(
)
.icon-wrapper(
*ngIf='hasIcons(button.submenuItems)',
[fastHtmlBind]='item.icon'
[innerHTML]='sanitizeIcon(item.icon)'
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
@@ -83,7 +83,7 @@ title-bar(
*ngIf='updatesAvailable',
title='Update available - Click to install',
(click)='updateApp()',
[fastHtmlBind]='updateIcon'
[innerHTML]='sanitizeIcon(updateIcon)'
)
window-controls.background(

View File

@@ -64,7 +64,6 @@ $tab-border-radius: 4px;
&>.drag-space {
min-width: 1px;
flex: 1 0 1%;
margin-top: 2px; // for window resizing
-webkit-app-region: drag;
&.persistent {

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component, Inject, Input, HostListener, HostBinding } from '@angular/core'
import { trigger, style, animate, transition, state } from '@angular/animations'
import { DomSanitizer } from '@angular/platform-browser'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { ElectronService } from '../services/electron.service'
@@ -20,8 +20,8 @@ import { AppService, ToolbarButton, ToolbarButtonProvider } from '../api'
/** @hidden */
@Component({
selector: 'app-root',
template: require('./appRoot.component.pug'),
styles: [require('./appRoot.component.scss')],
templateUrl: './appRoot.component.pug',
styleUrls: ['./appRoot.component.scss'],
animations: [
trigger('animateTab', [
state('in', style({
@@ -75,6 +75,7 @@ export class AppRootComponent {
public hostApp: HostAppService,
public config: ConfigService,
public app: AppService,
private domSanitizer: DomSanitizer,
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
log: LogService,
ngbModal: NgbModal,
@@ -108,15 +109,6 @@ export class AppRootComponent {
if (hotkey === 'previous-tab') {
this.app.previousTab()
}
if (hotkey === 'move-tab-left') {
this.app.moveSelectedTabLeft()
}
if (hotkey === 'move-tab-right') {
this.app.moveSelectedTabRight()
}
if (hotkey === 'reopen-tab') {
this.app.reopenLastTab()
}
}
if (hotkey === 'toggle-fullscreen') {
this.hostApp.toggleFullscreen()
@@ -128,8 +120,17 @@ export class AppRootComponent {
this.docking.dock()
})
this.hostApp.secondInstance$.subscribe(() => {
this.presentWindow()
})
this.hotkeys.globalHotkey.subscribe(() => {
this.onGlobalHotkey()
})
this.hostApp.windowCloseRequest$.subscribe(async () => {
this.app.closeWindow()
if (await this.app.closeAllTabs()) {
this.hostApp.closeWindow()
}
})
if (window['safeModeReason']) {
@@ -168,6 +169,40 @@ export class AppRootComponent {
})
}
onGlobalHotkey () {
if (this.hostApp.getWindow().isFocused()) {
this.hideWindow()
} else {
this.presentWindow()
}
}
presentWindow () {
if (!this.hostApp.getWindow().isVisible()) {
// unfocused, invisible
this.hostApp.getWindow().show()
this.hostApp.getWindow().focus()
} else {
if (this.config.store.appearance.dock === 'off') {
// not docked, visible
setTimeout(() => {
this.hostApp.getWindow().focus()
})
} else {
// docked, visible
this.hostApp.getWindow().hide()
}
}
}
hideWindow () {
this.electron.loseFocus()
this.hostApp.getWindow().blur()
if (this.hostApp.platform !== Platform.macOS) {
this.hostApp.getWindow().hide()
}
}
async ngOnInit () {
this.ready = true
@@ -219,6 +254,10 @@ export class AppRootComponent {
return submenuItems.some(x => !!x.icon)
}
sanitizeIcon (icon: string): any {
return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
}
private getToolbarButtons (aboveZero: boolean): ToolbarButton[] {
let buttons: ToolbarButton[] = []
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {

View File

@@ -1,6 +1,5 @@
import { Observable, Subject } from 'rxjs'
import { ViewRef } from '@angular/core'
import { RecoveryToken } from '../api/tabRecovery'
/**
* Represents an active "process" inside a tab,
@@ -14,11 +13,6 @@ export interface BaseTabProcess {
* Abstract base class for custom tab components
*/
export abstract class BaseTabComponent {
/**
* Parent tab (usually a SplitTabComponent)
*/
parent: BaseTabComponent|null = null
/**
* Current tab title
*/
@@ -44,7 +38,7 @@ export abstract class BaseTabComponent {
*/
color: string|null = null
hasFocus = false
protected hasFocus = false
/**
* Ping this if your recovery state has been changed and you want
@@ -68,7 +62,7 @@ export abstract class BaseTabComponent {
get destroyed$ (): Observable<void> { return this.destroyed }
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
protected constructor () {
constructor () {
this.focused$.subscribe(() => {
this.hasFocus = true
})
@@ -77,7 +71,7 @@ export abstract class BaseTabComponent {
})
}
setTitle (title: string): void {
setTitle (title: string) {
this.title = title
if (!this.customTitle) {
this.titleChange.next(title)
@@ -89,7 +83,7 @@ export abstract class BaseTabComponent {
*
* @param {type} progress: value between 0 and 1, or `null` to remove
*/
setProgress (progress: number|null): void {
setProgress (progress: number|null) {
this.progress.next(progress)
if (progress) {
if (this.progressClearTimeout) {
@@ -124,7 +118,7 @@ export abstract class BaseTabComponent {
* @return JSON serializable tab state representation
* for your [[TabRecoveryProvider]] to parse
*/
async getRecoveryToken (): Promise<RecoveryToken|null> {
async getRecoveryToken (): Promise<any> {
return null
}
@@ -142,11 +136,11 @@ export abstract class BaseTabComponent {
return true
}
emitFocused (): void {
emitFocused () {
this.focused.next()
}
emitBlurred (): void {
emitBlurred () {
this.blurred.next()
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { NgZone, Component, Input, HostBinding, HostListener } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'

View File

@@ -1,11 +1,10 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component, Input, ElementRef, ViewChild } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
/** @hidden */
@Component({
selector: 'rename-tab-modal',
template: require('./renameTabModal.component.pug'),
templateUrl: './renameTabModal.component.pug',
})
export class RenameTabModalComponent {
@Input() value: string

View File

@@ -3,7 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
/** @hidden */
@Component({
template: require('./safeModeModal.component.pug'),
templateUrl: './safeModeModal.component.pug',
})
export class SafeModeModalComponent {
@Input() error: Error
@@ -14,7 +14,7 @@ export class SafeModeModalComponent {
this.error = window['safeModeReason']
}
close (): void {
close () {
this.modalInstance.dismiss()
}
}

View File

@@ -1,26 +0,0 @@
.modal-body
input.form-control(
type='text',
[(ngModel)]='filter',
autofocus,
[placeholder]='name',
(ngModelChange)='onFilterChange()'
)
.list-group.mt-3(*ngIf='filteredOptions.length')
a.list-group-item.list-group-item-action.d-flex.align-items-center(
#item,
(click)='selectOption(option)',
[class.active]='selectedIndex == i',
*ngFor='let option of filteredOptions; let i = index'
)
i.icon(
class='fa-fw fas fa-{{option.icon}}',
*ngIf='!iconIsSVG(option.icon)'
)
.icon(
[fastHtmlBind]='option.icon',
*ngIf='iconIsSVG(option.icon)'
)
.mr-2.title {{getOptionText(option)}}
.text-muted {{option.description}}

View File

@@ -1,13 +0,0 @@
.list-group {
max-height: 70vh;
overflow: auto;
}
.icon {
width: 1.25rem;
margin-right: 0.25rem;
}
.title {
margin-left: 10px;
}

View File

@@ -1,78 +0,0 @@
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { SelectorOption } from '../api/selector'
/** @hidden */
@Component({
template: require('./selectorModal.component.pug'),
styles: [require('./selectorModal.component.scss')],
})
export class SelectorModalComponent<T> {
@Input() options: SelectorOption<T>[]
@Input() filteredOptions: SelectorOption<T>[]
@Input() filter = ''
@Input() name: string
@Input() selectedIndex = 0
@ViewChildren('item') itemChildren: QueryList<ElementRef>
constructor (
public modalInstance: NgbActiveModal,
) { }
ngOnInit (): void {
this.onFilterChange()
}
@HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void {
if (event.key === 'ArrowUp') {
this.selectedIndex--
}
if (event.key === 'ArrowDown') {
this.selectedIndex++
}
if (event.key === 'Enter') {
this.selectOption(this.filteredOptions[this.selectedIndex])
}
if (event.key === 'Escape') {
this.close()
}
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
})
}
onFilterChange (): void {
const f = this.filter.trim().toLowerCase()
if (!f) {
this.filteredOptions = this.options.filter(x => !x.freeInputPattern)
} else {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
this.filteredOptions = this.options.filter(x => x.freeInputPattern || (x.name + (x.description || '')).toLowerCase().includes(f))
}
this.selectedIndex = Math.max(0, this.selectedIndex)
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
}
getOptionText (option: SelectorOption<T>): string {
if (option.freeInputPattern) {
return option.freeInputPattern.replace('%s', this.filter)
}
return option.name
}
selectOption (option: SelectorOption<T>): void {
option.callback?.(this.filter)
this.modalInstance.close(option.result)
}
close (): void {
this.modalInstance.dismiss()
}
iconIsSVG (icon: string): boolean {
return icon?.startsWith('<')
}
}

View File

@@ -3,24 +3,3 @@
position: relative;
flex: auto;
}
::ng-deep split-tab > .child {
position: absolute;
transition: 0.125s all;
opacity: .75;
&.focused {
opacity: 1;
}
&.minimized {
opacity: .1;
}
&.maximized {
z-index: 2;
box-shadow: rgba(0, 0, 0, 0.25) 0px 0px 30px;
backdrop-filter: blur(10px);
border-radius: 10px;
}
}

View File

@@ -1,7 +1,7 @@
import { Observable, Subject, Subscription } from 'rxjs'
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy } from '@angular/core'
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, OnInit, OnDestroy } from '@angular/core'
import { BaseTabComponent, BaseTabProcess } from './baseTab.component'
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from '../api/tabRecovery'
import { TabRecoveryProvider, RecoveredTab } from '../api/tabRecovery'
import { TabsService } from '../services/tabs.service'
import { HotkeysService } from '../services/hotkeys.service'
import { TabRecoveryService } from '../services/tabRecovery.service'
@@ -48,7 +48,7 @@ export class SplitContainer {
/**
* Remove unnecessarily nested child containers and renormalizes [[ratios]]
*/
normalize (): void {
normalize () {
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i]
@@ -93,7 +93,7 @@ export class SplitContainer {
return s
}
async serialize (): Promise<RecoveryToken> {
async serialize () {
const children: any[] = []
for (const child of this.children) {
if (child instanceof SplitContainer) {
@@ -138,11 +138,9 @@ export interface SplitSpannerInfo {
(change)='onSpannerAdjusted(spanner)'
></split-tab-spanner>
`,
styles: [require('./splitTab.component.scss')],
styleUrls: ['./splitTab.component.scss'],
})
export class SplitTabComponent extends BaseTabComponent implements AfterViewInit, OnDestroy {
static DIRECTIONS: SplitDirection[] = ['t', 'r', 'b', 'l']
export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
/** @hidden */
@ViewChild('vc', { read: ViewContainerRef }) viewContainer: ViewContainerRef
@@ -158,7 +156,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
_spanners: SplitSpannerInfo[] = []
private focusedTab: BaseTabComponent
private maximizedTab: BaseTabComponent|null = null
private hotkeysSubscription: Subscription
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
@@ -166,7 +163,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
private tabRemoved = new Subject<BaseTabComponent>()
private splitAdjusted = new Subject<SplitSpannerInfo>()
private focusChanged = new Subject<BaseTabComponent>()
private initialized = new Subject<void>()
get tabAdded$ (): Observable<BaseTabComponent> { return this.tabAdded }
get tabRemoved$ (): Observable<BaseTabComponent> { return this.tabRemoved }
@@ -181,11 +177,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
*/
get focusChanged$ (): Observable<BaseTabComponent> { return this.focusChanged }
/**
* Fired once tab layout is created and child tabs can be added
*/
get initialized$ (): Observable<void> { return this.initialized }
/** @hidden */
constructor (
private hotkeys: HotkeysService,
@@ -235,13 +226,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
case 'pane-nav-down':
this.navigate('b')
break
case 'pane-maximize':
if (this.maximizedTab) {
this.maximize(null)
} else if (this.getAllTabs().length > 1) {
this.maximize(this.focusedTab)
}
break
case 'close-pane':
this.removeTab(this.focusedTab)
break
@@ -250,7 +234,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
/** @hidden */
async ngAfterViewInit (): Promise<void> {
async ngOnInit () {
if (this._recoveredState) {
await this.recoverContainer(this.root, this._recoveredState)
this.layout()
@@ -261,17 +245,15 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
})
}
this.initialized.next()
this.initialized.complete()
}
/** @hidden */
ngOnDestroy (): void {
ngOnDestroy () {
this.hotkeysSubscription.unsubscribe()
}
/** @returns Flat list of all sub-tabs */
getAllTabs (): BaseTabComponent[] {
getAllTabs () {
return this.root.getAllTabs()
}
@@ -279,11 +261,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
return this.focusedTab
}
getMaximizedTab (): BaseTabComponent|null {
return this.maximizedTab
}
focus (tab: BaseTabComponent): void {
focus (tab: BaseTabComponent) {
this.focusedTab = tab
for (const x of this.getAllTabs()) {
if (x !== tab) {
@@ -294,22 +272,13 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
tab.emitFocused()
this.focusChanged.next(tab)
}
if (this.maximizedTab !== tab) {
this.maximizedTab = null
}
this.layout()
}
maximize (tab: BaseTabComponent|null): void {
this.maximizedTab = tab
this.layout()
}
/**
* Focuses the first available tab inside the given [[SplitContainer]]
*/
focusAnyIn (parent: BaseTabComponent | SplitContainer): void {
focusAnyIn (parent: BaseTabComponent | SplitContainer) {
if (!parent) {
return
}
@@ -323,9 +292,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
/**
* Inserts a new `tab` to the `side` of the `relative` tab
*/
async addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection): Promise<void> {
tab.parent = this
addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection) {
let target = (relative ? this.getParentOf(relative) : null) || this.root
let insertIndex = relative ? target.children.indexOf(relative) : -1
@@ -355,9 +322,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
target.children.splice(insertIndex, 0, tab)
this.recoveryStateChangedHint.next()
await this.initialized$.toPromise()
this.attachTabView(tab)
setImmediate(() => {
@@ -367,7 +331,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
})
}
removeTab (tab: BaseTabComponent): void {
removeTab (tab: BaseTabComponent) {
const parent = this.getParentOf(tab)
if (!parent) {
return
@@ -377,11 +341,11 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
parent.children.splice(index, 1)
this.detachTabView(tab)
tab.parent = null
this.layout()
this.tabRemoved.next(tab)
if (this.root.children.length === 0) {
this.destroy()
} else {
@@ -392,7 +356,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
/**
* Moves focus in the given direction
*/
navigate (dir: SplitDirection): void {
navigate (dir: SplitDirection) {
let rel: BaseTabComponent | SplitContainer = this.focusedTab
let parent = this.getParentOf(rel)
if (!parent) {
@@ -425,12 +389,11 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
}
async splitTab (tab: BaseTabComponent, dir: SplitDirection): Promise<BaseTabComponent|null> {
async splitTab (tab: BaseTabComponent, dir: SplitDirection) {
const newTab = await this.tabsService.duplicate(tab)
if (newTab) {
this.addTab(newTab, tab, dir)
}
return newTab
}
/**
@@ -468,18 +431,11 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
}
/** @hidden */
onSpannerAdjusted (spanner: SplitSpannerInfo): void {
onSpannerAdjusted (spanner: SplitSpannerInfo) {
this.layout()
this.splitAdjusted.next(spanner)
}
destroy (): void {
super.destroy()
for (const x of this.getAllTabs()) {
x.destroy()
}
}
private attachTabView (tab: BaseTabComponent) {
const ref = this.viewContainer.insert(tab.hostView) as EmbeddedViewRef<any> // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
this.viewRefs.set(tab, ref)
@@ -529,25 +485,14 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
if (child instanceof SplitContainer) {
this.layoutInternal(child, childX, childY, childW, childH)
} else {
const viewRef = this.viewRefs.get(child)
if (viewRef) {
const element = viewRef.rootNodes[0]
element.classList.toggle('child', true)
element.classList.toggle('maximized', child === this.maximizedTab)
element.classList.toggle('minimized', this.maximizedTab && child !== this.maximizedTab)
element.classList.toggle('focused', child === this.focusedTab)
element.style.left = `${childX}%`
element.style.top = `${childY}%`
element.style.width = `${childW}%`
element.style.height = `${childH}%`
const element = this.viewRefs.get(child)!.rootNodes[0]
element.style.position = 'absolute'
element.style.left = `${childX}%`
element.style.top = `${childY}%`
element.style.width = `${childW}%`
element.style.height = `${childH}%`
if (child === this.maximizedTab) {
element.style.left = '5%'
element.style.top = '5%'
element.style.width = '90%'
element.style.height = '90%'
}
}
element.style.opacity = child === this.focusedTab ? 1 : 0.75
}
offset += sizes[i]
@@ -575,24 +520,19 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
if (recovered) {
const tab = this.tabsService.create(recovered.type, recovered.options)
children.push(tab)
tab.parent = this
this.attachTabView(tab)
} else {
state.ratios.splice(state.children.indexOf(childState), 0)
}
}
}
while (root.ratios.length < root.children.length) {
root.ratios.push(1)
}
root.normalize()
}
}
/** @hidden */
@Injectable()
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
return {
type: SplitTabComponent,

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component, Input, HostBinding, ElementRef, Output, EventEmitter } from '@angular/core'
import { SplitContainer } from './splitTab.component'
@@ -6,7 +5,7 @@ import { SplitContainer } from './splitTab.component'
@Component({
selector: 'split-tab-spanner',
template: '',
styles: [require('./splitTabSpanner.component.scss')],
styleUrls: ['./splitTabSpanner.component.scss'],
})
export class SplitTabSpannerComponent {
@Input() container: SplitContainer
@@ -17,17 +16,13 @@ export class SplitTabSpannerComponent {
@HostBinding('class.v') isVertical = true
@HostBinding('style.left') cssLeft: string
@HostBinding('style.top') cssTop: string
@HostBinding('style.width') cssWidth: string | null
@HostBinding('style.height') cssHeight: string | null
@HostBinding('style.width') cssWidth: string
@HostBinding('style.height') cssHeight: string
private marginOffset = -5
constructor (private element: ElementRef) { }
ngAfterViewInit () {
this.element.nativeElement.addEventListener('dblclick', () => {
this.reset()
})
this.element.nativeElement.addEventListener('mousedown', (e: MouseEvent) => {
this.isActive = true
const start = this.isVertical ? e.pageY : e.pageX
@@ -54,16 +49,14 @@ export class SplitTabSpannerComponent {
diff = Math.max(diff, -this.container.ratios[this.index - 1] + 0.1)
diff = Math.min(diff, this.container.ratios[this.index] - 0.1)
if (diff) {
this.container.ratios[this.index - 1] += diff
this.container.ratios[this.index] -= diff
this.change.emit()
}
this.container.ratios[this.index - 1] += diff
this.container.ratios[this.index] -= diff
this.change.emit()
}
document.addEventListener('mouseup', offHandler, { passive: true })
document.addEventListener('mouseup', offHandler)
this.element.nativeElement.parentElement.addEventListener('mousemove', dragHandler)
}, { passive: true })
})
}
ngOnChanges () {
@@ -86,17 +79,10 @@ export class SplitTabSpannerComponent {
}
}
reset () {
const ratio = (this.container.ratios[this.index - 1] + this.container.ratios[this.index]) / 2
this.container.ratios[this.index - 1] = ratio
this.container.ratios[this.index] = ratio
this.change.emit()
}
private setDimensions (x: number, y: number, w: number, h: number) {
this.cssLeft = `${x}%`
this.cssTop = `${y}%`
this.cssWidth = w ? `${w}%` : null
this.cssHeight = h ? `${h}%` : null
this.cssWidth = w ? `${w}%` : 'initial'
this.cssHeight = h ? `${h}%` : 'initial'
}
}

View File

@@ -7,13 +7,13 @@ import { ToolbarButton, ToolbarButtonProvider } from '../api'
/** @hidden */
@Component({
selector: 'start-page',
template: require('./startPage.component.pug'),
styles: [require('./startPage.component.scss')],
templateUrl: './startPage.component.pug',
styleUrls: ['./startPage.component.scss'],
})
export class StartPageComponent {
version: string
private constructor (
constructor (
private config: ConfigService,
private domSanitizer: DomSanitizer,
public homeBase: HomeBaseService,

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component, Input, ViewChild, HostBinding, ViewContainerRef, OnChanges } from '@angular/core'
import { BaseTabComponent } from '../components/baseTab.component'
@@ -11,9 +10,9 @@ import { BaseTabComponent } from '../components/baseTab.component'
</perfect-scrollbar-->
<ng-template #placeholder></ng-template>
`,
styles: [
require('./tabBody.component.scss'),
require('./tabBody.deep.component.css'),
styleUrls: [
'./tabBody.component.scss',
'./tabBody.deep.component.css',
],
})
export class TabBodyComponent implements OnChanges {

View File

@@ -20,7 +20,7 @@ $tabs-height: 38px;
cursor: -webkit-grab;
margin-left: 10px;
width: 22px;
width: 20px;
border-radius: 10px;
text-align: center;
transition: 0.25s all;

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
import { SortableComponent } from 'ng2-dnd'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@@ -18,8 +17,8 @@ export interface SortableComponentProxy {
/** @hidden */
@Component({
selector: 'tab-header',
template: require('./tabHeader.component.pug'),
styles: [require('./tabHeader.component.scss')],
templateUrl: './tabHeader.component.pug',
styleUrls: ['./tabHeader.component.scss'],
})
export class TabHeaderComponent {
@Input() index: number
@@ -49,15 +48,12 @@ export class TabHeaderComponent {
}
ngOnInit () {
this.tab.progress$.subscribe(progress => {
this.progress = progress
})
}
ngAfterViewInit () {
if (this.hostApp.platform === Platform.macOS) {
this.parentDraggable.setDragHandle(this.handle.nativeElement)
}
this.tab.progress$.subscribe(progress => {
this.progress = progress
})
}
showRenameTabModal (): void {

View File

@@ -1,9 +1,12 @@
import { Component } from '@angular/core'
import { HostAppService } from '../services/hostApp.service'
/** @hidden */
@Component({
selector: 'title-bar',
template: require('./titleBar.component.pug'),
styles: [require('./titleBar.component.scss')],
templateUrl: './titleBar.component.pug',
styleUrls: ['./titleBar.component.scss'],
})
export class TitleBarComponent { } // eslint-disable-line @typescript-eslint/no-extraneous-class
export class TitleBarComponent {
constructor (public hostApp: HostAppService) { }
}

View File

@@ -11,7 +11,7 @@ import { CheckboxComponent } from './checkbox.component'
<label class="custom-control-label"></label>
</div>
`,
styles: [require('./toggle.component.scss')],
styleUrls: ['./toggle.component.scss'],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: ToggleComponent, multi: true },
],

View File

@@ -1,29 +1,19 @@
.container.mt-5.mb-5
.mb-4
.terminus-logo
h1.terminus-title Terminus
sup α
.mb-4
.terminus-logo
h1.terminus-title Terminus
sup α
.container
.text-center.mb-5 Thank you for downloading Terminus!
.form-line
.header
.title Enable analytics
.description Help us track the number of Terminus installs across the world!
toggle([(ngModel)]='config.store.enableAnalytics')
.form-line
.header
.title Enable SSH plugin
.description Adds an SSH connection manager UI to Terminus
toggle([(ngModel)]='enableSSH')
.form-line
.header
.title Enable Serial plugin
.description Allows attaching Terminus to serial ports
toggle([(ngModel)]='enableSerial')
toggle(
[(ngModel)]='config.store.enableAnalytics',
(ngModelChange)='config.save(); config.requestRestart()',
)
.text-center.mt-5
button.btn.btn-primary((click)='closeAndDisable()') Close and never show again

View File

@@ -2,7 +2,5 @@
display: flex;
flex-direction: column;
margin: auto;
flex: auto;
max-height: 100%;
overflow-y: auto;
flex: 0 1 500px;
}

View File

@@ -1,39 +1,26 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component } from '@angular/core'
import { BaseTabComponent } from './baseTab.component'
import { ConfigService } from '../services/config.service'
import { HostAppService } from '../services/hostApp.service'
import { AppService } from '../services/app.service'
/** @hidden */
@Component({
selector: 'welcome-page',
template: require('./welcomeTab.component.pug'),
styles: [require('./welcomeTab.component.scss')],
templateUrl: './welcomeTab.component.pug',
styleUrls: ['./welcomeTab.component.scss'],
})
export class WelcomeTabComponent extends BaseTabComponent {
enableSSH = false
enableSerial = false
constructor (
private hostApp: HostAppService,
private app: AppService,
public config: ConfigService,
) {
super()
this.setTitle('Welcome')
this.enableSSH = !config.store.pluginBlacklist.includes('ssh')
this.enableSerial = !config.store.pluginBlacklist.includes('serial')
}
closeAndDisable () {
this.config.store.enableWelcomeTab = false
this.config.store.pluginBlacklist = []
if (!this.enableSSH) {
this.config.store.pluginBlacklist.push('ssh')
}
if (!this.enableSerial) {
this.config.store.pluginBlacklist.push('serial')
}
this.config.save()
this.hostApp.getWindow().reload()
this.app.closeTab(this)
}
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Component } from '@angular/core'
import { HostAppService } from '../services/hostApp.service'
import { AppService } from '../services/app.service'
@@ -6,13 +5,15 @@ import { AppService } from '../services/app.service'
/** @hidden */
@Component({
selector: 'window-controls',
template: require('./windowControls.component.pug'),
styles: [require('./windowControls.component.scss')],
templateUrl: './windowControls.component.pug',
styleUrls: ['./windowControls.component.scss'],
})
export class WindowControlsComponent {
private constructor (public hostApp: HostAppService, public app: AppService) { }
constructor (public hostApp: HostAppService, public app: AppService) { }
async closeWindow () {
this.app.closeWindow()
if (await this.app.closeAllTabs()) {
this.hostApp.closeWindow()
}
}
}

View File

@@ -7,8 +7,6 @@ hotkeys:
- 'F11'
close-tab:
- 'Ctrl-Shift-W'
reopen-tab:
- 'Ctrl-Shift-T'
toggle-last-tab: []
rename-tab:
- 'Ctrl-Shift-R'
@@ -18,10 +16,6 @@ hotkeys:
previous-tab:
- 'Ctrl-Shift-Left'
- 'Ctrl-Shift-Tab'
move-tab-left:
- 'Ctrl-Shift-PageUp'
move-tab-right:
- 'Ctrl-Shift-PageDown'
tab-1:
- 'Alt-1'
tab-2:
@@ -56,7 +50,5 @@ hotkeys:
- 'Ctrl-Alt-Up'
pane-nav-left:
- 'Ctrl-Alt-Left'
pane-maximize:
- 'Ctrl-Alt-Enter'
close-pane: []
pluginBlacklist: ['ssh']

View File

@@ -7,8 +7,6 @@ hotkeys:
- 'Ctrl+⌘+F'
close-tab:
- '⌘-W'
reopen-tab:
- '⌘-Shift-T'
toggle-last-tab: []
rename-tab:
- '⌘-R'
@@ -16,10 +14,6 @@ hotkeys:
- 'Ctrl-Tab'
previous-tab:
- 'Ctrl-Shift-Tab'
move-tab-left:
- '⌘-Shift-Left'
move-tab-right:
- '⌘-Shift-Right'
tab-1:
- '⌘-1'
tab-2:
@@ -54,8 +48,6 @@ hotkeys:
- '⌘-⌥-Up'
pane-nav-left:
- '⌘-⌥-Left'
pane-maximize:
- '⌘-⌥-Enter'
close-pane:
- '⌘-Shift-W'
pluginBlacklist: ['ssh']

View File

@@ -5,11 +5,8 @@ hotkeys:
- 'Ctrl+Space'
toggle-fullscreen:
- 'F11'
- 'Alt-Enter'
close-tab:
- 'Ctrl-Shift-W'
reopen-tab:
- 'Ctrl-Shift-T'
toggle-last-tab: []
rename-tab:
- 'Ctrl-Shift-R'
@@ -19,10 +16,6 @@ hotkeys:
previous-tab:
- 'Ctrl-Shift-Left'
- 'Ctrl-Shift-Tab'
move-tab-left:
- 'Ctrl-Shift-PageUp'
move-tab-right:
- 'Ctrl-Shift-PageDown'
tab-1:
- 'Alt-1'
tab-2:
@@ -57,7 +50,5 @@ hotkeys:
- 'Ctrl-Alt-Up'
pane-nav-left:
- 'Ctrl-Alt-Left'
pane-maximize:
- 'Ctrl-Alt-Enter'
close-pane: []
pluginBlacklist: []

View File

@@ -2,15 +2,13 @@ appearance:
dock: off
dockScreen: current
dockFill: 0.5
dockHideOnBlur: false
dockAlwaysOnTop: true
tabsLocation: top
cycleTabs: true
theme: Standard
frame: thin
css: '/* * { color: blue !important; } */'
opacity: 1.0
vibrancy: true
vibrancy: false
vibrancyType: 'blur'
enableAnalytics: true
enableWelcomeTab: true

View File

@@ -7,7 +7,7 @@ import { Directive, AfterViewInit, ElementRef } from '@angular/core'
export class AutofocusDirective implements AfterViewInit {
constructor (private el: ElementRef) { }
ngAfterViewInit (): void {
ngAfterViewInit () {
this.el.nativeElement.blur()
setTimeout(() => {
this.el.nativeElement.focus()

View File

@@ -1,14 +0,0 @@
import { Directive, Input, ElementRef, OnChanges } from '@angular/core'
/** @hidden */
@Directive({
selector: '[fastHtmlBind]',
})
export class FastHtmlBindDirective implements OnChanges {
@Input() fastHtmlBind: string
constructor (private el: ElementRef) { }
ngOnChanges (): void {
this.el.nativeElement.innerHTML = this.fastHtmlBind || ''
}
}

View File

@@ -25,10 +25,6 @@ export class AppHotkeyProvider extends HotkeyProvider {
id: 'close-tab',
name: 'Close tab',
},
{
id: 'reopen-tab',
name: 'Reopen last tab',
},
{
id: 'toggle-last-tab',
name: 'Toggle last tab',
@@ -41,14 +37,6 @@ export class AppHotkeyProvider extends HotkeyProvider {
id: 'previous-tab',
name: 'Previous tab',
},
{
id: 'move-tab-left',
name: 'Move tab to the left',
},
{
id: 'move-tab-right',
name: 'Move tab to the right',
},
{
id: 'tab-1',
name: 'Tab 1',
@@ -105,10 +93,6 @@ export class AppHotkeyProvider extends HotkeyProvider {
id: 'split-top',
name: 'Split to the top',
},
{
id: 'pane-maximize',
name: 'Maximize the active pane',
},
{
id: 'pane-nav-up',
name: 'Focus the pane above',

View File

@@ -1,10 +1,11 @@
import { NgModule, ModuleWithProviders } from '@angular/core'
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar'
import { DndModule } from 'ng2-dnd'
// import { DndModule } from 'ng2-dnd'
import { AppRootComponent } from './components/appRoot.component'
import { CheckboxComponent } from './components/checkbox.component'
@@ -16,18 +17,16 @@ import { TitleBarComponent } from './components/titleBar.component'
import { ToggleComponent } from './components/toggle.component'
import { WindowControlsComponent } from './components/windowControls.component'
import { RenameTabModalComponent } from './components/renameTabModal.component'
import { SelectorModalComponent } from './components/selectorModal.component'
import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component'
import { SplitTabSpannerComponent } from './components/splitTabSpanner.component'
import { WelcomeTabComponent } from './components/welcomeTab.component'
import { AutofocusDirective } from './directives/autofocus.directive'
import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
import { HotkeyProvider } from './api/hotkeyProvider'
import { ConfigProvider } from './api/configProvider'
import { Theme } from './api/theme'
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
// import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
import { TabRecoveryProvider } from './api/tabRecovery'
import { AppService } from './services/app.service'
@@ -36,7 +35,7 @@ import { ConfigService } from './services/config.service'
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
import { CoreConfigProvider } from './config'
import { AppHotkeyProvider } from './hotkeys'
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu } from './tabContextMenu'
// import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu'
import 'perfect-scrollbar/css/perfect-scrollbar.css'
import 'ng2-dnd/bundles/style.css'
@@ -53,9 +52,9 @@ const PROVIDERS = [
{ provide: Theme, useClass: StandardCompactTheme, multi: true },
{ provide: Theme, useClass: PaperTheme, multi: true },
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: TabManagementContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
// { provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
// { provide: TabContextMenuItemProvider, useClass: CloseContextMenu, multi: true },
// { provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
{ provide: TabRecoveryProvider, useClass: SplitTabRecoveryProvider, multi: true },
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } },
]
@@ -68,8 +67,9 @@ const PROVIDERS = [
FormsModule,
NgbModule,
PerfectScrollbarModule,
DndModule.forRoot(),
// DndModule,
],
providers: PROVIDERS,
declarations: [
AppRootComponent as any,
CheckboxComponent,
@@ -82,8 +82,6 @@ const PROVIDERS = [
RenameTabModalComponent,
SafeModeModalComponent,
AutofocusDirective,
FastHtmlBindDirective,
SelectorModalComponent,
SplitTabComponent,
SplitTabSpannerComponent,
WelcomeTabComponent,
@@ -91,7 +89,6 @@ const PROVIDERS = [
entryComponents: [
RenameTabModalComponent,
SafeModeModalComponent,
SelectorModalComponent,
SplitTabComponent,
WelcomeTabComponent,
],
@@ -101,7 +98,7 @@ const PROVIDERS = [
AutofocusDirective,
],
})
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
export class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
constructor (app: AppService, config: ConfigService) {
app.ready$.subscribe(() => {
if (config.store.enableWelcomeTab) {
@@ -109,18 +106,17 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
}
})
}
static forRoot (): ModuleWithProviders {
return {
ngModule: AppModule,
providers: PROVIDERS,
}
}
}
export default AppModule
export { AppRootComponent as bootstrap }
export * from './api'
// Deprecations
export { ToolbarButton as IToolbarButton } from './api'
export { HotkeyDescription as IHotkeyDescription } from './api'
export function fakeBootstrap () {
return platformBrowserDynamic().bootstrapModule(AppModule)
}

View File

@@ -2,13 +2,9 @@
import { Observable, Subject, AsyncSubject } from 'rxjs'
import { takeUntil } from 'rxjs/operators'
import { Injectable } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { BaseTabComponent } from '../components/baseTab.component'
import { SplitTabComponent } from '../components/splitTab.component'
import { SelectorModalComponent } from '../components/selectorModal.component'
import { SelectorOption } from '../api/selector'
import { RecoveryToken } from '../api/tabRecovery'
import { ConfigService } from './config.service'
import { HostAppService } from './hostApp.service'
@@ -50,7 +46,6 @@ export class AppService {
private lastTabIndex = 0
private _activeTab: BaseTabComponent
private closedTabsStack: RecoveryToken[] = []
private activeTabChange = new Subject<BaseTabComponent>()
private tabsChanged = new Subject<void>()
@@ -69,53 +64,38 @@ export class AppService {
get ready$ (): Observable<void> { return this.ready }
/** @hidden */
private constructor (
constructor (
private config: ConfigService,
private hostApp: HostAppService,
private tabRecovery: TabRecoveryService,
private tabsService: TabsService,
private ngbModal: NgbModal,
) {
this.tabsChanged$.subscribe(() => {
this.tabRecovery.saveTabs(this.tabs)
})
setInterval(() => {
this.tabRecovery.saveTabs(this.tabs)
}, 30000)
if (hostApp.getWindow().id === 1) {
if (config.store.terminal.recoverTabs) {
this.tabRecovery.recoverTabs().then(tabs => {
for (const tab of tabs) {
this.openNewTabRaw(tab.type, tab.options)
}
this.tabRecovery.enabled = true
this.startTabStorage()
})
} else {
/** Continue to store the tabs even if the setting is currently off */
this.tabRecovery.enabled = true
this.startTabStorage()
}
}
hostApp.windowFocused$.subscribe(() => {
this._activeTab?.emitFocused()
})
this.tabClosed$.subscribe(async tab => {
const token = await tab.getRecoveryToken()
if (token) {
this.closedTabsStack.push(token)
}
})
}
addTabRaw (tab: BaseTabComponent, index: number|null = null): void {
if (index !== null) {
this.tabs.splice(index, 0, tab)
} else {
this.tabs.push(tab)
}
startTabStorage () {
this.tabsChanged$.subscribe(() => {
this.tabRecovery.saveTabs(this.tabs)
})
setInterval(() => {
this.tabRecovery.saveTabs(this.tabs)
}, 30000)
}
addTabRaw (tab: BaseTabComponent) {
this.tabs.push(tab)
this.selectTab(tab)
this.tabsChanged.next()
this.tabOpened.next(tab)
@@ -141,18 +121,13 @@ export class AppService {
this.tabsChanged.next()
this.tabClosed.next(tab)
})
if (tab instanceof SplitTabComponent) {
tab.tabAdded$.subscribe(() => this.emitTabsChanged())
tab.tabRemoved$.subscribe(() => this.emitTabsChanged())
}
}
/**
* Adds a new tab **without** wrapping it in a SplitTabComponent
* @param inputs Properties to be assigned on the new tab component instance
*/
openNewTabRaw (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
openNewTabRaw (type: TabComponentType, inputs?: any): BaseTabComponent {
const tab = this.tabsService.create(type, inputs)
this.addTabRaw(tab)
return tab
@@ -162,7 +137,7 @@ export class AppService {
* Adds a new tab while wrapping it in a SplitTabComponent
* @param inputs Properties to be assigned on the new tab component instance
*/
openNewTab (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
openNewTab (type: TabComponentType, inputs?: any): BaseTabComponent {
const splitTab = this.tabsService.create(SplitTabComponent) as SplitTabComponent
const tab = this.tabsService.create(type, inputs)
splitTab.addTab(tab, null, 'r')
@@ -170,24 +145,7 @@ export class AppService {
return tab
}
async reopenLastTab (): Promise<BaseTabComponent|null> {
const token = this.closedTabsStack.pop()
if (token) {
const recoveredTab = await this.tabRecovery.recoverTab(token)
if (recoveredTab) {
const tab = this.tabsService.create(recoveredTab.type, recoveredTab.options)
if (this.activeTab) {
this.addTabRaw(tab, this.tabs.indexOf(this.activeTab) + 1)
} else {
this.addTabRaw(tab)
}
return tab
}
}
return null
}
selectTab (tab: BaseTabComponent): void {
selectTab (tab: BaseTabComponent) {
if (this._activeTab === tab) {
this._activeTab.emitFocused()
return
@@ -211,26 +169,15 @@ export class AppService {
}
}
getParentTab (tab: BaseTabComponent): SplitTabComponent|null {
for (const topLevelTab of this.tabs) {
if (topLevelTab instanceof SplitTabComponent) {
if (topLevelTab.getAllTabs().includes(tab)) {
return topLevelTab
}
}
}
return null
}
/** Switches between the current tab and the previously active one */
toggleLastTab (): void {
toggleLastTab () {
if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
this.lastTabIndex = 0
}
this.selectTab(this.tabs[this.lastTabIndex])
}
nextTab (): void {
nextTab () {
if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex < this.tabs.length - 1) {
@@ -241,7 +188,7 @@ export class AppService {
}
}
previousTab (): void {
previousTab () {
if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex > 0) {
@@ -252,37 +199,8 @@ export class AppService {
}
}
moveSelectedTabLeft (): void {
if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex > 0) {
this.swapTabs(this._activeTab, this.tabs[tabIndex - 1])
} else if (this.config.store.appearance.cycleTabs) {
this.swapTabs(this._activeTab, this.tabs[this.tabs.length - 1])
}
}
}
moveSelectedTabRight (): void {
if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex < this.tabs.length - 1) {
this.swapTabs(this._activeTab, this.tabs[tabIndex + 1])
} else if (this.config.store.appearance.cycleTabs) {
this.swapTabs(this._activeTab, this.tabs[0])
}
}
}
swapTabs (a: BaseTabComponent, b: BaseTabComponent): void {
const i1 = this.tabs.indexOf(a)
const i2 = this.tabs.indexOf(b)
this.tabs[i1] = b
this.tabs[i2] = a
}
/** @hidden */
emitTabsChanged (): void {
emitTabsChanged () {
this.tabsChanged.next()
}
@@ -296,12 +214,11 @@ export class AppService {
tab.destroy()
}
async duplicateTab (tab: BaseTabComponent): Promise<BaseTabComponent|null> {
async duplicateTab (tab: BaseTabComponent) {
const dup = await this.tabsService.duplicate(tab)
if (dup) {
this.addTabRaw(dup, this.tabs.indexOf(tab) + 1)
this.addTabRaw(dup)
}
return dup
}
/**
@@ -319,18 +236,8 @@ export class AppService {
return true
}
async closeWindow (): Promise<void> {
this.tabRecovery.enabled = false
await this.tabRecovery.saveTabs(this.tabs)
if (await this.closeAllTabs()) {
this.hostApp.closeWindow()
} else {
this.tabRecovery.enabled = true
}
}
/** @hidden */
emitReady (): void {
emitReady () {
this.ready.next()
this.ready.complete()
this.hostApp.emitReady()
@@ -351,15 +258,7 @@ export class AppService {
return this.completionObservers.get(tab)!.done$
}
stopObservingTabCompletion (tab: BaseTabComponent): void {
stopObservingTabCompletion (tab: BaseTabComponent) {
this.completionObservers.delete(tab)
}
showSelector <T> (name: string, options: SelectorOption<T>[]): Promise<T> {
const modal = this.ngbModal.open(SelectorModalComponent)
const instance: SelectorModalComponent<T> = modal.componentInstance
instance.name = name
instance.options = options
return modal.result as Promise<T>
}
}

View File

@@ -20,7 +20,7 @@ function isNonStructuralObjectMember (v): boolean {
/** @hidden */
export class ConfigProxy {
constructor (real: Record<string, any>, defaults: Record<string, any>) {
constructor (real: any, defaults: any) {
for (const key in defaults) {
if (isStructuralMember(defaults[key])) {
if (!real[key]) {
@@ -71,10 +71,8 @@ export class ConfigProxy {
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
getValue (_key: string): any { }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
setValue (_key: string, _value: any) { }
getValue (_key: string): any { } // eslint-disable-line @typescript-eslint/no-empty-function
setValue (_key: string, _value: any) { } // eslint-disable-line @typescript-eslint/no-empty-function
}
@Injectable({ providedIn: 'root' })
@@ -102,7 +100,7 @@ export class ConfigService {
get changed$ (): Observable<void> { return this.changed }
/** @hidden */
private constructor (
constructor (
electron: ElectronService,
private hostApp: HostAppService,
@Inject(ConfigProvider) configProviders: ConfigProvider[],
@@ -126,23 +124,8 @@ export class ConfigService {
})
}
getDefaults (): Record<string, any> {
const cleanup = o => {
if (o instanceof Array) {
return o.map(cleanup)
} else if (o instanceof Object) {
const r = {}
for (const k of Object.keys(o)) {
if (k !== '__nonStructural') {
r[k] = cleanup(o[k])
}
}
return r
} else {
return o
}
}
return cleanup(this.defaults)
getDefaults () {
return this.defaults
}
load (): void {
@@ -155,11 +138,9 @@ export class ConfigService {
}
save (): void {
// Scrub undefined values
this._store = JSON.parse(JSON.stringify(this._store))
fs.writeFileSync(this.path, yaml.safeDump(this._store), 'utf8')
this.emitChange()
this.hostApp.broadcastConfigChange(this.store)
this.hostApp.broadcastConfigChange()
}
/**
@@ -192,11 +173,11 @@ export class ConfigService {
enabledServices<T extends object> (services: T[]): T[] {
if (!this.servicesCache) {
this.servicesCache = {}
const ngModule = window['rootModule'].ɵinj
const ngModule = window['rootModule'].ngInjectorDef
for (const imp of ngModule.imports) {
const module = imp['ngModule'] || imp
if (module.ɵinj?.providers) {
this.servicesCache[module['pluginName']] = module.ɵinj.providers.map(provider => {
if (module.ngInjectorDef && module.ngInjectorDef.providers) {
this.servicesCache[module['pluginName']] = module.ngInjectorDef.providers.map(provider => {
return provider['useClass'] || provider
})
}

View File

@@ -6,7 +6,7 @@ import { HostAppService, Bounds } from '../services/hostApp.service'
@Injectable({ providedIn: 'root' })
export class DockingService {
/** @hidden */
private constructor (
constructor (
private electron: ElectronService,
private config: ConfigService,
private hostApp: HostAppService,
@@ -15,7 +15,7 @@ export class DockingService {
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
}
dock (): void {
dock () {
const dockSide = this.config.store.appearance.dock
if (dockSide === 'off') {
@@ -53,25 +53,22 @@ export class DockingService {
newBounds.y = display.bounds.y
}
const alwaysOnTop = this.config.store.appearance.dockAlwaysOnTop
this.hostApp.setAlwaysOnTop(alwaysOnTop)
this.hostApp.setAlwaysOnTop(true)
setImmediate(() => {
this.hostApp.setBounds(newBounds)
})
}
getCurrentScreen (): Electron.Display {
getCurrentScreen () {
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
}
getScreens (): Electron.Display[] {
getScreens () {
const primaryDisplayID = this.electron.screen.getPrimaryDisplay().id
return this.electron.screen.getAllDisplays().sort((a, b) =>
a.bounds.x === b.bounds.x ? a.bounds.y - b.bounds.y : a.bounds.x - b.bounds.x
).map((display, index) => {
).map((display,index) => {
return {
...display,
id: display.id,
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index +1}`,
}

View File

@@ -25,7 +25,7 @@ export class ElectronService {
private electron: any
/** @hidden */
private constructor () {
constructor () {
this.electron = require('electron')
this.remote = this.electron.remote
this.app = this.remote.app
@@ -43,6 +43,15 @@ export class ElectronService {
this.MenuItem = this.remote.MenuItem
}
/**
* Removes OS focus from Terminus' window
*/
loseFocus () {
if (process.platform === 'darwin') {
this.remote.Menu.sendActionToFirstResponder('hide:')
}
}
async showMessageBox (
browserWindow: Electron.BrowserWindow,
options: Electron.MessageBoxOptions

View File

@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'
import { ElectronService } from './electron.service'
import { ConfigService } from './config.service'
import * as mixpanel from 'mixpanel'
import { v4 as uuidv4 } from 'uuid'
import * as uuidv4 from 'uuid/v4'
@Injectable({ providedIn: 'root' })
export class HomeBaseService {
@@ -11,7 +11,7 @@ export class HomeBaseService {
mixpanel: any
/** @hidden */
private constructor (
constructor (
private electron: ElectronService,
private config: ConfigService,
) {
@@ -22,29 +22,24 @@ export class HomeBaseService {
}
}
openGitHub (): void {
openGitHub () {
this.electron.shell.openExternal('https://github.com/eugeny/terminus')
}
reportBug (): void {
reportBug () {
let body = `Version: ${this.appVersion}\n`
body += `Platform: ${os.platform()} ${os.release()}\n`
const label = {
aix: 'OS: IBM AIX',
android: 'OS: Android',
darwin: 'OS: macOS',
freebsd: 'OS: FreeBSD',
windows: 'OS: Windows',
linux: 'OS: Linux',
openbsd: 'OS: OpenBSD',
sunos: 'OS: Solaris',
win32: 'OS: Windows',
}[os.platform()]
const plugins = (window as any).installedPlugins.filter(x => !x.isBuiltin).map(x => x.name)
body += `Plugins: ${plugins.join(', ') || 'none'}\n\n`
this.electron.shell.openExternal(`https://github.com/eugeny/terminus/issues/new?body=${encodeURIComponent(body)}&labels=${label}`)
}
enableAnalytics (): void {
enableAnalytics () {
if (!window.localStorage.analyticsUserID) {
window.localStorage.analyticsUserID = uuidv4()
}
@@ -56,7 +51,7 @@ export class HomeBaseService {
this.mixpanel.track('launch', this.getAnalyticsProperties())
}
getAnalyticsProperties (): Record<string, string> {
getAnalyticsProperties () {
return {
distinct_id: window.localStorage.analyticsUserID, // eslint-disable-line @typescript-eslint/camelcase
platform: process.platform,

View File

@@ -4,7 +4,6 @@ import { Observable, Subject } from 'rxjs'
import { Injectable, NgZone, EventEmitter } from '@angular/core'
import { ElectronService } from './electron.service'
import { Logger, LogService } from './log.service'
import { isWindowsBuild, WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED, WIN_BUILD_FLUENT_BG_SUPPORTED } from '../utils'
export enum Platform {
Linux, macOS, Windows,
@@ -40,7 +39,6 @@ export class HostAppService {
private configChangeBroadcast = new Subject<void>()
private windowCloseRequest = new Subject<void>()
private windowMoved = new Subject<void>()
private windowFocused = new Subject<void>()
private displayMetricsChanged = new Subject<void>()
private logger: Logger
private windowId: number
@@ -87,8 +85,6 @@ export class HostAppService {
get windowMoved$ (): Observable<void> { return this.windowMoved }
get windowFocused$ (): Observable<void> { return this.windowFocused }
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
private constructor (
@@ -132,10 +128,6 @@ export class HostAppService {
this.zone.run(() => this.windowMoved.next())
})
electron.ipcRenderer.on('host:window-focused', () => {
this.zone.run(() => this.windowFocused.next())
})
electron.ipcRenderer.on('host:display-metrics-changed', () => {
this.zone.run(() => this.displayMetricsChanged.next())
})
@@ -165,60 +157,53 @@ export class HostAppService {
electron.ipcRenderer.on('host:config-change', () => this.zone.run(() => {
this.configChangeBroadcast.next()
}))
if (
isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED) &&
!isWindowsBuild(WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED)
) {
electron.ipcRenderer.send('window-set-disable-vibrancy-while-dragging', true)
}
}
/**
* Returns the current remote [[BrowserWindow]]
*/
getWindow (): Electron.BrowserWindow {
getWindow () {
return this.electron.BrowserWindow.fromId(this.windowId)
}
newWindow (): void {
newWindow () {
this.electron.ipcRenderer.send('app:new-window')
}
toggleFullscreen (): void {
toggleFullscreen () {
const window = this.getWindow()
window.setFullScreen(!this.isFullScreen)
}
openDevTools (): void {
openDevTools () {
this.getWindow().webContents.openDevTools({ mode: 'undocked' })
}
focusWindow (): void {
focusWindow () {
this.electron.ipcRenderer.send('window-focus')
}
minimize (): void {
minimize () {
this.electron.ipcRenderer.send('window-minimize')
}
maximize (): void {
maximize () {
this.electron.ipcRenderer.send('window-maximize')
}
unmaximize (): void {
unmaximize () {
this.electron.ipcRenderer.send('window-unmaximize')
}
toggleMaximize (): void {
toggleMaximize () {
this.electron.ipcRenderer.send('window-toggle-maximize')
}
setBounds (bounds: Bounds): void {
setBounds (bounds: Bounds) {
this.electron.ipcRenderer.send('window-set-bounds', bounds)
}
setAlwaysOnTop (flag: boolean): void {
setAlwaysOnTop (flag: boolean) {
this.electron.ipcRenderer.send('window-set-always-on-top', flag)
}
@@ -227,50 +212,48 @@ export class HostAppService {
*
* @param type `null`, or `fluent` when supported (Windowd only)
*/
setVibrancy (enable: boolean, type: string|null): void {
if (!isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
type = null
}
setVibrancy (enable: boolean, type: string) {
document.body.classList.toggle('vibrant', enable)
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
if (this.platform === Platform.macOS) {
this.getWindow().setVibrancy(enable ? 'dark' : null as any) // electron issue 20269
}
if (this.platform === Platform.Windows) {
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
}
}
setTitle (title: string): void {
setTitle (title: string) {
this.electron.ipcRenderer.send('window-set-title', title)
}
setTouchBar (touchBar: Electron.TouchBar): void {
setTouchBar (touchBar: Electron.TouchBar) {
this.getWindow().setTouchBar(touchBar)
}
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]): void {
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]) {
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
}
/**
* Notifies other windows of config file changes
*/
broadcastConfigChange (configStore: {[k: string]: any}): void {
this.electron.ipcRenderer.send('app:config-change', configStore)
broadcastConfigChange () {
this.electron.ipcRenderer.send('app:config-change')
}
emitReady (): void {
emitReady () {
this.electron.ipcRenderer.send('app:ready')
}
bringToFront (): void {
bringToFront () {
this.electron.ipcRenderer.send('window-bring-to-front')
}
closeWindow (): void {
closeWindow () {
this.electron.ipcRenderer.send('window-close')
}
registerGlobalHotkey (specs: string[]): void {
this.electron.ipcRenderer.send('app:register-global-hotkey', specs)
}
relaunch (): void {
relaunch () {
if (this.isPortable) {
this.electron.app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE })
} else {
@@ -279,7 +262,7 @@ export class HostAppService {
this.electron.app.exit()
}
quit (): void {
quit () {
this.logger.info('Quitting')
this.electron.app.quit()
}

View File

@@ -1,10 +1,8 @@
import { Injectable, Inject, NgZone, EventEmitter } from '@angular/core'
import { Observable, Subject } from 'rxjs'
import { HotkeyDescription, HotkeyProvider } from '../api/hotkeyProvider'
import { stringifyKeySequence } from './hotkeys.util'
import { ConfigService } from './config.service'
import { ElectronService } from './electron.service'
import { HostAppService } from './hostApp.service'
import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
export interface PartialHotkeyMatch {
id: string
@@ -22,23 +20,14 @@ interface EventBufferEntry {
@Injectable({ providedIn: 'root' })
export class HotkeysService {
key = new EventEmitter<KeyboardEvent>()
/** @hidden */
matchedHotkey = new EventEmitter<string>()
/**
* Fired for each recognized hotkey
*/
get hotkey$ (): Observable<string> { return this._hotkey }
private _hotkey = new Subject<string>()
globalHotkey = new EventEmitter<void>()
private currentKeystrokes: EventBufferEntry[] = []
private disabledLevel = 0
private hotkeyDescriptions: HotkeyDescription[] = []
private constructor (
private zone: NgZone,
private hostApp: HostAppService,
private electron: ElectronService,
private config: ConfigService,
@Inject(HotkeyProvider) private hotkeyProviders: HotkeyProvider[],
@@ -60,9 +49,6 @@ export class HotkeysService {
this.getHotkeyDescriptions().then(hotkeys => {
this.hotkeyDescriptions = hotkeys
})
// deprecated
this.hotkey$.subscribe(h => this.matchedHotkey.emit(h))
}
/**
@@ -71,7 +57,7 @@ export class HotkeysService {
* @param name DOM event name
* @param nativeEvent event object
*/
pushKeystroke (name: string, nativeEvent: KeyboardEvent): void {
pushKeystroke (name: string, nativeEvent: KeyboardEvent) {
(nativeEvent as any).event = name
this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
}
@@ -79,26 +65,26 @@ export class HotkeysService {
/**
* Check the buffer for new complete keystrokes
*/
processKeystrokes (): void {
processKeystrokes () {
if (this.isEnabled()) {
this.zone.run(() => {
const matched = this.getCurrentFullyMatchedHotkey()
if (matched) {
console.log('Matched hotkey', matched)
this._hotkey.next(matched)
this.matchedHotkey.emit(matched)
this.clearCurrentKeystrokes()
}
})
}
}
emitKeyEvent (nativeEvent: KeyboardEvent): void {
emitKeyEvent (nativeEvent: KeyboardEvent) {
this.zone.run(() => {
this.key.emit(nativeEvent)
})
}
clearCurrentKeystrokes (): void {
clearCurrentKeystrokes () {
this.currentKeystrokes = []
}
@@ -156,15 +142,15 @@ export class HotkeysService {
return this.hotkeyDescriptions.filter((x) => x.id === id)[0]
}
enable (): void {
enable () {
this.disabledLevel--
}
disable (): void {
disable () {
this.disabledLevel++
}
isEnabled (): boolean {
isEnabled () {
return this.disabledLevel === 0
}
@@ -183,7 +169,6 @@ export class HotkeysService {
if (typeof value === 'string') {
value = [value]
}
const specs: string[] = []
value.forEach((item: string | string[]) => {
item = typeof item === 'string' ? [item] : item
@@ -192,13 +177,13 @@ export class HotkeysService {
electronKeySpec = electronKeySpec.replace('⌘', 'Command')
electronKeySpec = electronKeySpec.replace('⌥', 'Alt')
electronKeySpec = electronKeySpec.replace(/-/g, '+')
specs.push(electronKeySpec)
this.electron.globalShortcut.register(electronKeySpec, () => {
this.globalHotkey.emit()
})
} catch (err) {
console.error('Could not register the global hotkey:', err)
}
})
this.hostApp.registerGlobalHotkey(specs)
}
private getHotkeysConfig () {
@@ -218,9 +203,6 @@ export class HotkeysService {
if (typeof value === 'string') {
value = [value]
}
if (!(value instanceof Array)) {
continue
}
if (value) {
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
keys[key] = value

View File

@@ -32,27 +32,27 @@ export class Logger {
private name: string,
) {}
debug (...args: any[]): void {
debug (...args: any[]) {
this.doLog('debug', ...args)
}
info (...args: any[]): void {
info (...args: any[]) {
this.doLog('info', ...args)
}
warn (...args: any[]): void {
warn (...args: any[]) {
this.doLog('warn', ...args)
}
error (...args: any[]): void {
error (...args: any[]) {
this.doLog('error', ...args)
}
log (...args: any[]): void {
log (...args: any[]) {
this.doLog('log', ...args)
}
private doLog (level: string, ...args: any[]): void {
private doLog (level: string, ...args: any[]) {
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
if (this.winstonLogger) {
this.winstonLogger[level](...args)
@@ -65,7 +65,7 @@ export class LogService {
private log: any
/** @hidden */
private constructor (electron: ElectronService) {
constructor (electron: ElectronService) {
this.log = initializeWinston(electron)
}

View File

@@ -8,7 +8,7 @@ import { HostAppService, Platform } from './hostApp.service'
/* eslint-disable block-scoped-var */
try {
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires, no-var
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires
} catch (_) { }
@Injectable({ providedIn: 'root' })
@@ -18,22 +18,15 @@ export class ShellIntegrationService {
private automatorWorkflowsDestination: string
private registryKeys = [
{
path: 'Software\\Classes\\Directory\\Background\\shell\\Terminus',
value: 'Open Terminus here',
path: 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here',
command: 'open "%V"',
},
{
path: 'SOFTWARE\\Classes\\Directory\\shell\\Terminus',
value: 'Open Terminus here',
command: 'open "%V"',
},
{
path: 'Software\\Classes\\*\\shell\\Terminus',
value: 'Paste path into Terminus',
path: 'Software\\Classes\\*\\shell\\Paste path into Terminus',
command: 'paste "%V"',
},
]
private constructor (
constructor (
private electron: ElectronService,
private hostApp: HostAppService,
) {
@@ -58,7 +51,7 @@ export class ShellIntegrationService {
return true
}
async install (): Promise<void> {
async install () {
const exe: string = process.env.PORTABLE_EXECUTABLE_FILE || this.electron.app.getPath('exe')
if (this.hostApp.platform === Platform.macOS) {
for (const wf of this.automatorWorkflows) {
@@ -68,21 +61,13 @@ export class ShellIntegrationService {
for (const registryKey of this.registryKeys) {
wnr.createRegistryKey(wnr.HK.CU, registryKey.path)
wnr.createRegistryKey(wnr.HK.CU, registryKey.path + '\\command')
wnr.setRegistryValue(wnr.HK.CU, registryKey.path, '', wnr.REG.SZ, registryKey.value)
wnr.setRegistryValue(wnr.HK.CU, registryKey.path, 'Icon', wnr.REG.SZ, exe)
wnr.setRegistryValue(wnr.HK.CU, registryKey.path + '\\command', '', wnr.REG.SZ, exe + ' ' + registryKey.command)
}
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')
}
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')
}
}
}
async remove (): Promise<void> {
async remove () {
if (this.hostApp.platform === Platform.macOS) {
for (const wf of this.automatorWorkflows) {
await exec(`rm -rf "${this.automatorWorkflowsDestination}/${wf}"`)

View File

@@ -1,5 +1,5 @@
import { Injectable, Inject } from '@angular/core'
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from '../api/tabRecovery'
import { TabRecoveryProvider, RecoveredTab } from '../api/tabRecovery'
import { BaseTabComponent } from '../components/baseTab.component'
import { Logger, LogService } from '../services/log.service'
import { ConfigService } from '../services/config.service'
@@ -8,9 +8,8 @@ import { ConfigService } from '../services/config.service'
@Injectable({ providedIn: 'root' })
export class TabRecoveryService {
logger: Logger
enabled = false
private constructor (
constructor (
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
private config: ConfigService,
log: LogService
@@ -18,41 +17,21 @@ export class TabRecoveryService {
this.logger = log.create('tabRecovery')
}
async saveTabs (tabs: BaseTabComponent[]): Promise<void> {
if (!this.enabled) {
return
}
async saveTabs (tabs: BaseTabComponent[]) {
window.localStorage.tabsRecovery = JSON.stringify(
await Promise.all(
tabs
.map(tab => {
let token = tab.getRecoveryToken()
if (token) {
token = token.then(r => {
if (r) {
r.tabTitle = tab.title
if (tab.color) {
r.tabColor = tab.color
}
}
return r
})
}
return token
})
.map(tab => tab.getRecoveryToken())
.filter(token => !!token)
)
)
}
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
async recoverTab (token: any): Promise<RecoveredTab|null> {
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
try {
const tab = await provider.recover(token)
if (tab !== null) {
tab.options = tab.options || {}
tab.options.color = token.tabColor || null
tab.options.title = token.tabTitle || ''
if (tab) {
return tab
}
} catch (error) {

View File

@@ -8,7 +8,7 @@ export type TabComponentType = new (...args: any[]) => BaseTabComponent
@Injectable({ providedIn: 'root' })
export class TabsService {
/** @hidden */
private constructor (
constructor (
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
private tabRecovery: TabRecoveryService,
@@ -17,7 +17,7 @@ export class TabsService {
/**
* Instantiates a tab component and assigns given inputs
*/
create (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
create (type: TabComponentType, inputs?: any): BaseTabComponent {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type)
const componentRef = componentFactory.create(this.injector)
const tab = componentRef.instance

View File

@@ -7,7 +7,7 @@ export class ThemesService {
private styleElement: HTMLElement|null = null
/** @hidden */
private constructor (
constructor (
private config: ConfigService,
@Inject(Theme) private themes: Theme[],
) {

View File

@@ -14,7 +14,7 @@ export class TouchbarService {
private tabSegments: SegmentedControlSegment[] = []
private nsImageCache: {[id: string]: Electron.NativeImage} = {}
private constructor (
constructor (
private app: AppService,
private hostApp: HostAppService,
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
@@ -48,7 +48,7 @@ export class TouchbarService {
})
}
updateTabs (): void {
updateTabs () {
this.tabSegments = this.app.tabs.map(tab => ({
label: this.shortenTitle(tab.title),
}))
@@ -56,7 +56,7 @@ export class TouchbarService {
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab)
}
update (): void {
update () {
if (this.hostApp.platform !== Platform.macOS) {
return
}

View File

@@ -8,7 +8,6 @@ import { Injectable } from '@angular/core'
import { Logger, LogService } from './log.service'
import { ElectronService } from './electron.service'
import { ConfigService } from './config.service'
import { AppUpdater } from 'electron-updater'
const UPDATES_URL = 'https://api.github.com/repos/eugeny/terminus/releases/latest'
@@ -19,27 +18,21 @@ export class UpdaterService {
private downloaded: Promise<boolean>
private electronUpdaterAvailable = true
private updateURL: string
private autoUpdater: AppUpdater
private autoUpdater
private constructor (
constructor (
log: LogService,
private electron: ElectronService,
private config: ConfigService,
config: ConfigService,
) {
this.logger = log.create('updater')
if (process.platform === 'linux') {
this.electronUpdaterAvailable = false
return
}
this.autoUpdater = electron.remote.require('electron-updater').autoUpdater
this.autoUpdater.autoInstallOnAppQuit = !!config.store.enableAutomaticUpdates
this.autoUpdater.on('update-available', () => {
this.logger.info('Update available')
this.autoUpdater.downloadUpdate()
})
this.autoUpdater.once('update-not-available', () => {
this.logger.info('No updates')
@@ -49,8 +42,9 @@ export class UpdaterService {
this.autoUpdater.once('update-downloaded', () => resolve(true))
})
if (config.store.enableAutomaticUpdates && this.electronUpdaterAvailable && !process.env.TERMINUS_DEV) {
this.logger.debug('Checking for updates')
this.logger.debug('Checking for updates')
if (this.electronUpdaterAvailable && !process.env.TERMINUS_DEV) {
try {
this.autoUpdater.checkForUpdates()
} catch (e) {
@@ -61,9 +55,6 @@ export class UpdaterService {
}
async check (): Promise<boolean> {
if (!this.config.store.enableAutomaticUpdates) {
return false
}
if (!this.electronUpdaterAvailable) {
this.logger.debug('Checking for updates through fallback method.')
const response = await axios.get(UPDATES_URL)
@@ -80,7 +71,7 @@ export class UpdaterService {
return this.downloaded
}
async update (): Promise<void> {
async update () {
if (!this.electronUpdaterAvailable) {
this.electron.shell.openExternal(this.updateURL)
} else {

View File

@@ -1,16 +1,13 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Injectable, NgZone } from '@angular/core'
import { Subscription } from 'rxjs'
import { AppService } from './services/app.service'
import { BaseTabComponent } from './components/baseTab.component'
import { TabHeaderComponent } from './components/tabHeader.component'
import { SplitTabComponent, SplitDirection } from './components/splitTab.component'
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
/** @hidden */
@Injectable()
export class TabManagementContextMenu extends TabContextMenuItemProvider {
weight = 99
@Injectable({ providedIn: 'root' })
export class CloseContextMenu extends TabContextMenuItemProvider {
weight = -5
constructor (
private app: AppService,
@@ -19,67 +16,39 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = [
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
return [
{
label: 'Close',
click: () => this.zone.run(() => {
if (this.app.tabs.includes(tab)) {
this.app.closeTab(tab, true)
} else {
tab.destroy()
this.app.closeTab(tab, true)
}),
},
{
label: 'Close other tabs',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.filter(x => x !== tab)) {
this.app.closeTab(t, true)
}
}),
},
{
label: 'Close tabs to the right',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
this.app.closeTab(t, true)
}
}),
},
{
label: 'Close tabs to the left',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
this.app.closeTab(t, true)
}
}),
},
]
if (tabHeader) {
items = [
...items,
{
label: 'Close other tabs',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.filter(x => x !== tab)) {
this.app.closeTab(t, true)
}
}),
},
{
label: 'Close tabs to the right',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
this.app.closeTab(t, true)
}
}),
},
{
label: 'Close tabs to the left',
click: () => this.zone.run(() => {
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
this.app.closeTab(t, true)
}
}),
},
]
} else {
if (tab.parent instanceof SplitTabComponent) {
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
items.push({
label: 'Split',
submenu: directions.map(dir => ({
label: {
r: 'Right',
b: 'Down',
l: 'Left',
t: 'Up',
}[dir],
click: () => this.zone.run(() => {
(tab.parent as SplitTabComponent).splitTab(tab, dir)
}),
})) as Electron.MenuItemConstructorOptions[],
})
}
}
return items
}
}
@@ -94,7 +63,7 @@ const COLORS = [
]
/** @hidden */
@Injectable()
@Injectable({ providedIn: 'root' })
export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
weight = -1
@@ -106,38 +75,33 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = []
if (tabHeader) {
items = [
...items,
{
label: 'Rename',
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
},
{
label: 'Duplicate',
click: () => this.zone.run(() => this.app.duplicateTab(tab)),
},
{
label: 'Color',
sublabel: COLORS.find(x => x.value === tab.color)!.name,
submenu: COLORS.map(color => ({
label: color.name,
type: 'radio',
checked: tab.color === color.value,
click: () => this.zone.run(() => {
tab.color = color.value
}),
})) as Electron.MenuItemConstructorOptions[],
},
]
}
return items
return [
{
label: 'Rename',
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
},
{
label: 'Duplicate',
click: () => this.zone.run(() => this.app.duplicateTab(tab)),
},
{
label: 'Color',
sublabel: COLORS.find(x => x.value === tab.color)!.name,
submenu: COLORS.map(color => ({
label: color.name,
type: 'radio',
checked: tab.color === color.value,
click: () => this.zone.run(() => {
tab.color = color.value
}),
})) as Electron.MenuItemConstructorOptions[],
},
]
}
}
/** @hidden */
@Injectable()
@Injectable({ providedIn: 'root' })
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
constructor (
private app: AppService,
@@ -148,61 +112,36 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
const process = await tab.getCurrentProcess()
let items: Electron.MenuItemConstructorOptions[] = []
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
if (process) {
items.push({
id: 'process-name',
enabled: false,
label: 'Current process: ' + process.name,
})
items.push({
label: 'Notify when done',
type: 'checkbox',
checked: extTab.__completionNotificationEnabled,
click: () => this.zone.run(() => {
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
return [
{
id: 'process-name',
enabled: false,
label: 'Current process: ' + process.name,
},
{
label: 'Notify when done',
type: 'checkbox',
checked: (tab as any).__completionNotificationEnabled,
click: () => this.zone.run(() => {
(tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
if (extTab.__completionNotificationEnabled) {
this.app.observeTabCompletion(tab).subscribe(() => {
new Notification('Process completed', {
body: process.name,
}).addEventListener('click', () => {
this.app.selectTab(tab)
})
extTab.__completionNotificationEnabled = false
})
} else {
this.app.stopObservingTabCompletion(tab)
}
}),
})
}
items.push({
label: 'Notify on activity',
type: 'checkbox',
checked: !!extTab.__outputNotificationSubscription,
click: () => this.zone.run(() => {
if (extTab.__outputNotificationSubscription) {
extTab.__outputNotificationSubscription.unsubscribe()
extTab.__outputNotificationSubscription = null
} else {
extTab.__outputNotificationSubscription = tab.activity$.subscribe(active => {
if (extTab.__outputNotificationSubscription && active) {
extTab.__outputNotificationSubscription.unsubscribe()
extTab.__outputNotificationSubscription = null
new Notification('Tab activity', {
body: tab.title,
}).addEventListener('click', () => {
this.app.selectTab(tab)
if ((tab as any).__completionNotificationEnabled) {
this.app.observeTabCompletion(tab).subscribe(() => {
new Notification('Process completed', {
body: process.name,
}).addEventListener('click', () => {
this.app.selectTab(tab)
})
;(tab as any).__completionNotificationEnabled = false
})
} else {
this.app.stopObservingTabCompletion(tab)
}
})
}
}),
})
return items
}),
},
]
}
return []
}
}

View File

@@ -16,12 +16,4 @@ app-root {
terminaltab .content {
margin: 5px !important;
}
ssh-tab .content {
margin: 5px !important;
}
serial-tab .content {
margin: 5px !important;
}
}

View File

@@ -246,7 +246,7 @@ ngb-tabset .tab-content {
}
.list-group-item {
transition: 0.0625s background;
transition: 0.25s background;
i + * {
margin-left: 10px;
@@ -262,29 +262,6 @@ ngb-tabset .tab-content {
}
}
.list-group-light {
.list-group-item {
background: transparent;
border: none;
border-top: 1px solid rgba(255, 255, 255, .1);
&:not(.combi) {
padding: $list-group-item-padding-y $list-group-item-padding-x;
}
&:first-child {
border-top: none;
}
&.list-group-item-action {
&:hover, &.active {
background: $list-group-hover-bg;
}
}
}
}
checkbox i.on {
color: $blue;
}
@@ -415,7 +392,3 @@ search-panel {
border-color: $nav-tabs-link-active-border-color;
}
}
hr {
border-color: $list-group-border-color;
}

View File

@@ -142,7 +142,7 @@ $nav-tabs-link-active-border-color: #eee;
$navbar-padding-y: 0;
$navbar-padding-x: 0;
$dropdown-bg: $content-bg-solid;
$dropdown-bg: $table-bg;
$dropdown-color: $body-color;
$dropdown-border-width: 1px;
$dropdown-box-shadow: 0 .5rem 1rem rgba($black,.175);

View File

@@ -2,6 +2,9 @@
"extends": "../tsconfig.json",
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"baseUrl": "src"
"baseUrl": "src",
"paths": {
"*": ["../../app/node_modules/*"]
}
}
}

View File

@@ -1,10 +1,11 @@
const path = require('path')
const { AngularCompilerPlugin } = require('@ngtools/webpack')
module.exports = {
target: 'node',
entry: 'src/index.ts',
context: __dirname,
devtool: 'eval-cheap-module-source-map',
devtool: 'cheap-module-source-map',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
@@ -23,22 +24,26 @@ module.exports = {
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.json'),
typeRoots: [
path.resolve(__dirname, 'node_modules/@types'),
path.resolve(__dirname, '../node_modules/@types'),
],
paths: {
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
"*": [path.resolve(__dirname, '../app/node_modules/*')],
},
},
},
test: /(?:\.ngfactory\.js|\.ngfactory|\.ngstyle\.js|\.ts)$/,
loader: '@ngtools/webpack',
},
// {
// test: /\.ts$/,
// use: {
// loader: 'awesome-typescript-loader',
// options: {
// configFileName: path.resolve(__dirname, 'tsconfig.json'),
// typeRoots: [
// path.resolve(__dirname, 'node_modules/@types'),
// path.resolve(__dirname, '../node_modules/@types'),
// ],
// paths: {
// "terminus-*": [path.resolve(__dirname, '../terminus-*')],
// "*": [path.resolve(__dirname, '../app/node_modules/*')],
// },
// },
// },
// },
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['to-string-loader', 'css-loader'], include: /component\.css/ },
@@ -57,4 +62,12 @@ module.exports = {
/^@angular/,
/^@ng-bootstrap/,
],
plugins: [
new AngularCompilerPlugin({
tsConfigPath: path.resolve(__dirname, 'tsconfig.json'),
entryModule: './terminus-core/src/index#AppModule',
sourceMap: true,
directTemplateLoading: true,
}),
],
}

View File

@@ -3,21 +3,14 @@
"@types/js-yaml@^3.9.0":
version "3.12.4"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.4.tgz#7d3b534ec35a0585128e2d332db1403ebe057e25"
integrity sha512-fYMgzN+9e28R81weVN49inn/u798ruU91En1ZnGvSZzCRc5jXx9B2EDhlRaWmcO1RIxFHL8AajRXzxDuJu93+A==
version "3.12.1"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656"
integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==
"@types/node@*":
version "13.7.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
"@types/semver@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
dependencies:
"@types/node" "*"
"@types/semver@^6.0.2":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
"@types/shell-escape@^0.2.0":
version "0.2.0"
@@ -52,27 +45,23 @@ async@^2.6.1:
dependencies:
lodash "^4.17.11"
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
axios@^0.19.0:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
version "0.19.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
dependencies:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
bootstrap@^4.1.3:
version "4.4.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
version "4.3.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
builder-util-runtime@8.7.0:
version "8.7.0"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d"
integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==
builder-util-runtime@8.4.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.4.0.tgz#3163fffc078e6b8f3dd5b6eb12a8345573590682"
integrity sha512-CJB/eKfPf2vHrkmirF5eicVnbDCkMBbwd5tRYlTlgud16zFeqD7QmrVUAOEXdnsrcNkiLg9dbuUsQKtl/AwsYQ==
dependencies:
debug "^4.1.1"
sax "^1.2.4"
@@ -129,9 +118,9 @@ colorspace@1.1.x:
text-hex "1.0.x"
core-js@^3.1.2:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
version "3.4.2"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.4.2.tgz#ee2b1a60b50388d8ddcda8cdb44a92c7a9ea76df"
integrity sha512-bUTfqFWtNKWp73oNIfRkqwYZJeNT3lstzZcAkhhiuvDraRSgOH1/+F9ZklbpR4zpdKuo4cpXN8tKP7s61yjX+g==
core-util-is@~1.0.0:
version "1.0.2"
@@ -174,17 +163,18 @@ diagnostics@^1.1.1:
kuler "1.0.x"
electron-updater@^4.0.6:
version "4.3.1"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.1.tgz#9d485b6262bc56fcf7ee62b1dc1b3b105a3e96a7"
integrity sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==
version "4.2.0"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.2.0.tgz#f9ecfc657f65ead737d42b9efecf628d3756b550"
integrity sha512-GuS3g7HDh17x/SaFjxjswlWUaKHczksYkV2Xc5CKj/bZH0YCvTSHtOmnBAdAmCk99u/71p3zP8f0jIqDfGcjww==
dependencies:
"@types/semver" "^7.1.0"
builder-util-runtime "8.7.0"
fs-extra "^9.0.0"
"@types/semver" "^6.0.2"
builder-util-runtime "8.4.0"
fs-extra "^8.1.0"
js-yaml "^3.13.1"
lazy-val "^1.0.4"
lodash.isequal "^4.5.0"
semver "^7.1.3"
pako "^1.0.10"
semver "^6.3.0"
enabled@1.0.x:
version "1.0.2"
@@ -232,15 +222,14 @@ follow-redirects@1.5.10:
dependencies:
debug "=3.1.0"
fs-extra@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^1.0.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.2"
@@ -265,6 +254,11 @@ is-arrayish@^0.3.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-buffer@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -276,19 +270,17 @@ isarray@~1.0.0:
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
js-yaml@^3.13.1, js-yaml@^3.9.0:
version "3.14.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
jsonfile@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
dependencies:
universalify "^1.0.0"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
@@ -360,6 +352,11 @@ one-time@0.0.4:
resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
pako@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
perfect-scrollbar@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.4.0.tgz#5d014ef9775e1f43058a1dbae9ed1daf0e7091f1"
@@ -407,10 +404,10 @@ sax@^1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
semver@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
shell-escape@^0.2.0:
version "0.2.0"
@@ -458,20 +455,20 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
universalify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^8.0.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
uuid@^3.3.2:
version "3.3.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
winston-transport@^4.3.0:
version "4.3.0"

View File

@@ -1,6 +1,6 @@
{
"name": "terminus-plugin-manager",
"version": "1.0.104-nightly.0",
"version": "1.0.98-nightly.0",
"description": "Terminus' plugin manager",
"keywords": [
"terminus-builtin-plugin"
@@ -17,10 +17,10 @@
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/semver": "^7.1.0",
"@types/semver": "^6.0.0",
"axios": "^0.19.0",
"mz": "^2.6.0",
"semver": "^7.1.1"
"semver": "^6.1.0"
},
"peerDependencies": {
"@angular/common": "^7",

View File

@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { BehaviorSubject, Observable } from 'rxjs'
import { debounceTime, distinctUntilChanged, first, tap, flatMap, map } from 'rxjs/operators'
import semverGt from 'semver/functions/gt'
import * as semver from 'semver'
import { Component, Input } from '@angular/core'
import { ConfigService, ElectronService } from 'terminus-core'
@@ -49,7 +48,7 @@ export class PluginsSettingsTabComponent {
return plugins
})).subscribe(available => {
for (const plugin of this.pluginManager.installedPlugins) {
this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semverGt(x.version, plugin.version)) || null
this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semver.gt(x.version, plugin.version)) || null
}
})
}

View File

@@ -8,10 +8,6 @@ const NAME_PREFIX = 'terminus-'
const KEYWORD = 'terminus-plugin'
const OFFICIAL_NPM_ACCOUNT = 'eugenepankov'
const BLACKLIST = [
'terminus-shell-selector', // superseded by profiles
]
export interface PluginInfo {
name: string
description: string
@@ -34,13 +30,13 @@ export class PluginManagerService {
private npmReady: Promise<void>
private npm: any
private constructor (
constructor (
log: LogService,
) {
this.logger = log.create('pluginManager')
}
async getNPM (): Promise<any> {
async getNPM () {
if (!this.npm) {
if (!this.npmReady) {
this.npmReady = new Promise(resolve => {
@@ -79,11 +75,10 @@ export class PluginManagerService {
isOfficial: item.package.publisher.username === OFFICIAL_NPM_ACCOUNT,
}))),
map(plugins => plugins.filter(x => x.packageName.startsWith(NAME_PREFIX))),
map(plugins => plugins.filter(x => !BLACKLIST.includes(x.packageName))),
)
}
async installPlugin (plugin: PluginInfo): Promise<void> {
async installPlugin (plugin: PluginInfo) {
(await this.getNPM()).commands.install([`${plugin.packageName}@${plugin.version}`], err => {
if (err) {
this.logger.error(err)
@@ -93,7 +88,7 @@ export class PluginManagerService {
})
}
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
async uninstallPlugin (plugin: PluginInfo) {
(await this.getNPM()).commands.remove([plugin.packageName], err => {
if (err) {
this.logger.error(err)

View File

@@ -2,17 +2,10 @@
# yarn lockfile v1
"@types/node@*":
version "13.7.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113"
integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==
"@types/semver@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
dependencies:
"@types/node" "*"
"@types/semver@^6.0.0":
version "6.2.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
any-promise@^1.0.0:
version "1.3.0"
@@ -20,11 +13,12 @@ any-promise@^1.0.0:
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
axios@^0.19.0:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
version "0.19.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
dependencies:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
debug@=3.1.0:
version "3.1.0"
@@ -40,6 +34,11 @@ follow-redirects@1.5.10:
dependencies:
debug "=3.1.0"
is-buffer@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -59,10 +58,10 @@ object-assign@^4.0.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
semver@^7.1.1:
version "7.2.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.2.tgz#d01432d74ed3010a20ffaf909d63a691520521cd"
integrity sha512-Zo84u6o2PebMSK3zjJ6Zp5wi8VnQZnEaCP13Ul/lt1ANsLACxnJxq4EEm1PY94/por1Hm9+7xpIswdS5AkieMA==
semver@^6.1.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
thenify-all@^1.0.0:
version "1.6.0"

View File

@@ -1,37 +0,0 @@
{
"name": "terminus-serial",
"version": "1.0.104-nightly.0",
"description": "Serial connection manager for Terminus",
"keywords": [
"terminus-builtin-plugin"
],
"main": "dist/index.js",
"typings": "typings/index.d.ts",
"scripts": {
"build": "webpack --progress --color",
"watch": "webpack --progress --color --watch"
},
"files": [
"dist"
],
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/node": "12.7.3",
"@types/ssh2": "^0.5.35",
"ansi-colors": "^4.1.1",
"cli-spinner": "^0.2.10",
"electron-rebuild": "^1.10.0",
"terminus-terminal": "^1.0.98-nightly.0"
},
"peerDependencies": {
"@angular/common": "^7",
"@angular/core": "^7",
"@angular/forms": "^7",
"@ng-bootstrap/ng-bootstrap": "^1",
"rxjs": "^5",
"terminus-core": "*",
"terminus-settings": "*",
"terminus-terminal": "*"
}
}

View File

@@ -1,156 +0,0 @@
import { BaseSession } from 'terminus-terminal'
import { SerialPort } from 'serialport'
import { Logger } from 'terminus-core'
import { Subject, Observable } from 'rxjs'
export interface LoginScript {
expect: string
send: string
isRegex?: boolean
optional?: boolean
}
export interface SerialConnection {
name: string
port: string
baudrate: number
databits: number
stopbits: number
parity: string
rtscts: boolean
xon: boolean
xoff: boolean
xany: boolean
scripts?: LoginScript[]
color?: string
}
export const BAUD_RATES = [
110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600,
]
export interface SerialPortInfo {
name: string
description?: string
}
export class SerialSession extends BaseSession {
scripts?: LoginScript[]
serial: SerialPort
logger: Logger
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
private serviceMessage = new Subject<string>()
constructor (public connection: SerialConnection) {
super()
this.scripts = connection.scripts || []
}
async start (): Promise<void> {
this.open = true
this.serial.on('data', data => {
const dataString = data.toString()
this.emitOutput(data)
if (this.scripts) {
let found = false
for (const script of this.scripts) {
let match = false
let cmd = ''
if (script.isRegex) {
const re = new RegExp(script.expect, 'g')
if (dataString.match(re)) {
cmd = dataString.replace(re, script.send)
match = true
found = true
}
} else {
if (dataString.includes(script.expect)) {
cmd = script.send
match = true
found = true
}
}
if (match) {
this.logger.info('Executing script: "' + cmd + '"')
this.serial.write(cmd + '\n')
this.scripts = this.scripts.filter(x => x !== script)
} else {
if (script.optional) {
this.logger.debug('Skip optional script: ' + script.expect)
found = true
this.scripts = this.scripts.filter(x => x !== script)
} else {
break
}
}
}
if (found) {
this.executeUnconditionalScripts()
}
}
})
this.serial.on('end', () => {
this.logger.info('Shell session ended')
if (this.open) {
this.destroy()
}
})
this.executeUnconditionalScripts()
}
write (data: Buffer): void {
if (this.serial) {
this.serial.write(data.toString())
}
}
async destroy (): Promise<void> {
this.serviceMessage.complete()
await super.destroy()
}
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
resize (_, __) { }
kill (_?: string): void {
this.serial.close()
}
async getChildProcesses (): Promise<any[]> {
return []
}
async gracefullyKillProcess (): Promise<void> {
this.kill('TERM')
}
async getWorkingDirectory (): Promise<string|null> {
return null
}
private executeUnconditionalScripts () {
if (this.scripts) {
for (const script of this.scripts) {
if (!script.expect) {
console.log('Executing script:', script.send)
this.serial.write(script.send + '\n')
this.scripts = this.scripts.filter(x => x !== script)
} else {
break
}
}
}
}
}
export interface SerialConnectionGroup {
name: string
connections: SerialConnection[]
}

Some files were not shown because too many files have changed in this diff Show More