mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-19 07:41:53 +00:00
Compare commits
217 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f6d4a51239 | ||
![]() |
36f77c5b63 | ||
![]() |
3676b90c9f | ||
![]() |
c4204167cd | ||
![]() |
604d7c464f | ||
![]() |
e42bd11725 | ||
![]() |
864932d663 | ||
![]() |
9e68c735dc | ||
![]() |
be43f8b50d | ||
![]() |
c290633e7e | ||
![]() |
d03211631a | ||
![]() |
ca27c05f0f | ||
![]() |
62a21b03ea | ||
![]() |
6236ee95c3 | ||
![]() |
836014c270 | ||
![]() |
0bf870738e | ||
![]() |
7c1697b9cb | ||
![]() |
c800dd6e44 | ||
![]() |
68e9a1f66b | ||
![]() |
f925d63fb0 | ||
![]() |
e79fc13de9 | ||
![]() |
0c963dcbcc | ||
![]() |
b7b672ce9b | ||
![]() |
4c8bb45d01 | ||
![]() |
d4f8a88451 | ||
![]() |
fac8fafa36 | ||
![]() |
bc854fcfff | ||
![]() |
ebc83b8064 | ||
![]() |
6757deab67 | ||
![]() |
fe68d9a34e | ||
![]() |
2840ae2aa7 | ||
![]() |
b275f5311d | ||
![]() |
4e084cdc93 | ||
![]() |
910b207160 | ||
![]() |
f54ff37010 | ||
![]() |
03d9d46a8c | ||
![]() |
7111f35268 | ||
![]() |
44427ac3b6 | ||
![]() |
8816910e43 | ||
![]() |
31464ee37a | ||
![]() |
4bdb72021b | ||
![]() |
7d5e70c718 | ||
![]() |
6af92c9f95 | ||
![]() |
4a8fe78b07 | ||
![]() |
1aa6bc3c10 | ||
![]() |
93d74bf3cb | ||
![]() |
9e16ef5a57 | ||
![]() |
741c77506c | ||
![]() |
507cc16190 | ||
![]() |
bfeb353858 | ||
![]() |
806bfef8bf | ||
![]() |
975b5a117d | ||
![]() |
46e4832a66 | ||
![]() |
6ab7093cc6 | ||
![]() |
00cc2474cc | ||
![]() |
4e4d02041a | ||
![]() |
09ac506dd3 | ||
![]() |
769ce6bc0b | ||
![]() |
26605124c1 | ||
![]() |
7465c32645 | ||
![]() |
846ac62a7f | ||
![]() |
eae2c5ee16 | ||
![]() |
4fd89105e5 | ||
![]() |
87c1bef16e | ||
![]() |
eed35c2613 | ||
![]() |
678f2f7a85 | ||
![]() |
0b1bacaf0d | ||
![]() |
98b5a27382 | ||
![]() |
76a81b9402 | ||
![]() |
634b221aa3 | ||
![]() |
ffcb3e72c2 | ||
![]() |
b4b7bdeb16 | ||
![]() |
21daa4aa18 | ||
![]() |
867dbcddcc | ||
![]() |
b906dbd8d6 | ||
![]() |
e5c7d0649f | ||
![]() |
55286bc7e7 | ||
![]() |
359e41f884 | ||
![]() |
cc93578ada | ||
![]() |
2e54fa317c | ||
![]() |
c3bd725ce8 | ||
![]() |
18f69c5527 | ||
![]() |
0102a2a61b | ||
![]() |
1de709561c | ||
![]() |
9f985ee8f0 | ||
![]() |
1a35ed3c73 | ||
![]() |
a241144827 | ||
![]() |
18e341f886 | ||
![]() |
3182d4428d | ||
![]() |
6dfcb9422a | ||
![]() |
ad5993b94f | ||
![]() |
eb9826fb2a | ||
![]() |
1c81baa6f2 | ||
![]() |
e07c5db0a8 | ||
![]() |
b93989d02b | ||
![]() |
15bfde6077 | ||
![]() |
4243e79a11 | ||
![]() |
eb49001614 | ||
![]() |
3aaa670400 | ||
![]() |
5371b2d1a6 | ||
![]() |
e46281a9a7 | ||
![]() |
9d4aa179a0 | ||
![]() |
20118afd1f | ||
![]() |
b29daac3c6 | ||
![]() |
8ba9e8b210 | ||
![]() |
f3f3edfbb6 | ||
![]() |
472cb18a16 | ||
![]() |
7c8d8ebc81 | ||
![]() |
18fc0fa886 | ||
![]() |
5a90c246b9 | ||
![]() |
9bc31556f2 | ||
![]() |
2c81491825 | ||
![]() |
9ed18d965c | ||
![]() |
b4f76847bf | ||
![]() |
b9bcb14dd7 | ||
![]() |
ee3e17981b | ||
![]() |
415d833ae6 | ||
![]() |
ed9117670e | ||
![]() |
0ecd47346d | ||
![]() |
bc0024ec06 | ||
![]() |
bdec20f7c7 | ||
![]() |
45ebe3caf9 | ||
![]() |
7315bc8d8b | ||
![]() |
a969dc1ea4 | ||
![]() |
2733dc69be | ||
![]() |
bb86848cd3 | ||
![]() |
e844ad6063 | ||
![]() |
a096a691cc | ||
![]() |
a28e25e96a | ||
![]() |
a09ce13709 | ||
![]() |
123d8ceb5f | ||
![]() |
c0155c8d4e | ||
![]() |
fcda35b02e | ||
![]() |
9d6a1031da | ||
![]() |
c119d3283e | ||
![]() |
3667fb45ee | ||
![]() |
92d34343f1 | ||
![]() |
8afad944b7 | ||
![]() |
707d077eb2 | ||
![]() |
92eabab509 | ||
![]() |
888cfc6548 | ||
![]() |
9cb10c3e21 | ||
![]() |
661d5af9ba | ||
![]() |
26429bf209 | ||
![]() |
4779c41f48 | ||
![]() |
b11eda8653 | ||
![]() |
23bff8750c | ||
![]() |
aab1ae3ceb | ||
![]() |
9b5b5a9d00 | ||
![]() |
9c87cf3f3a | ||
![]() |
a8c7134218 | ||
![]() |
9734830a74 | ||
![]() |
5fa056751d | ||
![]() |
6fdccd0a02 | ||
![]() |
41ee7b7bbf | ||
![]() |
a755fdaa4e | ||
![]() |
1149d68d1c | ||
![]() |
1d92a3f89d | ||
![]() |
3557345d70 | ||
![]() |
86ebdd92b4 | ||
![]() |
4764ec8249 | ||
![]() |
b1752bd0b4 | ||
![]() |
1e697a952a | ||
![]() |
6bad2a2167 | ||
![]() |
61a46e3b4a | ||
![]() |
cba90cec0a | ||
![]() |
7583d92747 | ||
![]() |
e2b99d71ad | ||
![]() |
c829daac41 | ||
![]() |
aac38fa190 | ||
![]() |
7098622c8f | ||
![]() |
8695003c74 | ||
![]() |
43a27a7b7c | ||
![]() |
dd2d2ce20d | ||
![]() |
73574374f0 | ||
![]() |
5bd1bfd565 | ||
![]() |
0611afa8b5 | ||
![]() |
91c9e8affd | ||
![]() |
322ffc5847 | ||
![]() |
21084b5d24 | ||
![]() |
4c840a0db1 | ||
![]() |
3b69172f62 | ||
![]() |
e0efb4073a | ||
![]() |
c42b62afe6 | ||
![]() |
e2b11c83d5 | ||
![]() |
891fa5770a | ||
![]() |
6b395cc2b3 | ||
![]() |
448a1a094f | ||
![]() |
788dd61a13 | ||
![]() |
467684d9ab | ||
![]() |
5069070040 | ||
![]() |
ecf5297bc3 | ||
![]() |
78bd90ac55 | ||
![]() |
712589eb93 | ||
![]() |
f103e71285 | ||
![]() |
0cf883cc4a | ||
![]() |
2b0ad0d558 | ||
![]() |
67bacb9dd3 | ||
![]() |
d0a597634d | ||
![]() |
322014c409 | ||
![]() |
c751a8725b | ||
![]() |
5417efe558 | ||
![]() |
bf356fcd19 | ||
![]() |
10ee66b9dd | ||
![]() |
6545a2fda6 | ||
![]() |
763da0d80c | ||
![]() |
8d46bb2181 | ||
![]() |
fe936c7726 | ||
![]() |
2f3e32990a | ||
![]() |
22344f8d54 | ||
![]() |
f6d37a39f4 | ||
![]() |
0e4c60ad4b | ||
![]() |
e8c2171d8f | ||
![]() |
f7a5be2c67 | ||
![]() |
ceb638e08d | ||
![]() |
040098050d | ||
![]() |
00de7c148f |
@@ -343,6 +343,33 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "VectorKappa",
|
||||
"name": "Piotr Patalong",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/29167842?v=4",
|
||||
"profile": "http://patalong.pl",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "clarkwang",
|
||||
"name": "Clark Wang",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/157076?v=4",
|
||||
"profile": "https://github.com/clarkwang",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "iamchating",
|
||||
"name": "iamchating",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7088153?v=4",
|
||||
"profile": "https://github.com/iamchating",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@@ -1,6 +1,8 @@
|
||||
parser: '@typescript-eslint/parser'
|
||||
parserOptions:
|
||||
project: tsconfig.json
|
||||
project:
|
||||
- tsconfig.json
|
||||
- '*/tsconfig.typings.json'
|
||||
extends:
|
||||
- 'plugin:@typescript-eslint/all'
|
||||
plugins:
|
||||
@@ -37,6 +39,7 @@ rules:
|
||||
'@typescript-eslint/no-misused-promises': off
|
||||
'@typescript-eslint/typedef': off
|
||||
'@typescript-eslint/consistent-type-imports': off
|
||||
'@typescript-eslint/sort-type-union-intersection-members': off
|
||||
'@typescript-eslint/no-use-before-define':
|
||||
- error
|
||||
- classes: false
|
||||
@@ -81,7 +84,8 @@ rules:
|
||||
argsIgnorePattern: ^_
|
||||
no-undef: error
|
||||
no-var: error
|
||||
object-curly-spacing:
|
||||
object-curly-spacing: off
|
||||
'@typescript-eslint/object-curly-spacing':
|
||||
- error
|
||||
- always
|
||||
quote-props:
|
||||
|
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@@ -23,6 +23,7 @@ jobs:
|
||||
cd ..
|
||||
rm app/node_modules/.yarn-integrity
|
||||
yarn
|
||||
yarn run build:typings
|
||||
yarn run docs
|
||||
rsync -e "ssh -o StrictHostKeyChecking=no" -arv docs/api/ root@ajenti.org:/srv/terminus-docs/
|
||||
|
||||
|
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@@ -21,6 +21,10 @@ jobs:
|
||||
cd ..
|
||||
rm app/node_modules/.yarn-integrity
|
||||
yarn
|
||||
./node_modules/.bin/patch-package
|
||||
cd app
|
||||
../node_modules/.bin/patch-package
|
||||
cd ..
|
||||
|
||||
- name: Build native deps
|
||||
run: scripts/build-native.js
|
||||
|
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
@@ -26,6 +26,10 @@ jobs:
|
||||
cd ..
|
||||
rm app/node_modules/.yarn-integrity
|
||||
yarn
|
||||
./node_modules/.bin/patch-package
|
||||
cd app
|
||||
../node_modules/.bin/patch-package
|
||||
cd ..
|
||||
|
||||
- name: Build native deps
|
||||
run: scripts/build-native.js
|
||||
|
10
HACKING.md
10
HACKING.md
@@ -10,27 +10,25 @@ First, install the dependencies:
|
||||
|
||||
```
|
||||
# macOS/Linux:
|
||||
npm install
|
||||
./scripts/install-deps.js
|
||||
yarn
|
||||
./scripts/build-native.js
|
||||
|
||||
# Windows:
|
||||
npm -g install windows-build-tools
|
||||
npm install
|
||||
node scripts\install-deps.js
|
||||
yarn
|
||||
node scripts\build-native.js
|
||||
```
|
||||
|
||||
Now, check if your build is working:
|
||||
|
||||
```
|
||||
npm run build
|
||||
yarn run build
|
||||
```
|
||||
|
||||
Start Terminus with
|
||||
|
||||
```
|
||||
npm start
|
||||
yarn start
|
||||
```
|
||||
|
||||
# Project layout
|
||||
|
@@ -1,4 +1,4 @@
|
||||
****
|
||||

