Compare commits
365 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f7b603a631 | ||
![]() |
44040ba54b | ||
![]() |
f87efcf5bd | ||
![]() |
220ae6ccaa | ||
![]() |
3c6374be19 | ||
![]() |
d32e31d45e | ||
![]() |
d7a33dc0ce | ||
![]() |
bc736dd13a | ||
![]() |
7cf8f8d58e | ||
![]() |
ff0cd36b6a | ||
![]() |
767bc8e56f | ||
![]() |
8801839c7a | ||
![]() |
7ab3238617 | ||
![]() |
6d89d7a8d0 | ||
![]() |
e277c52f71 | ||
![]() |
2cafd97751 | ||
![]() |
ad78f38210 | ||
![]() |
4f32908c48 | ||
![]() |
8f0ba06f63 | ||
![]() |
d221ad3078 | ||
![]() |
5b4d5efcc9 | ||
![]() |
8987cc39aa | ||
![]() |
2f2dd442ad | ||
![]() |
8bfc86e623 | ||
![]() |
50b1fb2410 | ||
![]() |
327daf03ef | ||
![]() |
224a72d029 | ||
![]() |
3c5615e464 | ||
![]() |
e99908761d | ||
![]() |
0ff81abb0c | ||
![]() |
b4e703674b | ||
![]() |
dc53668685 | ||
![]() |
2df848f4c0 | ||
![]() |
247cf6f93e | ||
![]() |
797265abb1 | ||
![]() |
62bdcb1af4 | ||
![]() |
25ae56718d | ||
![]() |
b24978dc0e | ||
![]() |
46a4df108b | ||
![]() |
3091e2be69 | ||
![]() |
9a49e94642 | ||
![]() |
cf13fca835 | ||
![]() |
174a1bcca7 | ||
![]() |
80c781a8ca | ||
![]() |
d71ee6b6f1 | ||
![]() |
3a7204c2ee | ||
![]() |
5236956469 | ||
![]() |
4dfb8df7fa | ||
![]() |
61e65c7ec8 | ||
![]() |
64ab172b8e | ||
![]() |
bd46b08c9d | ||
![]() |
4a97cc4383 | ||
![]() |
2c11feed83 | ||
![]() |
481aa654a3 | ||
![]() |
7d1ec5b869 | ||
![]() |
5f098ef791 | ||
![]() |
15029066e4 | ||
![]() |
dbf90a5ce3 | ||
![]() |
c6d4eb7083 | ||
![]() |
e56fac03b9 | ||
![]() |
1132a18a0a | ||
![]() |
ebc8d846e3 | ||
![]() |
123f68d705 | ||
![]() |
8f9a7539c4 | ||
![]() |
98d46468e5 | ||
![]() |
a6d5a93e6e | ||
![]() |
558ef9894c | ||
![]() |
7357dc178a | ||
![]() |
cd7df7c700 | ||
![]() |
a4c4c93bac | ||
![]() |
a97619a474 | ||
![]() |
cd1cac96e9 | ||
![]() |
9861766da0 | ||
![]() |
bcd5f3b8bf | ||
![]() |
3e4f2c467d | ||
![]() |
e84270609f | ||
![]() |
62b1538462 | ||
![]() |
d6a62344b8 | ||
![]() |
d2e16cd73a | ||
![]() |
87d3b08c37 | ||
![]() |
3a7db137c5 | ||
![]() |
da0f4e7afc | ||
![]() |
e1980a6611 | ||
![]() |
08cc19946f | ||
![]() |
f6d4a51239 | ||
![]() |
36f77c5b63 | ||
![]() |
3676b90c9f | ||
![]() |
c4204167cd | ||
![]() |
604d7c464f | ||
![]() |
e42bd11725 | ||
![]() |
864932d663 | ||
![]() |
9e68c735dc | ||
![]() |
be43f8b50d | ||
![]() |
c290633e7e | ||
![]() |
d03211631a | ||
![]() |
ca27c05f0f | ||
![]() |
62a21b03ea | ||
![]() |
2f7d29c523 | ||
![]() |
6236ee95c3 | ||
![]() |
836014c270 | ||
![]() |
0bf870738e | ||
![]() |
7c1697b9cb | ||
![]() |
c800dd6e44 | ||
![]() |
68e9a1f66b | ||
![]() |
f925d63fb0 | ||
![]() |
e79fc13de9 | ||
![]() |
0c963dcbcc | ||
![]() |
b7b672ce9b | ||
![]() |
4c8bb45d01 | ||
![]() |
d4f8a88451 | ||
![]() |
fac8fafa36 | ||
![]() |
bc854fcfff | ||
![]() |
ebc83b8064 | ||
![]() |
6757deab67 | ||
![]() |
fe68d9a34e | ||
![]() |
f42c3cdde4 | ||
![]() |
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 | ||
![]() |
39fa0424a6 | ||
![]() |
bcb1b6a13b | ||
![]() |
a19f35ac44 | ||
![]() |
ea92f1a700 | ||
![]() |
b5701cf9f9 | ||
![]() |
4742530cf3 | ||
![]() |
a8d78ce185 | ||
![]() |
bba1eaccbe | ||
![]() |
cd6d05aa69 | ||
![]() |
412403c72a | ||
![]() |
93ae907dd1 | ||
![]() |
ce24b9cc52 | ||
![]() |
dc68372d76 | ||
![]() |
e0fe125cf2 | ||
![]() |
e594fcd0e7 | ||
![]() |
0219da4d85 | ||
![]() |
5e06b2248b | ||
![]() |
cdc3623986 | ||
![]() |
6d016002c0 | ||
![]() |
f3569f5d2d | ||
![]() |
4125582ef2 | ||
![]() |
c6331c9b1c | ||
![]() |
aaab475e5f | ||
![]() |
e6bf76c616 | ||
![]() |
e36bad2553 | ||
![]() |
154cc29333 | ||
![]() |
1b0402c2cf | ||
![]() |
15073cbc81 | ||
![]() |
3365b143d8 | ||
![]() |
4d9cc91e91 | ||
![]() |
946f4292ef | ||
![]() |
eb12b1ae60 | ||
![]() |
4765c97d31 | ||
![]() |
3fb32e1a97 | ||
![]() |
9ec1a0d253 | ||
![]() |
fef19615bb | ||
![]() |
4d237baf33 | ||
![]() |
03e654b5a0 | ||
![]() |
ef815eaa40 | ||
![]() |
4771a38747 | ||
![]() |
ce016793d4 | ||
![]() |
3a854f04e1 | ||
![]() |
b5658d61d9 | ||
![]() |
02750d8581 | ||
![]() |
077a3e6bba | ||
![]() |
5454be032a | ||
![]() |
ceb638e08d | ||
![]() |
040098050d | ||
![]() |
00de7c148f | ||
![]() |
8a0b4f82db | ||
![]() |
74fd1aeea5 | ||
![]() |
aac230e362 | ||
![]() |
ae82ed4a47 | ||
![]() |
9d1b0e9861 | ||
![]() |
8cb4e9f27d | ||
![]() |
c8c00a2c9b | ||
![]() |
bacb475896 | ||
![]() |
c8faa67083 | ||
![]() |
b6c0e3cdfb | ||
![]() |
323581d513 | ||
![]() |
21b81f476c | ||
![]() |
2283a5dad9 | ||
![]() |
d7565e497d | ||
![]() |
7b4e99fc5f | ||
![]() |
035a6f8da8 |
@@ -334,6 +334,51 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "frauhottelmann",
|
||||
"name": "frauhottelmann",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/902705?v=4",
|
||||
"profile": "https://github.com/frauhottelmann",
|
||||
"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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "starxg",
|
||||
"name": "starxg",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/34997494?v=4",
|
||||
"profile": "https://github.com/starxg",
|
||||
"contributions": [
|
||||
"plugin"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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:
|
||||
@@ -29,7 +31,6 @@ rules:
|
||||
'@typescript-eslint/no-magic-numbers': off
|
||||
'@typescript-eslint/member-delimiter-style': off
|
||||
'@typescript-eslint/promise-function-async': off
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': off
|
||||
'@typescript-eslint/require-array-sort-compare': off
|
||||
'@typescript-eslint/no-floating-promises': off
|
||||
'@typescript-eslint/prefer-readonly': off
|
||||
@@ -38,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
|
||||
@@ -82,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:
|
||||
@@ -95,25 +98,22 @@ rules:
|
||||
- error
|
||||
- single
|
||||
- allowTemplateLiterals: true
|
||||
'@typescript-eslint/no-confusing-void-expression': off
|
||||
'@typescript-eslint/no-non-null-assertion': off
|
||||
'@typescript-eslint/no-unnecessary-condition': off
|
||||
'@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors
|
||||
'@typescript-eslint/no-unnecessary-condition':
|
||||
- error
|
||||
- allowConstantLoopConditions: true
|
||||
'@typescript-eslint/restrict-template-expressions': off
|
||||
'@typescript-eslint/no-dynamic-delete': off
|
||||
'@typescript-eslint/prefer-nullish-coalescing': off
|
||||
'@typescript-eslint/prefer-readonly-parameter-types': off
|
||||
'@typescript-eslint/no-unsafe-member-access': off
|
||||
'@typescript-eslint/no-unsafe-call': off
|
||||
'@typescript-eslint/no-unsafe-return': off
|
||||
'@typescript-eslint/no-base-to-string': off # broken in typescript-eslint
|
||||
'@typescript-eslint/no-unsafe-assignment': off
|
||||
'@typescript-eslint/naming-convention': off
|
||||
'@typescript-eslint/lines-between-class-members':
|
||||
- error
|
||||
- exceptAfterSingleLine: true
|
||||
'@typescript-eslint/dot-notation': off
|
||||
'@typescript-eslint/no-confusing-void-expression': off
|
||||
'@typescript-eslint/no-implicit-any-catch': off
|
||||
'@typescript-eslint/member-ordering': off
|
||||
'@typescript-eslint/no-var-requires': off
|
||||
'@typescript-eslint/no-shadow': off
|
||||
|
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/
|
||||
|
||||
|
16
.github/workflows/linux.yml
vendored
@@ -2,7 +2,7 @@ name: Linux Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-16.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -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
|
||||
@@ -36,6 +40,16 @@ jobs:
|
||||
env:
|
||||
DEBUG: electron-builder,electron-builder:*
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
USE_HARD_LINKS: false
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
sudo npm install -g @sentry/cli --unsafe-perm
|
||||
./scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
|
14
.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
|
||||
@@ -52,6 +56,7 @@ jobs:
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
|
||||
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
|
||||
USE_HARD_LINKS: false
|
||||
# DEBUG: electron-builder,electron-builder:*
|
||||
|
||||
- name: Build packages without signing
|
||||
@@ -61,6 +66,15 @@ jobs:
|
||||
ARCH: ${{matrix.arch}}
|
||||
# DEBUG: electron-builder,electron-builder:*
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
sudo npm install -g @sentry/cli --unsafe-perm
|
||||
./scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
mkdir artifact-pkg
|
||||
|
11
.github/workflows/windows.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15
|
||||
node-version: 14
|
||||
|
||||
- name: Build
|
||||
shell: powershell
|
||||
@@ -34,6 +34,15 @@ jobs:
|
||||
run: node scripts/build-windows.js
|
||||
if: github.repository != 'Eugeny/terminus' || github.event_name != 'push'
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
npm install @sentry/cli
|
||||
node scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
mkdir artifact-setup
|
||||
|
1
.gitignore
vendored
@@ -33,3 +33,4 @@ sentry.properties
|
||||
sentry-symbols.js
|
||||
|
||||
terminus-ssh/util/pagent.exe
|
||||
*.psd
|
||||
|
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
|
||||
|
172
README.md
@@ -1,44 +1,92 @@
|
||||

|
||||

|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/eugeny/terminus.svg?label=License&style=flat-square"></a> <a href="https://ci.appveyor.com/project/Eugeny/terminus"><img alt="AppVeyor" src="https://img.shields.io/appveyor/ci/eugeny/terminus.svg?label=CI&logo=appveyor&logoColor=white&style=flat-square"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/terminus/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/terminus/total.svg?label=DOWNLOAD&logo=github&style=for-the-badge"></a> <a href="https://ci.appveyor.com/project/Eugeny/terminus/build/artifacts"><img src="https://img.shields.io/badge/download-nightly%20build-magenta.svg?logo=appveyor&style=for-the-badge"/></a> <a href="https://gitter.im/terminus-terminal/community"><img alt="Gitter" src="https://img.shields.io/gitter/room/terminus/community.svg?color=blue&logo=gitter&style=for-the-badge"></a>
|
||||
<a href="https://github.com/Eugeny/terminus/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/terminus/total.svg?label=RELEASE&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/terminus/workflows/windows/master"><img src="https://shields.io/badge/-Nightly-blue?logo=windows&style=for-the-badge"/></a> <a href="https://nightly.link/Eugeny/terminus/workflows/macos/master"><img src="https://shields.io/badge/-Nightly-black?logo=apple&style=for-the-badge"/></a> <a href="https://nightly.link/Eugeny/terminus/workflows/linux/master"><img src="https://shields.io/badge/-Nightly-orange?logo=linux&style=for-the-badge"/></a> <a href="https://gitter.im/terminus-terminal/community"><img alt="Gitter" src="https://img.shields.io/gitter/room/terminus/community.svg?color=magenta&logo=gitter&style=for-the-badge"></a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
**Terminus** is a highly configurable terminal emulator for Windows, macOS and Linux
|
||||
**Terminus** is a highly configurable terminal emulator, SSH and serial client for Windows, macOS and Linux
|
||||
|
||||
* Integrated SSH client and connection manager
|
||||
* Theming and color schemes
|
||||
* Fully configurable shortcuts
|
||||
* Split panes
|
||||
* Remembers your tabs
|
||||
* PowerShell (and PS Core), WSL, Git-Bash, Cygwin, Cmder and CMD support
|
||||
* Direct file transfer from/to SSH sessions via Zmodem
|
||||
* Full Unicode support including double-width characters
|
||||
* Doesn't choke on fast-flowing outputs
|
||||
* Proper shell experience on Windows including tab completion (via Clink)
|
||||
* Integrated SSH client and connection manager
|
||||
* Integrated serial terminal
|
||||
* Theming and color schemes
|
||||
* Fully configurable shortcuts and multi-chord shortcuts
|
||||
* Split panes
|
||||
* Remembers your tabs
|
||||
* PowerShell (and PS Core), WSL, Git-Bash, Cygwin, Cmder and CMD support
|
||||
* Direct file transfer from/to SSH sessions via Zmodem
|
||||
* Full Unicode support including double-width characters
|
||||
* Doesn't choke on fast-flowing outputs
|
||||
* Proper shell experience on Windows including tab completion (via Clink)
|
||||
|
||||
|
||||
[](https://ko-fi.com/eugeny)
|
||||
|
||||
---
|
||||
|
||||
# Contents
|
||||
|
||||
- [Contents](#contents)
|
||||
- [What Terminus is and isn't](#what-terminus-is-and-isnt)
|
||||
- [Terminal features](#terminal-features)
|
||||
- [SSH Client](#ssh-client)
|
||||
- [Serial Terminal](#serial-terminal)
|
||||
- [Portable](#portable)
|
||||
- [Plugins](#plugins)
|
||||
- [Themes](#themes)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
<a name="about"></a>
|
||||
# What Terminus is and isn't
|
||||
|
||||
* **Terminus is** an alternative to Windows' standard terminal (conhost), PowerShell ISE, PuTTY or iTerm
|
||||
|
||||
* **Terminus is not** a new shell or a MinGW or Cygwin replacement. Neither is it lightweight - if RAM usage is of importance, consider [Conemu](https://conemu.github.io) or [Alacritty](https://github.com/jwilm/alacritty)
|
||||
|
||||
---
|
||||
<a name="terminal"></a>
|
||||
# Terminal features
|
||||
|
||||

|
||||
|
||||
* A V220 terminal + various extensions
|
||||
* Multiple nested split panes
|
||||
* Tabs on any side of the window
|
||||
* Optional dockable window with a global spawn hotkey ("Quake console")
|
||||
* Progress detection
|
||||
* Notification on process completion
|
||||
* Bracketed paste, multiline paste warnings
|
||||
* Font ligatures
|
||||
* Custom shell profiles
|
||||
* Optional RMB paste and copy-on select (PuTTY style)
|
||||
|
||||
<a name="ssh"></a>
|
||||
# SSH Client
|
||||
|
||||

|
||||
|
||||
* SSH2 client with a connection manager
|
||||
* X11 and port forwarding
|
||||
* Automatic jump host management
|
||||
* Agent forwarding (incl. Pageant and Windows native OpenSSH Agent)
|
||||
* Login scripts
|
||||
|
||||
<a name="serial"></a>
|
||||
# Serial Terminal
|
||||
|
||||
* Saved connections
|
||||
* Readline input support
|
||||
* Optional hex byte-by-byte input and hexdump output
|
||||
* Newline conversion
|
||||
* Automatic reconnection
|
||||
|
||||
<a name="portable"></a>
|
||||
# Portable
|
||||
|
||||
For portable in windows, user can create folder `data` at the same directory as `Terminal.exe` to save the settings.
|
||||
Terminus will run as a portable app on Windows, if you create a `data` folder in the same location where `Terminus.exe` lives.
|
||||
|
||||
<a name="plugins"></a>
|
||||
# Plugins
|
||||
|
||||
Plugins and themes can be installed directly from the Settings view inside Terminus.
|
||||
@@ -48,7 +96,9 @@ Plugins and themes can be installed directly from the Settings view inside Termi
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - quickly send commands to one or all terminal tabs
|
||||
* [save-output](https://github.com/Eugeny/terminus-save-output) - record terminal output into a file
|
||||
* [scrollbar](https://github.com/kbjr/terminus-scrollbar) - adds a scrollbar to hterm tabs
|
||||
* [sync-config](https://github.com/starxg/terminus-sync-config) - sync the config to Gist or Gitee
|
||||
|
||||
<a name="themes"></a>
|
||||
# Themes
|
||||
|
||||
* [hype](https://github.com/Eugeny/terminus-theme-hype) - a Hyper inspired theme
|
||||
@@ -57,8 +107,7 @@ Plugins and themes can be installed directly from the Settings view inside Termi
|
||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10)
|
||||
* [altair](https://github.com/yxuko/terminus-altair)
|
||||
|
||||
---
|
||||
|
||||
<a name="contributing"></a>
|
||||
# Contributing
|
||||
|
||||
Pull requests and plugins are welcome!
|
||||
@@ -66,6 +115,7 @@ Pull requests and plugins are welcome!
|
||||
See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) and [API docs](http://ajenti.org/terminus-docs/) for information of how the project is laid out, and a very brief plugin development tutorial.
|
||||
|
||||
---
|
||||
<a name="contributors"></a>
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
@@ -74,57 +124,63 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4" width="100px;" alt=""/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4" width="100px;" alt=""/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=zend" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4" width="100px;" alt=""/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=matishadow" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4" width="100px;" alt=""/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=pinpins" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=zend" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=matishadow" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=pinpins" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4" 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/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>
|
||||
<td align="center"><a href="https://github.com/starxg"><img src="https://avatars.githubusercontent.com/u/34997494?v=4?s=100" width="100px;" alt=""/><br /><sub><b>starxg</b></sub></a><br /><a href="#plugin-starxg" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
@@ -1,55 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{opacity:0.16;fill:url(#SVGID_2_);}
|
||||
.st2{fill:url(#SVGID_3_);}
|
||||
.st3{opacity:0.16;fill:url(#SVGID_4_);}
|
||||
.st4{fill:url(#SVGID_5_);}
|
||||
.st5{opacity:0.15;fill:url(#SVGID_6_);}
|
||||
.st6{fill:url(#SVGID_7_);}
|
||||
</style>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="260.9675" y1="871.1813" x2="919.1845" y2="491.1596">
|
||||
<stop offset="0" style="stop-color:#669ABD"/>
|
||||
<stop offset="1" style="stop-color:#77DBDB"/>
|
||||
</linearGradient>
|
||||
<polygon class="st0" points="297.54,934.52 882.6,596.72 882.61,427.82 297.54,765.65 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="553.5051" y1="617.8278" x2="626.647" y2="744.5132">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st1" points="297.54,934.52 882.6,596.72 882.61,427.82 297.54,765.65 "/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="114.6631" y1="744.5275" x2="334.0905" y2="871.2141">
|
||||
<stop offset="0" style="stop-color:#6A8FAD"/>
|
||||
<stop offset="1" style="stop-color:#669ABD"/>
|
||||
</linearGradient>
|
||||
<polygon class="st2" points="151.23,681.18 151.22,850.09 297.54,934.52 297.54,765.65 "/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="260.9478" y1="744.5281" x2="187.8059" y2="871.2135">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st3" points="151.23,681.18 151.22,850.09 297.54,934.52 297.54,765.65 "/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="114.663" y1="237.793" x2="553.5026" y2="491.1571">
|
||||
<stop offset="0" style="stop-color:#6A8FAD"/>
|
||||
<stop offset="1" style="stop-color:#669ABD"/>
|
||||
</linearGradient>
|
||||
<polygon class="st4" points="151.23,174.45 151.21,343.36 443.79,512.27 590.08,427.81 "/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="370.6562" y1="301.1281" x2="297.5094" y2="427.8221">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st5" points="151.23,174.45 151.21,343.36 443.79,512.27 590.08,427.81 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="78.0912" y1="554.4979" x2="736.3375" y2="174.4593">
|
||||
<stop offset="0" style="stop-color:#CCECFF"/>
|
||||
<stop offset="1" style="stop-color:#9FECED"/>
|
||||
</linearGradient>
|
||||
<polygon class="st6" points="297.51,765.64 151.23,681.18 590.08,427.81 151.23,174.45 297.5,90 882.61,427.82 "/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 1024 1024" xml:space="preserve" style="enable-background:new 0 0 1024 1024"><style type="text/css">.st0{fill:url(#SVGID_1_)}.st1{opacity:.16;fill:url(#SVGID_2_)}.st2{fill:url(#SVGID_3_)}.st3{opacity:.16;fill:url(#SVGID_4_)}.st4{fill:url(#SVGID_5_)}.st5{opacity:.15;fill:url(#SVGID_6_)}.st6{fill:url(#SVGID_7_)}</style><g><linearGradient id="SVGID_1_" x1="260.967" x2="919.184" y1="871.181" y2="491.16" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#669abd"/><stop offset="1" style="stop-color:#77dbdb"/></linearGradient><polygon points="297.54 934.52 882.6 596.72 882.61 427.82 297.54 765.65" class="st0"/><linearGradient id="SVGID_2_" x1="553.505" x2="626.647" y1="617.828" y2="744.513" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="297.54 934.52 882.6 596.72 882.61 427.82 297.54 765.65" class="st1"/></g><g><linearGradient id="SVGID_3_" x1="114.663" x2="334.091" y1="744.528" y2="871.214" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="151.23 681.18 151.22 850.09 297.54 934.52 297.54 765.65" class="st2"/><linearGradient id="SVGID_4_" x1="260.948" x2="187.806" y1="744.528" y2="871.213" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="151.23 681.18 151.22 850.09 297.54 934.52 297.54 765.65" class="st3"/></g><g><linearGradient id="SVGID_5_" x1="114.663" x2="553.503" y1="237.793" y2="491.157" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="151.23 174.45 151.21 343.36 443.79 512.27 590.08 427.81" class="st4"/><linearGradient id="SVGID_6_" x1="370.656" x2="297.509" y1="301.128" y2="427.822" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="151.23 174.45 151.21 343.36 443.79 512.27 590.08 427.81" class="st5"/></g><linearGradient id="SVGID_7_" x1="78.091" x2="736.337" y1="554.498" y2="174.459" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#ccecff"/><stop offset="1" style="stop-color:#9feced"/></linearGradient><polygon points="297.51 765.64 151.23 681.18 590.08 427.81 151.23 174.45 297.5 90 882.61 427.82" class="st6"/></svg>
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -1,12 +1,21 @@
|
||||
import { app, ipcMain, Menu, Tray, shell, screen, globalShortcut, MenuItemConstructorOptions } from 'electron'
|
||||
import * as promiseIpc from 'electron-promise-ipc'
|
||||
import * as remote from '@electron/remote/main'
|
||||
|
||||
import { loadConfig } from './config'
|
||||
import { Window, WindowOptions } from './window'
|
||||
import { pluginManager } from './pluginManager'
|
||||
import { PTYManager } from './pty'
|
||||
|
||||
export class Application {
|
||||
private tray: Tray
|
||||
private tray?: Tray
|
||||
private ptyManager = new PTYManager()
|
||||
private windows: Window[] = []
|
||||
|
||||
constructor () {
|
||||
remote.initialize()
|
||||
this.ptyManager.init(this)
|
||||
|
||||
ipcMain.on('app:config-change', (_event, config) => {
|
||||
this.broadcast('host:config-change', config)
|
||||
})
|
||||
@@ -20,6 +29,14 @@ export class Application {
|
||||
}
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:install', (path, name, version) => {
|
||||
return pluginManager.install(path, name, version)
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:uninstall', (path, name) => {
|
||||
return pluginManager.uninstall(path, name)
|
||||
})
|
||||
|
||||
const configData = loadConfig()
|
||||
if (process.platform === 'linux') {
|
||||
app.commandLine.appendSwitch('no-sandbox')
|
||||
@@ -30,6 +47,7 @@ export class Application {
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch('disable-http-cache')
|
||||
app.commandLine.appendSwitch('max-active-webgl-contexts', '9000')
|
||||
app.commandLine.appendSwitch('lang', 'EN')
|
||||
app.allowRendererProcessReuse = false
|
||||
|
||||
@@ -65,7 +83,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()
|
||||
}
|
||||
@@ -96,7 +114,7 @@ export class Application {
|
||||
}
|
||||
|
||||
enableTray (): void {
|
||||
if (this.tray) {
|
||||
if (this.tray || process.platform === 'linux') {
|
||||
return
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
@@ -121,10 +139,11 @@ export class Application {
|
||||
}
|
||||
|
||||
disableTray (): void {
|
||||
if (this.tray) {
|
||||
this.tray.destroy()
|
||||
this.tray = null
|
||||
if (process.platform === 'linux') {
|
||||
return
|
||||
}
|
||||
this.tray?.destroy()
|
||||
this.tray = null
|
||||
}
|
||||
|
||||
hasWindows (): boolean {
|
||||
@@ -139,7 +158,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 () {
|
||||
|
57
app/lib/bufferizedPTY.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/** @hidden */
|
||||
module.exports = function patchPTYModule (mod) {
|
||||
const oldSpawn = mod.spawn
|
||||
if (mod.patched) {
|
||||
return
|
||||
}
|
||||
mod.patched = true
|
||||
mod.spawn = (file, args, opt) => {
|
||||
let terminal = oldSpawn(file, args, opt)
|
||||
let timeout = null
|
||||
let buffer = Buffer.from('')
|
||||
let lastFlush = 0
|
||||
let nextTimeout = 0
|
||||
|
||||
// Minimum prebuffering window (ms) if the input is non-stop flowing
|
||||
const minWindow = 5
|
||||
|
||||
// Maximum buffering time (ms) until output must be flushed unconditionally
|
||||
const maxWindow = 100
|
||||
|
||||
function flush () {
|
||||
if (buffer.length) {
|
||||
terminal.emit('data-buffered', buffer)
|
||||
}
|
||||
lastFlush = Date.now()
|
||||
buffer = Buffer.from('')
|
||||
}
|
||||
|
||||
function reschedule () {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
nextTimeout = Date.now() + minWindow
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
flush()
|
||||
}, minWindow)
|
||||
}
|
||||
|
||||
terminal.on('data', data => {
|
||||
if (typeof data === 'string') {
|
||||
data = Buffer.from(data)
|
||||
}
|
||||
buffer = Buffer.concat([buffer, data])
|
||||
if (Date.now() - lastFlush > maxWindow) {
|
||||
// Taking too much time buffering, flush to keep things interactive
|
||||
flush()
|
||||
} else {
|
||||
if (Date.now() > nextTimeout - maxWindow / 10) {
|
||||
// Extend the window if it's expiring
|
||||
reschedule()
|
||||
}
|
||||
}
|
||||
})
|
||||
return terminal
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@ export function parseArgs (argv: string[], cwd: string): any {
|
||||
argv = argv.slice(1)
|
||||
}
|
||||
|
||||
return require('yargs')
|
||||
return require('yargs/yargs')(argv.slice(1))
|
||||
.usage('terminus [command] [arguments]')
|
||||
.command('open [directory]', 'open a shell in a directory', {
|
||||
directory: { type: 'string', 'default': cwd },
|
||||
@@ -41,5 +41,5 @@ export function parseArgs (argv: string[], cwd: string): any {
|
||||
type: 'boolean',
|
||||
})
|
||||
.help('help')
|
||||
.parse(argv.slice(1))
|
||||
.parse()
|
||||
}
|
||||
|
@@ -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 {}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import './portable'
|
||||
import 'source-map-support/register'
|
||||
import './sentry'
|
||||
import './lru'
|
||||
import { app, ipcMain, Menu } from 'electron'
|
||||
@@ -52,7 +53,7 @@ if (argv.d) {
|
||||
})
|
||||
}
|
||||
|
||||
app.on('ready', () => {
|
||||
app.on('ready', async () => {
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.setMenu(Menu.buildFromTemplate([
|
||||
{
|
||||
@@ -64,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)
|
||||
})
|
||||
|
40
app/lib/pluginManager.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { promisify } from 'util'
|
||||
|
||||
|
||||
export class PluginManager {
|
||||
npm: any
|
||||
npmReady?: Promise<void>
|
||||
|
||||
async ensureLoaded (): Promise<void> {
|
||||
if (!this.npmReady) {
|
||||
this.npmReady = new Promise(resolve => {
|
||||
const npm = require('npm')
|
||||
npm.load(err => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return
|
||||
}
|
||||
npm.config.set('global', false)
|
||||
this.npm = npm
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
return this.npmReady
|
||||
}
|
||||
|
||||
async install (path: string, name: string, version: string): Promise<void> {
|
||||
await this.ensureLoaded()
|
||||
this.npm.prefix = path
|
||||
return promisify(this.npm.commands.install)([`${name}@${version}`])
|
||||
}
|
||||
|
||||
async uninstall (path: string, name: string): Promise<void> {
|
||||
await this.ensureLoaded()
|
||||
this.npm.prefix = path
|
||||
return promisify(this.npm.commands.remove)([name])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const pluginManager = new PluginManager()
|
@@ -1,24 +1,14 @@
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as electron from 'electron'
|
||||
|
||||
let appPath: string | null = null
|
||||
try {
|
||||
appPath = path.dirname(require('electron').app.getPath('exe'))
|
||||
} catch {
|
||||
appPath = path.dirname(require('electron').remote.app.getPath('exe'))
|
||||
}
|
||||
const appPath = path.dirname(electron.app.getPath('exe'))
|
||||
|
||||
if (null != appPath) {
|
||||
if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
|
||||
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
|
||||
}
|
||||
const portableData = path.join(appPath, 'data')
|
||||
if (fs.existsSync(portableData)) {
|
||||
console.log('reset user data to ' + portableData)
|
||||
try {
|
||||
require('electron').app.setPath('userData', portableData)
|
||||
} catch {
|
||||
require('electron').remote.app.setPath('userData', portableData)
|
||||
}
|
||||
}
|
||||
if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
|
||||
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
|
||||
}
|
||||
const portableData = path.join(appPath, 'data')
|
||||
if (fs.existsSync(portableData)) {
|
||||
console.log('reset user data to ' + portableData)
|
||||
electron.app.setPath('userData', portableData)
|
||||
}
|
||||
|
154
app/lib/pty.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import * as nodePTY from '@terminus-term/node-pty'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ipcMain } from 'electron'
|
||||
import { Application } from './app'
|
||||
|
||||
class PTYDataQueue {
|
||||
private buffers: Buffer[] = []
|
||||
private delta = 0
|
||||
private maxChunk = 1024
|
||||
private maxDelta = 1024 * 50
|
||||
private flowPaused = false
|
||||
|
||||
constructor (private pty: nodePTY.IPty, private onData: (data: Buffer) => void) { }
|
||||
|
||||
push (data: Buffer) {
|
||||
this.buffers.push(data)
|
||||
this.maybeEmit()
|
||||
}
|
||||
|
||||
ack (length: number) {
|
||||
this.delta -= length
|
||||
this.maybeEmit()
|
||||
}
|
||||
|
||||
private maybeEmit () {
|
||||
if (this.delta <= this.maxDelta && this.flowPaused) {
|
||||
this.resume()
|
||||
return
|
||||
}
|
||||
if (this.buffers.length > 0) {
|
||||
if (this.delta > this.maxDelta && !this.flowPaused) {
|
||||
this.pause()
|
||||
return
|
||||
}
|
||||
|
||||
const buffersToSend = []
|
||||
let totalLength = 0
|
||||
while (totalLength < this.maxChunk && this.buffers.length) {
|
||||
totalLength += this.buffers[0].length
|
||||
buffersToSend.push(this.buffers.shift())
|
||||
}
|
||||
|
||||
if (buffersToSend.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let toSend = Buffer.concat(buffersToSend)
|
||||
if (toSend.length > this.maxChunk) {
|
||||
this.buffers.unshift(toSend.slice(this.maxChunk))
|
||||
toSend = toSend.slice(0, this.maxChunk)
|
||||
}
|
||||
this.onData(toSend)
|
||||
this.delta += toSend.length
|
||||
|
||||
if (this.buffers.length) {
|
||||
setImmediate(() => this.maybeEmit())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private pause () {
|
||||
this.pty.pause()
|
||||
this.flowPaused = true
|
||||
}
|
||||
|
||||
private resume () {
|
||||
this.pty.resume()
|
||||
this.flowPaused = false
|
||||
this.maybeEmit()
|
||||
}
|
||||
}
|
||||
|
||||
export class PTY {
|
||||
private pty: nodePTY.IPty
|
||||
private outputQueue: PTYDataQueue
|
||||
|
||||
constructor (private id: string, private app: Application, ...args: any[]) {
|
||||
this.pty = (nodePTY as any).spawn(...args)
|
||||
for (const key of ['close', 'exit']) {
|
||||
(this.pty as any).on(key, (...eventArgs) => this.emit(key, ...eventArgs))
|
||||
}
|
||||
|
||||
this.outputQueue = new PTYDataQueue(this.pty, data => {
|
||||
setImmediate(() => this.emit('data-buffered', data))
|
||||
})
|
||||
|
||||
this.pty.on('data', data => this.outputQueue.push(Buffer.from(data)))
|
||||
}
|
||||
|
||||
getPID (): number {
|
||||
return this.pty.pid
|
||||
}
|
||||
|
||||
resize (columns: number, rows: number): void {
|
||||
if ((this.pty as any)._writable) {
|
||||
this.pty.resize(columns, rows)
|
||||
}
|
||||
}
|
||||
|
||||
write (buffer: Buffer): void {
|
||||
if ((this.pty as any)._writable) {
|
||||
this.pty.write(buffer.toString())
|
||||
}
|
||||
}
|
||||
|
||||
ackData (length: number): void {
|
||||
this.outputQueue.ack(length)
|
||||
}
|
||||
|
||||
kill (signal?: string): void {
|
||||
this.pty.kill(signal)
|
||||
}
|
||||
|
||||
private emit (event: string, ...args: any[]) {
|
||||
this.app.broadcast(`pty:${this.id}:${event}`, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
export class PTYManager {
|
||||
private ptys: Record<string, PTY|undefined> = {}
|
||||
|
||||
init (app: Application): void {
|
||||
//require('./bufferizedPTY')(nodePTY) // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
ipcMain.on('pty:spawn', (event, ...options) => {
|
||||
const id = uuidv4().toString()
|
||||
event.returnValue = id
|
||||
this.ptys[id] = new PTY(id, app, ...options)
|
||||
})
|
||||
|
||||
ipcMain.on('pty:exists', (event, id) => {
|
||||
event.returnValue = !!this.ptys[id]
|
||||
})
|
||||
|
||||
ipcMain.on('pty:get-pid', (event, id) => {
|
||||
event.returnValue = this.ptys[id]?.getPID()
|
||||
})
|
||||
|
||||
ipcMain.on('pty:resize', (_event, id, columns, rows) => {
|
||||
this.ptys[id]?.resize(columns, rows)
|
||||
})
|
||||
|
||||
ipcMain.on('pty:write', (_event, id, data) => {
|
||||
this.ptys[id]?.write(Buffer.from(data))
|
||||
})
|
||||
|
||||
ipcMain.on('pty:kill', (_event, id, signal) => {
|
||||
this.ptys[id]?.kill(signal)
|
||||
})
|
||||
|
||||
ipcMain.on('pty:ack-data', (_event, id, length) => {
|
||||
this.ptys[id]?.ackData(length)
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,16 +1,14 @@
|
||||
const { init } = String(process.type) === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
|
||||
import * as isDev from 'electron-is-dev'
|
||||
|
||||
|
||||
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
|
||||
let release = null
|
||||
try {
|
||||
release = require('electron').app.getVersion()
|
||||
} catch {
|
||||
release = require('electron').remote.app.getVersion()
|
||||
release = require('@electron/remote').app.getVersion()
|
||||
}
|
||||
|
||||
if (!isDev) {
|
||||
if (!process.env.TERMINUS_DEV) {
|
||||
init({
|
||||
dsn: SENTRY_DSN,
|
||||
release,
|
||||
|
@@ -1,7 +1,4 @@
|
||||
import * as glasstron from 'glasstron'
|
||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||
glasstron.init()
|
||||
}
|
||||
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { debounceTime } from 'rxjs/operators'
|
||||
@@ -9,6 +6,8 @@ import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowCons
|
||||
import ElectronConfig = require('electron-config')
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
import macOSRelease from 'macos-release'
|
||||
import * as compareVersions from 'compare-versions'
|
||||
|
||||
import { parseArgs } from './cli'
|
||||
import { loadConfig } from './config'
|
||||
@@ -27,15 +26,17 @@ abstract class GlasstronWindow extends BrowserWindow {
|
||||
abstract setBlur (_: boolean)
|
||||
}
|
||||
|
||||
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions.compare(macOSRelease().version, '10.14', '>=') ? 'fullscreen-ui' : 'dark' : null
|
||||
|
||||
export class Window {
|
||||
ready: Promise<void>
|
||||
private visible = new Subject<boolean>()
|
||||
private closed = new Subject<void>()
|
||||
private window: GlasstronWindow
|
||||
private window?: GlasstronWindow
|
||||
private windowConfig: ElectronConfig
|
||||
private windowBounds: Rectangle
|
||||
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
|
||||
|
||||
@@ -45,7 +46,7 @@ export class Window {
|
||||
constructor (options?: WindowOptions) {
|
||||
this.configStore = loadConfig()
|
||||
|
||||
options = options || {}
|
||||
options = options ?? {}
|
||||
|
||||
this.windowConfig = new ElectronConfig({ name: 'window' })
|
||||
this.windowBounds = this.windowConfig.get('windowBoundaries')
|
||||
@@ -62,7 +63,9 @@ export class Window {
|
||||
preload: path.join(__dirname, 'sentry.js'),
|
||||
backgroundThrottling: false,
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
maximizable: true,
|
||||
frame: false,
|
||||
show: false,
|
||||
backgroundColor: '#00000000',
|
||||
@@ -85,15 +88,19 @@ export class Window {
|
||||
bwOptions.frame = true
|
||||
} else {
|
||||
if (process.platform === 'darwin') {
|
||||
bwOptions.titleBarStyle = 'hiddenInset'
|
||||
bwOptions.titleBarStyle = 'hidden'
|
||||
}
|
||||
}
|
||||
|
||||
this.window = new glasstron.BrowserWindow(bwOptions)
|
||||
if (process.platform === 'darwin') {
|
||||
this.window = new BrowserWindow(bwOptions) as GlasstronWindow
|
||||
} else {
|
||||
this.window = new glasstron.BrowserWindow(bwOptions)
|
||||
}
|
||||
|
||||
this.window.once('ready-to-show', () => {
|
||||
if (process.platform === 'darwin') {
|
||||
this.window.setVibrancy('window')
|
||||
this.window.setVibrancy(macOSVibrancyType)
|
||||
} else if (process.platform === 'win32' && (this.configStore.appearance || {}).vibrancy) {
|
||||
this.setVibrancy(true)
|
||||
}
|
||||
@@ -141,7 +148,11 @@ export class Window {
|
||||
if (process.platform === 'win32') {
|
||||
if (parseFloat(os.release()) >= 10) {
|
||||
this.window.blurType = enabled ? type === 'fluent' ? 'acrylic' : 'blurbehind' : null
|
||||
this.window.setBlur(enabled)
|
||||
try {
|
||||
this.window.setBlur(enabled)
|
||||
} catch (error) {
|
||||
console.error('Failed to set window blur', error)
|
||||
}
|
||||
} else {
|
||||
DwmEnableBlurBehindWindow(this.window, enabled)
|
||||
}
|
||||
@@ -149,7 +160,7 @@ export class Window {
|
||||
this.window.setBackgroundColor(enabled ? '#00000000' : '#131d27')
|
||||
this.window.setBlur(enabled)
|
||||
} else {
|
||||
this.window.setVibrancy(enabled ? 'dark' : null as any) // electron issue 20269
|
||||
this.window.setVibrancy(enabled ? macOSVibrancyType : null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +191,10 @@ export class Window {
|
||||
return this.window.isFocused()
|
||||
}
|
||||
|
||||
isVisible (): boolean {
|
||||
return this.window.isVisible()
|
||||
}
|
||||
|
||||
hide (): void {
|
||||
if (process.platform === 'darwin') {
|
||||
// Lose focus
|
||||
@@ -215,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,45 @@
|
||||
"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",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
|
||||
"@terminus-term/node-pty": "0.10.0-beta10",
|
||||
"@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",
|
||||
"@electron/remote": "^1.0.4",
|
||||
"@ng-bootstrap/ng-bootstrap": "^7.0.0",
|
||||
"any-promise": "^1.3.0",
|
||||
"electron-config": "2.0.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-is-dev": "1.1.0",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"fontmanager-redux": "1.0.0",
|
||||
"glasstron": "0.0.5",
|
||||
"js-yaml": "3.14.0",
|
||||
"keytar": "^7.2.0",
|
||||
"glasstron": "0.0.7",
|
||||
"js-yaml": "4.0.0",
|
||||
"keytar": "^7.6.0",
|
||||
"mz": "^2.7.0",
|
||||
"ngx-toastr": "^12.0.1",
|
||||
"npm": "7.0.15",
|
||||
"native-process-working-directory": "^1.0.2",
|
||||
"ngx-toastr": "^13.2.1",
|
||||
"@terminus-term/node-pty": "0.10.0-terminus.3",
|
||||
"npm": "6",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "^6.5.5",
|
||||
"rxjs-compat": "^6.6.0",
|
||||
"yargs": "^15.4.1",
|
||||
"zone.js": "^0.11.3"
|
||||
"rxjs": "^6.6.6",
|
||||
"yargs": "^16.2.0",
|
||||
"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/mz": "2.7.3",
|
||||
"@types/node": "14.14.35",
|
||||
"node-abi": "^2.21.0",
|
||||
"source-map-support": "^0.5.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"terminus-community-color-schemes": "*",
|
||||
@@ -58,5 +62,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 = [
|
||||
|
@@ -2,8 +2,6 @@ import 'zone.js'
|
||||
import 'core-js/proposals/reflect-metadata'
|
||||
import 'rxjs'
|
||||
|
||||
import * as isDev from 'electron-is-dev'
|
||||
|
||||
import './global.scss'
|
||||
import './toastr.scss'
|
||||
|
||||
@@ -23,7 +21,7 @@ if (process.platform === 'win32' && !('HOME' in process.env)) {
|
||||
process.env.HOME = `${process.env.HOMEDRIVE}${process.env.HOMEPATH}`
|
||||
}
|
||||
|
||||
if (isDev) {
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
console.warn('Running in debug mode')
|
||||
} else {
|
||||
enableProdMode()
|
||||
@@ -39,7 +37,7 @@ async function bootstrap (plugins: PluginInfo[], safeMode = false): Promise<NgMo
|
||||
const module = getRootModule(pluginsModules)
|
||||
window['rootModule'] = module
|
||||
return platformBrowserDynamic().bootstrapModule(module).then(moduleRef => {
|
||||
if (isDev) {
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
const applicationRef = moduleRef.injector.get(ApplicationRef)
|
||||
const componentRef = applicationRef.components[0]
|
||||
enableDebugTools(componentRef)
|
||||
@@ -58,8 +56,8 @@ findPlugins().then(async plugins => {
|
||||
window['safeModeReason'] = error
|
||||
try {
|
||||
await bootstrap(plugins, true)
|
||||
} catch (error) {
|
||||
console.error('Bootstrap failed:', error)
|
||||
} catch (error2) {
|
||||
console.error('Bootstrap failed:', error2)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -17,6 +17,10 @@ body {
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
& > svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -95,3 +99,23 @@ input[type=range] {
|
||||
&::-moz-range-track { @include track(); }
|
||||
&::-ms-track { @include track(); }
|
||||
}
|
||||
|
||||
a[ngbdropdownitem] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ngb-typeahead-window {
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.hover-reveal {
|
||||
opacity: 0;
|
||||
|
||||
.hover-reveal-parent:hover &,
|
||||
*:hover > &,
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
@@ -1,27 +1,28 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import * as remote from '@electron/remote'
|
||||
const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
const nodeRequire = (global as any).require
|
||||
|
||||
function normalizePath (path: string): string {
|
||||
function normalizePath (p: string): string {
|
||||
const cygwinPrefix = '/cygdrive/'
|
||||
if (path.startsWith(cygwinPrefix)) {
|
||||
path = path.substring(cygwinPrefix.length).replace('/', '\\')
|
||||
path = path[0] + ':' + path.substring(1)
|
||||
if (p.startsWith(cygwinPrefix)) {
|
||||
p = p.substring(cygwinPrefix.length).replace('/', '\\')
|
||||
p = p[0] + ':' + p.substring(1)
|
||||
}
|
||||
return path
|
||||
return p
|
||||
}
|
||||
|
||||
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
|
||||
nodeModule.globalPaths.unshift(path.dirname(remote.app.getAppPath()))
|
||||
}
|
||||
|
||||
const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(require('electron').remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
|
||||
const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
|
||||
|
||||
const userPluginsPath = path.join(
|
||||
require('electron').remote.app.getPath('userData'),
|
||||
remote.app.getPath('userData'),
|
||||
'plugins',
|
||||
)
|
||||
|
||||
@@ -63,7 +64,6 @@ const builtinModules = [
|
||||
'ngx-toastr',
|
||||
'rxjs',
|
||||
'rxjs/operators',
|
||||
'rxjs-compat/Subject',
|
||||
'terminus-core',
|
||||
'terminus-settings',
|
||||
'terminus-terminal',
|
||||
|
@@ -7,6 +7,7 @@
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
animation: 0.5s ease-out fadeIn;
|
||||
background: radial-gradient(#3a66820a 0%, #000e17 30%, black 100%);
|
||||
|
||||
&>div {
|
||||
width: 200px;
|
||||
@@ -23,6 +24,7 @@
|
||||
transition: 1s ease-out width;
|
||||
background: #a1c5e4;
|
||||
height: 3px;
|
||||
box-shadow: 0 0 2px #ffffff1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,8 +39,8 @@
|
||||
|
||||
|
||||
.terminus-logo {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
background: url('../assets/logo.svg');
|
||||
background-repeat: none;
|
||||
background-size: contain;
|
||||
@@ -51,7 +53,7 @@
|
||||
font-family: 'Source Sans Pro';
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
font-size: 42px;
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
|
||||
sup {
|
||||
|
@@ -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;
|
||||
|
@@ -68,7 +68,6 @@ module.exports = {
|
||||
'@ng-bootstrap/ng-bootstrap': 'commonjs @ng-bootstrap/ng-bootstrap',
|
||||
child_process: 'commonjs child_process',
|
||||
electron: 'commonjs electron',
|
||||
'electron-is-dev': 'commonjs electron-is-dev',
|
||||
fs: 'commonjs fs',
|
||||
'ngx-toastr': 'commonjs ngx-toastr',
|
||||
module: 'commonjs module',
|
||||
|
@@ -1,9 +1,10 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
|
||||
module.exports = {
|
||||
name: 'terminus-main',
|
||||
target: 'node',
|
||||
target: 'electron-main',
|
||||
entry: {
|
||||
main: path.resolve(__dirname, 'lib/index.ts'),
|
||||
},
|
||||
@@ -33,16 +34,25 @@ module.exports = {
|
||||
],
|
||||
},
|
||||
externals: {
|
||||
'any-promise': 'commonjs any-promise',
|
||||
electron: 'commonjs electron',
|
||||
'electron-config': 'commonjs electron-config',
|
||||
'electron-debug': 'commonjs electron-debug',
|
||||
'electron-promise-ipc': 'commonjs electron-promise-ipc',
|
||||
'electron-vibrancy': 'commonjs electron-vibrancy',
|
||||
fs: 'commonjs fs',
|
||||
glasstron: 'commonjs glasstron',
|
||||
mz: 'commonjs mz',
|
||||
npm: 'commonjs npm',
|
||||
'@terminus-term/node-pty': 'commonjs @terminus-term/node-pty',
|
||||
path: 'commonjs path',
|
||||
yargs: 'commonjs yargs',
|
||||
rxjs: 'commonjs rxjs',
|
||||
'rxjs/operators': 'commonjs rxjs/operators',
|
||||
util: 'commonjs util',
|
||||
'source-map-support': 'commonjs source-map-support',
|
||||
'windows-swca': 'commonjs windows-swca',
|
||||
'windows-blurbehind': 'commonjs windows-blurbehind',
|
||||
'yargs/yargs': 'commonjs yargs/yargs',
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
@@ -51,3 +61,7 @@ module.exports = {
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
if (process.env.BUNDLE_ANALYZER) {
|
||||
module.exports.plugins.push(new BundleAnalyzerPlugin())
|
||||
}
|
||||
|
3168
app/yarn.lock
BIN
build/icons/Icon-MacOS-512x512@2x.png
Normal file
After Width: | Height: | Size: 166 KiB |
@@ -1,57 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.8;fill:#00232E;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:0.16;fill:url(#SVGID_2_);}
|
||||
.st3{fill:url(#SVGID_3_);}
|
||||
.st4{opacity:0.16;fill:url(#SVGID_4_);}
|
||||
.st5{fill:url(#SVGID_5_);}
|
||||
.st6{opacity:0.15;fill:url(#SVGID_6_);}
|
||||
.st7{fill:url(#SVGID_7_);}
|
||||
</style>
|
||||
<polygon class="st0" points="449.5,645.47 407.51,621.23 533.47,548.5 407.51,475.77 449.5,451.53 617.45,548.5 "/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="439.0065" y1="603.0394" x2="627.9464" y2="493.9549">
|
||||
<stop offset="0" style="stop-color:#669ABD"/>
|
||||
<stop offset="1" style="stop-color:#77DBDB"/>
|
||||
</linearGradient>
|
||||
<polygon class="st1" points="449.5,621.22 617.45,524.25 617.45,475.77 449.5,572.75 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="522.9788" y1="530.3148" x2="543.9741" y2="566.6795">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st2" points="449.5,621.22 617.45,524.25 617.45,475.77 449.5,572.75 "/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="397.0101" y1="566.6837" x2="459.9963" y2="603.0487">
|
||||
<stop offset="0" style="stop-color:#6A8FAD"/>
|
||||
<stop offset="1" style="stop-color:#669ABD"/>
|
||||
</linearGradient>
|
||||
<polygon class="st3" points="407.51,548.5 407.5,596.99 449.5,621.22 449.5,572.75 "/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="439.0009" y1="566.6838" x2="418.0056" y2="603.0486">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st4" points="407.51,548.5 407.5,596.99 449.5,621.22 449.5,572.75 "/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="397.0101" y1="421.2265" x2="522.9781" y2="493.9542">
|
||||
<stop offset="0" style="stop-color:#6A8FAD"/>
|
||||
<stop offset="1" style="stop-color:#669ABD"/>
|
||||
</linearGradient>
|
||||
<polygon class="st5" points="407.51,403.04 407.5,451.53 491.49,500.01 533.48,475.77 "/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="470.4924" y1="439.4067" x2="449.4958" y2="475.774">
|
||||
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</linearGradient>
|
||||
<polygon class="st6" points="407.51,403.04 407.5,451.53 491.49,500.01 533.48,475.77 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="386.5123" y1="512.136" x2="575.4605" y2="403.0467">
|
||||
<stop offset="0" style="stop-color:#CCECFF"/>
|
||||
<stop offset="1" style="stop-color:#9FECED"/>
|
||||
</linearGradient>
|
||||
<polygon class="st7" points="449.5,572.74 407.51,548.5 533.48,475.77 407.51,403.04 449.49,378.8 617.45,475.77 "/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 1024 1024" xml:space="preserve" style="enable-background:new 0 0 1024 1024"><style type="text/css">.st0{opacity:.8;fill:#00232e}.st1{fill:url(#SVGID_1_)}.st2{opacity:.16;fill:url(#SVGID_2_)}.st3{fill:url(#SVGID_3_)}.st4{opacity:.16;fill:url(#SVGID_4_)}.st5{fill:url(#SVGID_5_)}.st6{opacity:.15;fill:url(#SVGID_6_)}.st7{fill:url(#SVGID_7_)}</style><polygon points="449.5 645.47 407.51 621.23 533.47 548.5 407.51 475.77 449.5 451.53 617.45 548.5" class="st0"/><g><linearGradient id="SVGID_1_" x1="439.007" x2="627.946" y1="603.039" y2="493.955" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#669abd"/><stop offset="1" style="stop-color:#77dbdb"/></linearGradient><polygon points="449.5 621.22 617.45 524.25 617.45 475.77 449.5 572.75" class="st1"/><linearGradient id="SVGID_2_" x1="522.979" x2="543.974" y1="530.315" y2="566.679" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="449.5 621.22 617.45 524.25 617.45 475.77 449.5 572.75" class="st2"/></g><g><linearGradient id="SVGID_3_" x1="397.01" x2="459.996" y1="566.684" y2="603.049" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="407.51 548.5 407.5 596.99 449.5 621.22 449.5 572.75" class="st3"/><linearGradient id="SVGID_4_" x1="439.001" x2="418.006" y1="566.684" y2="603.049" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="407.51 548.5 407.5 596.99 449.5 621.22 449.5 572.75" class="st4"/></g><g><linearGradient id="SVGID_5_" x1="397.01" x2="522.978" y1="421.226" y2="493.954" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="407.51 403.04 407.5 451.53 491.49 500.01 533.48 475.77" class="st5"/><linearGradient id="SVGID_6_" x1="470.492" x2="449.496" y1="439.407" y2="475.774" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="407.51 403.04 407.5 451.53 491.49 500.01 533.48 475.77" class="st6"/></g><linearGradient id="SVGID_7_" x1="386.512" x2="575.461" y1="512.136" y2="403.047" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#ccecff"/><stop offset="1" style="stop-color:#9feced"/></linearGradient><polygon points="449.5 572.74 407.51 548.5 533.48 475.77 407.51 403.04 449.49 378.8 617.45 475.77" class="st7"/></svg>
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
docs/readme-ssh.png
Normal file
After Width: | Height: | Size: 371 KiB |
BIN
docs/readme-terminal.png
Normal file
After Width: | Height: | Size: 728 KiB |
@@ -6,11 +6,33 @@ npmRebuild: false
|
||||
afterSign: "./build/mac/afterSignHook.js"
|
||||
afterAllArtifactBuild: "./build/mac/afterBuildHook.js"
|
||||
files:
|
||||
- "**/*"
|
||||
- '**/*'
|
||||
- dist
|
||||
- '!lib'
|
||||
- '!src'
|
||||
- '!**/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'
|
||||
- '!**/node_modules/node-gyp'
|
||||
- '!**/node_modules/**/*.d.ts'
|
||||
- '!**/node_modules/**/*.map'
|
||||
- '!**/node_modules/**/include/node'
|
||||
- '!**/node_modules/.bin'
|
||||
- '!**/node_modules/*/*/{esm5,fesm5,esm2015,fesm2015,_esm2015,_fesm2015}'
|
||||
- '!**/*.{woff,ttf,otf,eot}'
|
||||
- '!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}'
|
||||
- '!.editorconfig'
|
||||
- '!**/._*'
|
||||
- '!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}'
|
||||
- '!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}'
|
||||
- '!**/{appveyor.yml,.travis.yml,circle.yml}'
|
||||
- '!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json'
|
||||
extraResources:
|
||||
- builtin-plugins
|
||||
- extras
|
||||
asarUnpack:
|
||||
- dist/*.map
|
||||
publish:
|
||||
- provider: github
|
||||
|
||||
@@ -22,6 +44,7 @@ nsis:
|
||||
oneClick: false
|
||||
artifactName: terminus-${version}-setup.${ext}
|
||||
installerIcon: "./build/windows/icon.ico"
|
||||
allowToChangeInstallationDirectory: true
|
||||
|
||||
mac:
|
||||
category: public.app-category.video
|
||||
@@ -42,7 +65,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:
|
||||
@@ -67,3 +90,6 @@ rpm:
|
||||
depends:
|
||||
- screen
|
||||
- gnome-keyring
|
||||
fpm:
|
||||
- '--rpm-rpmbuild-define'
|
||||
- '_build_id_links none'
|
||||
|
76
package.json
@@ -1,78 +1,80 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||
"@sentry/cli": "^1.61.0",
|
||||
"@sentry/electron": "^2.0.4",
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@sentry/cli": "^1.63.1",
|
||||
"@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/fs-extra": "^9.0.9",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/node": "14.14.35",
|
||||
"@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",
|
||||
"core-js": "^3.8.1",
|
||||
"cross-env": "7.0.2",
|
||||
"css-loader": "3.4.2",
|
||||
"electron": "^11.1.1",
|
||||
"electron-builder": "22.10.3",
|
||||
"compare-versions": "^3.6.0",
|
||||
"core-js": "^3.9.1",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "5.2.0",
|
||||
"electron": "12.0.4",
|
||||
"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",
|
||||
"node-abi": "^2.19.3",
|
||||
"macos-release": "^2.4.1",
|
||||
"node-abi": "^2.21.0",
|
||||
"node-gyp": "^7.1.2",
|
||||
"node-sass": "^5.0.0",
|
||||
"npmlog": "4.1.2",
|
||||
"npx": "^10.2.2",
|
||||
"pug": "^2.0.4",
|
||||
"patch-package": "^6.4.7",
|
||||
"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": "^1.3.0",
|
||||
"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.32",
|
||||
"typescript": "^3.9.9",
|
||||
"url-loader": "^4.1.1",
|
||||
"val-loader": "3.1.0",
|
||||
"webpack": "^5.31.0",
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-cli": "^4.6.0",
|
||||
"yaml-loader": "0.6.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/node-abi": "^2.19.3",
|
||||
"*/node-abi": "^2.20.0",
|
||||
"**/graceful-fs": "^4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:typings && webpack --color --config app/webpack.main.config.js && webpack --color --config app/webpack.config.js && webpack --color --config terminus-core/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-terminal/webpack.config.js && webpack --color --config terminus-plugin-manager/webpack.config.js && webpack --color --config terminus-community-color-schemes/webpack.config.js && webpack --color --config terminus-ssh/webpack.config.js && webpack --color --config terminus-serial/webpack.config.js",
|
||||
"build:typings": "node scripts/build-typings.js",
|
||||
"watch": "cross-env TERMINUS_DEV=1 webpack --progress --color --watch",
|
||||
"start": "cross-env TERMINUS_DEV=1 electron app --debug",
|
||||
"start": "cross-env TERMINUS_DEV=1 electron app --debug --inspect",
|
||||
"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 => {
|
||||
|
24
scripts/sentry-upload.js
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env node
|
||||
const sh = require('shelljs')
|
||||
const vars = require('./vars')
|
||||
|
||||
const sentryCli = process.platform === 'win32' ? 'node_modules\\.bin\\sentry-cli.cmd' : 'sentry-cli'
|
||||
|
||||
sh.exec(`${sentryCli} releases new ${vars.version}`)
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
for (const path of [
|
||||
'app/node_modules/@serialport/bindings/build/Release/bindings.node',
|
||||
'app/node_modules/@terminus-term/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/fontmanager-redux/build/Release/fontmanager.node',
|
||||
'app/node_modules/macos-native-processlist/build/Release/native.node',
|
||||
]) {
|
||||
sh.exec('dsymutil ' + path)
|
||||
}
|
||||
}
|
||||
|
||||
sh.exec(`${sentryCli} upload-dif app/node_modules`)
|
||||
sh.exec(`${sentryCli} releases set-commits --auto ${vars.version}`)
|
||||
for (const p of vars.builtinPlugins) {
|
||||
sh.exec(`${sentryCli} releases files ${vars.version} upload-sourcemaps ${p}/dist -u ${p}/dist/ -d ${process.platform}-${p}`)
|
||||
}
|
@@ -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
@@ -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,20 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^3.9.0",
|
||||
"@electron/remote": "^1.0.4",
|
||||
"@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",
|
||||
"clone-deep": "^4.0.1",
|
||||
"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",
|
||||
|
@@ -8,7 +8,5 @@ export interface HotkeyDescription {
|
||||
* must also provide the `hotkeys.foo` config options with the default values
|
||||
*/
|
||||
export abstract class HotkeyProvider {
|
||||
hotkeys: HotkeyDescription[] = []
|
||||
|
||||
abstract provide (): Promise<HotkeyDescription[]>
|
||||
}
|
||||
|
@@ -17,7 +17,9 @@ 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'
|
||||
export { UpdaterService } from '../services/updater.service'
|
||||
export * from '../utils'
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import deepClone from 'clone-deep'
|
||||
import { TabComponentType } from '../services/tabs.service'
|
||||
|
||||
export interface RecoveredTab {
|
||||
@@ -35,10 +36,26 @@ export interface RecoveryToken {
|
||||
* ```
|
||||
*/
|
||||
export abstract class TabRecoveryProvider {
|
||||
/**
|
||||
* @param recoveryToken a recovery token found in the saved tabs list
|
||||
* @returns [[boolean]] whether this [[TabRecoveryProvider]] can recover a tab from this token
|
||||
*/
|
||||
abstract async applicableTo (recoveryToken: RecoveryToken): Promise<boolean>
|
||||
|
||||
/**
|
||||
* @param recoveryToken a recovery token found in the saved tabs list
|
||||
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
|
||||
* or `null` if this token is from a different tab type or is not supported
|
||||
*/
|
||||
abstract async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null>
|
||||
abstract async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab>
|
||||
|
||||
/**
|
||||
* @param recoveryToken a recovery token found in the saved tabs list
|
||||
* @returns [[RecoveryToken]] a new recovery token to create the duplicate tab from
|
||||
*
|
||||
* The default implementation just returns a deep copy of the original token
|
||||
*/
|
||||
duplicate (recoveryToken: RecoveryToken): RecoveryToken {
|
||||
return deepClone(recoveryToken)
|
||||
}
|
||||
}
|
||||
|
@@ -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(
|
||||
@@ -24,7 +25,6 @@ title-bar(
|
||||
[index]='idx',
|
||||
[tab]='tab',
|
||||
[active]='tab == app.activeTab',
|
||||
[hasActivity]='tab.activity$|async',
|
||||
@animateTab,
|
||||
[@.disabled]='hasVerticalTabs()',
|
||||
(click)='app.selectTab(tab)',
|
||||
@@ -85,7 +85,7 @@ title-bar(
|
||||
button.btn.btn-secondary.btn-tab-bar.btn-update(
|
||||
*ngIf='updatesAvailable',
|
||||
title='Update available - Click to install',
|
||||
(click)='updateApp()',
|
||||
(click)='updater.update()',
|
||||
[fastHtmlBind]='updateIcon'
|
||||
)
|
||||
|
||||
@@ -94,12 +94,14 @@ title-bar(
|
||||
&& (hostApp.platform == Platform.Windows || hostApp.platform == Platform.Linux)',
|
||||
)
|
||||
|
||||
start-page(*ngIf='ready && app.tabs.length == 0')
|
||||
.content
|
||||
start-page.content-tab.content-tab-active(*ngIf='ready && app.tabs.length == 0')
|
||||
|
||||
tab-body(
|
||||
*ngFor='let tab of unsortedTabs',
|
||||
[active]='tab == app.activeTab',
|
||||
[tab]='tab',
|
||||
)
|
||||
tab-body.content-tab(
|
||||
*ngFor='let tab of unsortedTabs',
|
||||
[class.content-tab-active]='tab == app.activeTab',
|
||||
[active]='tab == app.activeTab',
|
||||
[tab]='tab',
|
||||
)
|
||||
|
||||
ng-template(ngbModalContainer)
|
||||
|
@@ -26,8 +26,8 @@ $side-tab-width: 200px;
|
||||
|
||||
.content {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
flex: auto;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
@@ -66,6 +66,10 @@ $side-tab-width: 200px;
|
||||
.drag-space {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
&>.inset {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,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;
|
||||
@@ -92,7 +97,7 @@ $side-tab-width: 200px;
|
||||
color: #aaa;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
||||
|
||||
align-items: center;
|
||||
|
||||
&.dropdown-toggle::after {
|
||||
@@ -121,7 +126,6 @@ $side-tab-width: 200px;
|
||||
width: 85px;
|
||||
height: $tabs-height;
|
||||
flex: none;
|
||||
opacity: 0;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
@@ -130,9 +134,24 @@ $side-tab-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-content {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
.content {
|
||||
flex: 1 1 0;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
|
||||
> .content-tab {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
left: -100%;
|
||||
|
||||
&.content-tab-active {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hotkey-hint {
|
||||
|
@@ -68,7 +68,6 @@ export class AppRootComponent {
|
||||
|
||||
private constructor (
|
||||
private docking: DockingService,
|
||||
private electron: ElectronService,
|
||||
private hotkeys: HotkeysService,
|
||||
private updater: UpdaterService,
|
||||
private touchbar: TouchbarService,
|
||||
@@ -76,6 +75,7 @@ export class AppRootComponent {
|
||||
public config: ConfigService,
|
||||
public app: AppService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
electron: ElectronService,
|
||||
log: LogService,
|
||||
ngbModal: NgbModal,
|
||||
_themes: ThemesService,
|
||||
@@ -136,12 +136,18 @@ export class AppRootComponent {
|
||||
ngbModal.open(SafeModeModalComponent)
|
||||
}
|
||||
|
||||
this.updater.check().then(available => {
|
||||
this.updatesAvailable = available
|
||||
})
|
||||
setInterval(() => {
|
||||
if (this.config.store.enableAutomaticUpdates) {
|
||||
this.updater.check().then(available => {
|
||||
this.updatesAvailable = available
|
||||
})
|
||||
}
|
||||
}, 3600 * 12)
|
||||
|
||||
this.touchbar.update()
|
||||
|
||||
this.hostApp.useBuiltinGraphics()
|
||||
|
||||
config.changed$.subscribe(() => this.updateVibrancy())
|
||||
this.updateVibrancy()
|
||||
|
||||
@@ -188,20 +194,6 @@ export class AppRootComponent {
|
||||
return this.config.store.appearance.tabsLocation === 'left' || this.config.store.appearance.tabsLocation === 'right'
|
||||
}
|
||||
|
||||
async updateApp () {
|
||||
if ((await this.electron.showMessageBox(
|
||||
this.hostApp.getWindow(),
|
||||
{
|
||||
type: 'warning',
|
||||
message: 'Installing the update will close all tabs and restart Terminus.',
|
||||
buttons: ['Cancel', 'Update'],
|
||||
defaultId: 1,
|
||||
}
|
||||
)).response === 1) {
|
||||
this.updater.update()
|
||||
}
|
||||
}
|
||||
|
||||
onTabDragStart () {
|
||||
this.tabsDragging = true
|
||||
}
|
||||
@@ -229,8 +221,8 @@ export class AppRootComponent {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
return buttons
|
||||
.filter(button => (button.weight || 0) > 0 === aboveZero)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
||||
.filter(button => (button.weight ?? 0) > 0 === aboveZero)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
}
|
||||
|
||||
private 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 {
|
||||
@@ -11,3 +17,8 @@
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
@@ -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')],
|
||||
})
|
||||
@@ -50,7 +51,7 @@ export class SelectorModalComponent<T> {
|
||||
this.filteredOptions = this.options.filter(x => !x.freeInputPattern)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
this.filteredOptions = this.options.filter(x => x.freeInputPattern || (x.name + (x.description || '')).toLowerCase().includes(f))
|
||||
this.filteredOptions = this.options.filter(x => x.freeInputPattern ?? (x.name + (x.description ?? '')).toLowerCase().includes(f))
|
||||
}
|
||||
this.selectedIndex = Math.max(0, this.selectedIndex)
|
||||
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
|
||||
@@ -72,7 +73,7 @@ export class SelectorModalComponent<T> {
|
||||
this.modalInstance.dismiss()
|
||||
}
|
||||
|
||||
iconIsSVG (icon: string): boolean {
|
||||
return icon?.startsWith('<')
|
||||
iconIsSVG (icon?: string): boolean {
|
||||
return icon?.startsWith('<') ?? false
|
||||
}
|
||||
}
|
||||
|
@@ -161,7 +161,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
_allFocusMode = false
|
||||
|
||||
/** @hidden */
|
||||
private focusedTab: BaseTabComponent
|
||||
private focusedTab: BaseTabComponent|null = null
|
||||
private maximizedTab: BaseTabComponent|null = null
|
||||
private hotkeysSubscription: Subscription
|
||||
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
|
||||
@@ -211,7 +211,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
if (!this.hasFocus || !this.focusedTab) {
|
||||
return
|
||||
}
|
||||
switch (hotkey) {
|
||||
@@ -256,7 +256,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/** @hidden */
|
||||
async ngAfterViewInit (): Promise<void> {
|
||||
if (this._recoveredState) {
|
||||
await this.recoverContainer(this.root, this._recoveredState)
|
||||
await this.recoverContainer(this.root, this._recoveredState, this._recoveredState.duplicate)
|
||||
this.layout()
|
||||
setTimeout(() => {
|
||||
if (this.hasFocus) {
|
||||
@@ -280,7 +280,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
return this.root.getAllTabs()
|
||||
}
|
||||
|
||||
getFocusedTab (): BaseTabComponent {
|
||||
getFocusedTab (): BaseTabComponent|null {
|
||||
return this.focusedTab
|
||||
}
|
||||
|
||||
@@ -295,10 +295,8 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
x.emitBlurred()
|
||||
}
|
||||
}
|
||||
if (tab) {
|
||||
tab.emitFocused()
|
||||
this.focusChanged.next(tab)
|
||||
}
|
||||
tab.emitFocused()
|
||||
this.focusChanged.next(tab)
|
||||
|
||||
if (this.maximizedTab !== tab) {
|
||||
this.maximizedTab = null
|
||||
@@ -314,7 +312,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/**
|
||||
* Focuses the first available tab inside the given [[SplitContainer]]
|
||||
*/
|
||||
focusAnyIn (parent: BaseTabComponent | SplitContainer): void {
|
||||
focusAnyIn (parent?: BaseTabComponent | SplitContainer): void {
|
||||
if (!parent) {
|
||||
return
|
||||
}
|
||||
@@ -331,7 +329,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
async addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection): Promise<void> {
|
||||
tab.parent = this
|
||||
|
||||
let target = (relative ? this.getParentOf(relative) : null) || this.root
|
||||
let target = (relative ? this.getParentOf(relative) : null) ?? this.root
|
||||
let insertIndex = relative ? target.children.indexOf(relative) : -1
|
||||
|
||||
if (
|
||||
@@ -398,6 +396,10 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
* Moves focus in the given direction
|
||||
*/
|
||||
navigate (dir: SplitDirection): void {
|
||||
if (!this.focusedTab) {
|
||||
return
|
||||
}
|
||||
|
||||
let rel: BaseTabComponent | SplitContainer = this.focusedTab
|
||||
let parent = this.getParentOf(rel)
|
||||
if (!parent) {
|
||||
@@ -442,7 +444,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
* @returns the immediate parent of `tab`
|
||||
*/
|
||||
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer|null {
|
||||
root = root || this.root
|
||||
root = root ?? this.root
|
||||
for (const child of root.children) {
|
||||
if (child instanceof SplitContainer) {
|
||||
const r = this.getParentOf(tab, child)
|
||||
@@ -469,7 +471,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
/** @hidden */
|
||||
async getCurrentProcess (): Promise<BaseTabProcess|null> {
|
||||
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) || null
|
||||
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) ?? null
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@@ -503,6 +505,9 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
if (tab.title) {
|
||||
this.setTitle(tab.title)
|
||||
}
|
||||
tab.recoveryStateChangedHint$.subscribe(() => {
|
||||
this.recoveryStateChangedHint.next()
|
||||
})
|
||||
tab.destroyed$.subscribe(() => {
|
||||
this.removeTab(tab)
|
||||
})
|
||||
@@ -518,7 +523,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
private layoutInternal (root: SplitContainer, x: number, y: number, w: number, h: number) {
|
||||
const size = root.orientation === 'v' ? h : w
|
||||
const sizes = root.ratios.map(x => x * size)
|
||||
const sizes = root.ratios.map(ratio => ratio * size)
|
||||
|
||||
root.x = x
|
||||
root.y = y
|
||||
@@ -565,7 +570,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
})
|
||||
}
|
||||
|
||||
private async recoverContainer (root: SplitContainer, state: any) {
|
||||
private async recoverContainer (root: SplitContainer, state: any, duplicate = false) {
|
||||
const children: (SplitContainer | BaseTabComponent)[] = []
|
||||
root.orientation = state.orientation
|
||||
root.ratios = state.ratios
|
||||
@@ -573,10 +578,10 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
for (const childState of state.children) {
|
||||
if (childState.type === 'app:split-tab') {
|
||||
const child = new SplitContainer()
|
||||
await this.recoverContainer(child, childState)
|
||||
await this.recoverContainer(child, childState, duplicate)
|
||||
children.push(child)
|
||||
} else {
|
||||
const recovered = await this.tabRecovery.recoverTab(childState)
|
||||
const recovered = await this.tabRecovery.recoverTab(childState, duplicate)
|
||||
if (recovered) {
|
||||
const tab = this.tabsService.create(recovered.type, recovered.options)
|
||||
children.push(tab)
|
||||
@@ -597,13 +602,21 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
|
||||
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
|
||||
return {
|
||||
type: SplitTabComponent,
|
||||
options: { _recoveredState: recoveryToken },
|
||||
}
|
||||
async applicableTo (recoveryToken: RecoveryToken): Promise<boolean> {
|
||||
return recoveryToken.type === 'app:split-tab'
|
||||
}
|
||||
|
||||
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab> {
|
||||
return {
|
||||
type: SplitTabComponent,
|
||||
options: { _recoveredState: recoveryToken },
|
||||
}
|
||||
}
|
||||
|
||||
duplicate (recoveryToken: RecoveryToken): RecoveryToken {
|
||||
return {
|
||||
...recoveryToken,
|
||||
duplicate: true,
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@@ -34,8 +34,8 @@ export class SplitTabSpannerComponent {
|
||||
let current = start
|
||||
const oldPosition: number = this.isVertical ? this.element.nativeElement.offsetTop : this.element.nativeElement.offsetLeft
|
||||
|
||||
const dragHandler = (e: MouseEvent) => {
|
||||
current = this.isVertical ? e.pageY : e.pageX
|
||||
const dragHandler = (dragEvent: MouseEvent) => {
|
||||
current = this.isVertical ? dragEvent.pageY : dragEvent.pageX
|
||||
const newPosition = oldPosition + (current - start)
|
||||
if (this.isVertical) {
|
||||
this.element.nativeElement.style.top = `${newPosition - this.marginOffset}px`
|
||||
|
@@ -26,10 +26,10 @@ export class StartPageComponent {
|
||||
.map(provider => provider.provide())
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter(x => !!x.click)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
}
|
||||
|
||||
sanitizeIcon (icon: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
|
||||
sanitizeIcon (icon?: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon ?? '')
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,11 @@
|
||||
:host {
|
||||
display: none;
|
||||
display: flex;
|
||||
flex: auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
|
||||
>* {
|
||||
flex: auto;
|
||||
}
|
||||
>* {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
> perfect-scrollbar {
|
||||
|
@@ -1,7 +1,10 @@
|
||||
.colorbar([style.background-color]='tab.color', *ngIf='tab.color != null')
|
||||
.progressbar([style.width]='progress + "%"', *ngIf='progress != null')
|
||||
.index(*ngIf='!config.store.terminal.hideTabIndex',
|
||||
#handle,
|
||||
[style.background-color]='tab.color',
|
||||
) {{index + 1}}
|
||||
.name([title]='tab.customTitle || tab.title') {{tab.customTitle || tab.title}}
|
||||
.activity-indicator(*ngIf='tab.activity$|async')
|
||||
|
||||
.index(*ngIf='!config.store.terminal.hideTabIndex', #handle) {{index + 1}}
|
||||
.name(
|
||||
[title]='tab.customTitle || tab.title',
|
||||
[class.no-hover]='config.store.terminal.hideCloseButton'
|
||||
) {{tab.customTitle || tab.title}}
|
||||
button(*ngIf='!config.store.terminal.hideCloseButton',(click)='app.closeTab(tab, true)') ×
|
||||
|
@@ -4,8 +4,16 @@ $tabs-height: 38px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
> * { cursor: pointer; }
|
||||
|
||||
flex: 1000 1 200px;
|
||||
width: 200px;
|
||||
padding: 0 10px;
|
||||
|
||||
&.flex-width {
|
||||
flex: 1000 1 auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -24,7 +32,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 +41,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 +49,10 @@ $tabs-height: 38px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.index + .name {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
flex: none;
|
||||
@@ -49,13 +60,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 +78,13 @@ $tabs-height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .name:not(.no-hover) {
|
||||
-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;
|
||||
@@ -83,8 +103,30 @@ $tabs-height: 38px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 5px;
|
||||
z-index: -1;
|
||||
height: 3px;
|
||||
z-index: 1;
|
||||
transition: 0.25s width;
|
||||
}
|
||||
|
||||
.colorbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&.active .activity-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.activity-indicator {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 4px;
|
||||
height: 2px;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import type { MenuItemConstructorOptions } from 'electron'
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef, NgZone } from '@angular/core'
|
||||
import { SortableComponent } from 'ng2-dnd'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { TabContextMenuItemProvider } from '../api/tabContextMenuProvider'
|
||||
@@ -26,10 +26,9 @@ export interface SortableComponentProxy {
|
||||
export class TabHeaderComponent {
|
||||
@Input() index: number
|
||||
@Input() @HostBinding('class.active') active: boolean
|
||||
@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,
|
||||
@@ -38,6 +37,7 @@ export class TabHeaderComponent {
|
||||
private hostApp: HostAppService,
|
||||
private ngbModal: NgbModal,
|
||||
private hotkeys: HotkeysService,
|
||||
private zone: NgZone,
|
||||
@Inject(SortableComponent) private parentDraggable: SortableComponentProxy,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
) {
|
||||
@@ -53,12 +53,14 @@ export class TabHeaderComponent {
|
||||
|
||||
ngOnInit () {
|
||||
this.tab.progress$.subscribe(progress => {
|
||||
this.progress = progress
|
||||
this.zone.run(() => {
|
||||
this.progress = progress
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ngAfterViewInit () {
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
if (this.handle && this.hostApp.platform === Platform.macOS) {
|
||||
this.parentDraggable.setDragHandle(this.handle.nativeElement)
|
||||
}
|
||||
}
|
||||
@@ -81,6 +83,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()
|
||||
}
|
||||
@@ -101,7 +107,7 @@ export class TabHeaderComponent {
|
||||
if ($event.which === 3) {
|
||||
$event.preventDefault()
|
||||
|
||||
const contextMenu = this.electron.remote.Menu.buildFromTemplate(await this.buildContextMenu())
|
||||
const contextMenu = this.electron.Menu.buildFromTemplate(await this.buildContextMenu())
|
||||
|
||||
contextMenu.popup({
|
||||
x: $event.pageX,
|
||||
|
@@ -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,
|
||||
|
@@ -46,13 +46,13 @@ class CompletionObserver {
|
||||
export class AppService {
|
||||
tabs: BaseTabComponent[] = []
|
||||
|
||||
get activeTab (): BaseTabComponent { return this._activeTab }
|
||||
get activeTab (): BaseTabComponent|null { return this._activeTab ?? null }
|
||||
|
||||
private lastTabIndex = 0
|
||||
private _activeTab: BaseTabComponent
|
||||
private _activeTab: BaseTabComponent | null = null
|
||||
private closedTabsStack: RecoveryToken[] = []
|
||||
|
||||
private activeTabChange = new Subject<BaseTabComponent>()
|
||||
private activeTabChange = new Subject<BaseTabComponent|null>()
|
||||
private tabsChanged = new Subject<void>()
|
||||
private tabOpened = new Subject<BaseTabComponent>()
|
||||
private tabClosed = new Subject<BaseTabComponent>()
|
||||
@@ -60,7 +60,7 @@ export class AppService {
|
||||
|
||||
private completionObservers = new Map<BaseTabComponent, CompletionObserver>()
|
||||
|
||||
get activeTabChange$ (): Observable<BaseTabComponent> { return this.activeTabChange }
|
||||
get activeTabChange$ (): Observable<BaseTabComponent|null> { return this.activeTabChange }
|
||||
get tabOpened$ (): Observable<BaseTabComponent> { return this.tabOpened }
|
||||
get tabsChanged$ (): Observable<void> { return this.tabsChanged }
|
||||
get tabClosed$ (): Observable<BaseTabComponent> { return this.tabClosed }
|
||||
@@ -97,12 +97,10 @@ export class AppService {
|
||||
}
|
||||
}
|
||||
|
||||
hostApp.windowFocused$.subscribe(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
})
|
||||
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)
|
||||
}
|
||||
@@ -187,12 +185,12 @@ export class AppService {
|
||||
return null
|
||||
}
|
||||
|
||||
selectTab (tab: BaseTabComponent): void {
|
||||
if (this._activeTab === tab) {
|
||||
selectTab (tab: BaseTabComponent|null): void {
|
||||
if (tab && this._activeTab === tab) {
|
||||
this._activeTab.emitFocused()
|
||||
return
|
||||
}
|
||||
if (this.tabs.includes(this._activeTab)) {
|
||||
if (this._activeTab && this.tabs.includes(this._activeTab)) {
|
||||
this.lastTabIndex = this.tabs.indexOf(this._activeTab)
|
||||
} else {
|
||||
this.lastTabIndex = 0
|
||||
@@ -203,12 +201,10 @@ export class AppService {
|
||||
}
|
||||
this._activeTab = tab
|
||||
this.activeTabChange.next(tab)
|
||||
if (this._activeTab) {
|
||||
setImmediate(() => {
|
||||
this._activeTab.emitFocused()
|
||||
})
|
||||
this.hostApp.setTitle(this._activeTab.title)
|
||||
}
|
||||
setImmediate(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
})
|
||||
this.hostApp.setTitle(this._activeTab?.title)
|
||||
}
|
||||
|
||||
getParentTab (tab: BaseTabComponent): SplitTabComponent|null {
|
||||
@@ -231,6 +227,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
nextTab (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex < this.tabs.length - 1) {
|
||||
@@ -242,6 +241,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
previousTab (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex > 0) {
|
||||
@@ -253,23 +255,29 @@ export class AppService {
|
||||
}
|
||||
|
||||
moveSelectedTabLeft (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex > 0) {
|
||||
this.swapTabs(this._activeTab, this.tabs[tabIndex - 1])
|
||||
} else if (this.config.store.appearance.cycleTabs) {
|
||||
this.swapTabs(this._activeTab, this.tabs[this.tabs.length - 1])
|
||||
this.tabs.push(this.tabs.shift()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveSelectedTabRight (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex < this.tabs.length - 1) {
|
||||
this.swapTabs(this._activeTab, this.tabs[tabIndex + 1])
|
||||
} else if (this.config.store.appearance.cycleTabs) {
|
||||
this.swapTabs(this._activeTab, this.tabs[0])
|
||||
this.tabs.unshift(this.tabs.pop()!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -109,10 +109,7 @@ export class ConfigService {
|
||||
) {
|
||||
this.path = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||
this.defaults = configProviders.map(provider => {
|
||||
let defaults = {}
|
||||
if (provider.platformDefaults) {
|
||||
defaults = configMerge(defaults, provider.platformDefaults[hostApp.platform] || {})
|
||||
}
|
||||
let defaults = provider.platformDefaults[hostApp.platform] || {}
|
||||
if (provider.defaults) {
|
||||
defaults = configMerge(defaults, provider.defaults)
|
||||
}
|
||||
@@ -147,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 = {}
|
||||
}
|
||||
@@ -157,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)))
|
||||
}
|
||||
@@ -166,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()
|
||||
|
@@ -26,6 +26,7 @@ export class DockingService {
|
||||
|
||||
let display = this.electron.screen.getAllDisplays()
|
||||
.filter(x => x.id === this.config.store.appearance.dockScreen)[0]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!display) {
|
||||
display = this.getCurrentScreen()
|
||||
}
|
||||
@@ -33,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 { Injectable } from '@angular/core'
|
||||
import { App, IpcRenderer, Shell, Dialog, Clipboard, GlobalShortcut, Screen, Remote, AutoUpdater, TouchBar, BrowserWindow, Menu, MenuItem, NativeImage, MessageBoxOptions } from 'electron'
|
||||
import * as remote from '@electron/remote'
|
||||
|
||||
export interface MessageBoxResponse {
|
||||
response: number
|
||||
@@ -17,30 +18,31 @@ export class ElectronService {
|
||||
nativeImage: typeof NativeImage
|
||||
screen: Screen
|
||||
remote: Remote
|
||||
process: any
|
||||
autoUpdater: AutoUpdater
|
||||
TouchBar: typeof TouchBar
|
||||
BrowserWindow: typeof BrowserWindow
|
||||
Menu: typeof Menu
|
||||
MenuItem: typeof MenuItem
|
||||
private electron: any
|
||||
|
||||
/** @hidden */
|
||||
private constructor () {
|
||||
this.electron = require('electron')
|
||||
this.remote = this.electron.remote
|
||||
this.app = this.remote.app
|
||||
this.screen = this.remote.screen
|
||||
this.dialog = this.remote.dialog
|
||||
this.shell = this.electron.shell
|
||||
this.clipboard = this.electron.clipboard
|
||||
this.ipcRenderer = this.electron.ipcRenderer
|
||||
this.globalShortcut = this.remote.globalShortcut
|
||||
this.nativeImage = this.remote.nativeImage
|
||||
this.autoUpdater = this.remote.autoUpdater
|
||||
this.TouchBar = this.remote.TouchBar
|
||||
this.BrowserWindow = this.remote.BrowserWindow
|
||||
this.Menu = this.remote.Menu
|
||||
this.MenuItem = this.remote.MenuItem
|
||||
const electron = require('electron')
|
||||
this.shell = electron.shell
|
||||
this.clipboard = electron.clipboard
|
||||
this.ipcRenderer = electron.ipcRenderer
|
||||
|
||||
this.process = remote.process
|
||||
this.app = remote.app
|
||||
this.screen = remote.screen
|
||||
this.dialog = remote.dialog
|
||||
this.globalShortcut = remote.globalShortcut
|
||||
this.nativeImage = remote.nativeImage
|
||||
this.autoUpdater = remote.autoUpdater
|
||||
this.TouchBar = remote.TouchBar
|
||||
this.BrowserWindow = remote.BrowserWindow
|
||||
this.Menu = remote.Menu
|
||||
this.MenuItem = remote.MenuItem
|
||||
}
|
||||
|
||||
async showMessageBox (
|
||||
|
@@ -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()
|
||||
}
|
||||
}))
|
||||
@@ -235,15 +247,15 @@ export class HostAppService {
|
||||
* @param type `null`, or `fluent` when supported (Windowd only)
|
||||
*/
|
||||
setVibrancy (enable: boolean, type: string|null): void {
|
||||
if (!isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
if (this.platform === Platform.Windows && !isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
type = null
|
||||
}
|
||||
document.body.classList.toggle('vibrant', enable)
|
||||
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
|
||||
}
|
||||
|
||||
setTitle (title: string): void {
|
||||
this.electron.ipcRenderer.send('window-set-title', title)
|
||||
setTitle (title?: string): void {
|
||||
this.electron.ipcRenderer.send('window-set-title', title ?? 'Terminus')
|
||||
}
|
||||
|
||||
setTouchBar (touchBar: TouchBar): void {
|
||||
@@ -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 })
|
||||
|
@@ -172,7 +172,7 @@ export class HotkeysService {
|
||||
return (
|
||||
await Promise.all(
|
||||
this.config.enabledServices(this.hotkeyProviders)
|
||||
.map(async x => x.provide ? x.provide() : x.hotkeys)
|
||||
.map(async x => x.provide())
|
||||
)
|
||||
).reduce((a, b) => a.concat(b))
|
||||
}
|
||||
@@ -222,7 +222,7 @@ export class HotkeysService {
|
||||
if (!(value instanceof Array)) {
|
||||
continue
|
||||
}
|
||||
if (value) {
|
||||
if (value.length > 0) {
|
||||
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
|
||||
keys[key] = value
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ export const altKeyName = {
|
||||
linux: 'Alt',
|
||||
}[process.platform]
|
||||
|
||||
const REGEX_LATIN_KEYNAME = /^[A-Za-z]$/
|
||||
|
||||
export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
|
||||
const items: string[] = []
|
||||
events = events.slice()
|
||||
@@ -37,23 +39,29 @@ export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
|
||||
}
|
||||
|
||||
let key = event.code
|
||||
key = key.replace('Key', '')
|
||||
key = key.replace('Arrow', '')
|
||||
key = key.replace('Digit', '')
|
||||
key = {
|
||||
Comma: ',',
|
||||
Period: '.',
|
||||
Slash: '/',
|
||||
Backslash: '\\',
|
||||
IntlBackslash: '\\',
|
||||
Backquote: '`',
|
||||
Minus: '-',
|
||||
Equal: '=',
|
||||
Semicolon: ';',
|
||||
Quote: '\'',
|
||||
BracketLeft: '[',
|
||||
BracketRight: ']',
|
||||
}[key] || key
|
||||
if (REGEX_LATIN_KEYNAME.test(event.key)) {
|
||||
// Handle Dvorak etc via the reported "character" instead of the scancode
|
||||
key = event.key.toUpperCase()
|
||||
} else {
|
||||
key = key.replace('Key', '')
|
||||
key = key.replace('Arrow', '')
|
||||
key = key.replace('Digit', '')
|
||||
key = {
|
||||
Comma: ',',
|
||||
Period: '.',
|
||||
Slash: '/',
|
||||
Backslash: '\\',
|
||||
IntlBackslash: '`',
|
||||
Backquote: '~', // Electron says it's the tilde
|
||||
Minus: '-',
|
||||
Equal: '=',
|
||||
Semicolon: ';',
|
||||
Quote: '\'',
|
||||
BracketLeft: '[',
|
||||
BracketRight: ']',
|
||||
}[key] || key
|
||||
}
|
||||
|
||||
itemKeys.push(key)
|
||||
items.push(itemKeys.join('-'))
|
||||
}
|
||||
|
@@ -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)
|
||||
@@ -54,9 +56,7 @@ export class Logger {
|
||||
|
||||
private doLog (level: string, ...args: any[]): void {
|
||||
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
|
||||
if (this.winstonLogger) {
|
||||
this.winstonLogger[level](...args)
|
||||
}
|
||||
this.winstonLogger[level](...args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,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
@@ -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)
|
||||
}
|
||||
}
|
@@ -59,7 +59,7 @@ export class ShellIntegrationService {
|
||||
}
|
||||
|
||||
async install (): Promise<void> {
|
||||
const exe: string = process.env.PORTABLE_EXECUTABLE_FILE || this.electron.app.getPath('exe')
|
||||
const exe: string = process.env.PORTABLE_EXECUTABLE_FILE ?? this.electron.app.getPath('exe')
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
for (const wf of this.automatorWorkflows) {
|
||||
await exec(`cp -r "${this.automatorWorkflowsLocation}/${wf}" "${this.automatorWorkflowsDestination}"`)
|
||||
|
@@ -11,7 +11,7 @@ export class TabRecoveryService {
|
||||
enabled = false
|
||||
|
||||
private constructor (
|
||||
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
|
||||
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[]|null,
|
||||
private config: ConfigService,
|
||||
log: LogService
|
||||
) {
|
||||
@@ -23,38 +23,37 @@ export class TabRecoveryService {
|
||||
return
|
||||
}
|
||||
window.localStorage.tabsRecovery = JSON.stringify(
|
||||
await Promise.all(
|
||||
tabs
|
||||
.map(tab => {
|
||||
let token = tab.getRecoveryToken()
|
||||
if (token) {
|
||||
token = token.then(r => {
|
||||
if (r) {
|
||||
r.tabTitle = tab.title
|
||||
if (tab.color) {
|
||||
r.tabColor = tab.color
|
||||
}
|
||||
}
|
||||
return r
|
||||
})
|
||||
}
|
||||
return token
|
||||
})
|
||||
.filter(token => !!token)
|
||||
)
|
||||
(await Promise.all(
|
||||
tabs.map(async tab => this.getFullRecoveryToken(tab))
|
||||
)).filter(token => !!token)
|
||||
)
|
||||
}
|
||||
|
||||
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
|
||||
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, duplicate = false): Promise<RecoveredTab|null> {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders ?? [])) {
|
||||
try {
|
||||
const tab = await provider.recover(token)
|
||||
if (tab !== null) {
|
||||
tab.options = tab.options || {}
|
||||
tab.options.color = token.tabColor || null
|
||||
tab.options.title = token.tabTitle || ''
|
||||
return tab
|
||||
if (!await provider.applicableTo(token)) {
|
||||
continue
|
||||
}
|
||||
if (duplicate) {
|
||||
token = provider.duplicate(token)
|
||||
}
|
||||
const tab = await provider.recover(token)
|
||||
tab.options = tab.options || {}
|
||||
tab.options.color = token.tabColor ?? null
|
||||
tab.options.title = token.tabTitle || ''
|
||||
return tab
|
||||
} catch (error) {
|
||||
this.logger.warn('Tab recovery crashed:', token, provider, error)
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ export class TabsService {
|
||||
const componentRef = componentFactory.create(this.injector)
|
||||
const tab = componentRef.instance
|
||||
tab.hostView = componentRef.hostView
|
||||
Object.assign(tab, inputs || {})
|
||||
Object.assign(tab, inputs ?? {})
|
||||
return tab
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ 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
|
||||
}
|
||||
const dup = await this.tabRecovery.recoverTab(token)
|
||||
const dup = await this.tabRecovery.recoverTab(token, true)
|
||||
if (dup) {
|
||||
return this.create(dup.type, dup.options)
|
||||
}
|
||||
|
@@ -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()
|
||||
@@ -18,11 +20,11 @@ export class ThemesService {
|
||||
}
|
||||
|
||||
findTheme (name: string): Theme|null {
|
||||
return this.config.enabledServices(this.themes).find(x => x.name === name) || null
|
||||
return this.config.enabledServices(this.themes).find(x => x.name === name) ?? null
|
||||
}
|
||||
|
||||
findCurrentTheme (): Theme {
|
||||
return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard')!
|
||||
return this.findTheme(this.config.store.appearance.theme) ?? this.findTheme('Standard')!
|
||||
}
|
||||
|
||||
applyTheme (theme: Theme): void {
|
||||
@@ -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,
|
||||
) {
|
||||
@@ -33,6 +27,7 @@ export class TouchbarService {
|
||||
app.tabOpened$.subscribe(tab => {
|
||||
tab.titleChange$.subscribe(title => {
|
||||
const segment = this.tabSegments[app.tabs.indexOf(tab)]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (segment) {
|
||||
segment.label = this.shortenTitle(title)
|
||||
this.tabsSegmentedControl.segments = this.tabSegments
|
||||
@@ -41,6 +36,7 @@ export class TouchbarService {
|
||||
tab.activity$.subscribe(hasActivity => {
|
||||
const showIcon = this.app.activeTab !== tab && hasActivity
|
||||
const segment = this.tabSegments[app.tabs.indexOf(tab)]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (segment) {
|
||||
segment.icon = showIcon ? activityIcon : undefined
|
||||
}
|
||||
@@ -53,7 +49,7 @@ export class TouchbarService {
|
||||
label: this.shortenTitle(tab.title),
|
||||
}))
|
||||
this.tabsSegmentedControl.segments = this.tabSegments
|
||||
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab)
|
||||
this.tabsSegmentedControl.selectedIndex = this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : 0
|
||||
}
|
||||
|
||||
update (): void {
|
||||
@@ -61,60 +57,22 @@ 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.tabs.indexOf(this.app.activeTab),
|
||||
selectedIndex: this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : undefined,
|
||||
change: (selectedIndex) => this.zone.run(() => {
|
||||
this.app.selectTab(this.app.tabs[selectedIndex])
|
||||
}),
|
||||
})
|
||||
|
||||
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) {
|
||||
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) + '...'
|
||||
|
@@ -4,6 +4,7 @@ import { Injectable } from '@angular/core'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { HostAppService } from './hostApp.service'
|
||||
|
||||
const UPDATES_URL = 'https://api.github.com/repos/eugeny/terminus/releases/latest'
|
||||
|
||||
@@ -17,8 +18,9 @@ export class UpdaterService {
|
||||
|
||||
private constructor (
|
||||
log: LogService,
|
||||
config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
this.logger = log.create('updater')
|
||||
|
||||
@@ -35,6 +37,10 @@ export class UpdaterService {
|
||||
this.logger.info('No updates')
|
||||
})
|
||||
|
||||
electron.autoUpdater.once('error', err => {
|
||||
this.logger.error(err)
|
||||
})
|
||||
|
||||
this.downloaded = new Promise<boolean>(resolve => {
|
||||
electron.autoUpdater.once('update-downloaded', () => resolve(true))
|
||||
})
|
||||
@@ -54,10 +60,42 @@ export class UpdaterService {
|
||||
}
|
||||
|
||||
async check (): Promise<boolean> {
|
||||
if (!this.config.store.enableAutomaticUpdates) {
|
||||
return false
|
||||
}
|
||||
if (!this.electronUpdaterAvailable) {
|
||||
if (this.electronUpdaterAvailable) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line @typescript-eslint/init-declarations, prefer-const
|
||||
let cancel
|
||||
const onNoUpdate = () => {
|
||||
cancel()
|
||||
resolve(false)
|
||||
}
|
||||
const onUpdate = () => {
|
||||
cancel()
|
||||
resolve(this.downloaded)
|
||||
}
|
||||
const onError = (err) => {
|
||||
cancel()
|
||||
reject(err)
|
||||
}
|
||||
cancel = () => {
|
||||
this.electron.autoUpdater.off('error', onError)
|
||||
this.electron.autoUpdater.off('update-not-available', onNoUpdate)
|
||||
this.electron.autoUpdater.off('update-available', onUpdate)
|
||||
}
|
||||
this.electron.autoUpdater.on('error', onError)
|
||||
this.electron.autoUpdater.on('update-not-available', onNoUpdate)
|
||||
this.electron.autoUpdater.on('update-available', onUpdate)
|
||||
this.electron.autoUpdater.checkForUpdates()
|
||||
})
|
||||
|
||||
this.electron.autoUpdater.on('update-available', () => {
|
||||
this.logger.info('Update available')
|
||||
})
|
||||
|
||||
this.electron.autoUpdater.once('update-not-available', () => {
|
||||
this.logger.info('No updates')
|
||||
})
|
||||
|
||||
} else {
|
||||
this.logger.debug('Checking for updates through fallback method.')
|
||||
const response = await axios.get(UPDATES_URL)
|
||||
const data = response.data
|
||||
@@ -77,8 +115,18 @@ export class UpdaterService {
|
||||
if (!this.electronUpdaterAvailable) {
|
||||
this.electron.shell.openExternal(this.updateURL)
|
||||
} else {
|
||||
await this.downloaded
|
||||
this.electron.autoUpdater.quitAndInstall()
|
||||
if ((await this.electron.showMessageBox(
|
||||
this.hostApp.getWindow(),
|
||||
{
|
||||
type: 'warning',
|
||||
message: 'Installing the update will close all tabs and restart Terminus.',
|
||||
buttons: ['Cancel', 'Update'],
|
||||
defaultId: 1,
|
||||
}
|
||||
)).response === 1) {
|
||||
await this.downloaded
|
||||
this.electron.autoUpdater.quitAndInstall()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
...items,
|
||||
{
|
||||
label: 'Rename',
|
||||
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
|
||||
click: () => this.zone.run(() => tabHeader.showRenameTabModal()),
|
||||
},
|
||||
{
|
||||
label: 'Duplicate',
|
||||
|
@@ -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 {
|
||||
|
@@ -108,7 +108,7 @@ window-controls {
|
||||
|
||||
button:hover {
|
||||
background: rgba($black, 0.125);
|
||||
|
||||
|
||||
svg {
|
||||
fill: $black;
|
||||
}
|
||||
@@ -132,8 +132,6 @@ body {
|
||||
app-root {
|
||||
&> .content {
|
||||
.tab-bar {
|
||||
height: 40px;
|
||||
|
||||
.btn-tab-bar {
|
||||
background: transparent;
|
||||
line-height: 42px;
|
||||
@@ -171,6 +169,10 @@ app-root {
|
||||
background: $blue;
|
||||
}
|
||||
|
||||
.activity-indicator {
|
||||
background:rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $black;
|
||||
background: $content-bg;
|
||||
@@ -192,10 +194,6 @@ app-root {
|
||||
&.active {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
&.has-activity:not(.active) {
|
||||
background: linear-gradient(to bottom, rgba(208, 0, 0, 0) 95%, #36beff 96%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,10 +208,6 @@ app-root {
|
||||
&.active {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
&.has-activity:not(.active) {
|
||||
background: linear-gradient(to top, rgba(208, 0, 0, 0) 95%, #36beff 96%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,11 +224,10 @@ tab-body {
|
||||
background: $content-bg;
|
||||
}
|
||||
|
||||
settings-tab > ngb-tabset {
|
||||
border-right: 1px solid $body-bg;
|
||||
|
||||
settings-tab > .content {
|
||||
& > .nav {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border-right: 1px solid $body-bg;
|
||||
|
||||
& > .nav-item > .nav-link {
|
||||
border: none;
|
||||
@@ -317,10 +310,6 @@ hotkey-input-modal {
|
||||
}
|
||||
}
|
||||
|
||||
ngb-tabset .tab-content {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
[ngbradiogroup] > label.active {
|
||||
background: $blue;
|
||||
}
|
||||
|
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -74,6 +76,10 @@ app-root {
|
||||
background: $green;
|
||||
}
|
||||
|
||||
.activity-indicator {
|
||||
background:rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: white;
|
||||
background: $content-bg;
|
||||
@@ -95,10 +101,6 @@ app-root {
|
||||
&.active {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
&.has-activity:not(.active) {
|
||||
background: linear-gradient(to bottom, rgba(208, 0, 0, 0) 95%, #1aa99c 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +115,6 @@ app-root {
|
||||
&.active {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
&.has-activity:not(.active) {
|
||||
background: linear-gradient(to top, rgba(208, 0, 0, 0) 95%, #1aa99c 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,30 +131,6 @@ tab-body {
|
||||
background: $content-bg;
|
||||
}
|
||||
|
||||
settings-tab > ngb-tabset {
|
||||
border-right: 1px solid $body-bg;
|
||||
|
||||
& > .nav {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
flex-shrink: 0;
|
||||
|
||||
& > .nav-item > .nav-link {
|
||||
border: none;
|
||||
padding: 10px 50px 10px 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 0;
|
||||
|
||||
&:not(.active) {
|
||||
color: $body-color;
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multi-hotkey-input {
|
||||
.item {
|
||||
background: $body-bg2;
|
||||
@@ -219,10 +193,6 @@ hotkey-input-modal {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
ngb-tabset .tab-content {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
[ngbradiogroup] > label.active {
|
||||
background: $blue;
|
||||
}
|
||||
@@ -269,10 +239,6 @@ ngb-tabset .tab-content {
|
||||
border: none;
|
||||
border-top: 1px solid rgba(255, 255, 255, .1);
|
||||
|
||||
&:not(.combi) {
|
||||
padding: $list-group-item-padding-y $list-group-item-padding-x;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
@@ -319,7 +285,7 @@ checkbox i.on {
|
||||
}
|
||||
|
||||
search-panel {
|
||||
background: rgba(39, 49, 60, 0.65) !important;
|
||||
background: rgba(39, 49, 60, 0.95) !important;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -15,6 +15,8 @@ export class StandardCompactTheme extends Theme {
|
||||
name = 'Compact'
|
||||
css = require('./theme.compact.scss')
|
||||
terminalBackground = '#222a33'
|
||||
macOSWindowButtonsInsetX = 8
|
||||
macOSWindowButtonsInsetY = 12
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
|
@@ -46,7 +46,6 @@ $body-color: #ccc;
|
||||
$body-bg: #131d27;
|
||||
$body-bg2: #20333e;
|
||||
|
||||
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$font-family-monospace: "Source Code Pro";
|
||||
$font-size-base: 14rem / 16;
|
||||
@@ -55,6 +54,12 @@ $font-size-sm: .85rem;
|
||||
|
||||
$line-height-base: 1.6;
|
||||
|
||||
$border-radius: .4rem;
|
||||
$border-radius-lg: .6rem;
|
||||
$border-radius-sm: .2rem;
|
||||
|
||||
// -----
|
||||
|
||||
$headings-color: #ced9e2;
|
||||
$headings-font-weight: lighter;
|
||||
|
||||
|
@@ -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,17 @@
|
||||
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==
|
||||
"@electron/remote@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-1.0.4.tgz#f1c8cf3560bab762b462bfae9991919cced8bc33"
|
||||
integrity sha512-kguDJRhL3ZynHrkbX8Tr7xoAzGsNgh4eqXkycXb6cgXbOgehGqkBVe+MnjSVMXz3QJykerGKPy28gqcM7AFGYw==
|
||||
|
||||
"@types/semver@^7.3.1":
|
||||
"@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.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
|
||||
@@ -40,12 +45,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,26 +60,35 @@ 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"
|
||||
|
||||
clone-deep@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
|
||||
integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
|
||||
dependencies:
|
||||
is-plain-object "^2.0.4"
|
||||
kind-of "^6.0.2"
|
||||
shallow-clone "^3.0.0"
|
||||
|
||||
color-convert@^1.9.1:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
@@ -124,22 +136,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 +152,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 +165,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 +194,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 +209,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"
|
||||
@@ -249,6 +247,13 @@ is-arrayish@^0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-plain-object@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
|
||||
integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
|
||||
dependencies:
|
||||
isobject "^3.0.1"
|
||||
|
||||
is-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
|
||||
@@ -259,13 +264,17 @@ 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==
|
||||
isobject@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
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"
|
||||
@@ -276,6 +285,11 @@ jsonfile@^6.0.1:
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
kind-of@^6.0.2:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||
|
||||
kuler@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
|
||||
@@ -302,6 +316,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 +330,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 +340,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 +356,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 +408,19 @@ 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"
|
||||
|
||||
shallow-clone@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
|
||||
integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
|
||||
dependencies:
|
||||
kind-of "^6.0.2"
|
||||
|
||||
shell-escape@^0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -408,11 +434,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 +463,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 +479,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 +505,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,8 @@
|
||||
"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,42 +10,36 @@
|
||||
|
||||
.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}}
|
||||
|
||||
button.btn.btn-primary.ml-2(
|
||||
*ngIf='knownUpgrades[plugin.name]',
|
||||
(click)='upgradePlugin(plugin)',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-arrow-up(*ngIf='busy[plugin.name] != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
|
||||
i.fas.fa-fw.fa-arrow-up(*ngIf='busy.get(plugin.name) != BusyState.Installing')
|
||||
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',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-trash(*ngIf='busy[plugin.name] != BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-trash(*ngIf='busy.get(plugin.name) != BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Uninstalling')
|
||||
|
||||
div
|
||||
h3.mt-4 Available
|
||||
@@ -69,10 +62,10 @@ div
|
||||
.list-group-item.d-flex.align-items-center(*ngIf='!isAlreadyInstalled(plugin)')
|
||||
button.btn.btn-primary.mr-3(
|
||||
(click)='installPlugin(plugin)',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-download(*ngIf='busy[plugin.name] != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
|
||||
i.fas.fa-fw.fa-download(*ngIf='busy.get(plugin.name) != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing')
|
||||
|
||||
div((click)='showPluginInfo(plugin)')
|
||||
div
|
||||
|
@@ -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'),
|
||||
@@ -20,7 +22,7 @@ export class PluginsSettingsTabComponent {
|
||||
@Input() availablePluginsQuery$ = new BehaviorSubject<string>('')
|
||||
@Input() availablePluginsReady = false
|
||||
@Input() knownUpgrades: Record<string, PluginInfo|null> = {}
|
||||
@Input() busy: Record<string, BusyState> = {}
|
||||
@Input() busy = new Map<string, BusyState>()
|
||||
@Input() erroredPlugin: string
|
||||
@Input() errorMessage: string
|
||||
|
||||
@@ -67,29 +69,29 @@ export class PluginsSettingsTabComponent {
|
||||
}
|
||||
|
||||
async installPlugin (plugin: PluginInfo): Promise<void> {
|
||||
this.busy[plugin.name] = BusyState.Installing
|
||||
this.busy.set(plugin.name, BusyState.Installing)
|
||||
try {
|
||||
await this.pluginManager.installPlugin(plugin)
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
this.config.requestRestart()
|
||||
} catch (err) {
|
||||
this.erroredPlugin = plugin.name
|
||||
this.errorMessage = err
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
|
||||
this.busy[plugin.name] = BusyState.Uninstalling
|
||||
this.busy.set(plugin.name, BusyState.Uninstalling)
|
||||
try {
|
||||
await this.pluginManager.uninstallPlugin(plugin)
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
this.config.requestRestart()
|
||||
} catch (err) {
|
||||
this.erroredPlugin = plugin.name
|
||||
this.errorMessage = err
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -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,4 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import promiseIpc from 'electron-promise-ipc'
|
||||
import { Observable, from } from 'rxjs'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { Injectable } from '@angular/core'
|
||||
@@ -31,39 +32,15 @@ export class PluginManagerService {
|
||||
userPluginsPath: string = (window as any).userPluginsPath
|
||||
installedPlugins: PluginInfo[] = (window as any).installedPlugins
|
||||
|
||||
private npmReady: Promise<void>
|
||||
private npm: any
|
||||
|
||||
private constructor (
|
||||
log: LogService,
|
||||
) {
|
||||
this.logger = log.create('pluginManager')
|
||||
}
|
||||
|
||||
async getNPM (): Promise<any> {
|
||||
if (!this.npm) {
|
||||
if (!this.npmReady) {
|
||||
this.npmReady = new Promise(resolve => {
|
||||
const npm = (global as any).require('npm')
|
||||
npm.load({
|
||||
prefix: this.userPluginsPath,
|
||||
}, err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
this.npm = npm
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
await this.npmReady
|
||||
}
|
||||
return this.npm
|
||||
}
|
||||
|
||||
listAvailable (query?: string): Observable<PluginInfo[]> {
|
||||
return from(
|
||||
axios.get(`https://www.npmjs.com/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=1000`, {
|
||||
axios.get(`https://www.npmjs.com/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query ?? '')}&from=0&size=1000`, {
|
||||
headers: {
|
||||
'x-spiferack': '1',
|
||||
},
|
||||
@@ -80,25 +57,28 @@ export class PluginManagerService {
|
||||
}))),
|
||||
map(plugins => plugins.filter(x => x.packageName.startsWith(NAME_PREFIX))),
|
||||
map(plugins => plugins.filter(x => !BLACKLIST.includes(x.packageName))),
|
||||
map(plugins => plugins.sort((a, b) => a.name.localeCompare(b.name))),
|
||||
)
|
||||
}
|
||||
|
||||
async installPlugin (plugin: PluginInfo): Promise<void> {
|
||||
(await this.getNPM()).commands.install([`${plugin.packageName}@${plugin.version}`], err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
try {
|
||||
await (promiseIpc as any).send('plugin-manager:install', this.userPluginsPath, plugin.packageName, plugin.version)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
this.installedPlugins.push(plugin)
|
||||
})
|
||||
} catch (err) {
|
||||
this.logger.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
|
||||
(await this.getNPM()).commands.remove([plugin.packageName], err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
try {
|
||||
await (promiseIpc as any).send('plugin-manager:uninstall', this.userPluginsPath, plugin.packageName)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
})
|
||||
} catch (err) {
|
||||
this.logger.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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',
|
||||
'npm',
|
||||
'path',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'plugin-manager',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -12,31 +12,136 @@ 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"
|
||||
|
||||
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==
|
||||
call-bind@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce"
|
||||
integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.0"
|
||||
|
||||
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==
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
object-keys "^1.0.12"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
electron-promise-ipc@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-promise-ipc/-/electron-promise-ipc-2.2.4.tgz#b82daf86ca6d0f0b8655937fdbe9a554590deeea"
|
||||
integrity sha512-xCkFEeuru9l7H/+m1gpK4F1utexvTT7+n1PTquP2MVTpmBmpgFBlLqSXC7TqwpROkHRm9wGpaCJEx0djonnSEg==
|
||||
dependencies:
|
||||
is-electron-renderer "^2.0.1"
|
||||
object.entries "^1.1.3"
|
||||
serialize-error "^5.0.0"
|
||||
uuid "^3.0.1"
|
||||
|
||||
es-abstract@^1.18.0-next.1:
|
||||
version "1.18.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
|
||||
integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
|
||||
dependencies:
|
||||
es-to-primitive "^1.2.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
is-callable "^1.2.2"
|
||||
is-negative-zero "^2.0.0"
|
||||
is-regex "^1.1.1"
|
||||
object-inspect "^1.8.0"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.1"
|
||||
string.prototype.trimend "^1.0.1"
|
||||
string.prototype.trimstart "^1.0.1"
|
||||
|
||||
es-to-primitive@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
|
||||
dependencies:
|
||||
is-callable "^1.1.4"
|
||||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
get-intrinsic@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
|
||||
integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
has-symbols@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
|
||||
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
is-callable@^1.1.4, is-callable@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
|
||||
integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
|
||||
|
||||
is-date-object@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
|
||||
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
|
||||
|
||||
is-electron-renderer@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz#a469d056f975697c58c98c6023eb0aa79af895a2"
|
||||
integrity sha1-pGnQVvl1aXxYyYxgI+sKp5r4laI=
|
||||
|
||||
is-negative-zero@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
|
||||
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
|
||||
|
||||
is-regex@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
|
||||
integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
is-symbol@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
|
||||
integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
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"
|
||||
@@ -52,10 +157,65 @@ object-assign@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-inspect@^1.8.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
|
||||
integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
|
||||
|
||||
object-keys@^1.0.12, object-keys@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
object.assign@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
|
||||
integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
has-symbols "^1.0.1"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
object.entries@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.3.tgz#c601c7f168b62374541a07ddbd3e2d5e4f7711a6"
|
||||
integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.18.0-next.1"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-5.0.0.tgz#a7ebbcdb03a5d71a6ed8461ffe0fc1a1afed62ac"
|
||||
integrity sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==
|
||||
dependencies:
|
||||
type-fest "^0.8.0"
|
||||
|
||||
string.prototype.trimend@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b"
|
||||
integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
|
||||
string.prototype.trimstart@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa"
|
||||
integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
|
||||
thenify-all@^1.0.0:
|
||||
version "1.6.0"
|
||||
@@ -70,3 +230,18 @@ thenify-all@^1.0.0:
|
||||
integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
type-fest@^0.8.0:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
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",
|
||||
|