|
||||
|
||||
|
||||
<p align="center">
|
||||
@@ -121,6 +121,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Takuro Onoda</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=TakuroOnoda" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frauhottelmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=frauhottelmann" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://patalong.pl"><img src="https://avatars.githubusercontent.com/u/29167842?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotr Patalong</b></sub></a><br /><a href="#design-VectorKappa" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/clarkwang"><img src="https://avatars.githubusercontent.com/u/157076?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Clark Wang</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=clarkwang" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/iamchating"><img src="https://avatars.githubusercontent.com/u/7088153?v=4?s=100" width="100px;" alt=""/><br /><sub><b>iamchating</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=iamchating" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@@ -75,7 +75,7 @@ export class Application {
|
||||
}
|
||||
|
||||
onGlobalHotkey (): void {
|
||||
if (this.windows.some(x => x.isFocused())) {
|
||||
if (this.windows.some(x => x.isFocused() && x.isVisible())) {
|
||||
for (const window of this.windows) {
|
||||
window.hide()
|
||||
}
|
||||
@@ -147,7 +147,7 @@ export class Application {
|
||||
|
||||
handleSecondInstance (argv: string[], cwd: string): void {
|
||||
this.presentAllWindows()
|
||||
this.windows[this.windows.length - 1].handleSecondInstance(argv, cwd)
|
||||
this.windows[this.windows.length - 1].passCliArguments(argv, cwd, true)
|
||||
}
|
||||
|
||||
private setupMenu () {
|
||||
|
@@ -6,7 +6,7 @@ import { app } from 'electron'
|
||||
export function loadConfig (): any {
|
||||
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
if (fs.existsSync(configPath)) {
|
||||
return yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
|
||||
return yaml.load(fs.readFileSync(configPath, 'utf8'))
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ if (argv.d) {
|
||||
})
|
||||
}
|
||||
|
||||
app.on('ready', () => {
|
||||
app.on('ready', async () => {
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.setMenu(Menu.buildFromTemplate([
|
||||
{
|
||||
@@ -65,5 +65,8 @@ app.on('ready', () => {
|
||||
]))
|
||||
}
|
||||
application.init()
|
||||
application.newWindow({ hidden: argv.hidden })
|
||||
|
||||
const window = await application.newWindow({ hidden: argv.hidden })
|
||||
await window.ready
|
||||
window.passCliArguments(process.argv, process.cwd(), false)
|
||||
})
|
||||
|
@@ -36,7 +36,7 @@ export class Window {
|
||||
private windowConfig: ElectronConfig
|
||||
private windowBounds?: Rectangle
|
||||
private closing = false
|
||||
private lastVibrancy: {enabled: boolean, type?: string} | null = null
|
||||
private lastVibrancy: { enabled: boolean, type?: string } | null = null
|
||||
private disableVibrancyWhileDragging = false
|
||||
private configStore: any
|
||||
|
||||
@@ -65,6 +65,7 @@ export class Window {
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
maximizable: true,
|
||||
frame: false,
|
||||
show: false,
|
||||
backgroundColor: '#00000000',
|
||||
@@ -87,7 +88,7 @@ export class Window {
|
||||
bwOptions.frame = true
|
||||
} else {
|
||||
if (process.platform === 'darwin') {
|
||||
bwOptions.titleBarStyle = 'hiddenInset'
|
||||
bwOptions.titleBarStyle = 'hidden'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +191,10 @@ export class Window {
|
||||
return this.window.isFocused()
|
||||
}
|
||||
|
||||
isVisible (): boolean {
|
||||
return this.window.isVisible()
|
||||
}
|
||||
|
||||
hide (): void {
|
||||
if (process.platform === 'darwin') {
|
||||
// Lose focus
|
||||
@@ -225,8 +230,8 @@ export class Window {
|
||||
}
|
||||
}
|
||||
|
||||
handleSecondInstance (argv: string[], cwd: string): void {
|
||||
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
|
||||
passCliArguments (argv: string[], cwd: string, secondInstance: boolean): void {
|
||||
this.send('cli', parseArgs(argv, cwd), cwd, secondInstance)
|
||||
}
|
||||
|
||||
private setupWindowManagement () {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "terminus",
|
||||
"description": "A terminal for a modern age",
|
||||
"private": true,
|
||||
"repository": "https://github.com/eugeny/terminus",
|
||||
"author": {
|
||||
"name": "Eugene Pankov",
|
||||
@@ -13,42 +14,43 @@
|
||||
"watch": "webpack --progress --color --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^9.1.9",
|
||||
"@angular/common": "^9.1.11",
|
||||
"@angular/compiler": "^9.1.9",
|
||||
"@angular/core": "^9.1.9",
|
||||
"@angular/forms": "^9.1.11",
|
||||
"@angular/platform-browser": "^9.1.9",
|
||||
"@angular/platform-browser-dynamic": "^9.1.9",
|
||||
"@angular/animations": "^11.1.1",
|
||||
"@angular/common": "^11.1.1",
|
||||
"@angular/compiler": "^11.1.1",
|
||||
"@angular/core": "^11.1.1",
|
||||
"@angular/forms": "^11.1.1",
|
||||
"@angular/platform-browser": "^11.1.1",
|
||||
"@angular/platform-browser-dynamic": "^11.1.1",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
|
||||
"@terminus-term/node-pty": "0.10.0-beta11",
|
||||
"@terminus-term/node-pty": "0.10.0-terminus.3",
|
||||
"electron-config": "2.0.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-is-dev": "1.1.0",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-is-dev": "1.2.0",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"fontmanager-redux": "1.0.0",
|
||||
"glasstron": "0.0.6",
|
||||
"js-yaml": "3.14.0",
|
||||
"keytar": "^7.2.0",
|
||||
"glasstron": "0.0.7",
|
||||
"js-yaml": "4.0.0",
|
||||
"keytar": "^7.4.0",
|
||||
"mz": "^2.7.0",
|
||||
"ngx-toastr": "^12.0.1",
|
||||
"native-process-working-directory": "^1.0.2",
|
||||
"ngx-toastr": "^13.2.0",
|
||||
"npm": "6",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "^6.5.5",
|
||||
"rxjs": "^6.6.6",
|
||||
"yargs": "^15.4.1",
|
||||
"zone.js": "^0.11.3"
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"macos-native-processlist": "^2.0.0",
|
||||
"serialport": "^9.0.4",
|
||||
"serialport": "^9.0.7",
|
||||
"windows-blurbehind": "^1.0.1",
|
||||
"windows-native-registry": "^3.0.0",
|
||||
"windows-process-tree": "^0.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mz": "0.0.32",
|
||||
"@types/node": "14.14.14",
|
||||
"node-abi": "2.19.3",
|
||||
"@types/node": "14.14.31",
|
||||
"node-abi": "^2.21.0",
|
||||
"source-map-support": "^0.5.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -59,5 +61,8 @@
|
||||
"terminus-settings": "*",
|
||||
"terminus-ssh": "*",
|
||||
"terminus-terminal": "*"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/node-abi": "^2.20.0"
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ export function getRootModule (plugins: any[]) {
|
||||
positionClass: 'toast-bottom-center',
|
||||
toastClass: 'toast',
|
||||
preventDuplicates: true,
|
||||
extendedTimeOut: 5000,
|
||||
extendedTimeOut: 1000,
|
||||
}),
|
||||
]
|
||||
const bootstrap = [
|
||||
|
@@ -95,3 +95,12 @@ input[type=range] {
|
||||
&::-moz-range-track { @include track(); }
|
||||
&::-ms-track { @include track(); }
|
||||
}
|
||||
|
||||
a[ngbdropdownitem] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ngb-typeahead-window {
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
@@ -2,14 +2,16 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
padding: 20px 0 50px;
|
||||
|
||||
.toast {
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,.25);
|
||||
padding: 10px;
|
||||
padding: 7px 12px;
|
||||
background-image: none;
|
||||
width: auto;
|
||||
flex-basis: auto;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
|
||||
&.toast-error {
|
||||
background-color: #BD362F;
|
||||
|
378
app/yarn.lock
378
app/yarn.lock
@@ -2,40 +2,54 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@angular/animations@^9.1.9":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/animations/-/animations-9.1.13.tgz"
|
||||
integrity sha512-ane1eeQmsP7fcAiLgRhle7YIDgE88WDMMvzqJYhSxwLzXNF/hwqNeskmNcjo8bLt9h/yTIjrCQbycLCHJfU8UQ==
|
||||
"@angular/animations@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-11.2.0.tgz#383438758c61d98f43c5ea1078d8388eb8784387"
|
||||
integrity sha512-orYrBPNAsF8VpvuOaXTtPltwK2nsje5R8sWJnRC2dh1RCRdyIqHwmRIU0Mi6qLMiEaLNrFPGEMyQ9gB+sC/vYg==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/common@^9.1.11":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/common/-/common-9.1.13.tgz"
|
||||
integrity sha512-QACUhJWlly/nfHUmjopVS1p6ayxxa/NqjyftdCeBJaoyM2YohqWixP/n/keu1K/srJ96aFpUNsZQgmgoRv5SOQ==
|
||||
"@angular/common@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-11.2.0.tgz#90d602c0e33bb95a4d0c4c597f08255d78ed580f"
|
||||
integrity sha512-wsWI5F6Y2DNxne2D5uk8e9U/vn95UYZLMNBW+QXI9U/I9kDSXoa8yEvNcn1x0XfNXBMst5pi4iSF5M8mIck1eg==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/compiler@^9.1.9":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.13.tgz"
|
||||
integrity sha512-9MLB1Xx7odKuxDoybVwiOB1ZEUZpL8FurYm4RVuW39ntsUt0IMC9Hb8UagZLTAWhaWSHydkD/KBQVVobGqd0lA==
|
||||
"@angular/compiler@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-11.2.0.tgz#130bee57dd1daa1326d37bef4b63c02aa7309cc2"
|
||||
integrity sha512-EW6LM/kUYhQkuFqGt03c/eRKZAYr0LLEdMOn//j1uIh+wSq9KLffBGpky6b63xdfWxsXi8OucXUOydTQBckNEQ==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/core@^9.1.9":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/core/-/core-9.1.13.tgz"
|
||||
integrity sha512-mBm24Q9GjkAsxMAzqQ86U1078+yTEpr0+syMEruUtJ0HUH6Fzn3J+6xTLb+BVcGb9RkCkFaV9T5mcn6ZM0f++g==
|
||||
"@angular/core@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-11.2.0.tgz#309ae61d55b21fca0b644a6571109741d64b2467"
|
||||
integrity sha512-jnbnJTW2GwfkRoXG8J4zs5FMcahMZwo6jrZGe9FiXjCYG9cLEuOXy4h99Z1s/o0vc/VXyWgym7SmeEgv+urf8g==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/forms@^9.1.11":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/forms/-/forms-9.1.13.tgz"
|
||||
integrity sha512-soGVZmPq2bzkxvtTyeJB8p3ejzm4xxt+43hJw6Ag8NxpwUFPVa30oJge3JV+u8Y4yBtl5SbOZ4bBX3EkMxLcGQ==
|
||||
"@angular/forms@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-11.2.0.tgz#8ba7a98efdd464a4a6b901ba1f220162dd80c1ed"
|
||||
integrity sha512-FgIG9ou27FbmyFv0n6pF95cQEz412/+iyY9OSlDnezD/7yU4fwk4NNPgP6Z/b1k7ClLYxP/YKC00WVhi1i8HdA==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/platform-browser-dynamic@^9.1.9":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.13.tgz"
|
||||
integrity sha512-jCeHyAZ4Nap1/FOqAlKEg9UxQaSkHrxnQr6hYtWwC4ZDVUn3zLWQf6J+mbeYNOXN5yQxEiIqqhORYeOCLLqf1w==
|
||||
"@angular/platform-browser-dynamic@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.0.tgz#647fe6d8dfa7651d38564240cbf75f97f11754b7"
|
||||
integrity sha512-bBCtgtL87mvDT0K3HNBS19UC0BzIJUTGnYKJS9IugyfTEqlldB4juMmh/3FPjk30kxxJ8IB/ydaN2uVhBAxPVQ==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@angular/platform-browser@^9.1.9":
|
||||
version "9.1.13"
|
||||
resolved "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.13.tgz"
|
||||
integrity sha512-F3iTz1zNbtrs7KFKUxbj8qmTsd/fiuTNcpBExjE5TtatRiE6J8vNvN1+Z/1FgPe0UXBSdTzSwZ8/RxWKw20RMw==
|
||||
"@angular/platform-browser@^11.1.1":
|
||||
version "11.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-11.2.0.tgz#d1bbafd394ebfb600043060ec2d8543763041403"
|
||||
integrity sha512-xd3O4svQ95BN/KpzQUFkSWfvwiCURuLJhLlDkxzLA58ElA0qodHOjQmQz/1vRFh/nXQQoWg8z9ixbmcRGzWTow==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@iarna/cli@^1.2.0":
|
||||
version "1.2.0"
|
||||
@@ -51,78 +65,83 @@
|
||||
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-6.2.0.tgz#0506d612ca6002bd8fa398d006fa2641013e11d4"
|
||||
integrity sha512-wqwhnJFyEwvzWQJjXrEt+7oBTSvu2qPbdYvUFYhDVzOJLWB5M7YEhDAkMrfHQJ0pZNBMGr580FqYue+XiURY0Q==
|
||||
|
||||
"@serialport/binding-abstract@^9.0.2":
|
||||
version "9.0.2"
|
||||
resolved "https://registry.npmjs.org/@serialport/binding-abstract/-/binding-abstract-9.0.2.tgz"
|
||||
integrity sha512-kyMX6usn+VLpidt0YsDq5JwztIan9TPCX6skr0XcalOxI8I7w+/2qVZJzjgo2fSqDnPRcU2jMWTytwzEXFODvQ==
|
||||
"@serialport/binding-abstract@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/binding-abstract/-/binding-abstract-9.0.7.tgz#d2c7ecea0f100bdf20187bfc0d34ba90f5504e1e"
|
||||
integrity sha512-g1ncCMIG9rMsxo/28ObYmXZcHThlvtZygsCANmyMUuFS7SwXY4+PhcEnt2+ZcMkEDNRiOklT+ngtIVx5GGpt/A==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@serialport/binding-mock@^9.0.2":
|
||||
version "9.0.2"
|
||||
resolved "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-9.0.2.tgz"
|
||||
integrity sha512-HfrvJ/LXULHk8w63CGxwDNiDidFgDX8BnadY+cgVS6yHMHikbhLCLjCmUKsKBWaGKRqOznl0w+iUl7TMi1lkXQ==
|
||||
"@serialport/binding-mock@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/binding-mock/-/binding-mock-9.0.7.tgz#2fda427adc113320461f33f7426dfca73e8ad1de"
|
||||
integrity sha512-aR8H+htZwwZZkVb1MdbnNvGWw8eXVRqQ2qPhkbKyx0N/LY5aVIgCgT98Kt1YylLsG7SzNG+Jbhd4wzwEuPVT5Q==
|
||||
dependencies:
|
||||
"@serialport/binding-abstract" "^9.0.2"
|
||||
debug "^4.1.1"
|
||||
"@serialport/binding-abstract" "^9.0.7"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@serialport/bindings@^9.0.4":
|
||||
version "9.0.4"
|
||||
resolved "https://registry.npmjs.org/@serialport/bindings/-/bindings-9.0.4.tgz"
|
||||
integrity sha512-6dlE1vm5c1xk667f1Zm7D+msbHJ9jdnUr9l8DResKpj2iCBzbCNsW+yCYq26WxzXWc1L2HUaS3/aL+k0wm5amg==
|
||||
"@serialport/bindings@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/bindings/-/bindings-9.0.7.tgz#8f53fb56eb866d5a1021a19ced1ddc20a60916d7"
|
||||
integrity sha512-cNWaxnEbbpLoSJ6GMb0ZeCpaciczm8XRE4jgBqe/BflWZb+wyiTYIocbsySxpS40WT3kJ0sNTFag77uSmQ6ftg==
|
||||
dependencies:
|
||||
"@serialport/binding-abstract" "^9.0.2"
|
||||
"@serialport/parser-readline" "^9.0.1"
|
||||
"@serialport/binding-abstract" "^9.0.7"
|
||||
"@serialport/parser-readline" "^9.0.7"
|
||||
bindings "^1.5.0"
|
||||
debug "^4.3.1"
|
||||
nan "^2.14.2"
|
||||
prebuild-install "^6.0.0"
|
||||
prebuild-install "^6.0.1"
|
||||
|
||||
"@serialport/parser-byte-length@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-9.0.1.tgz"
|
||||
integrity sha512-1Ikv4lgCNw8OMf35yCpgzjHwkpgBEkhBuXFXIdWZk+ixaHFLlAtp03QxGPZBmzHMK58WDmEQoBHC1V5BkkAKSQ==
|
||||
"@serialport/parser-byte-length@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-byte-length/-/parser-byte-length-9.0.7.tgz#9e362bba70eeffcd2eb0804afeca4bb1dee59d5f"
|
||||
integrity sha512-evf7oOOSBMBn2AZZbgBFMRIyEzlsyQkhqaPm7IBCPTxMDXRf4tKkFYJHYZB0/6d1W4eI0meH079UqmSsh/uoDA==
|
||||
|
||||
"@serialport/parser-cctalk@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-cctalk/-/parser-cctalk-9.0.1.tgz"
|
||||
integrity sha512-GtMda2DeJ+23bNqOc79JYV06dax2n3FLLFM3zA7nfReCOi98QbuDj4TUbFESMOnp4DB0oMO0GYHCR9gHOedTkg==
|
||||
"@serialport/parser-cctalk@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-cctalk/-/parser-cctalk-9.0.7.tgz#fa0e1539f067aced22a5ef7d64fdac14f1a6a4d3"
|
||||
integrity sha512-ert5jhMkeiTfr44TkbdySC09J8UwAsf/RxBucVN5Mz5enG509RggnkfFi4mfj3UCG2vZ7qsmM6gtZ62DshY02Q==
|
||||
|
||||
"@serialport/parser-delimiter@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-delimiter/-/parser-delimiter-9.0.1.tgz"
|
||||
integrity sha512-+oaSl5zEu47OlrRiF5p5tn2qgGqYuhVcE+NI+Pv4E1xsNB/A0fFxxMv/8XUw466CRLEJ5IESIB9qbFvKE6ltaQ==
|
||||
"@serialport/parser-delimiter@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-delimiter/-/parser-delimiter-9.0.7.tgz#7bef2447d4282dd00dc659719b310edeb30ff294"
|
||||
integrity sha512-Vb2NPeXPZ/28M4m5x4OAHFd8jRAeddNCgvL+Q+H/hqFPY1w47JcMLchC7pigRW8Cnt1fklmzfwdNQ8Fb+kMkxQ==
|
||||
|
||||
"@serialport/parser-readline@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-readline/-/parser-readline-9.0.1.tgz"
|
||||
integrity sha512-38058gxvyfgdeLpg3aUyD98NuWkVB9yyTLpcSdeQ3GYiupivwH6Tdy/SKPmxlHIw3Ml2qil5MR2mtW2fLPB5CQ==
|
||||
"@serialport/parser-inter-byte-timeout@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-9.0.7.tgz#55b315b49d8ad37f981ba69bb9443f25c96aec17"
|
||||
integrity sha512-lUZ3cwgUluBvJ1jf+0LQsqoiPYAokDO6+fRCw9HCfnrF/OS60Gm4rxuyo2uQIueqZkJ7NIFP+ibKsULrA47AEA==
|
||||
|
||||
"@serialport/parser-readline@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-readline/-/parser-readline-9.0.7.tgz#8b096028170fb2644bcf0f997d534a344cfd00e6"
|
||||
integrity sha512-ydoLbgVQQPxWrwbe3Fhh4XnZexbkEQAC6M/qgRTzjnKvTjrD61CJNxLc3vyDaAPI9bJIhTiI7eTX3JB5jJv8Hg==
|
||||
dependencies:
|
||||
"@serialport/parser-delimiter" "^9.0.1"
|
||||
"@serialport/parser-delimiter" "^9.0.7"
|
||||
|
||||
"@serialport/parser-ready@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-ready/-/parser-ready-9.0.1.tgz"
|
||||
integrity sha512-lgzGkVJaaV1rJVx26WwI2UKyPxc0vu1rsOeldzA3VVbF+ABrblUQA06+cRPpT6k96GY+X4+1fB1rWuPpt8HbgQ==
|
||||
"@serialport/parser-ready@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-ready/-/parser-ready-9.0.7.tgz#d9eb9801c6003fdb1450c557f3e256a188a9f3be"
|
||||
integrity sha512-3qYhI4cNUPAYqVYvdwV57Y+PVRl4dJf1fPBtMoWtwDgwopsAXTR93WCs49WuUq9JCyNW+8Hrfqv8x8eNAD5Dqg==
|
||||
|
||||
"@serialport/parser-regex@^9.0.1":
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/@serialport/parser-regex/-/parser-regex-9.0.1.tgz"
|
||||
integrity sha512-BHTV+Lkl+J8hSecFtDRENaR4fgA6tw44J+dmA1vEKEyum0iDN4bihbu8yvztYyo4PhBGUKDfm/PnD5EkJm0dPA==
|
||||
"@serialport/parser-regex@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-regex/-/parser-regex-9.0.7.tgz#d8a02e3a169faa2f6604e8293832cc676b865f48"
|
||||
integrity sha512-5XF+FXbhqQ/5bVKM4NaGs1m+E9KjfmeCx/obwsKaUZognQF67jwoTfjJJWNP/21jKfxdl8XoCYjZjASl3XKRAw==
|
||||
|
||||
"@serialport/stream@^9.0.2":
|
||||
version "9.0.2"
|
||||
resolved "https://registry.npmjs.org/@serialport/stream/-/stream-9.0.2.tgz"
|
||||
integrity sha512-0RkVe+gvwZu/PPfbb7ExQ+euGoCTGKD/B8TQ5fuhe+eKk1sh73RwjKmu9gp6veSNqx9Zljnh1dF6mhdEKWZpSA==
|
||||
"@serialport/stream@^9.0.7":
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-9.0.7.tgz#0bf023eb0233a714fcc5a86de09e381e466d9882"
|
||||
integrity sha512-c/h7HPAeFiryD9iTGlaSvPqHFHSZ0NMQHxC4rcmKS2Vu3qJuEtkBdTLABwsMp7iWEiSnI4KC3s7bHapaXP06FQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@terminus-term/node-pty@0.10.0-beta11":
|
||||
version "0.10.0-beta11"
|
||||
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-beta11.tgz#9e83041bc0644f17a4329c41a13d09575653c544"
|
||||
integrity sha512-ZrplD84UNV8qpCNpsG8DAo8fmoRP1Ynb9QsApIleCJjbeNvUP2ZAeR6wo0aV9B7Zqjvq5O4hoUSayIDGtORH+A==
|
||||
"@terminus-term/node-pty@0.10.0-terminus.3":
|
||||
version "0.10.0-terminus.3"
|
||||
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-terminus.3.tgz#9dbd64d52afda5079e66265a89d313fe42affab7"
|
||||
integrity sha512-HvIOts22dnoBXhRfLiK9DyPasuixYVgEUvgqZmOr0B0Ki9tF8e074oYPUtzLRll6Y553QiUzTWhriCS99MChNQ==
|
||||
dependencies:
|
||||
node-addon-api "^3.0.2"
|
||||
nan "^2.14.0"
|
||||
|
||||
"@types/mz@0.0.32":
|
||||
version "0.0.32"
|
||||
@@ -131,10 +150,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@14.14.14":
|
||||
version "14.14.14"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz"
|
||||
integrity sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==
|
||||
"@types/node@*", "@types/node@14.14.31":
|
||||
version "14.14.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
|
||||
integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
|
||||
|
||||
JSONStream@^1.3.4, JSONStream@^1.3.5:
|
||||
version "1.3.5"
|
||||
@@ -259,12 +278,10 @@ are-we-there-yet@~1.1.2:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^2.0.6"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
|
||||
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
asap@^2.0.0:
|
||||
version "2.0.6"
|
||||
@@ -709,7 +726,7 @@ debug@^3.1.0:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
|
||||
debug@^4.0.1, debug@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
|
||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||
@@ -837,10 +854,10 @@ electron-config@2.0.0:
|
||||
dependencies:
|
||||
conf "^1.0.0"
|
||||
|
||||
electron-debug@^3.0.1:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/electron-debug/-/electron-debug-3.1.0.tgz"
|
||||
integrity sha512-SWEqLj4MgfV3tGuO5eBLQ5/Nr6M+KPxsnE0bUJZvQebGJus6RAcdmvd7L+l0Ji31h2mmrN23l2tHFtCa2FvurA==
|
||||
electron-debug@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-debug/-/electron-debug-3.2.0.tgz#46a15b555c3b11872218c65ea01d058aa0814920"
|
||||
integrity sha512-7xZh+LfUvJ52M9rn6N+tPuDw6oRAjxUj9SoxAZfJ0hVCXhZCsdkrSt7TgXOiWiEOBgEV8qwUIO/ScxllsPS7ow==
|
||||
dependencies:
|
||||
electron-is-dev "^1.1.0"
|
||||
electron-localshortcut "^3.1.0"
|
||||
@@ -850,7 +867,12 @@ electron-is-accelerator@^0.1.0:
|
||||
resolved "https://registry.npmjs.org/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz"
|
||||
integrity sha1-UJ5RDCala1Xhf4Y6SwThEYRqsns=
|
||||
|
||||
electron-is-dev@1.1.0, electron-is-dev@^1.1.0:
|
||||
electron-is-dev@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-1.2.0.tgz#2e5cea0a1b3ccf1c86f577cee77363ef55deb05e"
|
||||
integrity sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==
|
||||
|
||||
electron-is-dev@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.1.0.tgz"
|
||||
integrity sha512-Z1qA/1oHNowGtSBIcWk0pcLEqYT/j+13xUw/MYOrBUOL4X7VN0i0KCTf5SqyvMPmW5pSPKbo28wkxMxzZ20YnQ==
|
||||
@@ -972,11 +994,6 @@ escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
esprima@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
execa@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
|
||||
@@ -1217,10 +1234,10 @@ github-from-package@0.0.0:
|
||||
resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz"
|
||||
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
|
||||
|
||||
glasstron@0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/glasstron/-/glasstron-0.0.6.tgz#1438899cd49a1cda1999290be2165310b759fd62"
|
||||
integrity sha512-WBE1zH3ZcYhLlfKATfKzuN05Anno2WYlVfImWteU5RM+gqdFLHGIxxM3VR16JvFF5oIYah01MBGQ2+3xTq44iQ==
|
||||
glasstron@0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/glasstron/-/glasstron-0.0.7.tgz#d0f3e8344351bbcb89a39323282b4ddb06b03ba0"
|
||||
integrity sha512-zeqfC0E153yBKWHB8ZBA5rT1o1dCCQcPECBryzWLX3uy6VTX3CUcy7kjk/4BlVztEIbpV2plEetpOxSAOe5cqw==
|
||||
dependencies:
|
||||
node-addon-api "^3.0.0"
|
||||
x11 "^2.3.0"
|
||||
@@ -1405,7 +1422,7 @@ inherits@2.0.3:
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
||||
ini@^1.3.4, ini@^1.3.5, ini@^1.3.8, ini@~1.3.0:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz"
|
||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||
@@ -1581,13 +1598,12 @@ isstream@~0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
js-yaml@3.14.0:
|
||||
version "3.14.0"
|
||||
resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz"
|
||||
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
|
||||
js-yaml@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
|
||||
integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
@@ -1644,10 +1660,10 @@ keyboardevents-areequal@^0.2.1:
|
||||
resolved "https://registry.npmjs.org/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz"
|
||||
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
|
||||
|
||||
keytar@^7.2.0:
|
||||
version "7.3.0"
|
||||
resolved "https://registry.npmjs.org/keytar/-/keytar-7.3.0.tgz"
|
||||
integrity sha512-t8YD0ETO5AeRxCaaN4N/hzj3JusIH0ugjVooE724+ozaVG9+l16Mau62T+U8tEhCv7SozY/g69BWF1U+o47qJg==
|
||||
keytar@^7.4.0:
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/keytar/-/keytar-7.4.0.tgz#0a508d64850ca05aa3ba4127818037d13ca3219f"
|
||||
integrity sha512-nELmc35YjSE4ZNSFaID/743CgDt/MdV4JLX7rRewAh9mKvU72RtF3uJMY0MdMpwdDYZhmD8FSdRCD1J97lEyVg==
|
||||
dependencies:
|
||||
node-addon-api "^3.0.0"
|
||||
prebuild-install "^6.0.0"
|
||||
@@ -2073,7 +2089,7 @@ mz@^2.7.0:
|
||||
object-assign "^4.0.1"
|
||||
thenify-all "^1.0.0"
|
||||
|
||||
nan@^2.13.2, nan@^2.14.2:
|
||||
nan@^2.13.2, nan@^2.14.0, nan@^2.14.2:
|
||||
version "2.14.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
||||
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
|
||||
@@ -2083,17 +2099,24 @@ napi-build-utils@^1.0.1:
|
||||
resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz"
|
||||
integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
|
||||
|
||||
ngx-toastr@^12.0.1:
|
||||
version "12.1.0"
|
||||
resolved "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-12.1.0.tgz"
|
||||
integrity sha512-rytCRBhvuudj614Kfj9GoIVQDrFuLvHSMP1YrMwTmR1SNkNJZOpGKmaSDCCBrNDkSrGouzMWBlFbl1UDBBsiqw==
|
||||
native-process-working-directory@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/native-process-working-directory/-/native-process-working-directory-1.0.2.tgz#7843e2fa1490f53cf8d2c7d1913de8b275e8b89a"
|
||||
integrity sha512-3a67QQV8r3YMUTSOgvtMOCjPDgCpb/8xjv93L8Cqb8bv3hOKsWis4/+8HCu3bgj8ADQV75SCYFSsAGM5G0cXmQ==
|
||||
dependencies:
|
||||
tslib "^1.10.0"
|
||||
node-addon-api "^3.1.0"
|
||||
|
||||
node-abi@2.19.3, node-abi@^2.7.0:
|
||||
version "2.19.3"
|
||||
resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz"
|
||||
integrity sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==
|
||||
ngx-toastr@^13.2.0:
|
||||
version "13.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-13.2.0.tgz#3ef047c977a7d0fb67fed9338b8f5add3c87b356"
|
||||
integrity sha512-XU+wACX5hxwOJ4BtPMAUExQmYbjfvH3C/R4vcC9QK/dX2Zw+2w9tS9m4W6TUFyR92xZ/tGLBtsqRdrDRn3fJCw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
node-abi@^2.20.0, node-abi@^2.21.0, node-abi@^2.7.0:
|
||||
version "2.21.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.21.0.tgz#c2dc9ebad6f4f53d6ea9b531e7b8faad81041d48"
|
||||
integrity sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
@@ -2102,7 +2125,7 @@ node-addon-api@3.0.0:
|
||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz"
|
||||
integrity sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==
|
||||
|
||||
node-addon-api@^3.0.0, node-addon-api@^3.0.2:
|
||||
node-addon-api@^3.0.0, node-addon-api@^3.0.2, node-addon-api@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz"
|
||||
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
|
||||
@@ -2270,9 +2293,9 @@ npm-user-validate@^1.0.1:
|
||||
integrity sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==
|
||||
|
||||
npm@6:
|
||||
version "6.14.10"
|
||||
resolved "https://registry.yarnpkg.com/npm/-/npm-6.14.10.tgz#f45c8e4244294ba793770f2ab0e9ce2d0b93fd29"
|
||||
integrity sha512-FT23Qy/JMA+qxEYReMOr1MY7642fKn8Onn+72LASPi872Owvmw0svm+/DXTHOC3yO9CheEO+EslyXEpdBdRtIA==
|
||||
version "6.14.11"
|
||||
resolved "https://registry.yarnpkg.com/npm/-/npm-6.14.11.tgz#e0b5598d7b9a42d275e61d8bd28cd7eee0074a3b"
|
||||
integrity sha512-1Zh7LjuIoEhIyjkBflSSGzfjuPQwDlghNloppjruOH5bmj9midT9qcNT0tRUZRR04shU9ekrxNy9+UTBrqeBpQ==
|
||||
dependencies:
|
||||
JSONStream "^1.3.5"
|
||||
abbrev "~1.1.1"
|
||||
@@ -2309,7 +2332,7 @@ npm@6:
|
||||
infer-owner "^1.0.4"
|
||||
inflight "~1.0.6"
|
||||
inherits "^2.0.4"
|
||||
ini "^1.3.5"
|
||||
ini "^1.3.8"
|
||||
init-package-json "^1.10.3"
|
||||
is-cidr "^3.0.0"
|
||||
json-parse-better-errors "^1.0.2"
|
||||
@@ -2693,6 +2716,27 @@ prebuild-install@^6.0.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
prebuild-install@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.1.tgz#5902172f7a40eb67305b96c2a695db32636ee26d"
|
||||
integrity sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
expand-template "^2.0.3"
|
||||
github-from-package "0.0.0"
|
||||
minimist "^1.2.3"
|
||||
mkdirp-classic "^0.5.3"
|
||||
napi-build-utils "^1.0.1"
|
||||
node-abi "^2.7.0"
|
||||
noop-logger "^0.1.1"
|
||||
npmlog "^4.0.1"
|
||||
pump "^3.0.0"
|
||||
rc "^1.2.7"
|
||||
simple-get "^3.0.3"
|
||||
tar-fs "^2.0.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
prepend-http@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
@@ -3018,23 +3062,23 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
dependencies:
|
||||
aproba "^1.1.1"
|
||||
|
||||
rxjs@^6.5.5:
|
||||
version "6.6.3"
|
||||
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz"
|
||||
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
|
||||
rxjs@^6.6.6:
|
||||
version "6.6.6"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
|
||||
integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0:
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
||||
@@ -3059,21 +3103,22 @@ serialize-error@^5.0.0:
|
||||
dependencies:
|
||||
type-fest "^0.8.0"
|
||||
|
||||
serialport@^9.0.4:
|
||||
version "9.0.4"
|
||||
resolved "https://registry.npmjs.org/serialport/-/serialport-9.0.4.tgz"
|
||||
integrity sha512-Wtl6sxciHKNdJKW8jUZm+f5KRXt0J0UP25ksM8N31l08KTdAhZ5MmKNUFpoO/YYG6TvHFOu+07PUX35m+TUw7g==
|
||||
serialport@^9.0.7:
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/serialport/-/serialport-9.0.7.tgz#bd116a70bd7acbfd587491acd3ee03e02a0df71c"
|
||||
integrity sha512-NeDfVks3JAJ7s8cXDopx1iUUgC/7TaltE7iQGiSewIWMZaK7oStiz3VJzcuKgor7F+U/y6zbAnj4i6eHq0on+g==
|
||||
dependencies:
|
||||
"@serialport/binding-mock" "^9.0.2"
|
||||
"@serialport/bindings" "^9.0.4"
|
||||
"@serialport/parser-byte-length" "^9.0.1"
|
||||
"@serialport/parser-cctalk" "^9.0.1"
|
||||
"@serialport/parser-delimiter" "^9.0.1"
|
||||
"@serialport/parser-readline" "^9.0.1"
|
||||
"@serialport/parser-ready" "^9.0.1"
|
||||
"@serialport/parser-regex" "^9.0.1"
|
||||
"@serialport/stream" "^9.0.2"
|
||||
debug "^4.1.1"
|
||||
"@serialport/binding-mock" "^9.0.7"
|
||||
"@serialport/bindings" "^9.0.7"
|
||||
"@serialport/parser-byte-length" "^9.0.7"
|
||||
"@serialport/parser-cctalk" "^9.0.7"
|
||||
"@serialport/parser-delimiter" "^9.0.7"
|
||||
"@serialport/parser-inter-byte-timeout" "^9.0.7"
|
||||
"@serialport/parser-readline" "^9.0.7"
|
||||
"@serialport/parser-ready" "^9.0.7"
|
||||
"@serialport/parser-regex" "^9.0.7"
|
||||
"@serialport/stream" "^9.0.7"
|
||||
debug "^4.3.1"
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -3201,11 +3246,6 @@ split-on-first@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz"
|
||||
@@ -3463,15 +3503,15 @@ tough-cookie@~2.5.0:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tslib@^1.10.0, tslib@^1.9.0:
|
||||
tslib@^1.9.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
|
||||
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
@@ -3836,9 +3876,9 @@ yargs@^8.0.2:
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^7.0.0"
|
||||
|
||||
zone.js@^0.11.3:
|
||||
version "0.11.3"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.11.3.tgz#255a6313174731cc014d63233ef04fd9858da375"
|
||||
integrity sha512-Y4hTHoh4VcxU5BDGAqEoOnOiyT254w6CiHtpQxAJUSMZPyVgdbKf+5R7Mwz6xsPhMIeBXk5rTopRZDpjssTCUg==
|
||||
zone.js@^0.11.4:
|
||||
version "0.11.4"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.11.4.tgz#0f70dcf6aba80f698af5735cbb257969396e8025"
|
||||
integrity sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
@@ -8,8 +8,9 @@ afterAllArtifactBuild: "./build/mac/afterBuildHook.js"
|
||||
files:
|
||||
- '**/*'
|
||||
- dist
|
||||
- '!lib'
|
||||
- '!src'
|
||||
- '!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}'
|
||||
- '!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme,node.lib}'
|
||||
- '!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples,docs}'
|
||||
- '!**/node_modules/@angular/common/locales'
|
||||
- '!**/node_modules/@angular/compiler/src'
|
||||
@@ -62,7 +63,7 @@ mac:
|
||||
NSRemovableVolumesUsageDescription: 'A subprocess requests access to files on a removable volume.'
|
||||
|
||||
linux:
|
||||
category: Utilities
|
||||
category: Utility
|
||||
icon: "./build/icons"
|
||||
artifactName: terminus-${version}-linux.${ext}
|
||||
executableArgs:
|
||||
@@ -87,3 +88,6 @@ rpm:
|
||||
depends:
|
||||
- screen
|
||||
- gnome-keyring
|
||||
fpm:
|
||||
- '--rpm-rpmbuild-define'
|
||||
- '_build_id_links none'
|
||||
|
65
package.json
65
package.json
@@ -1,33 +1,34 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||
"@sentry/cli": "^1.61.0",
|
||||
"@sentry/electron": "^2.0.4",
|
||||
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||
"@sentry/cli": "^1.63.0",
|
||||
"@sentry/electron": "^2.4.0",
|
||||
"@terminus-term/to-string-loader": "1.1.7-beta.1",
|
||||
"@types/electron-config": "^3.2.2",
|
||||
"@types/electron-debug": "^2.1.0",
|
||||
"@types/fs-extra": "^8.1.1",
|
||||
"@types/js-yaml": "^3.12.5",
|
||||
"@types/node": "14.14.14",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/node": "14.14.31",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
||||
"@typescript-eslint/parser": "^4.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
||||
"@typescript-eslint/parser": "^4.17.0",
|
||||
"apply-loader": "2.0.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"compare-versions": "^3.6.0",
|
||||
"core-js": "^3.8.1",
|
||||
"cross-env": "7.0.2",
|
||||
"css-loader": "3.4.2",
|
||||
"electron": "^11.1.1",
|
||||
"electron-builder": "22.10.4",
|
||||
"core-js": "^3.9.1",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "5.0.1",
|
||||
"electron": "12.0.1",
|
||||
"electron-builder": "22.10.5",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"electron-rebuild": "^2.3.4",
|
||||
"eslint": "^7.6.0",
|
||||
"electron-rebuild": "^2.3.5",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-plugin-import": "^2.21.1",
|
||||
"file-loader": "^5.1.0",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"html-loader": "0.5.5",
|
||||
"file-loader": "^6.2.0",
|
||||
"graceful-fs": "^4.2.6",
|
||||
"html-loader": "2.1.2",
|
||||
"json-loader": "0.5.7",
|
||||
"lru-cache": "^6.0.0",
|
||||
"macos-release": "^2.4.1",
|
||||
@@ -36,31 +37,31 @@
|
||||
"node-sass": "^5.0.0",
|
||||
"npmlog": "4.1.2",
|
||||
"npx": "^10.2.2",
|
||||
"pug": "^2.0.4",
|
||||
"patch-package": "^6.2.2",
|
||||
"pug": "^3.0.2",
|
||||
"pug-html-loader": "1.1.5",
|
||||
"pug-lint": "^2.6.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-static-loader": "2.0.0",
|
||||
"raw-loader": "4.0.1",
|
||||
"sass-loader": "^10.1.0",
|
||||
"raw-loader": "4.0.2",
|
||||
"sass-loader": "^11.0.1",
|
||||
"shelljs": "0.8.4",
|
||||
"source-code-pro": "^2.30.2",
|
||||
"source-sans-pro": "3.6.0",
|
||||
"ssh2-streams": "^0.4.10",
|
||||
"style-loader": "^2.0.0",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"to-string-loader": "1.1.6",
|
||||
"tslib": "^2.0.3",
|
||||
"typedoc": "^0.18.0",
|
||||
"typescript": "^3.9.7",
|
||||
"url-loader": "^3.0.0",
|
||||
"val-loader": "2.1.1",
|
||||
"webpack": "^5.11.0",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"tslib": "^2.1.0",
|
||||
"typedoc": "^0.20.28",
|
||||
"typescript": "^3.9.9",
|
||||
"url-loader": "^4.1.1",
|
||||
"val-loader": "3.0.0",
|
||||
"webpack": "^5.18.0",
|
||||
"webpack-cli": "^4.5.0",
|
||||
"yaml-loader": "0.6.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/node-abi": "^2.19.3",
|
||||
"*/node-abi": "^2.20.0",
|
||||
"**/graceful-fs": "^4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -70,11 +71,9 @@
|
||||
"start": "cross-env TERMINUS_DEV=1 electron app --debug",
|
||||
"start:prod": "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",
|
||||
"docs": "typedoc --out docs/api --tsconfig terminus-core/src/tsconfig.typings.json terminus-core/src/index.ts && typedoc --out docs/api/terminal --tsconfig terminus-terminal/tsconfig.typings.json terminus-terminal/src/index.ts && typedoc --out docs/api/settings --tsconfig terminus-settings/tsconfig.typings.json terminus-settings/src/index.ts",
|
||||
"lint": "eslint --ext ts */src */lib",
|
||||
"postinstall": "node ./scripts/install-deps.js"
|
||||
},
|
||||
"repository": "eugeny/terminus",
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT"
|
||||
"private": true
|
||||
}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
#!/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/')
|
||||
|
||||
@@ -16,6 +14,7 @@ builder({
|
||||
extraMetadata: {
|
||||
version: vars.version,
|
||||
},
|
||||
npmRebuild: process.env.ARCH !== 'arm64',
|
||||
},
|
||||
publish: isTag ? 'always' : 'onTag',
|
||||
}).catch(e => {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-community-color-schemes",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Community color schemes for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
|
42
terminus-community-color-schemes/schemes/Nord
Normal file
42
terminus-community-color-schemes/schemes/Nord
Normal file
@@ -0,0 +1,42 @@
|
||||
!
|
||||
!
|
||||
*.foreground: #d8dee9
|
||||
*.background: #2e3440
|
||||
*.cursorColor: #d8dee9
|
||||
!
|
||||
! Black
|
||||
*.color0: #3b4252
|
||||
*.color8: #373e4d
|
||||
!
|
||||
! Red
|
||||
*.color1: #bf616a
|
||||
*.color9: #94545d
|
||||
!
|
||||
! Green
|
||||
*.color2: #a3be8c
|
||||
*.color10: #809575
|
||||
!
|
||||
! Yellow
|
||||
*.color3: #ebcb8b
|
||||
*.color11: #b29e75
|
||||
!
|
||||
! Blue
|
||||
*.color4: #81a1c1
|
||||
*.color12: #68809a
|
||||
!
|
||||
! Magenta
|
||||
*.color5: #b48ead
|
||||
*.color13: #8c738c
|
||||
!
|
||||
! Cyan
|
||||
*.color6: #88c0d0
|
||||
*.color14: #6d96a5
|
||||
!
|
||||
! White
|
||||
*.color7: #e5e9f0
|
||||
*.color15: #aeb3bb
|
||||
!
|
||||
! Bold, Italic, Underline
|
||||
*.colorBD: #a5abb6
|
||||
!*.colorIT:
|
||||
!*.colorUL:
|
@@ -1,14 +1,14 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TerminalColorSchemeProvider, TerminalColorScheme } from 'terminus-terminal'
|
||||
|
||||
const schemeContents = require.context('../schemes/', true, /.*/)
|
||||
const schemeContents = require.context('../schemes/', false, /.*/)
|
||||
|
||||
@Injectable()
|
||||
export class ColorSchemes extends TerminalColorSchemeProvider {
|
||||
async getSchemes (): Promise<TerminalColorScheme[]> {
|
||||
const schemes: TerminalColorScheme[] = []
|
||||
|
||||
schemeContents.keys().forEach(schemeFile => {
|
||||
schemeContents.keys().filter(x => !x.startsWith('./')).forEach(schemeFile => {
|
||||
const lines = (schemeContents(schemeFile).default as string).split('\n')
|
||||
|
||||
// process #define variables
|
||||
|
@@ -1,51 +1,6 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-community-color-schemes:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
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: /[\\\/]schemes[\\\/]/, use: "raw-loader" },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'community-color-schemes',
|
||||
dirname: __dirname,
|
||||
})
|
||||
module.exports.module.rules.push({ test: /[\\\/]schemes[\\\/]/, use: 'raw-loader' })
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-core",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Terminus core",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -17,18 +17,18 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^3.9.0",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/shell-escape": "^0.2.0",
|
||||
"@types/winston": "^2.3.6",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "^4.1.3",
|
||||
"core-js": "^3.1.2",
|
||||
"deepmerge": "^4.1.1",
|
||||
"electron-updater": "^4.0.6",
|
||||
"js-yaml": "^3.9.0",
|
||||
"js-yaml": "^4.0.0",
|
||||
"mixpanel": "^0.10.2",
|
||||
"ng2-dnd": "^5.0.2",
|
||||
"ngx-perfect-scrollbar": "^8.0.0",
|
||||
"ngx-perfect-scrollbar": "^10.1.0",
|
||||
"readable-stream": "2.3.7",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^8.0.0",
|
||||
|
@@ -17,6 +17,7 @@ export { Logger, LogService } from '../services/log.service'
|
||||
export { HomeBaseService } from '../services/homeBase.service'
|
||||
export { HotkeysService } from '../services/hotkeys.service'
|
||||
export { HostAppService, Platform } from '../services/hostApp.service'
|
||||
export { NotificationsService } from '../services/notifications.service'
|
||||
export { ShellIntegrationService } from '../services/shellIntegration.service'
|
||||
export { ThemesService } from '../services/themes.service'
|
||||
export { TabsService } from '../services/tabs.service'
|
||||
|
@@ -10,4 +10,7 @@ export abstract class Theme {
|
||||
css: string
|
||||
|
||||
terminalBackground: string
|
||||
|
||||
macOSWindowButtonsInsetX?: number
|
||||
macOSWindowButtonsInsetY?: number
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
title-bar(
|
||||
*ngIf='!hostApp.isFullScreen && config.store.appearance.frame == "full" && config.store.appearance.dock == "off"',
|
||||
[class.inset]='hostApp.platform == Platform.macOS'
|
||||
[class.inset]='hostApp.platform == Platform.macOS && !hostApp.isFullScreen'
|
||||
)
|
||||
|
||||
.content(
|
||||
@@ -9,6 +9,7 @@ title-bar(
|
||||
)
|
||||
.tab-bar
|
||||
.inset.background(*ngIf='hostApp.platform == Platform.macOS \
|
||||
&& !hostApp.isFullScreen \
|
||||
&& config.store.appearance.frame == "thin" \
|
||||
&& (config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left")')
|
||||
.tabs(
|
||||
|
@@ -85,6 +85,7 @@ $side-tab-width: 200px;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 15px;
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 2px solid transparent;
|
||||
|
@@ -142,6 +142,8 @@ export class AppRootComponent {
|
||||
|
||||
this.touchbar.update()
|
||||
|
||||
this.hostApp.useBuiltinGraphics()
|
||||
|
||||
config.changed$.subscribe(() => this.updateVibrancy())
|
||||
this.updateVibrancy()
|
||||
|
||||
|
@@ -17,7 +17,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
})
|
||||
export class CheckboxComponent implements ControlValueAccessor {
|
||||
@HostBinding('class.active') @Input() model: boolean
|
||||
@Input() disabled: boolean
|
||||
@HostBinding('class.disabled') @Input() disabled: boolean
|
||||
@Input() text: string
|
||||
private changed = new Array<(val: boolean) => void>()
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
(ngModelChange)='onFilterChange()'
|
||||
)
|
||||
|
||||
.list-group.mt-3(*ngIf='filteredOptions.length')
|
||||
.list-group(*ngIf='filteredOptions.length')
|
||||
a.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||
#item,
|
||||
(click)='selectOption(option)',
|
||||
|
@@ -1,6 +1,12 @@
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
max-height: 70vh;
|
||||
overflow: auto;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core'
|
||||
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core' // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { SelectorOption } from '../api/selector'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'selector-modal',
|
||||
template: require('./selectorModal.component.pug'),
|
||||
styles: [require('./selectorModal.component.scss')],
|
||||
})
|
||||
|
@@ -6,6 +6,12 @@ $tabs-height: 38px;
|
||||
|
||||
flex: 1000 1 200px;
|
||||
width: 200px;
|
||||
padding: 0 10px;
|
||||
|
||||
&.flex-width {
|
||||
flex: 1000 1 auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -24,7 +30,6 @@ $tabs-height: 38px;
|
||||
-webkit-app-region: no-drag;
|
||||
cursor: -webkit-grab;
|
||||
|
||||
margin-left: 10px;
|
||||
width: 22px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
@@ -34,7 +39,7 @@ $tabs-height: 38px;
|
||||
|
||||
.name {
|
||||
flex: auto;
|
||||
margin: 0 1px 0 10px;
|
||||
margin-top: 1px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
@@ -42,6 +47,10 @@ $tabs-height: 38px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.index + .name {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
flex: none;
|
||||
@@ -49,13 +58,15 @@ $tabs-height: 38px;
|
||||
opacity: 0;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
$button-size: 26px;
|
||||
width: $button-size;
|
||||
height: $button-size;
|
||||
border-radius: $button-size / 2;
|
||||
line-height: $button-size;
|
||||
align-self: center;
|
||||
margin-right: 10px;
|
||||
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
@@ -65,6 +76,13 @@ $tabs-height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .name {
|
||||
-webkit-mask-image: linear-gradient(black 0 0), linear-gradient(to left, transparent 0%, black 100%);
|
||||
-webkit-mask-size: calc(100% - 60px) auto, 60px auto;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
-webkit-mask-position: left, right;
|
||||
}
|
||||
|
||||
&:hover button {
|
||||
transition: 0.25s opacity;
|
||||
display: block;
|
||||
|
@@ -29,7 +29,7 @@ export class TabHeaderComponent {
|
||||
@Input() @HostBinding('class.has-activity') hasActivity: boolean
|
||||
@Input() tab: BaseTabComponent
|
||||
@Input() progress: number|null
|
||||
@ViewChild('handle') handle: ElementRef
|
||||
@ViewChild('handle') handle?: ElementRef
|
||||
|
||||
private constructor (
|
||||
public app: AppService,
|
||||
@@ -58,7 +58,7 @@ export class TabHeaderComponent {
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
if (this.handle && this.hostApp.platform === Platform.macOS) {
|
||||
this.parentDraggable.setDragHandle(this.handle.nativeElement)
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,10 @@ export class TabHeaderComponent {
|
||||
return items.slice(1)
|
||||
}
|
||||
|
||||
@HostBinding('class.flex-width') get isFlexWidthEnabled (): boolean {
|
||||
return this.config.store.appearance.flexTabs
|
||||
}
|
||||
|
||||
@HostListener('dblclick') onDoubleClick (): void {
|
||||
this.showRenameTabModal()
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@
|
||||
$toggle-size: 18px;
|
||||
$height: 30px;
|
||||
$padding: 2px;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
overflow: visible;
|
||||
border-radius: 3px;
|
||||
@@ -16,8 +15,11 @@
|
||||
padding-left: 10px;
|
||||
margin-left: -10px;
|
||||
|
||||
&[disabled] {
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
* {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,16 @@ hotkeys:
|
||||
- 'Alt-9'
|
||||
tab-10:
|
||||
- 'Alt-0'
|
||||
tab-11: []
|
||||
tab-12: []
|
||||
tab-13: []
|
||||
tab-14: []
|
||||
tab-15: []
|
||||
tab-16: []
|
||||
tab-17: []
|
||||
tab-18: []
|
||||
tab-19: []
|
||||
tab-20: []
|
||||
split-right:
|
||||
- 'Ctrl-Shift-E'
|
||||
split-bottom:
|
||||
|
@@ -40,6 +40,16 @@ hotkeys:
|
||||
- '⌘-9'
|
||||
tab-10:
|
||||
- '⌘-0'
|
||||
tab-11: []
|
||||
tab-12: []
|
||||
tab-13: []
|
||||
tab-14: []
|
||||
tab-15: []
|
||||
tab-16: []
|
||||
tab-17: []
|
||||
tab-18: []
|
||||
tab-19: []
|
||||
tab-20: []
|
||||
split-right:
|
||||
- '⌘-Shift-D'
|
||||
split-bottom:
|
||||
|
@@ -43,6 +43,16 @@ hotkeys:
|
||||
- 'Alt-9'
|
||||
tab-10:
|
||||
- 'Alt-0'
|
||||
tab-11: []
|
||||
tab-12: []
|
||||
tab-13: []
|
||||
tab-14: []
|
||||
tab-15: []
|
||||
tab-16: []
|
||||
tab-17: []
|
||||
tab-18: []
|
||||
tab-19: []
|
||||
tab-20: []
|
||||
split-right:
|
||||
- 'Ctrl-Shift-E'
|
||||
split-bottom:
|
||||
|
@@ -2,8 +2,10 @@ appearance:
|
||||
dock: off
|
||||
dockScreen: current
|
||||
dockFill: 0.5
|
||||
dockSpace: 1
|
||||
dockHideOnBlur: false
|
||||
dockAlwaysOnTop: true
|
||||
flexTabs: false
|
||||
tabsLocation: top
|
||||
cycleTabs: true
|
||||
theme: Standard
|
||||
|
@@ -89,6 +89,46 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
id: 'tab-10',
|
||||
name: 'Tab 10',
|
||||
},
|
||||
{
|
||||
id: 'tab-11',
|
||||
name: 'Tab 11',
|
||||
},
|
||||
{
|
||||
id: 'tab-12',
|
||||
name: 'Tab 12',
|
||||
},
|
||||
{
|
||||
id: 'tab-13',
|
||||
name: 'Tab 13',
|
||||
},
|
||||
{
|
||||
id: 'tab-14',
|
||||
name: 'Tab 14',
|
||||
},
|
||||
{
|
||||
id: 'tab-15',
|
||||
name: 'Tab 15',
|
||||
},
|
||||
{
|
||||
id: 'tab-16',
|
||||
name: 'Tab 16',
|
||||
},
|
||||
{
|
||||
id: 'tab-17',
|
||||
name: 'Tab 17',
|
||||
},
|
||||
{
|
||||
id: 'tab-18',
|
||||
name: 'Tab 18',
|
||||
},
|
||||
{
|
||||
id: 'tab-19',
|
||||
name: 'Tab 19',
|
||||
},
|
||||
{
|
||||
id: 'tab-20',
|
||||
name: 'Tab 20',
|
||||
},
|
||||
{
|
||||
id: 'split-right',
|
||||
name: 'Split to the right',
|
||||
|
@@ -44,8 +44,11 @@ import 'ng2-dnd/bundles/style.css'
|
||||
// PerfectScrollbar fix
|
||||
import { fromEvent } from 'rxjs/internal/observable/fromEvent'
|
||||
import { merge } from 'rxjs/internal/observable/merge'
|
||||
require('rxjs').fromEvent = fromEvent
|
||||
require('rxjs').merge = merge
|
||||
|
||||
try {
|
||||
require('rxjs').fromEvent = fromEvent
|
||||
require('rxjs').merge = merge
|
||||
} catch {}
|
||||
|
||||
const PROVIDERS = [
|
||||
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||
@@ -110,7 +113,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
})
|
||||
}
|
||||
|
||||
static forRoot (): ModuleWithProviders {
|
||||
static forRoot (): ModuleWithProviders<AppModule> {
|
||||
return {
|
||||
ngModule: AppModule,
|
||||
providers: PROVIDERS,
|
||||
|
@@ -100,7 +100,7 @@ export class AppService {
|
||||
hostApp.windowFocused$.subscribe(() => this._activeTab?.emitFocused())
|
||||
|
||||
this.tabClosed$.subscribe(async tab => {
|
||||
const token = await tab.getRecoveryToken()
|
||||
const token = await tabRecovery.getFullRecoveryToken(tab)
|
||||
if (token) {
|
||||
this.closedTabsStack.push(token)
|
||||
}
|
||||
@@ -263,7 +263,7 @@ export class AppService {
|
||||
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])
|
||||
this.tabs.push(this.tabs.shift()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ export class AppService {
|
||||
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])
|
||||
this.tabs.unshift(this.tabs.pop()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -144,7 +144,7 @@ export class ConfigService {
|
||||
|
||||
load (): void {
|
||||
if (fs.existsSync(this.path)) {
|
||||
this._store = yaml.safeLoad(fs.readFileSync(this.path, 'utf8'))
|
||||
this._store = yaml.load(fs.readFileSync(this.path, 'utf8'))
|
||||
} else {
|
||||
this._store = {}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ 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')
|
||||
fs.writeFileSync(this.path, yaml.dump(this._store), 'utf8')
|
||||
this.emitChange()
|
||||
this.hostApp.broadcastConfigChange(JSON.parse(JSON.stringify(this.store)))
|
||||
}
|
||||
@@ -163,14 +163,14 @@ export class ConfigService {
|
||||
* Reads config YAML as string
|
||||
*/
|
||||
readRaw (): string {
|
||||
return yaml.safeDump(this._store)
|
||||
return yaml.dump(this._store)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes config YAML as string
|
||||
*/
|
||||
writeRaw (data: string): void {
|
||||
this._store = yaml.safeLoad(data)
|
||||
this._store = yaml.load(data)
|
||||
this.save()
|
||||
this.load()
|
||||
this.emitChange()
|
||||
|
@@ -34,25 +34,30 @@ export class DockingService {
|
||||
const newBounds: Bounds = { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
const fill = this.config.store.appearance.dockFill <= 1 ? this.config.store.appearance.dockFill : 1
|
||||
const space = this.config.store.appearance.dockSpace <= 1 ? this.config.store.appearance.dockSpace : 1
|
||||
const [minWidth, minHeight] = this.hostApp.getWindow().getMinimumSize()
|
||||
|
||||
if (dockSide === 'left' || dockSide === 'right') {
|
||||
newBounds.width = Math.max(minWidth, Math.round(fill * display.bounds.width))
|
||||
newBounds.height = display.bounds.height
|
||||
newBounds.height = Math.round(display.bounds.height * space)
|
||||
}
|
||||
if (dockSide === 'top' || dockSide === 'bottom') {
|
||||
newBounds.width = display.bounds.width
|
||||
newBounds.width = Math.round(display.bounds.width * space)
|
||||
newBounds.height = Math.max(minHeight, Math.round(fill * display.bounds.height))
|
||||
}
|
||||
if (dockSide === 'right') {
|
||||
newBounds.x = display.bounds.x + display.bounds.width - newBounds.width
|
||||
} else {
|
||||
} else if (dockSide === 'left') {
|
||||
newBounds.x = display.bounds.x
|
||||
} else {
|
||||
newBounds.x = display.bounds.x + Math.round(display.bounds.width / 2 * (1 - space))
|
||||
}
|
||||
if (dockSide === 'bottom') {
|
||||
newBounds.y = display.bounds.y + display.bounds.height - newBounds.height
|
||||
} else {
|
||||
} else if (dockSide === 'top') {
|
||||
newBounds.y = display.bounds.y
|
||||
} else {
|
||||
newBounds.y = display.bounds.y + Math.round(display.bounds.height / 2 * (1 - space))
|
||||
}
|
||||
|
||||
const alwaysOnTop = this.config.store.appearance.dockAlwaysOnTop
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import type { BrowserWindow, TouchBar, MenuItemConstructorOptions } from 'electron'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'mz/fs'
|
||||
import shellEscape from 'shell-escape'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
||||
@@ -7,6 +8,12 @@ import { ElectronService } from './electron.service'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { isWindowsBuild, WIN_BUILD_FLUENT_BG_SUPPORTED } from '../utils'
|
||||
|
||||
/* eslint-disable block-scoped-var */
|
||||
|
||||
try {
|
||||
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires, no-var
|
||||
} catch (_) { }
|
||||
|
||||
export enum Platform {
|
||||
Linux = 'Linux',
|
||||
macOS = 'macOS',
|
||||
@@ -150,9 +157,10 @@ export class HostAppService {
|
||||
this.zone.run(() => this.displaysChanged.next())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:second-instance', (_$event, argv: any, cwd: string) => this.zone.run(() => {
|
||||
electron.ipcRenderer.on('cli', (_$event, argv: any, cwd: string, secondInstance: boolean) => this.zone.run(async () => {
|
||||
this.logger.info('Second instance', argv)
|
||||
const op = argv._[0]
|
||||
const opAsPath = op ? path.resolve(cwd, op) : null
|
||||
if (op === 'open') {
|
||||
this.cliOpenDirectory.next(path.resolve(cwd, argv.directory))
|
||||
} else if (op === 'run') {
|
||||
@@ -165,9 +173,13 @@ export class HostAppService {
|
||||
this.cliPaste.next(text)
|
||||
} else if (op === 'profile') {
|
||||
this.cliOpenProfile.next(argv.profileName)
|
||||
} else if (op === undefined) {
|
||||
} else if (secondInstance && op === undefined) {
|
||||
this.newWindow()
|
||||
} else {
|
||||
} else if (opAsPath && (await fs.lstat(opAsPath)).isDirectory()) {
|
||||
this.cliOpenDirectory.next(opAsPath)
|
||||
}
|
||||
|
||||
if (secondInstance) {
|
||||
this.secondInstance.next()
|
||||
}
|
||||
}))
|
||||
@@ -277,6 +289,20 @@ export class HostAppService {
|
||||
this.electron.ipcRenderer.send('app:register-global-hotkey', specs)
|
||||
}
|
||||
|
||||
useBuiltinGraphics (): void {
|
||||
const keyPath = 'SOFTWARE\\Microsoft\\DirectX\\UserGpuPreferences'
|
||||
const valueName = this.electron.app.getPath('exe')
|
||||
if (this.platform === Platform.Windows) {
|
||||
if (!wnr.getRegistryValue(wnr.HK.CU, keyPath, valueName)) {
|
||||
wnr.setRegistryValue(wnr.HK.CU, keyPath, valueName, wnr.REG.SZ, 'GpuPreference=1;')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTrafficLightInset (x: number, y: number): void {
|
||||
this.getWindow().setTrafficLightPosition({ x, y })
|
||||
}
|
||||
|
||||
relaunch (): void {
|
||||
if (this.isPortable) {
|
||||
this.electron.app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE })
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ElectronService } from './electron.service'
|
||||
import * as winston from 'winston'
|
||||
import type * as winston from 'winston'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
const initializeWinston = (electron: ElectronService) => {
|
||||
const logDirectory = electron.app.getPath('userData')
|
||||
// eslint-disable-next-line
|
||||
const winston = require('winston')
|
||||
|
||||
if (!fs.existsSync(logDirectory)) {
|
||||
fs.mkdirSync(logDirectory)
|
||||
@@ -64,7 +66,11 @@ export class LogService {
|
||||
|
||||
/** @hidden */
|
||||
private constructor (electron: ElectronService) {
|
||||
this.log = initializeWinston(electron)
|
||||
if (!process.env.XWEB) {
|
||||
this.log = initializeWinston(electron)
|
||||
} else {
|
||||
this.log = console as any
|
||||
}
|
||||
}
|
||||
|
||||
create (name: string): Logger {
|
||||
|
23
terminus-core/src/services/notifications.service.ts
Normal file
23
terminus-core/src/services/notifications.service.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class NotificationsService {
|
||||
private constructor (
|
||||
private toastr: ToastrService,
|
||||
) { }
|
||||
|
||||
notice (text: string): void {
|
||||
this.toastr.info(text, undefined, {
|
||||
timeOut: 1000,
|
||||
})
|
||||
}
|
||||
|
||||
info (text: string, details?: string): void {
|
||||
this.toastr.info(text, details)
|
||||
}
|
||||
|
||||
error (text: string, details?: string): void {
|
||||
this.toastr.error(text, details)
|
||||
}
|
||||
}
|
@@ -24,20 +24,22 @@ export class TabRecoveryService {
|
||||
}
|
||||
window.localStorage.tabsRecovery = JSON.stringify(
|
||||
(await Promise.all(
|
||||
tabs
|
||||
.map(async tab => tab.getRecoveryToken().then(r => {
|
||||
if (r) {
|
||||
r.tabTitle = tab.title
|
||||
if (tab.color) {
|
||||
r.tabColor = tab.color
|
||||
}
|
||||
}
|
||||
return r
|
||||
}))
|
||||
tabs.map(async tab => this.getFullRecoveryToken(tab))
|
||||
)).filter(token => !!token)
|
||||
)
|
||||
}
|
||||
|
||||
async getFullRecoveryToken (tab: BaseTabComponent): Promise<RecoveryToken|null> {
|
||||
const token = await tab.getRecoveryToken()
|
||||
if (token) {
|
||||
token.tabTitle = tab.title
|
||||
if (tab.color) {
|
||||
token.tabColor = tab.color
|
||||
}
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders ?? [])) {
|
||||
try {
|
||||
|
@@ -30,7 +30,7 @@ export class TabsService {
|
||||
* Duplicates an existing tab instance (using the tab recovery system)
|
||||
*/
|
||||
async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent|null> {
|
||||
const token = await tab.getRecoveryToken()
|
||||
const token = await this.tabRecovery.getFullRecoveryToken(tab)
|
||||
if (!token) {
|
||||
return null
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { Theme } from '../api/theme'
|
||||
import { HostAppService, Platform } from './hostApp.service'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ThemesService {
|
||||
@@ -9,6 +10,7 @@ export class ThemesService {
|
||||
/** @hidden */
|
||||
private constructor (
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
@Inject(Theme) private themes: Theme[],
|
||||
) {
|
||||
this.applyCurrentTheme()
|
||||
@@ -33,6 +35,12 @@ export class ThemesService {
|
||||
}
|
||||
this.styleElement.textContent = theme.css
|
||||
document.querySelector('style#custom-css')!.innerHTML = this.config.store.appearance.css
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
this.hostApp.setTrafficLightInset(
|
||||
theme.macOSWindowButtonsInsetX ?? 14,
|
||||
theme.macOSWindowButtonsInsetY ?? 22,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private applyCurrentTheme (): void {
|
||||
|
@@ -1,24 +1,18 @@
|
||||
import { NativeImage, SegmentedControlSegment, TouchBarSegmentedControl } from 'electron'
|
||||
import { Injectable, Inject, NgZone } from '@angular/core'
|
||||
import { SegmentedControlSegment, TouchBarSegmentedControl } from 'electron'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { AppService } from './app.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { HostAppService, Platform } from './hostApp.service'
|
||||
import { ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TouchbarService {
|
||||
private tabsSegmentedControl: TouchBarSegmentedControl
|
||||
private buttonsSegmentedControl: TouchBarSegmentedControl
|
||||
private tabSegments: SegmentedControlSegment[] = []
|
||||
private nsImageCache: Record<string, NativeImage> = {}
|
||||
|
||||
private constructor (
|
||||
private app: AppService,
|
||||
private hostApp: HostAppService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
private config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private zone: NgZone,
|
||||
) {
|
||||
@@ -63,16 +57,6 @@ export class TouchbarService {
|
||||
return
|
||||
}
|
||||
|
||||
let buttons: ToolbarButton[] = []
|
||||
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
buttons = buttons.filter(x => !!x.touchBarNSImage)
|
||||
buttons.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
this.tabSegments = this.app.tabs.map(tab => ({
|
||||
label: this.shortenTitle(tab.title),
|
||||
}))
|
||||
|
||||
this.tabsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
|
||||
segments: this.tabSegments,
|
||||
selectedIndex: this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : undefined,
|
||||
@@ -81,43 +65,14 @@ export class TouchbarService {
|
||||
}),
|
||||
})
|
||||
|
||||
this.buttonsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
|
||||
segments: buttons.map(button => this.getButton(button)),
|
||||
mode: 'buttons',
|
||||
change: (selectedIndex) => this.zone.run(() => {
|
||||
if (buttons[selectedIndex].click) {
|
||||
buttons[selectedIndex].click!()
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const touchBar = new this.electron.TouchBar({
|
||||
items: [
|
||||
this.tabsSegmentedControl,
|
||||
new this.electron.TouchBar.TouchBarSpacer({ size: 'flexible' }),
|
||||
new this.electron.TouchBar.TouchBarSpacer({ size: 'small' }),
|
||||
this.buttonsSegmentedControl,
|
||||
],
|
||||
})
|
||||
this.hostApp.setTouchBar(touchBar)
|
||||
}
|
||||
|
||||
private getButton (button: ToolbarButton): SegmentedControlSegment {
|
||||
return {
|
||||
label: button.touchBarNSImage ? undefined : this.shortenTitle(button.touchBarTitle ?? button.title),
|
||||
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : undefined,
|
||||
// click: () => this.zone.run(() => button.click()),
|
||||
}
|
||||
}
|
||||
|
||||
private getCachedNSImage (name: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!this.nsImageCache[name]) {
|
||||
this.nsImageCache[name] = this.electron.nativeImage.createFromNamedImage(name, [0, 0, 1])
|
||||
}
|
||||
return this.nsImageCache[name]
|
||||
}
|
||||
|
||||
private shortenTitle (title: string): string {
|
||||
if (title.length > 15) {
|
||||
title = title.substring(0, 15) + '...'
|
||||
|
@@ -1,6 +1,10 @@
|
||||
@import './theme.scss';
|
||||
|
||||
app-root {
|
||||
.tabs-on-side .tab-bar {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
height: 27px !important;
|
||||
|
||||
@@ -12,6 +16,10 @@ app-root {
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.inset {
|
||||
width: 70 !important;
|
||||
}
|
||||
}
|
||||
|
||||
terminaltab .content {
|
||||
|
@@ -66,7 +66,9 @@ app-root {
|
||||
border: none;
|
||||
transition: 0.25s all;
|
||||
|
||||
&:hover { background: $button-hover-bg !important; }
|
||||
right: 5px;
|
||||
|
||||
&:hover { background: $button-active-bg !important; }
|
||||
&:active { background: $button-active-bg !important; }
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,8 @@ export class StandardCompactTheme extends Theme {
|
||||
name = 'Compact'
|
||||
css = require('./theme.compact.scss')
|
||||
terminalBackground = '#222a33'
|
||||
macOSWindowButtonsInsetX = 8
|
||||
macOSWindowButtonsInsetY = 12
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
|
@@ -1,60 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-core:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
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: /\.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/ },
|
||||
{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /component\.css/ },
|
||||
{ test: /\.yaml$/, use: ['json-loader', 'yaml-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'electron',
|
||||
'fs',
|
||||
'os',
|
||||
'path',
|
||||
'windows-native-registry',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'core',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -11,12 +11,12 @@
|
||||
enabled "2.0.x"
|
||||
kuler "^2.0.0"
|
||||
|
||||
"@types/js-yaml@^3.9.0":
|
||||
version "3.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb"
|
||||
integrity sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==
|
||||
"@types/js-yaml@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.0.tgz#d1a11688112091f2c711674df3a65ea2f47b5dfb"
|
||||
integrity sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==
|
||||
|
||||
"@types/semver@^7.3.1":
|
||||
"@types/semver@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
|
||||
@@ -40,12 +40,10 @@ agent-base@^4.3.0:
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
async@^3.1.0:
|
||||
version "3.2.0"
|
||||
@@ -57,24 +55,24 @@ at-least-node@^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==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
bootstrap@^4.1.3:
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.3.tgz#c6a72b355aaf323920be800246a6e4ef30997fe6"
|
||||
integrity sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==
|
||||
|
||||
builder-util-runtime@8.7.2:
|
||||
version "8.7.2"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz#d93afc71428a12789b437e13850e1fa7da956d72"
|
||||
integrity sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==
|
||||
builder-util-runtime@8.7.3:
|
||||
version "8.7.3"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.3.tgz#0aaafa52d25295c939496f62231ca9ff06c30e40"
|
||||
integrity sha512-1Q2ReBqFblimF5g/TLg2+0M5Xzv0Ih5LxJ/BMWXvEy/e6pQKeeEpbkPMGsN6OiQgkygaZo5VXCXIjOkOQG5EoQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
debug "^4.3.2"
|
||||
sax "^1.2.4"
|
||||
|
||||
color-convert@^1.9.1:
|
||||
@@ -124,22 +122,15 @@ colorspace@1.1.x:
|
||||
text-hex "1.0.x"
|
||||
|
||||
core-js@^3.1.2:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.7.0.tgz#b0a761a02488577afbf97179e4681bf49568520f"
|
||||
integrity sha512-NwS7fI5M5B85EwpWuIwJN4i/fbisQUwLwiSNUWeXlkAZ0sbBjLEvLvFLf1uzAUV66PcEPt4xCGCmOZSxVf3xzA==
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae"
|
||||
integrity sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
@@ -147,10 +138,10 @@ debug@^3.1.0:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
|
||||
integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
|
||||
debug@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
@@ -160,17 +151,17 @@ deepmerge@^4.1.1:
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
electron-updater@^4.0.6:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.5.tgz#4fb36f593a031c87ea07ee141c9f064d5deffb15"
|
||||
integrity sha512-5jjN7ebvfj1cLI0VZMdCnJk6aC4bP+dy7ryBf21vArR0JzpRVk0OZHA2QBD+H5rm6ZSeDYHOY6+8PrMEqJ4wlQ==
|
||||
version "4.3.8"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.8.tgz#94f1731682a756385726183e2b04b959cb319456"
|
||||
integrity sha512-/tB82Ogb2LqaXrUzAD8waJC+TZV52Pr0Znfj7w+i4D+jA2GgrKFI3Pxjp+36y9FcBMQz7kYsMHcB6c5zBJao+A==
|
||||
dependencies:
|
||||
"@types/semver" "^7.3.1"
|
||||
builder-util-runtime "8.7.2"
|
||||
fs-extra "^9.0.1"
|
||||
js-yaml "^3.14.0"
|
||||
"@types/semver" "^7.3.4"
|
||||
builder-util-runtime "8.7.3"
|
||||
fs-extra "^9.1.0"
|
||||
js-yaml "^4.0.0"
|
||||
lazy-val "^1.0.4"
|
||||
lodash.isequal "^4.5.0"
|
||||
semver "^7.3.2"
|
||||
semver "^7.3.4"
|
||||
|
||||
enabled@2.0.x:
|
||||
version "2.0.0"
|
||||
@@ -189,11 +180,6 @@ es6-promisify@^5.0.0:
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
esprima@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
fast-safe-stringify@^2.0.4:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
|
||||
@@ -209,22 +195,20 @@ fn.name@1.x.x:
|
||||
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
|
||||
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
fs-extra@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
|
||||
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
|
||||
fs-extra@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
|
||||
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
|
||||
dependencies:
|
||||
at-least-node "^1.0.0"
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^1.0.0"
|
||||
universalify "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.4"
|
||||
@@ -259,13 +243,12 @@ isarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
js-yaml@^3.14.0, 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==
|
||||
js-yaml@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
|
||||
integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.1.0"
|
||||
@@ -302,6 +285,13 @@ logform@^2.2.0:
|
||||
ms "^2.1.1"
|
||||
triple-beam "^1.3.0"
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
mixpanel@^0.10.2:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.10.3.tgz#2dff3bc0e17b57d6365547d315cbbf3ecfdb8a00"
|
||||
@@ -309,11 +299,6 @@ mixpanel@^0.10.2:
|
||||
dependencies:
|
||||
https-proxy-agent "3.0.0"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@2.1.2, ms@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
@@ -324,13 +309,14 @@ ng2-dnd@^5.0.2:
|
||||
resolved "https://registry.yarnpkg.com/ng2-dnd/-/ng2-dnd-5.0.2.tgz#862278ac7dedfa14f5783bbf34014d5d73dfefb4"
|
||||
integrity sha512-5mWWBePwvEPsNd/HkdbD543Q9mPyJofL6zkNydl8/Ah3qrrvZT2DaEPbknY08OgkXpI2qUGksc01OzzVlRQ9dQ==
|
||||
|
||||
ngx-perfect-scrollbar@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-8.0.0.tgz#19c1bbf9b1a36d89b00a68f7834e39427d29182f"
|
||||
integrity sha512-IXoFbULQnxyJj0gdCcKCLE/6OW9HCP9KARzMCKS1kNxTuzG4DghjM2AaCBRM5/sFwdbn6rqOKMCINtHA8W8YCA==
|
||||
ngx-perfect-scrollbar@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-10.1.0.tgz#6f7e2d8c849e595077b1c71992b6b544d56084d7"
|
||||
integrity sha512-CQ4pthb+UOoccTh3dOVcmBJsUILpHNBsKMHatif6AB2jsvhH6y2O6elMaoslhQEFqpv1fJlrU25AKIUJQZIA4A==
|
||||
dependencies:
|
||||
perfect-scrollbar "^1.4.0"
|
||||
perfect-scrollbar "1.5.0"
|
||||
resize-observer-polyfill "^1.5.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
one-time@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -339,7 +325,7 @@ one-time@^1.0.0:
|
||||
dependencies:
|
||||
fn.name "1.x.x"
|
||||
|
||||
perfect-scrollbar@^1.4.0:
|
||||
perfect-scrollbar@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz#821d224ed8ff61990c23f26db63048cdc75b6b83"
|
||||
integrity sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==
|
||||
@@ -391,10 +377,12 @@ sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
semver@^7.3.2:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
|
||||
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
|
||||
semver@^7.3.4:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
shell-escape@^0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -408,11 +396,6 @@ simple-swizzle@^0.2.2:
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
stack-trace@0.0.x:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
@@ -442,10 +425,10 @@ 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==
|
||||
tslib@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -458,9 +441,9 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
uuid@^8.0.0:
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
|
||||
integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
winston-transport@^4.4.0:
|
||||
version "4.4.0"
|
||||
@@ -484,3 +467,8 @@ winston@*, winston@^3.3.3:
|
||||
stack-trace "0.0.x"
|
||||
triple-beam "^1.3.0"
|
||||
winston-transport "^4.4.0"
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-plugin-manager",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Terminus' plugin manager",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -18,7 +18,7 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/semver": "^7.1.0",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"mz": "^2.6.0",
|
||||
"semver": "^7.1.1"
|
||||
|
@@ -2,7 +2,6 @@
|
||||
strong Error in {{erroredPlugin}}:
|
||||
pre {{errorMessage}}
|
||||
|
||||
|
||||
.d-flex
|
||||
h3.mb-1 Installed
|
||||
button.btn.btn-outline-secondary.btn-sm.ml-auto((click)='openPluginsFolder()')
|
||||
@@ -11,11 +10,17 @@
|
||||
|
||||
.list-group.list-group-flush.mt-2
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let plugin of pluginManager.installedPlugins')
|
||||
toggle(
|
||||
[ngModel]='isPluginEnabled(plugin)',
|
||||
(ngModelChange)='togglePlugin(plugin)',
|
||||
[disabled]='!canDisablePlugin(plugin)'
|
||||
)
|
||||
|
||||
.mr-auto.d-flex.flex-column
|
||||
div
|
||||
strong {{plugin.name}}
|
||||
small.text-muted.ml-1(*ngIf='!plugin.isBuiltin') {{plugin.version}} / {{plugin.author}}
|
||||
small.text-warning.ml-1(*ngIf='config.store.pluginBlacklist.includes(plugin.name)') Disabled
|
||||
small.text-warning.ml-1(*ngIf='!isPluginEnabled(plugin)') Disabled
|
||||
a.text-muted.mb-0((click)='showPluginInfo(plugin)')
|
||||
small {{plugin.description}}
|
||||
|
||||
@@ -28,18 +33,6 @@
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing')
|
||||
span Upgrade ({{knownUpgrades[plugin.name].version}})
|
||||
|
||||
button.btn.btn-link.text-primary.ml-2(
|
||||
*ngIf='config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='enablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-play
|
||||
|
||||
button.btn.btn-link.ml-2(
|
||||
*ngIf='!config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='disablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-pause
|
||||
|
||||
button.btn.btn-link.text-danger.ml-2(
|
||||
(click)='uninstallPlugin(plugin)',
|
||||
*ngIf='!plugin.isBuiltin',
|
||||
|
@@ -9,6 +9,8 @@ import { PluginInfo, PluginManagerService } from '../services/pluginManager.serv
|
||||
|
||||
enum BusyState { Installing = 'Installing', Uninstalling = 'Uninstalling' }
|
||||
|
||||
const FORCE_ENABLE = ['terminus-core', 'terminus-settings']
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./pluginsSettingsTab.component.pug'),
|
||||
@@ -102,6 +104,22 @@ export class PluginsSettingsTabComponent {
|
||||
this.electron.shell.openExternal('https://www.npmjs.com/package/' + plugin.packageName)
|
||||
}
|
||||
|
||||
isPluginEnabled (plugin: PluginInfo) {
|
||||
return !this.config.store.pluginBlacklist.includes(plugin.name)
|
||||
}
|
||||
|
||||
canDisablePlugin (plugin: PluginInfo) {
|
||||
return !FORCE_ENABLE.includes(plugin.packageName)
|
||||
}
|
||||
|
||||
togglePlugin (plugin: PluginInfo) {
|
||||
if (this.isPluginEnabled(plugin)) {
|
||||
this.disablePlugin(plugin)
|
||||
} else {
|
||||
this.enablePlugin(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
enablePlugin (plugin: PluginInfo) {
|
||||
this.config.store.pluginBlacklist = this.config.store.pluginBlacklist.filter(x => x !== plugin.name)
|
||||
this.config.save()
|
||||
|
@@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import TerminusCorePlugin from 'terminus-core'
|
||||
import { SettingsTabProvider } from 'terminus-settings'
|
||||
|
||||
import { PluginsSettingsTabComponent } from './components/pluginsSettingsTab.component'
|
||||
@@ -14,6 +15,7 @@ import { PluginsSettingsTabProvider } from './settings'
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
NgbModule,
|
||||
TerminusCorePlugin,
|
||||
],
|
||||
providers: [
|
||||
{ provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true },
|
||||
|
@@ -1,56 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-plugin-manager:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
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: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'net',
|
||||
'path',
|
||||
'electron-promise-ipc',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'plugin-manager',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -12,12 +12,12 @@ any-promise@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
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==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
call-bind@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -27,13 +27,6 @@ call-bind@^1.0.0:
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.0"
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
@@ -78,12 +71,10 @@ es-to-primitive@^1.2.1:
|
||||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
@@ -145,10 +136,12 @@ is-symbol@^1.0.2:
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
mz@^2.6.0:
|
||||
version "2.7.0"
|
||||
@@ -195,9 +188,11 @@ object.entries@^1.1.3:
|
||||
has "^1.0.3"
|
||||
|
||||
semver@^7.1.1:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
|
||||
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
serialize-error@^5.0.0:
|
||||
version "5.0.0"
|
||||
@@ -245,3 +240,8 @@ uuid@^3.0.1:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-serial",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Serial connection manager for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -20,7 +20,10 @@
|
||||
"@types/node": "14.14.14",
|
||||
"@types/ssh2": "^0.5.35",
|
||||
"ansi-colors": "^4.1.1",
|
||||
"cli-spinner": "^0.2.10"
|
||||
"binstring": "^0.2.1",
|
||||
"buffer-replace": "^1.0.0",
|
||||
"cli-spinner": "^0.2.10",
|
||||
"hexer": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "^9.1.9",
|
||||
|
@@ -1,7 +1,15 @@
|
||||
import hexdump from 'hexer'
|
||||
import colors from 'ansi-colors'
|
||||
import binstring from 'binstring'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import bufferReplace from 'buffer-replace'
|
||||
import { BaseSession } from 'terminus-terminal'
|
||||
import { SerialPort } from 'serialport'
|
||||
import { Logger } from 'terminus-core'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { Subject, Observable, interval } from 'rxjs'
|
||||
import { debounce } from 'rxjs/operators'
|
||||
import { ReadLine, createInterface as createReadline, clearLine } from 'readline'
|
||||
import { PassThrough, Readable, Writable } from 'stream'
|
||||
|
||||
export interface LoginScript {
|
||||
expect: string
|
||||
@@ -23,6 +31,10 @@ export interface SerialConnection {
|
||||
xany: boolean
|
||||
scripts?: LoginScript[]
|
||||
color?: string
|
||||
inputMode?: InputMode
|
||||
inputNewlines?: NewlineMode
|
||||
outputMode?: OutputMode
|
||||
outputNewlines?: NewlineMode
|
||||
}
|
||||
|
||||
export const BAUD_RATES = [
|
||||
@@ -34,6 +46,10 @@ export interface SerialPortInfo {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type InputMode = null | 'readline' | 'readline-hex' // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
export type OutputMode = null | 'hex' // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
export type NewlineMode = null | 'cr' | 'lf' | 'crlf' // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
|
||||
export class SerialSession extends BaseSession {
|
||||
scripts?: LoginScript[]
|
||||
serial: SerialPort
|
||||
@@ -41,58 +57,38 @@ export class SerialSession extends BaseSession {
|
||||
|
||||
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||
private serviceMessage = new Subject<string>()
|
||||
private inputReadline: ReadLine
|
||||
private inputPromptVisible = true
|
||||
private inputReadlineInStream: Readable & Writable
|
||||
private inputReadlineOutStream: Readable & Writable
|
||||
|
||||
constructor (public connection: SerialConnection) {
|
||||
super()
|
||||
this.scripts = connection.scripts ?? []
|
||||
|
||||
this.inputReadlineInStream = new PassThrough()
|
||||
this.inputReadlineOutStream = new PassThrough()
|
||||
this.inputReadline = createReadline({
|
||||
input: this.inputReadlineInStream,
|
||||
output: this.inputReadlineOutStream,
|
||||
terminal: true,
|
||||
prompt: this.connection.inputMode === 'readline-hex' ? 'hex> ' : '> ',
|
||||
} as any)
|
||||
this.inputReadlineOutStream.on('data', data => {
|
||||
this.emitOutput(Buffer.from(data))
|
||||
})
|
||||
this.inputReadline.on('line', line => {
|
||||
this.onInput(new Buffer(line + '\n'))
|
||||
this.resetInputPrompt()
|
||||
})
|
||||
this.output$.pipe(debounce(() => interval(500))).subscribe(() => this.onOutputSettled())
|
||||
}
|
||||
|
||||
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('readable', () => {
|
||||
this.onOutput(this.serial.read())
|
||||
})
|
||||
|
||||
this.serial.on('end', () => {
|
||||
@@ -106,23 +102,33 @@ export class SerialSession extends BaseSession {
|
||||
}
|
||||
|
||||
write (data: Buffer): void {
|
||||
if (this.serial) {
|
||||
this.serial.write(data.toString())
|
||||
if (this.connection.inputMode?.startsWith('readline')) {
|
||||
this.inputReadlineInStream.write(data)
|
||||
} else {
|
||||
this.onInput(data)
|
||||
}
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
this.serviceMessage.complete()
|
||||
this.inputReadline.close()
|
||||
await super.destroy()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
|
||||
resize (_, __) { }
|
||||
resize (_, __) {
|
||||
this.inputReadlineOutStream.emit('resize')
|
||||
}
|
||||
|
||||
kill (_?: string): void {
|
||||
this.serial.close()
|
||||
}
|
||||
|
||||
emitServiceMessage (msg: string): void {
|
||||
this.serviceMessage.next(msg)
|
||||
this.logger.info(stripAnsi(msg))
|
||||
}
|
||||
|
||||
async getChildProcesses (): Promise<any[]> {
|
||||
return []
|
||||
}
|
||||
@@ -131,10 +137,126 @@ export class SerialSession extends BaseSession {
|
||||
this.kill('TERM')
|
||||
}
|
||||
|
||||
supportsWorkingDirectory (): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
async getWorkingDirectory (): Promise<string|null> {
|
||||
return null
|
||||
}
|
||||
|
||||
private replaceNewlines (data: Buffer, mode?: NewlineMode): Buffer {
|
||||
if (!mode) {
|
||||
return data
|
||||
}
|
||||
data = bufferReplace(data, '\r\n', '\n')
|
||||
data = bufferReplace(data, '\r', '\n')
|
||||
const replacement = {
|
||||
strip: '',
|
||||
cr: '\r',
|
||||
lf: '\n',
|
||||
crlf: '\r\n',
|
||||
}[mode]
|
||||
return bufferReplace(data, '\n', replacement)
|
||||
}
|
||||
|
||||
private onInput (data: Buffer) {
|
||||
if (this.connection.inputMode === 'readline-hex') {
|
||||
const tokens = data.toString().split(/\s/g)
|
||||
data = Buffer.concat(tokens.filter(t => !!t).map(t => {
|
||||
if (t.startsWith('0x')) {
|
||||
t = t.substring(2)
|
||||
}
|
||||
return binstring(t, { 'in': 'hex' })
|
||||
}))
|
||||
}
|
||||
|
||||
data = this.replaceNewlines(data, this.connection.inputNewlines)
|
||||
if (this.serial) {
|
||||
this.serial.write(data.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private onOutputSettled () {
|
||||
if (this.connection.inputMode?.startsWith('readline') && !this.inputPromptVisible) {
|
||||
this.resetInputPrompt()
|
||||
}
|
||||
}
|
||||
|
||||
private resetInputPrompt () {
|
||||
this.emitOutput(new Buffer('\r\n'))
|
||||
this.inputReadline.prompt(true)
|
||||
this.inputPromptVisible = true
|
||||
}
|
||||
|
||||
private onOutput (data: Buffer) {
|
||||
const dataString = data.toString()
|
||||
|
||||
if (this.connection.inputMode?.startsWith('readline')) {
|
||||
if (this.inputPromptVisible) {
|
||||
clearLine(this.inputReadlineOutStream, 0)
|
||||
this.inputPromptVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
data = this.replaceNewlines(data, this.connection.outputNewlines)
|
||||
|
||||
if (this.connection.outputMode === 'hex') {
|
||||
this.emitOutput(Buffer.concat([
|
||||
new Buffer('\r\n'),
|
||||
Buffer.from(hexdump(data, {
|
||||
group: 1,
|
||||
gutter: 4,
|
||||
divide: colors.gray(' | '),
|
||||
emptyHuman: colors.gray('╳'),
|
||||
}).replace(/\n/g, '\r\n')),
|
||||
new Buffer('\r\n\n'),
|
||||
]))
|
||||
} else {
|
||||
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 (re.test(dataString)) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private executeUnconditionalScripts () {
|
||||
if (this.scripts) {
|
||||
for (const script of this.scripts) {
|
||||
|
@@ -11,21 +11,84 @@
|
||||
[(ngModel)]='connection.name',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Path
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.port',
|
||||
[ngbTypeahead]='portsAutocomplete',
|
||||
[resultFormatter]='portsFormatter',
|
||||
)
|
||||
.row
|
||||
.col-6
|
||||
.form-group
|
||||
label Path
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.port',
|
||||
[ngbTypeahead]='portsAutocomplete',
|
||||
[resultFormatter]='portsFormatter',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Baud Rate
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.baudrate',
|
||||
)
|
||||
option([value]='x', *ngFor='let x of baudRates') {{x}}
|
||||
.col-6
|
||||
.form-group
|
||||
label Baud Rate
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.baudrate',
|
||||
)
|
||||
option([value]='x', *ngFor='let x of baudRates') {{x}}
|
||||
|
||||
.row
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Input mode
|
||||
|
||||
.d-flex(ngbDropdown)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
ngbDropdownToggle,
|
||||
) {{getInputModeName(connection.inputMode)}}
|
||||
|
||||
div(ngbDropdownMenu)
|
||||
a.d-flex.flex-column(
|
||||
*ngFor='let mode of inputModes',
|
||||
(click)='connection.inputMode = mode.key',
|
||||
ngbDropdownItem
|
||||
)
|
||||
div {{mode.name}}
|
||||
.text-muted {{mode.description}}
|
||||
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Input newlines
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.inputNewlines',
|
||||
)
|
||||
option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}}
|
||||
|
||||
.row
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Output mode
|
||||
|
||||
.d-flex(ngbDropdown)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
ngbDropdownToggle,
|
||||
) {{getOutputModeName(connection.outputMode)}}
|
||||
|
||||
div(ngbDropdownMenu)
|
||||
a.d-flex.flex-column(
|
||||
*ngFor='let mode of outputModes',
|
||||
(click)='connection.outputMode = mode.key',
|
||||
ngbDropdownItem
|
||||
)
|
||||
div {{mode.name}}
|
||||
.text-muted {{mode.description}}
|
||||
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Output newlines
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.outputNewlines',
|
||||
)
|
||||
option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}}
|
||||
|
||||
ngb-tab(id='advanced')
|
||||
ng-template(ngbTabTitle) Advanced
|
||||
|
@@ -15,6 +15,22 @@ export class EditConnectionModalComponent {
|
||||
connection: SerialConnection
|
||||
foundPorts: SerialPortInfo[]
|
||||
baudRates = BAUD_RATES
|
||||
inputModes = [
|
||||
{ key: null, name: 'Normal', description: 'Input is sent as you type' },
|
||||
{ key: 'readline', name: 'Line by line', description: 'Line editor, input is sent after you press Enter' },
|
||||
{ key: 'readline-hex', name: 'Hexadecimal', description: 'Send bytes by typing in hex values' },
|
||||
]
|
||||
outputModes = [
|
||||
{ key: null, name: 'Normal', description: 'Output is shown as it is received' },
|
||||
{ key: 'hex', name: 'Hexadecimal', description: 'Output is shown as a hexdump' },
|
||||
]
|
||||
newlineModes = [
|
||||
{ key: null, name: 'Keep' },
|
||||
{ key: 'strip', name: 'Strip' },
|
||||
{ key: 'cr', name: 'Force CR' },
|
||||
{ key: 'lf', name: 'Force LF' },
|
||||
{ key: 'crlf', name: 'Force CRLF' },
|
||||
]
|
||||
|
||||
constructor (
|
||||
private modalInstance: NgbActiveModal,
|
||||
@@ -24,6 +40,14 @@ export class EditConnectionModalComponent {
|
||||
) {
|
||||
}
|
||||
|
||||
getInputModeName (key) {
|
||||
return this.inputModes.find(x => x.key === key)?.name
|
||||
}
|
||||
|
||||
getOutputModeName (key) {
|
||||
return this.outputModes.find(x => x.key === key)?.name
|
||||
}
|
||||
|
||||
portsAutocomplete = text$ => text$.pipe(map(() => {
|
||||
return this.foundPorts.map(x => x.name)
|
||||
}))
|
||||
|
@@ -34,6 +34,10 @@ export class SerialSettingsTabComponent {
|
||||
xany: false,
|
||||
xoff: false,
|
||||
xon: false,
|
||||
inputMode: null,
|
||||
outputMode: null,
|
||||
inputNewlines: null,
|
||||
outputNewlines: null,
|
||||
}
|
||||
|
||||
const modal = this.ngbModal.open(EditConnectionModalComponent)
|
||||
|
@@ -1,16 +1,16 @@
|
||||
.tab-toolbar
|
||||
.tab-toolbar([class.show]='!session || !session.open')
|
||||
.btn.btn-outline-secondary.reveal-button
|
||||
i.fas.fa-ellipsis-h
|
||||
.toolbar(*ngIf='session', [class.show]='!session.open')
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session.open')
|
||||
strong(*ngIf='session') {{session.connection.port}} ({{session.connection.baudrate}})
|
||||
.toolbar
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session && session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session || !session.open')
|
||||
strong {{connection.port}} ({{connection.baudrate}})
|
||||
|
||||
.mr-auto
|
||||
|
||||
button.btn.btn-secondary.mr-3((click)='changeBaudRate()', *ngIf='session.open')
|
||||
button.btn.btn-secondary.mr-3((click)='changeBaudRate()', *ngIf='session && session.open')
|
||||
span Change baud rate
|
||||
|
||||
button.btn.btn-info((click)='reconnect()', *ngIf='!session.open')
|
||||
button.btn.btn-info((click)='reconnect()', *ngIf='!session || !session.open')
|
||||
i.fas.fa-reload
|
||||
span Reconnect
|
||||
|
@@ -11,14 +11,15 @@ import { Subscription } from 'rxjs'
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'serial-tab',
|
||||
template: BaseTerminalTabComponent.template + (require('./serialTab.component.pug') as string),
|
||||
template: `${BaseTerminalTabComponent.template} ${require('./serialTab.component.pug')}`,
|
||||
styles: [require('./serialTab.component.scss'), ...BaseTerminalTabComponent.styles],
|
||||
animations: BaseTerminalTabComponent.animations,
|
||||
})
|
||||
export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
connection?: SerialConnection
|
||||
session?: SerialSession
|
||||
session: SerialSession|null = null
|
||||
serialPort: any
|
||||
private serialService: SerialService
|
||||
private homeEndSubscription: Subscription
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
@@ -26,6 +27,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
injector: Injector,
|
||||
) {
|
||||
super(injector)
|
||||
this.serialService = injector.get(SerialService)
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
@@ -42,6 +44,9 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
case 'end':
|
||||
this.sendInput('\x1b[F' )
|
||||
break
|
||||
case 'restart-serial-session':
|
||||
this.reconnect()
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
@@ -62,12 +67,8 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this.session = this.injector.get(SerialService).createSession(this.connection)
|
||||
this.session.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' serial ')} ${msg}\r\n`)
|
||||
this.session?.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
this.attachSessionHandlers()
|
||||
const session = this.serialService.createSession(this.connection)
|
||||
this.setSession(session)
|
||||
this.write(`Connecting to `)
|
||||
|
||||
const spinner = new Spinner({
|
||||
@@ -80,15 +81,32 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
spinner.start()
|
||||
|
||||
try {
|
||||
this.serialPort = await this.injector.get(SerialService).connectSession(this.session)
|
||||
this.serialPort = await this.serialService.connectSession(this.session!)
|
||||
spinner.stop(true)
|
||||
session.emitServiceMessage('Port opened')
|
||||
} catch (e) {
|
||||
spinner.stop(true)
|
||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||
return
|
||||
}
|
||||
await this.session.start()
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
await this.session!.start()
|
||||
this.session!.resize(this.size.columns, this.size.rows)
|
||||
}
|
||||
|
||||
protected attachSessionHandlers () {
|
||||
this.attachSessionHandler(this.session!.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' Serial ')} ${msg}\r\n`)
|
||||
this.session?.resize(this.size.columns, this.size.rows)
|
||||
}))
|
||||
this.attachSessionHandler(this.session!.destroyed$.subscribe(() => {
|
||||
this.write('Press any key to reconnect\r\n')
|
||||
this.input$.pipe(first()).subscribe(() => {
|
||||
if (!this.session?.open) {
|
||||
this.reconnect()
|
||||
}
|
||||
})
|
||||
}))
|
||||
super.attachSessionHandlers()
|
||||
}
|
||||
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
@@ -99,8 +117,10 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
}
|
||||
}
|
||||
|
||||
reconnect () {
|
||||
this.initializeSession()
|
||||
async reconnect (): Promise<void> {
|
||||
this.session?.destroy()
|
||||
await this.initializeSession()
|
||||
this.session?.releaseInitialDataBuffer()
|
||||
}
|
||||
|
||||
async changeBaudRate () {
|
||||
|
@@ -12,6 +12,7 @@ export class SerialConfigProvider extends ConfigProvider {
|
||||
serial: [
|
||||
'Alt-K',
|
||||
],
|
||||
'restart-serial-session': [],
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,10 @@ export class SerialHotkeyProvider extends HotkeyProvider {
|
||||
id: 'serial',
|
||||
name: 'Show Serial connections',
|
||||
},
|
||||
{
|
||||
id: 'restart-serial-session',
|
||||
name: 'Restart current serial session',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import SerialPort from 'serialport'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { LogService, AppService, SelectorOption, ConfigService } from 'terminus-core'
|
||||
import { LogService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||
import { SettingsTabComponent } from 'terminus-settings'
|
||||
import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api'
|
||||
import { SerialTabComponent } from '../components/serialTab.component'
|
||||
@@ -11,7 +10,7 @@ export class SerialService {
|
||||
private constructor (
|
||||
private log: LogService,
|
||||
private zone: NgZone,
|
||||
private toastr: ToastrService,
|
||||
private notifications: NotificationsService,
|
||||
private app: AppService,
|
||||
private config: ConfigService,
|
||||
) { }
|
||||
@@ -30,10 +29,17 @@ export class SerialService {
|
||||
}
|
||||
|
||||
async connectSession (session: SerialSession): Promise<SerialPort> {
|
||||
const serial = new SerialPort(session.connection.port, { autoOpen: false, baudRate: session.connection.baudrate,
|
||||
dataBits: session.connection.databits, stopBits: session.connection.stopbits, parity: session.connection.parity,
|
||||
rtscts: session.connection.rtscts, xon: session.connection.xon, xoff: session.connection.xoff,
|
||||
xany: session.connection.xany })
|
||||
const serial = new SerialPort(session.connection.port, {
|
||||
autoOpen: false,
|
||||
baudRate: parseInt(session.connection.baudrate as any),
|
||||
dataBits: session.connection.databits,
|
||||
stopBits: session.connection.stopbits,
|
||||
parity: session.connection.parity,
|
||||
rtscts: session.connection.rtscts,
|
||||
xon: session.connection.xon,
|
||||
xoff: session.connection.xoff,
|
||||
xany: session.connection.xany,
|
||||
})
|
||||
session.serial = serial
|
||||
let connected = false
|
||||
await new Promise(async (resolve, reject) => {
|
||||
@@ -44,17 +50,21 @@ export class SerialService {
|
||||
serial.on('error', error => {
|
||||
this.zone.run(() => {
|
||||
if (connected) {
|
||||
this.toastr.error(error.toString())
|
||||
this.notifications.error(error.toString())
|
||||
} else {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
serial.on('close', () => {
|
||||
session.emitServiceMessage('Port closed')
|
||||
session.destroy()
|
||||
})
|
||||
|
||||
try {
|
||||
serial.open()
|
||||
} catch (e) {
|
||||
this.toastr.error(e.message)
|
||||
this.notifications.error(e.message)
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
@@ -103,7 +113,7 @@ export class SerialService {
|
||||
options.push({
|
||||
name: 'Manage connections',
|
||||
icon: 'cog',
|
||||
callback: () => this.app.openNewTab(SettingsTabComponent, { activeTab: 'serial' }),
|
||||
callback: () => this.app.openNewTabRaw(SettingsTabComponent, { activeTab: 'serial' }),
|
||||
})
|
||||
|
||||
options.push({
|
||||
@@ -131,7 +141,7 @@ export class SerialService {
|
||||
})
|
||||
return tab
|
||||
} catch (error) {
|
||||
this.toastr.error(`Could not connect: ${error}`)
|
||||
this.notifications.error(`Could not connect: ${error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@@ -1,59 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-serial:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js', '.node'],
|
||||
},
|
||||
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: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'keytar',
|
||||
'path',
|
||||
'ngx-toastr',
|
||||
'serialport',
|
||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'serial',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -27,12 +27,52 @@
|
||||
"@types/node" "*"
|
||||
"@types/ssh2-streams" "*"
|
||||
|
||||
ansi-color@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-color/-/ansi-color-0.2.1.tgz#3e75c037475217544ed763a8db5709fa9ae5bf9a"
|
||||
integrity sha1-PnXAN0dSF1RO12Oo21cJ+prlv5o=
|
||||
|
||||
ansi-colors@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
|
||||
|
||||
binstring@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/binstring/-/binstring-0.2.1.tgz#8a174d301f6d54efda550dd98bb4cb524eacd75d"
|
||||
integrity sha1-ihdNMB9tVO/aVQ3Zi7TLUk6s110=
|
||||
|
||||
buffer-replace@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-replace/-/buffer-replace-1.0.0.tgz#bc427c40af4c1f06d6933dede57110acba8ade54"
|
||||
integrity sha1-vEJ8QK9MHwbWkz3t5XEQrLqK3lQ=
|
||||
|
||||
cli-spinner@^0.2.10:
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinner/-/cli-spinner-0.2.10.tgz#f7d617a36f5c47a7bc6353c697fc9338ff782a47"
|
||||
integrity sha512-U0sSQ+JJvSLi1pAYuJykwiA8Dsr15uHEy85iCJ6A+0DjVxivr3d+N2Wjvodeg89uP5K6TswFkKBfAD7B3YSn/Q==
|
||||
|
||||
hexer@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/hexer/-/hexer-1.5.0.tgz#b86ce808598e8a9d1892c571f3cedd86fc9f0653"
|
||||
integrity sha1-uGzoCFmOip0YksVx887dhvyfBlM=
|
||||
dependencies:
|
||||
ansi-color "^0.2.1"
|
||||
minimist "^1.1.0"
|
||||
process "^0.10.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
minimist@^1.1.0:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
process@^0.10.0:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/process/-/process-0.10.1.tgz#842457cc51cfed72dc775afeeafb8c6034372725"
|
||||
integrity sha1-hCRXzFHP7XLcd1r+6vuMYDQ3JyU=
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-settings",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Terminus terminal settings page",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -17,7 +17,8 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/deep-equal": "1.0.1"
|
||||
"@types/deep-equal": "1.0.1",
|
||||
"utils-decorators": "^1.8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "^9.1.9",
|
||||
|
@@ -6,26 +6,27 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
i.fas.fa-fw.fa-window-maximize.mr-2
|
||||
| Application
|
||||
ng-template(ngbTabContent)
|
||||
.d-flex.align-items-center.mb-4
|
||||
.d-flex.align-items-center.flex-wrap.mb-4
|
||||
h1.terminus-title.mb-2.mr-2 Terminus
|
||||
sup α
|
||||
|
||||
.text-muted.mr-auto {{homeBase.appVersion}}
|
||||
|
||||
button.btn.btn-secondary.mr-3((click)='homeBase.openGitHub()')
|
||||
i.fab.fa-github
|
||||
span GitHub
|
||||
div
|
||||
button.btn.btn-secondary.mr-3((click)='homeBase.openGitHub()')
|
||||
i.fab.fa-github
|
||||
span GitHub
|
||||
|
||||
button.btn.btn-secondary((click)='homeBase.reportBug()')
|
||||
i.fas.fa-bug
|
||||
span Report a problem
|
||||
button.btn.btn-secondary((click)='homeBase.reportBug()')
|
||||
i.fas.fa-bug
|
||||
span Report a problem
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Theme
|
||||
select.form-control(
|
||||
[(ngModel)]='config.store.appearance.theme',
|
||||
(ngModelChange)='config.save()',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
)
|
||||
option(*ngFor='let theme of themes', [ngValue]='theme.name') {{theme.name}}
|
||||
|
||||
@@ -34,7 +35,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
.title Tabs location
|
||||
.btn-group(
|
||||
[(ngModel)]='config.store.appearance.tabsLocation',
|
||||
(ngModelChange)='config.save()',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
@@ -66,6 +67,29 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
)
|
||||
| Right
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Tabs width
|
||||
.btn-group(
|
||||
[(ngModel)]='config.store.appearance.flexTabs',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='true'
|
||||
)
|
||||
| Dynamic
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='false'
|
||||
)
|
||||
| Fixed
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(*ngIf='hostApp.platform !== Platform.macOS') Acrylic background
|
||||
@@ -74,7 +98,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
|
||||
toggle(
|
||||
[(ngModel)]='config.store.appearance.vibrancy',
|
||||
(ngModelChange)='config.save()'
|
||||
(ngModelChange)='saveConfiguration()'
|
||||
)
|
||||
|
||||
.form-line(*ngIf='config.store.appearance.vibrancy && isFluentVibrancySupported')
|
||||
@@ -82,7 +106,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
.title Background type
|
||||
.btn-group(
|
||||
[(ngModel)]='config.store.appearance.vibrancyType',
|
||||
(ngModelChange)='config.save()',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
@@ -106,7 +130,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
input(
|
||||
type='range',
|
||||
[(ngModel)]='config.store.appearance.opacity',
|
||||
(ngModelChange)='config.save(); (hostApp.platform === Platform.Linux && config.requestRestart())',
|
||||
(ngModelChange)='saveConfiguration(); (hostApp.platform === Platform.Linux && config.requestRestart())',
|
||||
min='0.4',
|
||||
max='1',
|
||||
step='0.01'
|
||||
@@ -125,7 +149,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
|
||||
.btn-group(
|
||||
[(ngModel)]='config.store.appearance.frame',
|
||||
(ngModelChange)='config.save(); config.requestRestart()',
|
||||
(ngModelChange)='saveConfiguration(true)',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
@@ -157,7 +181,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
|
||||
.btn-group(
|
||||
[(ngModel)]='config.store.appearance.dock',
|
||||
(ngModelChange)='config.save(); docking.dock()',
|
||||
(ngModelChange)='saveConfiguration(); docking.dock()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
@@ -196,14 +220,14 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
)
|
||||
| Bottom
|
||||
|
||||
.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.ml-5.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.header
|
||||
.title Display on
|
||||
.description Snaps the window to a side of the screen
|
||||
|
||||
div(
|
||||
[(ngModel)]='config.store.appearance.dockScreen',
|
||||
(ngModelChange)='config.save(); docking.dock()',
|
||||
(ngModelChange)='saveConfiguration(); docking.dock()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
@@ -221,34 +245,46 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
)
|
||||
| {{screen.name}}
|
||||
|
||||
.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.ml-5.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.header
|
||||
.title Dock always on top
|
||||
.description Keep docked terminal always on top
|
||||
toggle(
|
||||
[(ngModel)]='config.store.appearance.dockAlwaysOnTop',
|
||||
(ngModelChange)='config.save(); docking.dock()',
|
||||
(ngModelChange)='saveConfiguration(); docking.dock()',
|
||||
)
|
||||
|
||||
.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.ml-5.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.header
|
||||
.title Docked terminal size
|
||||
input(
|
||||
type='range',
|
||||
[(ngModel)]='config.store.appearance.dockFill',
|
||||
(mouseup)='config.save(); docking.dock()',
|
||||
(mouseup)='saveConfiguration(); docking.dock()',
|
||||
min='0.05',
|
||||
max='1',
|
||||
step='0.01'
|
||||
)
|
||||
|
||||
.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.ml-5.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.header
|
||||
.title Docked terminal space
|
||||
input(
|
||||
type='range',
|
||||
[(ngModel)]='config.store.appearance.dockSpace',
|
||||
(mouseup)='saveConfiguration(); docking.dock()',
|
||||
min='0.2',
|
||||
max='1',
|
||||
step='0.01'
|
||||
)
|
||||
|
||||
.ml-5.form-line(*ngIf='config.store.appearance.dock != "off"')
|
||||
.header
|
||||
.title Hide dock on blur
|
||||
.description Hides the docked terminal when you click away.
|
||||
toggle(
|
||||
[(ngModel)]='config.store.appearance.dockHideOnBlur',
|
||||
(ngModelChange)='config.save(); ',
|
||||
(ngModelChange)='saveConfiguration(); ',
|
||||
)
|
||||
|
||||
.form-line
|
||||
@@ -265,21 +301,21 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
.description We're only tracking your Terminus and OS versions.
|
||||
toggle(
|
||||
[(ngModel)]='config.store.enableAnalytics',
|
||||
(ngModelChange)='config.save(); config.requestRestart()',
|
||||
(ngModelChange)='saveConfiguration(true)',
|
||||
)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Automatic Updates
|
||||
.description Enable automatic installation of updates when they become available.
|
||||
toggle([(ngModel)]='config.store.enableAutomaticUpdates', (ngModelChange)='config.save()')
|
||||
toggle([(ngModel)]='config.store.enableAutomaticUpdates', (ngModelChange)='saveConfiguration()')
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Custom CSS
|
||||
textarea.form-control(
|
||||
[(ngModel)]='config.store.appearance.css',
|
||||
(ngModelChange)='config.save()',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
)
|
||||
|
||||
ngb-tab(id='hotkeys')
|
||||
@@ -308,7 +344,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
td.pr-5
|
||||
multi-hotkey-input(
|
||||
[model]='getHotkey(hotkey.id) || []',
|
||||
(modelChange)='setHotkey(hotkey.id, $event); config.save(); docking.dock()'
|
||||
(modelChange)='setHotkey(hotkey.id, $event); saveConfiguration(); docking.dock()'
|
||||
)
|
||||
|
||||
ngb-tab(*ngFor='let provider of settingsProviders', [id]='provider.id')
|
||||
@@ -327,7 +363,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
|
||||
.d-flex.flex-column.w-100.h-100
|
||||
.h-100.d-flex
|
||||
.w-100.d-flex.flex-column
|
||||
h3 Config file
|
||||
h3 Config File
|
||||
textarea.form-control.h-100(
|
||||
[(ngModel)]='configFile'
|
||||
)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import * as yaml from 'js-yaml'
|
||||
import { debounce } from 'utils-decorators/dist/cjs'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Component, Inject, Input, HostBinding, NgZone } from '@angular/core'
|
||||
import {
|
||||
@@ -60,7 +61,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
this.settingsProviders = config.enabledServices(this.settingsProviders)
|
||||
this.themes = config.enabledServices(this.themes)
|
||||
|
||||
this.configDefaults = yaml.safeDump(config.getDefaults())
|
||||
this.configDefaults = yaml.dump(config.getDefaults())
|
||||
|
||||
const onConfigChange = () => {
|
||||
this.configFile = config.readRaw()
|
||||
@@ -104,6 +105,14 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
this.hostApp.relaunch()
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
saveConfiguration (requireRestart?: boolean) {
|
||||
this.config.save()
|
||||
if (requireRestart) {
|
||||
this.config.requestRestart()
|
||||
}
|
||||
}
|
||||
|
||||
saveConfigFile () {
|
||||
if (this.isConfigFileValid()) {
|
||||
this.config.writeRaw(this.configFile)
|
||||
@@ -116,7 +125,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
|
||||
isConfigFileValid () {
|
||||
try {
|
||||
yaml.safeLoad(this.configFile)
|
||||
yaml.load(this.configFile)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
|
@@ -1,57 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-settings:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
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: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.css$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'path',
|
||||
'os',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'settings',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -6,3 +6,15 @@
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.1.tgz#71cfabb247c22bcc16d536111f50c0ed12476b03"
|
||||
integrity sha512-mMUu4nWHLBlHtxXY17Fg6+ucS/MnndyOWyOe7MmwkoMYxvfQU2ajtRaEvqSUv+aVkMqH/C0NCI8UoVfRNQ10yg==
|
||||
|
||||
tinyqueue@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
|
||||
integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
|
||||
|
||||
utils-decorators@^1.8.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-decorators/-/utils-decorators-1.8.1.tgz#6e7e2cf46c05a9554c05f004e5235696142bd5f7"
|
||||
integrity sha512-UpqzJj40jdTknZpxdeYL7p+8Ynl3bpHP6yoxoY+RmuDCOaelTiOz4GcDpScPvfZhv/ivHTV1bPJZeQd8tlxczA==
|
||||
dependencies:
|
||||
tinyqueue "^2.0.3"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-ssh",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.1",
|
||||
"description": "SSH connection manager for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -21,11 +21,10 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "14.14.14",
|
||||
"@types/node": "14.14.31",
|
||||
"@types/ssh2": "^0.5.35",
|
||||
"ansi-colors": "^4.1.1",
|
||||
"cli-spinner": "^0.2.10",
|
||||
"run-script-os": "^1.1.3",
|
||||
"ssh2": "^0.8.9",
|
||||
"ssh2-streams": "Eugeny/ssh2-streams#75f6d3425d071ac73a18fd46e2f5e738bfe897c5",
|
||||
"sshpk": "^1.16.1",
|
||||
@@ -33,6 +32,7 @@
|
||||
"temp": "^0.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"run-script-os": "^1.1.3",
|
||||
"socksv5": "^0.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@@ -140,6 +140,9 @@ export class SSHSession extends BaseSession {
|
||||
this.shell = await this.openShellChannel({ x11: this.connection.x11 })
|
||||
} catch (err) {
|
||||
this.emitServiceMessage(colors.bgRed.black(' X ') + ` Remote rejected opening a shell channel: ${err}`)
|
||||
if (err.toString().includes('Unable to request X11')) {
|
||||
this.emitServiceMessage(' Make sure `xauth` is installed on the remote side')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -245,7 +248,13 @@ export class SSHSession extends BaseSession {
|
||||
}
|
||||
socket.on('error', e => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
this.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not connect to the X server ${xHost}:${xPort}: ${e}`)
|
||||
this.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not connect to the X server: ${e}`)
|
||||
this.emitServiceMessage(` Terminus tried to connect to ${xHost}:${xPort} based on the DISPLAY environment var (${displaySpec})`)
|
||||
if (process.platform === 'win32') {
|
||||
this.emitServiceMessage(' To use X forwarding, you need a local X server, e.g.:')
|
||||
this.emitServiceMessage(' * VcXsrv: https://sourceforge.net/projects/vcxsrv/')
|
||||
this.emitServiceMessage(' * Xming: https://sourceforge.net/projects/xming/')
|
||||
}
|
||||
reject()
|
||||
})
|
||||
socket.on('connect', () => {
|
||||
@@ -363,6 +372,10 @@ export class SSHSession extends BaseSession {
|
||||
this.kill('TERM')
|
||||
}
|
||||
|
||||
supportsWorkingDirectory (): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
async getWorkingDirectory (): Promise<string|null> {
|
||||
return null
|
||||
}
|
||||
@@ -398,3 +411,9 @@ export interface SSHConnectionGroup {
|
||||
name: string
|
||||
connections: SSHConnection[]
|
||||
}
|
||||
|
||||
export const ALGORITHM_BLACKLIST = [
|
||||
// cause native crashes in node crypto, use EC instead
|
||||
'diffie-hellman-group-exchange-sha256',
|
||||
'diffie-hellman-group-exchange-sha1',
|
||||
]
|
||||
|
@@ -103,7 +103,7 @@
|
||||
.header
|
||||
.title Jump host
|
||||
select.form-control([(ngModel)]='connection.jumpHost')
|
||||
option([ngValue]='null') None
|
||||
option(value='') None
|
||||
option([ngValue]='x.name', *ngFor='let x of config.store.ssh.connections') {{x.name}}
|
||||
|
||||
.form-line
|
||||
|
@@ -3,7 +3,7 @@ import { Component } from '@angular/core'
|
||||
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
import { SSHConnection, LoginScript, SSHAlgorithmType } from '../api'
|
||||
import { SSHConnection, LoginScript, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
|
||||
import { PromptModalComponent } from './promptModal.component'
|
||||
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
||||
|
||||
@@ -40,8 +40,8 @@ export class EditConnectionModalComponent {
|
||||
[SSHAlgorithmType.CIPHER]: 'CIPHER',
|
||||
[SSHAlgorithmType.HMAC]: 'HMAC',
|
||||
}[k]
|
||||
this.supportedAlgorithms[k] = ALGORITHMS[supportedAlg]
|
||||
this.defaultAlgorithms[k] = ALGORITHMS[defaultAlg]
|
||||
this.supportedAlgorithms[k] = ALGORITHMS[supportedAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
this.defaultAlgorithms[k] = ALGORITHMS[defaultAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,14 @@
|
||||
.tab-toolbar
|
||||
.tab-toolbar([class.show]='!session || !session.open')
|
||||
.btn.btn-outline-secondary.reveal-button
|
||||
i.fas.fa-ellipsis-h
|
||||
.toolbar(*ngIf='session', [class.show]='!session.open')
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session.open')
|
||||
strong.mr-auto(*ngIf='session') {{session.connection.user}}@{{session.connection.host}}:{{session.connection.port}}
|
||||
.toolbar
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session && session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session || !session.open')
|
||||
strong.mr-auto {{connection.user}}@{{connection.host}}:{{connection.port}}
|
||||
|
||||
button.btn.btn-secondary.mr-2((click)='reconnect()', [class.btn-info]='!session.open')
|
||||
button.btn.btn-secondary.mr-2((click)='reconnect()', [class.btn-info]='!session || !session.open')
|
||||
span Reconnect
|
||||
|
||||
button.btn.btn-secondary((click)='showPortForwarding()', *ngIf='session.open')
|
||||
button.btn.btn-secondary((click)='showPortForwarding()', *ngIf='session && session.open')
|
||||
i.fas.fa-plug
|
||||
span Ports
|
||||
|
@@ -14,15 +14,17 @@ import { Subscription } from 'rxjs'
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'ssh-tab',
|
||||
template: BaseTerminalTabComponent.template + (require('./sshTab.component.pug') as string),
|
||||
template: `${BaseTerminalTabComponent.template} ${require('./sshTab.component.pug')}`,
|
||||
styles: [require('./sshTab.component.scss'), ...BaseTerminalTabComponent.styles],
|
||||
animations: BaseTerminalTabComponent.animations,
|
||||
})
|
||||
export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
connection?: SSHConnection
|
||||
session?: SSHSession
|
||||
session: SSHSession|null = null
|
||||
private sessionStack: SSHSession[] = []
|
||||
private homeEndSubscription: Subscription
|
||||
private recentInputs = ''
|
||||
private reconnectOffered = false
|
||||
|
||||
constructor (
|
||||
injector: Injector,
|
||||
@@ -52,11 +54,18 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
case 'end':
|
||||
this.sendInput('\x1b[F' )
|
||||
break
|
||||
case 'restart-ssh-session':
|
||||
this.reconnect()
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
this.frontendReady$.pipe(first()).subscribe(() => {
|
||||
this.initializeSession()
|
||||
this.input$.subscribe(data => {
|
||||
this.recentInputs += data
|
||||
this.recentInputs = this.recentInputs.substring(this.recentInputs.length - 32)
|
||||
})
|
||||
})
|
||||
|
||||
super.ngOnInit()
|
||||
@@ -68,12 +77,23 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
|
||||
async setupOneSession (session: SSHSession): Promise<void> {
|
||||
if (session.connection.jumpHost) {
|
||||
const jumpConnection = this.config.store.ssh.connections.find(x => x.name === session.connection.jumpHost)
|
||||
const jumpConnection: SSHConnection|null = this.config.store.ssh.connections.find(x => x.name === session.connection.jumpHost)
|
||||
|
||||
if (!jumpConnection) {
|
||||
throw new Error(`${session.connection.host}: jump host "${session.connection.jumpHost}" not found in your config`)
|
||||
}
|
||||
|
||||
const jumpSession = this.ssh.createSession(jumpConnection)
|
||||
|
||||
await this.setupOneSession(jumpSession)
|
||||
|
||||
jumpSession.destroyed$.subscribe(() => session.destroy())
|
||||
this.attachSessionHandler(
|
||||
jumpSession.destroyed$.subscribe(() => {
|
||||
if (session.open) {
|
||||
session.destroy()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut(
|
||||
'127.0.0.1', 0, session.connection.host, session.connection.port ?? 22,
|
||||
@@ -93,15 +113,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
this.sessionStack.push(session)
|
||||
}
|
||||
|
||||
|
||||
session.serviceMessage$.subscribe(msg => {
|
||||
this.attachSessionHandler(session.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' SSH ')} ${msg}\r\n`)
|
||||
session.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
}))
|
||||
|
||||
session.destroyed$.subscribe(() => {
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
|
||||
})
|
||||
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` Connecting to ${session.connection.host}\r\n`)
|
||||
|
||||
@@ -128,20 +144,51 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
}
|
||||
}
|
||||
|
||||
protected attachSessionHandlers (): void {
|
||||
const session = this.session!
|
||||
this.attachSessionHandler(session.destroyed$.subscribe(() => {
|
||||
if (
|
||||
// Ctrl-D
|
||||
this.recentInputs.charCodeAt(this.recentInputs.length - 1) === 4 ||
|
||||
this.recentInputs.endsWith('exit\r')
|
||||
) {
|
||||
// User closed the session
|
||||
this.destroy()
|
||||
} else {
|
||||
// Session was closed abruptly
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
|
||||
if (!this.reconnectOffered) {
|
||||
this.reconnectOffered = true
|
||||
this.write('Press any key to reconnect\r\n')
|
||||
this.input$.pipe(first()).subscribe(() => {
|
||||
if (!this.session?.open) {
|
||||
this.reconnect()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
super.attachSessionHandlers()
|
||||
}
|
||||
|
||||
async initializeSession (): Promise<void> {
|
||||
this.reconnectOffered = false
|
||||
if (!this.connection) {
|
||||
this.logger.error('No SSH connection info supplied')
|
||||
return
|
||||
}
|
||||
|
||||
this.session = this.ssh.createSession(this.connection)
|
||||
const session = this.ssh.createSession(this.connection)
|
||||
this.setSession(session)
|
||||
|
||||
await this.setupOneSession(this.session)
|
||||
try {
|
||||
await this.setupOneSession(session)
|
||||
} catch (e) {
|
||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||
}
|
||||
|
||||
this.attachSessionHandlers()
|
||||
|
||||
await this.session.start()
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
await this.session!.start()
|
||||
this.session!.resize(this.size.columns, this.size.rows)
|
||||
}
|
||||
|
||||
async getRecoveryToken (): Promise<RecoveryToken> {
|
||||
|
@@ -13,6 +13,7 @@ export class SSHConfigProvider extends ConfigProvider {
|
||||
ssh: [
|
||||
'Alt-S',
|
||||
],
|
||||
'restart-ssh-session': [],
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,10 @@ export class SSHHotkeyProvider extends HotkeyProvider {
|
||||
id: 'ssh',
|
||||
name: 'Show SSH connections',
|
||||
},
|
||||
{
|
||||
id: 'restart-ssh-session',
|
||||
name: 'Restart current SSH session',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
|
@@ -5,14 +5,26 @@ import * as keytar from 'keytar'
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PasswordStorageService {
|
||||
async savePassword (connection: SSHConnection, password: string): Promise<void> {
|
||||
return keytar.setPassword(`ssh@${connection.host}`, connection.user, password)
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
return keytar.setPassword(key, connection.user, password)
|
||||
}
|
||||
|
||||
async deletePassword (connection: SSHConnection): Promise<void> {
|
||||
await keytar.deletePassword(`ssh@${connection.host}`, connection.user)
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
await keytar.deletePassword(key, connection.user)
|
||||
}
|
||||
|
||||
async loadPassword (connection: SSHConnection): Promise<string|null> {
|
||||
return keytar.getPassword(`ssh@${connection.host}`, connection.user)
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
return keytar.getPassword(key, connection.user)
|
||||
}
|
||||
}
|
||||
|
@@ -9,10 +9,9 @@ import * as fs from 'mz/fs'
|
||||
import { execFile } from 'mz/child_process'
|
||||
import * as path from 'path'
|
||||
import * as sshpk from 'sshpk'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService } from 'terminus-core'
|
||||
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||
import { SettingsTabComponent } from 'terminus-settings'
|
||||
import { SSHConnection, SSHSession } from '../api'
|
||||
import { ALGORITHM_BLACKLIST, SSHConnection, SSHSession } from '../api'
|
||||
import { PromptModalComponent } from '../components/promptModal.component'
|
||||
import { PasswordStorageService } from './passwordStorage.service'
|
||||
import { SSHTabComponent } from '../components/sshTab.component'
|
||||
@@ -39,7 +38,7 @@ export class SSHService {
|
||||
private ngbModal: NgbModal,
|
||||
private hostApp: HostAppService,
|
||||
private passwordStorage: PasswordStorageService,
|
||||
private toastr: ToastrService,
|
||||
private notifications: NotificationsService,
|
||||
private app: AppService,
|
||||
private config: ConfigService,
|
||||
) {
|
||||
@@ -70,7 +69,7 @@ export class SSHService {
|
||||
privateKey = (await fs.readFile(privateKeyPath)).toString()
|
||||
} catch (error) {
|
||||
logCallback?.(colors.bgRed.black(' X ') + 'Could not read the private key file')
|
||||
this.toastr.error('Could not read the private key file')
|
||||
this.notifications.error('Could not read the private key file')
|
||||
}
|
||||
|
||||
if (privateKey) {
|
||||
@@ -147,6 +146,10 @@ export class SSHService {
|
||||
session.ssh = ssh
|
||||
let connected = false
|
||||
let savedPassword: string|null = null
|
||||
const algorithms = {}
|
||||
for (const key of Object.keys(session.connection.algorithms ?? {})) {
|
||||
algorithms[key] = session.connection.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
}
|
||||
await new Promise(async (resolve, reject) => {
|
||||
ssh.on('ready', () => {
|
||||
connected = true
|
||||
@@ -162,7 +165,7 @@ export class SSHService {
|
||||
this.zone.run(() => {
|
||||
if (connected) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
this.toastr.error(error.toString())
|
||||
this.notifications.error(error.toString())
|
||||
} else {
|
||||
reject(error)
|
||||
}
|
||||
@@ -258,7 +261,7 @@ export class SSHService {
|
||||
tryKeyboard: true,
|
||||
agent: agent ?? undefined,
|
||||
agentForward: session.connection.agentForward && !!agent,
|
||||
keepaliveInterval: session.connection.keepaliveInterval,
|
||||
keepaliveInterval: session.connection.keepaliveInterval ?? 15000,
|
||||
keepaliveCountMax: session.connection.keepaliveCountMax,
|
||||
readyTimeout: session.connection.readyTimeout,
|
||||
hostVerifier: (digest: string) => {
|
||||
@@ -267,7 +270,7 @@ export class SSHService {
|
||||
return true
|
||||
},
|
||||
hostHash: 'sha256' as any,
|
||||
algorithms: session.connection.algorithms,
|
||||
algorithms,
|
||||
sock: session.jumpStream,
|
||||
authHandler: methodsLeft => {
|
||||
while (true) {
|
||||
@@ -285,7 +288,7 @@ export class SSHService {
|
||||
},
|
||||
} as any)
|
||||
} catch (e) {
|
||||
this.toastr.error(e.message)
|
||||
this.notifications.error(e.message)
|
||||
return reject(e)
|
||||
}
|
||||
|
||||
@@ -379,7 +382,7 @@ export class SSHService {
|
||||
options.push({
|
||||
name: 'Manage connections',
|
||||
icon: 'cog',
|
||||
callback: () => this.app.openNewTab(SettingsTabComponent, { activeTab: 'ssh' }),
|
||||
callback: () => this.app.openNewTabRaw(SettingsTabComponent, { activeTab: 'ssh' }),
|
||||
})
|
||||
|
||||
options.push({
|
||||
@@ -407,7 +410,7 @@ export class SSHService {
|
||||
|
||||
return tab
|
||||
} catch (error) {
|
||||
this.toastr.error(`Could not connect: ${error}`)
|
||||
this.notifications.error(`Could not connect: ${error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -417,7 +420,9 @@ export class SSHService {
|
||||
let host = query
|
||||
let port = 22
|
||||
if (host.includes('@')) {
|
||||
[user, host] = host.split('@')
|
||||
const parts = host.split(/@/g)
|
||||
host = parts[parts.length - 1]
|
||||
user = parts.slice(0, parts.length - 1).join('@')
|
||||
}
|
||||
if (host.includes(':')) {
|
||||
port = parseInt(host.split(':')[1])
|
||||
|
@@ -1,61 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-ssh:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
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: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'child_process',
|
||||
'fs',
|
||||
'keytar',
|
||||
'path',
|
||||
'ngx-toastr',
|
||||
'socksv5',
|
||||
'windows-native-registry',
|
||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'ssh',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -2,10 +2,10 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@*", "@types/node@14.14.14":
|
||||
version "14.14.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae"
|
||||
integrity sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==
|
||||
"@types/node@*", "@types/node@14.14.31":
|
||||
version "14.14.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
|
||||
integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
|
||||
|
||||
"@types/ssh2-streams@*":
|
||||
version "0.1.7"
|
||||
@@ -230,9 +230,9 @@ rimraf@~2.6.2:
|
||||
glob "^7.1.3"
|
||||
|
||||
run-script-os@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/run-script-os/-/run-script-os-1.1.3.tgz#1069b418307f4fd36ff056b5eda309c273fca8b0"
|
||||
integrity sha512-xPlzE6533nvWVea5z7e5J7+JAIepfpxTu/HLGxcjJYlemVukOCWJBaRCod/DWXJFRIWEFOgSGbjd2m1QWTJi5w==
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/run-script-os/-/run-script-os-1.1.5.tgz#6038a92b370a1cbca5fa2fa73d1c740b0037b6ff"
|
||||
integrity sha512-kLvUnf1SM1+gSH2bY1P41MNFaWdXaG2nkhoJS9WQNQxk6g9KNuncKderBLG7vOsp77GtQqNs0bEazxip/I6wfg==
|
||||
|
||||
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-terminal",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"version": "1.0.135-nightly.0",
|
||||
"description": "Terminus' terminal emulation core",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -27,12 +27,12 @@
|
||||
"runes": "^0.4.2",
|
||||
"slugify": "^1.4.0",
|
||||
"xterm": "^4.9.0-beta.7",
|
||||
"xterm-addon-fit": "^0.4.0-beta.8",
|
||||
"xterm-addon-ligatures": "^0.4.0-beta.5",
|
||||
"xterm-addon-search": "^0.7.0-beta.2",
|
||||
"xterm-addon-serialize": "^0.3.0",
|
||||
"xterm-addon-fit": "^0.5.0",
|
||||
"xterm-addon-ligatures": "^0.4.0",
|
||||
"xterm-addon-search": "^0.8.0",
|
||||
"xterm-addon-serialize": "^0.5.0",
|
||||
"xterm-addon-unicode11": "^0.2.0",
|
||||
"xterm-addon-webgl": "^0.8.0",
|
||||
"xterm-addon-webgl": "^0.10.0",
|
||||
"zmodem.js": "^0.1.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import type { MenuItemConstructorOptions } from 'electron'
|
||||
import { Observable, Subject, Subscription } from 'rxjs'
|
||||
import { first } from 'rxjs/operators'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import colors from 'ansi-colors'
|
||||
import { NgZone, OnInit, OnDestroy, Injector, ViewChild, HostBinding, Input, ElementRef, InjectFlags } from '@angular/core'
|
||||
import { trigger, transition, style, animate, AnimationTriggerMetadata } from '@angular/animations'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent } from 'terminus-core'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent } from 'terminus-core'
|
||||
|
||||
import { BaseSession, SessionsService } from '../services/sessions.service'
|
||||
import { TerminalFrontendService } from '../services/terminalFrontend.service'
|
||||
@@ -15,10 +14,6 @@ import { ResizeEvent } from './interfaces'
|
||||
import { TerminalDecorator } from './decorator'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
export interface ToastrServiceProxy {
|
||||
info: (_: string) => void
|
||||
}
|
||||
/**
|
||||
* A class to base your custom terminal tabs on
|
||||
*/
|
||||
@@ -35,7 +30,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
]),
|
||||
])]
|
||||
|
||||
session?: BaseSession
|
||||
session: BaseSession|null = null
|
||||
savedState?: any
|
||||
|
||||
@Input() zoom = 0
|
||||
@@ -81,7 +76,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
protected sessions: SessionsService
|
||||
protected electron: ElectronService
|
||||
protected terminalContainersService: TerminalFrontendService
|
||||
protected toastr: ToastrServiceProxy
|
||||
protected notifications: NotificationsService
|
||||
protected log: LogService
|
||||
protected decorators: TerminalDecorator[] = []
|
||||
protected contextMenuProviders: TabContextMenuItemProvider[]
|
||||
@@ -89,11 +84,13 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
|
||||
protected logger: Logger
|
||||
protected output = new Subject<string>()
|
||||
protected sessionChanged = new Subject<BaseSession|null>()
|
||||
private sessionCloseSubscription: Subscription
|
||||
private hotkeysSubscription: Subscription
|
||||
private bellPlayer: HTMLAudioElement
|
||||
private termContainerSubscriptions: Subscription[] = []
|
||||
private allFocusModeSubscription: Subscription|null = null
|
||||
private sessionHandlers: Subscription[] = []
|
||||
|
||||
get input$ (): Observable<Buffer> {
|
||||
if (!this.frontend) {
|
||||
@@ -120,6 +117,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
|
||||
get frontendReady$ (): Observable<void> { return this.frontendReady }
|
||||
|
||||
get sessionChanged$ (): Observable<BaseSession|null> { return this.sessionChanged }
|
||||
|
||||
constructor (protected injector: Injector) {
|
||||
super()
|
||||
|
||||
@@ -132,7 +131,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.sessions = injector.get(SessionsService)
|
||||
this.electron = injector.get(ElectronService)
|
||||
this.terminalContainersService = injector.get(TerminalFrontendService)
|
||||
this.toastr = injector.get(ToastrService)
|
||||
this.notifications = injector.get(NotificationsService)
|
||||
this.log = injector.get(LogService)
|
||||
this.decorators = injector.get<any>(TerminalDecorator, null, InjectFlags.Optional) as TerminalDecorator[]
|
||||
this.contextMenuProviders = injector.get<any>(TabContextMenuItemProvider, null, InjectFlags.Optional) as TabContextMenuItemProvider[]
|
||||
@@ -140,7 +139,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.logger = this.log.create('baseTerminalTab')
|
||||
this.setTitle('Terminal')
|
||||
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(async hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
@@ -149,7 +148,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
if (this.frontend?.getSelection()) {
|
||||
this.frontend.copySelection()
|
||||
this.frontend.clearSelection()
|
||||
this.toastr.info('Copied')
|
||||
this.notifications.notice('Copied')
|
||||
} else {
|
||||
this.sendInput('\x03')
|
||||
}
|
||||
@@ -157,7 +156,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
case 'copy':
|
||||
this.frontend?.copySelection()
|
||||
this.frontend?.clearSelection()
|
||||
this.toastr.info('Copied')
|
||||
this.notifications.notice('Copied')
|
||||
break
|
||||
case 'paste':
|
||||
this.paste()
|
||||
@@ -207,6 +206,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
case 'pane-focus-all':
|
||||
this.focusAllPanes()
|
||||
break
|
||||
case 'copy-current-path':
|
||||
this.copyCurrentPath()
|
||||
break
|
||||
}
|
||||
})
|
||||
this.bellPlayer = document.createElement('audio')
|
||||
@@ -328,7 +330,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
|
||||
const percentageMatch = /(^|[^\d])(\d+(\.\d+)?)%([^\d]|$)/.exec(data)
|
||||
if (!this.alternateScreenActive && percentageMatch) {
|
||||
if (!this.alternateScreenActive && percentageMatch && this.config.store.terminal.detectProgress) {
|
||||
const percentage = percentageMatch[3] ? parseFloat(percentageMatch[2]) : parseInt(percentageMatch[2])
|
||||
if (percentage > 0 && percentage <= 100) {
|
||||
this.setProgress(percentage)
|
||||
@@ -343,7 +345,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
async paste (): Promise<void> {
|
||||
let data = this.electron.clipboard.readText()
|
||||
if (this.config.store.terminal.bracketedPaste) {
|
||||
data = '\x1b[200~' + data + '\x1b[201~'
|
||||
data = `\x1b[200~${data}\x1b[201~`
|
||||
}
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
data = data.replace(/\r\n/g, '\r')
|
||||
@@ -414,10 +416,11 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
return
|
||||
}
|
||||
if (this.parent instanceof SplitTabComponent) {
|
||||
this.parent._allFocusMode = true
|
||||
this.parent.layout()
|
||||
const parent = this.parent
|
||||
parent._allFocusMode = true
|
||||
parent.layout()
|
||||
this.allFocusModeSubscription = this.frontend?.input$.subscribe(data => {
|
||||
for (const tab of (this.parent as SplitTabComponent).getAllTabs()) {
|
||||
for (const tab of parent.getAllTabs()) {
|
||||
if (tab !== this && tab instanceof BaseTerminalTabComponent) {
|
||||
tab.sendInput(data)
|
||||
}
|
||||
@@ -438,6 +441,19 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
async copyCurrentPath (): Promise<void> {
|
||||
let cwd: string|null = null
|
||||
if (this.session?.supportsWorkingDirectory()) {
|
||||
cwd = await this.session.getWorkingDirectory()
|
||||
}
|
||||
if (cwd) {
|
||||
this.electron.clipboard.writeText(cwd)
|
||||
this.notifications.notice('Copied')
|
||||
} else {
|
||||
this.notifications.error('Shell does not support current path detection')
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
ngOnDestroy (): void {
|
||||
this.frontend?.detach(this.content.nativeElement)
|
||||
@@ -550,26 +566,56 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
]
|
||||
}
|
||||
|
||||
setSession (session: BaseSession|null, destroyOnSessionClose = false): void {
|
||||
if (session) {
|
||||
if (this.session) {
|
||||
this.setSession(null)
|
||||
}
|
||||
this.detachSessionHandlers()
|
||||
this.session = session
|
||||
this.attachSessionHandlers(destroyOnSessionClose)
|
||||
} else {
|
||||
this.detachSessionHandlers()
|
||||
this.session = null
|
||||
}
|
||||
this.sessionChanged.next(session)
|
||||
}
|
||||
|
||||
protected attachSessionHandler (subscription: Subscription): void {
|
||||
this.sessionHandlers.push(subscription)
|
||||
}
|
||||
|
||||
protected attachSessionHandlers (destroyOnSessionClose = false): void {
|
||||
if (!this.session) {
|
||||
throw new Error('Session not set')
|
||||
}
|
||||
|
||||
// this.session.output$.bufferTime(10).subscribe((datas) => {
|
||||
this.session.output$.subscribe(data => {
|
||||
this.attachSessionHandler(this.session.output$.subscribe(data => {
|
||||
if (this.enablePassthrough) {
|
||||
this.zone.run(() => {
|
||||
this.output.next(data)
|
||||
this.write(data)
|
||||
})
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
if (destroyOnSessionClose) {
|
||||
this.sessionCloseSubscription = this.session.closed$.subscribe(() => {
|
||||
this.attachSessionHandler(this.sessionCloseSubscription = this.session.closed$.subscribe(() => {
|
||||
this.frontend?.destroy()
|
||||
this.destroy()
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
this.attachSessionHandler(this.session.destroyed$.subscribe(() => {
|
||||
this.setSession(null)
|
||||
}))
|
||||
}
|
||||
|
||||
protected detachSessionHandlers (): void {
|
||||
for (const s of this.sessionHandlers) {
|
||||
s.unsubscribe()
|
||||
}
|
||||
this.sessionHandlers = []
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ export interface Profile {
|
||||
shell?: string
|
||||
isBuiltin?: boolean
|
||||
icon?: string
|
||||
disableDynamicTitle?: boolean
|
||||
}
|
||||
|
||||
export interface TerminalColorScheme {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
h3.mb-3 Appearance
|
||||
.d-flex
|
||||
.mr-5.w-100
|
||||
.row
|
||||
.col-12.col-md-6
|
||||
.form-line
|
||||
.header
|
||||
.title Font
|
||||
@@ -30,7 +30,8 @@ h3.mb-3 Appearance
|
||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.ligatures && config.store.terminal.frontend == "xterm-webgl"') Ligatures are not supported by the WebGL frontend
|
||||
|
||||
|
||||
color-scheme-preview([scheme]='config.store.terminal.colorScheme', [fontPreview]='true')
|
||||
.col-12.col-md-6
|
||||
color-scheme-preview([scheme]='config.store.terminal.colorScheme', [fontPreview]='true')
|
||||
|
||||
.form-line
|
||||
.header
|
||||
|
@@ -62,6 +62,12 @@
|
||||
placeholder='#000000'
|
||||
)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Disable dynamic tab title
|
||||
.description Connection name will be used as a title instead
|
||||
toggle([(ngModel)]='profile.disableDynamicTitle')
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary((click)='save()') Save
|
||||
button.btn.btn-outline-danger((click)='cancel()') Cancel
|
||||
|
@@ -10,7 +10,7 @@ import { Subject } from 'rxjs'
|
||||
})
|
||||
export class EnvironmentEditorComponent {
|
||||
@Output() modelChange = new Subject<any>()
|
||||
vars: {key: string, value: string}[] = []
|
||||
vars: { key: string, value: string }[] = []
|
||||
private cachedModel: any
|
||||
|
||||
@Input() get model (): any {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { Frontend, SearchOptions } from '../frontends/frontend'
|
||||
import { ConfigService } from 'terminus-core'
|
||||
import { ConfigService, NotificationsService } from 'terminus-core'
|
||||
|
||||
@Component({
|
||||
selector: 'search-panel',
|
||||
@@ -20,7 +19,7 @@ export class SearchPanelComponent {
|
||||
@Output() close = new EventEmitter()
|
||||
|
||||
constructor (
|
||||
private toastr: ToastrService,
|
||||
private notifications: NotificationsService,
|
||||
public config: ConfigService,
|
||||
) { }
|
||||
|
||||
@@ -35,7 +34,7 @@ export class SearchPanelComponent {
|
||||
}
|
||||
if (!this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })) {
|
||||
this.notFound = true
|
||||
this.toastr.error('Not found')
|
||||
this.notifications.notice('Not found')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ export class SearchPanelComponent {
|
||||
}
|
||||
if (!this.frontend.findPrevious(this.query, { ...this.options, incremental: incremental || undefined })) {
|
||||
this.notFound = true
|
||||
this.toastr.error('Not found')
|
||||
this.notifications.notice('Not found')
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -57,15 +57,14 @@ h3.mb-3 Shell
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Always Use Working Directory
|
||||
.description
|
||||
div By default, new terminals will open where the previous terminal was working.
|
||||
div Enabling this option will always launch new terminals in the working directory specified above.
|
||||
.title Directory for new tabs
|
||||
|
||||
toggle(
|
||||
select.form-control(
|
||||
[(ngModel)]='config.store.terminal.alwaysUseWorkingDirectory',
|
||||
(ngModelChange)='config.save()'
|
||||
(ngModelChange)='config.save()',
|
||||
)
|
||||
option([ngValue]='false') Same as active tab's directory
|
||||
option([ngValue]='true') The working directory from above
|
||||
|
||||
.form-line.align-items-start
|
||||
.header
|
||||
@@ -97,7 +96,7 @@ h3.mt-3 Saved Profiles
|
||||
button.btn.btn-outline-danger.ml-1((click)='$event.stopPropagation(); deleteProfile(profile)')
|
||||
i.fas.fa-trash
|
||||
|
||||
div(ngbDropdown, placement='top-left')
|
||||
.pb-4(ngbDropdown, placement='top-left')
|
||||
button.btn.btn-primary(ngbDropdownToggle)
|
||||
i.fas.fa-fw.fa-plus
|
||||
| New profile
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user