mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-06 01:11:56 +00:00
Compare commits
394 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8b307be92d | ||
![]() |
45516c4013 | ||
![]() |
5d8f7a4e34 | ||
![]() |
792c9279e2 | ||
![]() |
8825a8163e | ||
![]() |
7e42328c6f | ||
![]() |
2dd99d43ed | ||
![]() |
991b4fc965 | ||
![]() |
e9d7af5320 | ||
![]() |
bff23fe825 | ||
![]() |
79bd94ee6f | ||
![]() |
fdd833ef7c | ||
![]() |
c386504296 | ||
![]() |
9cc8649422 | ||
![]() |
625a9179c5 | ||
![]() |
66ed73f7c9 | ||
![]() |
95bd48d6c6 | ||
![]() |
328490a85e | ||
![]() |
d08413aeab | ||
![]() |
922f1fbade | ||
![]() |
cb96c8d470 | ||
![]() |
f3ebc43667 | ||
![]() |
e7696dcdf3 | ||
![]() |
4abf7d7738 | ||
![]() |
be206161d6 | ||
![]() |
dcd17f886e | ||
![]() |
2c94dea941 | ||
![]() |
7a2291f7db | ||
![]() |
af0d9142ed | ||
![]() |
6ba7d5b78f | ||
![]() |
bbf035d5fd | ||
![]() |
84bc4369cb | ||
![]() |
e01f77998c | ||
![]() |
08acd4df46 | ||
![]() |
2c9d968aa8 | ||
![]() |
19a3996861 | ||
![]() |
7cbec63039 | ||
![]() |
91320f1cd7 | ||
![]() |
5518ce5e0c | ||
![]() |
d59c52d7a5 | ||
![]() |
dd3a4cb289 | ||
![]() |
fc6ded4b1a | ||
![]() |
d4f61b3846 | ||
![]() |
ffad7b6ba7 | ||
![]() |
499f541328 | ||
![]() |
7c893a3c4b | ||
![]() |
1f5c55826b | ||
![]() |
197824004e | ||
![]() |
ee1d465bf6 | ||
![]() |
12bb070def | ||
![]() |
13ab29bcab | ||
![]() |
8cf0445b6d | ||
![]() |
90cc06c3fd | ||
![]() |
7d7b2cbcfd | ||
![]() |
3a76e0bb2e | ||
![]() |
9e2d070ed4 | ||
![]() |
f796718cae | ||
![]() |
a4c2ccdb93 | ||
![]() |
ccbaf1c2c2 | ||
![]() |
7ccd97eb49 | ||
![]() |
6b320e9cf3 | ||
![]() |
a6a5f2b132 | ||
![]() |
6fd7e97ef2 | ||
![]() |
fc821b5abd | ||
![]() |
f69a9b38fe | ||
![]() |
710b9d79ab | ||
![]() |
fddae662c8 | ||
![]() |
c3b3a3cea6 | ||
![]() |
2201cfe142 | ||
![]() |
a9ae3b2475 | ||
![]() |
3238706b25 | ||
![]() |
a5aec13b7f | ||
![]() |
454887ad21 | ||
![]() |
0ad585d647 | ||
![]() |
5aa3b889f5 | ||
![]() |
d371857fa8 | ||
![]() |
e116a42f8b | ||
![]() |
76acbc6c9f | ||
![]() |
572a6e24c4 | ||
![]() |
b3731a21ba | ||
![]() |
f58ba65d97 | ||
![]() |
45a99bb0cb | ||
![]() |
ab70be983a | ||
![]() |
cad1f96df7 | ||
![]() |
71866521f4 | ||
![]() |
56206d4fb8 | ||
![]() |
347681d199 | ||
![]() |
e6abdcf3e9 | ||
![]() |
dbae3b66cd | ||
![]() |
40ec457d20 | ||
![]() |
063caf3bcd | ||
![]() |
9325fd0977 | ||
![]() |
6231583590 | ||
![]() |
fce3a2c822 | ||
![]() |
73f45c9a24 | ||
![]() |
ca65f23c70 | ||
![]() |
f525398827 | ||
![]() |
cf2baa74a8 | ||
![]() |
fbd896d593 | ||
![]() |
f747107042 | ||
![]() |
760ad140cd | ||
![]() |
a0df434ed2 | ||
![]() |
0bcd5cfd8f | ||
![]() |
e0b71783c0 | ||
![]() |
45b76b2d3e | ||
![]() |
8228c99350 | ||
![]() |
c4dbd8180d | ||
![]() |
d3b1545a1e | ||
![]() |
57d7936239 | ||
![]() |
9e5315043d | ||
![]() |
89ba81f2e1 | ||
![]() |
1ee734cd18 | ||
![]() |
0bcfb6babf | ||
![]() |
fddd9e9db2 | ||
![]() |
2433fd1442 | ||
![]() |
437d832ac1 | ||
![]() |
c90aef1dfa | ||
![]() |
2d25f15041 | ||
![]() |
993d5bfd25 | ||
![]() |
4d8681b5ee | ||
![]() |
1384e26dd8 | ||
![]() |
809bf3360d | ||
![]() |
444875b82a | ||
![]() |
c261b64c8e | ||
![]() |
ab1b8a4500 | ||
![]() |
e65d5ba93b | ||
![]() |
6f8ba6b44b | ||
![]() |
aede1c47a2 | ||
![]() |
7b9ff043ad | ||
![]() |
d759104c76 | ||
![]() |
676bbba7a4 | ||
![]() |
b8d9f6442a | ||
![]() |
fc501b5e51 | ||
![]() |
3ddec27b69 | ||
![]() |
6574cf6b50 | ||
![]() |
d36ef2e48e | ||
![]() |
f8645df60c | ||
![]() |
f69942a3a3 | ||
![]() |
a36431a08c | ||
![]() |
f570d7e428 | ||
![]() |
fb502bc926 | ||
![]() |
2e12041688 | ||
![]() |
ca444bcf65 | ||
![]() |
da1b7b9a80 | ||
![]() |
e02d458109 | ||
![]() |
51e1a19e3e | ||
![]() |
68869a52e2 | ||
![]() |
8527c3f531 | ||
![]() |
4317094f1f | ||
![]() |
00cf7ef67d | ||
![]() |
21e7e762cd | ||
![]() |
ebb35cf9be | ||
![]() |
bd7f9a8030 | ||
![]() |
b1e0ed457e | ||
![]() |
59e40d53a1 | ||
![]() |
666a180f3f | ||
![]() |
ffc767c738 | ||
![]() |
49b252f7cf | ||
![]() |
81e9a0c796 | ||
![]() |
f3f5b21910 | ||
![]() |
b29ab2690f | ||
![]() |
f58cab0820 | ||
![]() |
b21631acd8 | ||
![]() |
52258f9949 | ||
![]() |
1308e842ce | ||
![]() |
c4ba51f4ee | ||
![]() |
65d411b00d | ||
![]() |
52d596b01b | ||
![]() |
1607dd90ba | ||
![]() |
11767f7d27 | ||
![]() |
7cbcf6844d | ||
![]() |
9f36258c60 | ||
![]() |
8f964ffc37 | ||
![]() |
4c137996ff | ||
![]() |
966bd5f917 | ||
![]() |
b55011d595 | ||
![]() |
38bd59641e | ||
![]() |
c449b60940 | ||
![]() |
ee618cdd1f | ||
![]() |
a5bddc21bb | ||
![]() |
35bf195f42 | ||
![]() |
044c2dda0e | ||
![]() |
9f2a70fc88 | ||
![]() |
409476c729 | ||
![]() |
91f8f25d26 | ||
![]() |
f853839939 | ||
![]() |
6099b44723 | ||
![]() |
e4e8140145 | ||
![]() |
8b34ab5102 | ||
![]() |
6dc987163d | ||
![]() |
a082c71a52 | ||
![]() |
cc37725014 | ||
![]() |
c6fd86dca6 | ||
![]() |
7f55d6f1e2 | ||
![]() |
129a7c1a09 | ||
![]() |
4969c4e2fc | ||
![]() |
d290fbe933 | ||
![]() |
358d3d82d6 | ||
![]() |
9b560c79ab | ||
![]() |
8b58bc420d | ||
![]() |
78a74ffe1b | ||
![]() |
565c675ce1 | ||
![]() |
a25a13188d | ||
![]() |
2daf85f753 | ||
![]() |
3189258fbb | ||
![]() |
d678bf68c5 | ||
![]() |
9498b17b98 | ||
![]() |
b48a335aed | ||
![]() |
71488e749a | ||
![]() |
0f1cbfa3ee | ||
![]() |
32d33bf85e | ||
![]() |
c7f1aa895d | ||
![]() |
675bc3d281 | ||
![]() |
c63ba8c22b | ||
![]() |
e9be73226e | ||
![]() |
4a72e554b6 | ||
![]() |
33bb3b0722 | ||
![]() |
46b4288c98 | ||
![]() |
9477117236 | ||
![]() |
33e048238e | ||
![]() |
5895d42444 | ||
![]() |
5d6abca503 | ||
![]() |
8ca91af927 | ||
![]() |
c886fd6915 | ||
![]() |
e403ca6eff | ||
![]() |
8f1b401137 | ||
![]() |
0952899204 | ||
![]() |
a11c643e41 | ||
![]() |
17fbdeafac | ||
![]() |
06e09f3a45 | ||
![]() |
4fa63aa939 | ||
![]() |
46622cd5d9 | ||
![]() |
6d3aace1c9 | ||
![]() |
e3a569be18 | ||
![]() |
2a256ef2bd | ||
![]() |
4f3fcc8b22 | ||
![]() |
045cc0d243 | ||
![]() |
51e33abbe6 | ||
![]() |
4900c043ca | ||
![]() |
09d55979ce | ||
![]() |
5d431fa9cf | ||
![]() |
113573b2d2 | ||
![]() |
2c3d93608b | ||
![]() |
d38af18582 | ||
![]() |
140f7c51f4 | ||
![]() |
ffa4350420 | ||
![]() |
99737323de | ||
![]() |
e9e2429632 | ||
![]() |
07597ac79a | ||
![]() |
248ec60612 | ||
![]() |
726847d5df | ||
![]() |
6065a95132 | ||
![]() |
e1259475d2 | ||
![]() |
ee018e7c02 | ||
![]() |
db43381f0d | ||
![]() |
28c58d4ec0 | ||
![]() |
68efe2b3c4 | ||
![]() |
795979be07 | ||
![]() |
c87a1b92d3 | ||
![]() |
2548ad6605 | ||
![]() |
b6519c6626 | ||
![]() |
2b8bb47aed | ||
![]() |
bbf332171e | ||
![]() |
ef5c9b52a5 | ||
![]() |
4632523d70 | ||
![]() |
56b996e6e4 | ||
![]() |
0ca0996493 | ||
![]() |
e1a8e72742 | ||
![]() |
50959f4490 | ||
![]() |
baaebb402e | ||
![]() |
9e862772eb | ||
![]() |
6cb5505ded | ||
![]() |
eb0d8615e1 | ||
![]() |
f2885c2fce | ||
![]() |
c04018bc70 | ||
![]() |
3e5032ca8b | ||
![]() |
a5014243d9 | ||
![]() |
2692eb141c | ||
![]() |
b447f1d52e | ||
![]() |
606b9af3f1 | ||
![]() |
3deab9af24 | ||
![]() |
afab0c5cde | ||
![]() |
e1a03f0dfb | ||
![]() |
bfe8dfab02 | ||
![]() |
a4335edc07 | ||
![]() |
8613698be9 | ||
![]() |
731ddc3e28 | ||
![]() |
2303e32256 | ||
![]() |
9064f123b3 | ||
![]() |
9d3ee4a612 | ||
![]() |
20602eed6d | ||
![]() |
f2cd86738c | ||
![]() |
fc55446342 | ||
![]() |
dbc12c06cb | ||
![]() |
efb551cd94 | ||
![]() |
a87c1aa864 | ||
![]() |
555f55592a | ||
![]() |
ab46739986 | ||
![]() |
7ac7958462 | ||
![]() |
46d5dace8f | ||
![]() |
aace3f42d0 | ||
![]() |
c4297f2b2b | ||
![]() |
3c90e904fc | ||
![]() |
f8c8065e4a | ||
![]() |
d45a5a35d8 | ||
![]() |
a9c6b868fb | ||
![]() |
ffe8168f0f | ||
![]() |
d1f5ebd546 | ||
![]() |
2e8b465b3f | ||
![]() |
4a535c94a6 | ||
![]() |
531d47cbd1 | ||
![]() |
7a2491fe49 | ||
![]() |
2773c61677 | ||
![]() |
788b063384 | ||
![]() |
0e112899df | ||
![]() |
d8c635bc1d | ||
![]() |
dfe55b94ff | ||
![]() |
6b4b6b522f | ||
![]() |
0d65fe348b | ||
![]() |
e4b7693685 | ||
![]() |
566aa83fa9 | ||
![]() |
eb2d88eac2 | ||
![]() |
316b77ec7b | ||
![]() |
a4dc6832f3 | ||
![]() |
7a895dda1a | ||
![]() |
b2fc016aa8 | ||
![]() |
32096ea4fd | ||
![]() |
30fd36ed26 | ||
![]() |
afdf09076a | ||
![]() |
04a0a0cc64 | ||
![]() |
fda4d2dcef | ||
![]() |
2c341e23b5 | ||
![]() |
953b06f43f | ||
![]() |
e1cc1d56ea | ||
![]() |
df2f4d4a6c | ||
![]() |
092820173f | ||
![]() |
58c7c23bd8 | ||
![]() |
920afe450a | ||
![]() |
e0eedca7c9 | ||
![]() |
3edcce29fa | ||
![]() |
e14c7fec10 | ||
![]() |
b3ed62244d | ||
![]() |
ff1bfa990c | ||
![]() |
bd3463880e | ||
![]() |
95a61ec369 | ||
![]() |
1b29797a81 | ||
![]() |
10b21ee085 | ||
![]() |
f5ffdc1707 | ||
![]() |
b3f17b84ff | ||
![]() |
1a332128e3 | ||
![]() |
b5db7e80d0 | ||
![]() |
5bba719624 | ||
![]() |
09d6838b08 | ||
![]() |
325d2dc2a4 | ||
![]() |
94c7e2b5c3 | ||
![]() |
9da2e8d489 | ||
![]() |
ff1c5df30b | ||
![]() |
159adf9911 | ||
![]() |
994a94f8f1 | ||
![]() |
571db20523 | ||
![]() |
a422d62db0 | ||
![]() |
feb2a52b37 | ||
![]() |
267ca2e95c | ||
![]() |
9691a932ac | ||
![]() |
94d51c029e | ||
![]() |
efd7b2ca2b | ||
![]() |
ed88784431 | ||
![]() |
e48f844ea0 | ||
![]() |
fd21be5408 | ||
![]() |
f4c2d01df8 | ||
![]() |
4828bb4df7 | ||
![]() |
037e91508b | ||
![]() |
735010dd1f | ||
![]() |
11364dd788 | ||
![]() |
0eced6f4a9 | ||
![]() |
3157c89be3 | ||
![]() |
a7f909d06a | ||
![]() |
527b55a46e | ||
![]() |
a610306f29 | ||
![]() |
3daf0b394e | ||
![]() |
f151928b6b | ||
![]() |
041a3ce2b6 | ||
![]() |
6348e7b8f0 | ||
![]() |
8be72618e6 | ||
![]() |
a50c7cb474 | ||
![]() |
8cef4e5cf9 | ||
![]() |
9705a1b5b5 | ||
![]() |
dfa17948e2 | ||
![]() |
3607391d55 | ||
![]() |
e7f2f54f1b | ||
![]() |
b467c7de65 | ||
![]() |
c3e793229d | ||
![]() |
14bcfb01c2 | ||
![]() |
5d28369b8b |
@@ -243,6 +243,34 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "nstefanou",
|
||||||
|
"name": "nstefanou",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/51129173?v=4",
|
||||||
|
"profile": "https://github.com/nstefanou",
|
||||||
|
"contributions": [
|
||||||
|
"code",
|
||||||
|
"plugin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "orin220444",
|
||||||
|
"name": "orin220444",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/30747229?v=4",
|
||||||
|
"profile": "https://github.com/orin220444",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Goobles",
|
||||||
|
"name": "Gobius Dolhain",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/8776771?v=4",
|
||||||
|
"profile": "https://github.com/Goobles",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
@@ -99,3 +99,8 @@ rules:
|
|||||||
'@typescript-eslint/restrict-template-expressions': off
|
'@typescript-eslint/restrict-template-expressions': off
|
||||||
'@typescript-eslint/no-dynamic-delete': off
|
'@typescript-eslint/no-dynamic-delete': off
|
||||||
'@typescript-eslint/prefer-nullish-coalescing': 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
|
||||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
version: 10
|
node-version: 10
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
version: 10
|
node-version: 10
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
|
5
.github/workflows/linux.yml
vendored
5
.github/workflows/linux.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
version: 10
|
node-version: 10
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
@@ -25,9 +25,6 @@ jobs:
|
|||||||
- name: Build native deps
|
- name: Build native deps
|
||||||
run: scripts/build-native.js
|
run: scripts/build-native.js
|
||||||
|
|
||||||
- name: Build typings
|
|
||||||
run: yarn run build:typings
|
|
||||||
|
|
||||||
- name: Webpack
|
- name: Webpack
|
||||||
run: yarn run build
|
run: yarn run build
|
||||||
|
|
||||||
|
9
.github/workflows/macos.yml
vendored
9
.github/workflows/macos.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
version: 10
|
node-version: 10
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
@@ -25,15 +25,14 @@ jobs:
|
|||||||
- name: Build native deps
|
- name: Build native deps
|
||||||
run: scripts/build-native.js
|
run: scripts/build-native.js
|
||||||
|
|
||||||
- name: Build typings
|
|
||||||
run: yarn run build:typings
|
|
||||||
|
|
||||||
- name: Webpack
|
- name: Webpack
|
||||||
run: yarn run build
|
run: yarn run build
|
||||||
|
|
||||||
- name: Prepackage plugins
|
- name: Prepackage plugins
|
||||||
run: scripts/prepackage-plugins.js
|
run: scripts/prepackage-plugins.js
|
||||||
|
|
||||||
|
- run: sed -i '' 's/updateInfo = await/\/\/updateInfo = await/g' node_modules/app-builder-lib/out/targets/ArchiveTarget.js
|
||||||
|
|
||||||
- name: Build and sign packages
|
- name: Build and sign packages
|
||||||
run: scripts/build-macos.js
|
run: scripts/build-macos.js
|
||||||
if: github.repository == 'Eugeny/terminus' && github.event_name == 'push'
|
if: github.repository == 'Eugeny/terminus' && github.event_name == 'push'
|
||||||
@@ -42,6 +41,8 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||||
|
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
|
||||||
|
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
|
||||||
|
|
||||||
- name: Build packages without signing
|
- name: Build packages without signing
|
||||||
run: scripts/build-macos.js
|
run: scripts/build-macos.js
|
||||||
|
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
version: 10
|
node-version: 10
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: powershell
|
shell: powershell
|
||||||
|
@@ -106,6 +106,11 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<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://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/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/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -8,17 +8,15 @@ html
|
|||||||
window.nodeRequire = require
|
window.nodeRequire = require
|
||||||
script(src='./preload.js')
|
script(src='./preload.js')
|
||||||
script(src='./bundle.js', defer)
|
script(src='./bundle.js', defer)
|
||||||
style#custom-css
|
|
||||||
style.
|
style.
|
||||||
body { transition: 0.5s background; }
|
body { transition: 0.5s background; }
|
||||||
body
|
body
|
||||||
|
style#custom-css
|
||||||
app-root
|
app-root
|
||||||
.preload-logo
|
.preload-logo
|
||||||
div
|
div
|
||||||
.terminus-logo
|
.terminus-logo
|
||||||
h1.terminus-title Terminus
|
h1.terminus-title Terminus
|
||||||
sup α
|
sup α
|
||||||
.progress
|
.progress
|
||||||
.bar(style='width: 0%')
|
.bar(style='width: 0%')
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { app, ipcMain, Menu, Tray, shell } from 'electron'
|
import { app, ipcMain, Menu, Tray, shell, globalShortcut } from 'electron'
|
||||||
// eslint-disable-next-line no-duplicate-imports
|
// eslint-disable-next-line no-duplicate-imports
|
||||||
import * as electron from 'electron'
|
import * as electron from 'electron'
|
||||||
import { loadConfig } from './config'
|
import { loadConfig } from './config'
|
||||||
@@ -9,8 +9,17 @@ export class Application {
|
|||||||
private windows: Window[] = []
|
private windows: Window[] = []
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
ipcMain.on('app:config-change', () => {
|
ipcMain.on('app:config-change', (_event, config) => {
|
||||||
this.broadcast('host:config-change')
|
this.broadcast('host:config-change', config)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('app:register-global-hotkey', (_event, specs) => {
|
||||||
|
globalShortcut.unregisterAll()
|
||||||
|
for (let spec of specs) {
|
||||||
|
globalShortcut.register(spec, () => {
|
||||||
|
this.onGlobalHotkey()
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const configData = loadConfig()
|
const configData = loadConfig()
|
||||||
@@ -31,7 +40,7 @@ export class Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init () {
|
init (): void {
|
||||||
electron.screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
|
electron.screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +54,9 @@ export class Application {
|
|||||||
this.enableTray()
|
this.enableTray()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
window.closed$.subscribe(() => {
|
||||||
|
this.windows = this.windows.filter(x => x !== window)
|
||||||
|
})
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
this.setupMenu()
|
this.setupMenu()
|
||||||
}
|
}
|
||||||
@@ -52,20 +64,38 @@ export class Application {
|
|||||||
return window
|
return window
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcast (event, ...args) {
|
onGlobalHotkey (): void {
|
||||||
|
if (this.windows.some(x => x.isFocused())) {
|
||||||
|
for (let window of this.windows) {
|
||||||
|
window.hide()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let window of this.windows) {
|
||||||
|
window.present()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
presentAllWindows (): void {
|
||||||
for (let window of this.windows) {
|
for (let window of this.windows) {
|
||||||
|
window.present()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcast (event: string, ...args): void {
|
||||||
|
for (const window of this.windows) {
|
||||||
window.send(event, ...args)
|
window.send(event, ...args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async send (event, ...args) {
|
async send (event: string, ...args): Promise<void> {
|
||||||
if (!this.hasWindows()) {
|
if (!this.hasWindows()) {
|
||||||
await this.newWindow()
|
await this.newWindow()
|
||||||
}
|
}
|
||||||
this.windows.filter(w => !w.isDestroyed())[0].send(event, ...args)
|
this.windows.filter(w => !w.isDestroyed())[0].send(event, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
enableTray () {
|
enableTray (): void {
|
||||||
if (this.tray) {
|
if (this.tray) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -90,23 +120,30 @@ export class Application {
|
|||||||
this.tray.setToolTip(`Terminus ${app.getVersion()}`)
|
this.tray.setToolTip(`Terminus ${app.getVersion()}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
disableTray () {
|
disableTray (): void {
|
||||||
if (this.tray) {
|
if (this.tray) {
|
||||||
this.tray.destroy()
|
this.tray.destroy()
|
||||||
this.tray = null
|
this.tray = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasWindows () {
|
hasWindows (): boolean {
|
||||||
return !!this.windows.length
|
return !!this.windows.length
|
||||||
}
|
}
|
||||||
|
|
||||||
focus () {
|
focus (): void {
|
||||||
for (let window of this.windows) {
|
for (let window of this.windows) {
|
||||||
window.show()
|
window.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSecondInstance (argv: string[], cwd: string): void {
|
||||||
|
this.presentAllWindows()
|
||||||
|
for (let window of this.windows) {
|
||||||
|
window.handleSecondInstance(argv, cwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setupMenu () {
|
private setupMenu () {
|
||||||
let template: Electron.MenuItemConstructorOptions[] = [
|
let template: Electron.MenuItemConstructorOptions[] = [
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
|
|
||||||
export function parseArgs (argv, cwd) {
|
export function parseArgs (argv: string[], cwd: string): any {
|
||||||
if (argv[0].includes('node')) {
|
if (argv[0].includes('node')) {
|
||||||
argv = argv.slice(1)
|
argv = argv.slice(1)
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@ process.on('uncaughtException' as any, err => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
app.on('second-instance', (_event, argv, cwd) => {
|
app.on('second-instance', (_event, argv, cwd) => {
|
||||||
application.send('host:second-instance', parseArgs(argv, cwd), cwd)
|
application.handleSecondInstance(argv, cwd)
|
||||||
})
|
})
|
||||||
|
|
||||||
const argv = parseArgs(process.argv, process.cwd())
|
const argv = parseArgs(process.argv, process.cwd())
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { Subject, Observable } from 'rxjs'
|
import { Subject, Observable } from 'rxjs'
|
||||||
import { debounceTime } from 'rxjs/operators'
|
import { debounceTime } from 'rxjs/operators'
|
||||||
import { BrowserWindow, app, ipcMain, Rectangle, screen } from 'electron'
|
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen } from 'electron'
|
||||||
import ElectronConfig = require('electron-config')
|
import ElectronConfig = require('electron-config')
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import { parseArgs } from './cli'
|
||||||
import { loadConfig } from './config'
|
import { loadConfig } from './config'
|
||||||
|
|
||||||
let SetWindowCompositionAttribute: any
|
let SetWindowCompositionAttribute: any
|
||||||
@@ -23,17 +24,20 @@ export interface WindowOptions {
|
|||||||
export class Window {
|
export class Window {
|
||||||
ready: Promise<void>
|
ready: Promise<void>
|
||||||
private visible = new Subject<boolean>()
|
private visible = new Subject<boolean>()
|
||||||
|
private closed = new Subject<void>()
|
||||||
private window: BrowserWindow
|
private window: BrowserWindow
|
||||||
private windowConfig: ElectronConfig
|
private windowConfig: ElectronConfig
|
||||||
private windowBounds: Rectangle
|
private windowBounds: Rectangle
|
||||||
private closing = false
|
private closing = false
|
||||||
private lastVibrancy: {enabled: boolean, type?: string} | null = null
|
private lastVibrancy: {enabled: boolean, type?: string} | null = null
|
||||||
private disableVibrancyWhileDragging = false
|
private disableVibrancyWhileDragging = false
|
||||||
|
private configStore: any
|
||||||
|
|
||||||
get visible$ (): Observable<boolean> { return this.visible }
|
get visible$ (): Observable<boolean> { return this.visible }
|
||||||
|
get closed$ (): Observable<void> { return this.closed }
|
||||||
|
|
||||||
constructor (options?: WindowOptions) {
|
constructor (options?: WindowOptions) {
|
||||||
let configData = loadConfig()
|
this.configStore = loadConfig()
|
||||||
|
|
||||||
options = options || {}
|
options = options || {}
|
||||||
|
|
||||||
@@ -70,7 +74,7 @@ export class Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((configData.appearance || {}).frame === 'native') {
|
if ((this.configStore.appearance || {}).frame === 'native') {
|
||||||
bwOptions.frame = true
|
bwOptions.frame = true
|
||||||
} else {
|
} else {
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
@@ -86,7 +90,7 @@ export class Window {
|
|||||||
this.window.once('ready-to-show', () => {
|
this.window.once('ready-to-show', () => {
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
this.window.setVibrancy('window')
|
this.window.setVibrancy('window')
|
||||||
} else if (process.platform === 'win32' && (configData.appearance || {}).vibrancy) {
|
} else if (process.platform === 'win32' && (this.configStore.appearance || {}).vibrancy) {
|
||||||
this.setVibrancy(true)
|
this.setVibrancy(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +101,13 @@ export class Window {
|
|||||||
this.window.show()
|
this.window.show()
|
||||||
}
|
}
|
||||||
this.window.focus()
|
this.window.focus()
|
||||||
|
this.window.moveTop()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.window.on('blur', () => {
|
||||||
|
if (this.configStore.appearance?.dockHideOnBlur) {
|
||||||
|
this.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -119,7 +130,7 @@ export class Window {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setVibrancy (enabled: boolean, type?: string) {
|
setVibrancy (enabled: boolean, type?: string): void {
|
||||||
this.lastVibrancy = { enabled, type }
|
this.lastVibrancy = { enabled, type }
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
if (parseFloat(os.release()) >= 10) {
|
if (parseFloat(os.release()) >= 10) {
|
||||||
@@ -140,25 +151,74 @@ export class Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
show (): void {
|
||||||
this.window.show()
|
this.window.show()
|
||||||
|
this.window.moveTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
focus () {
|
focus (): void {
|
||||||
this.window.focus()
|
this.window.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
send (event, ...args) {
|
send (event: string, ...args): void {
|
||||||
if (!this.window) {
|
if (!this.window) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.window.webContents.send(event, ...args)
|
this.window.webContents.send(event, ...args)
|
||||||
|
if (event === 'host:config-change') {
|
||||||
|
this.configStore = args[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isDestroyed () {
|
isDestroyed (): boolean {
|
||||||
return !this.window || this.window.isDestroyed()
|
return !this.window || this.window.isDestroyed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isFocused (): boolean {
|
||||||
|
return this.window.isFocused()
|
||||||
|
}
|
||||||
|
|
||||||
|
hide (): void {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
// Lose focus
|
||||||
|
Menu.sendActionToFirstResponder('hide:')
|
||||||
|
}
|
||||||
|
this.window.blur()
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
this.window.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
present (): void {
|
||||||
|
if (!this.window.isVisible()) {
|
||||||
|
// unfocused, invisible
|
||||||
|
this.window.show()
|
||||||
|
this.window.focus()
|
||||||
|
} else {
|
||||||
|
if (!this.configStore.appearance?.dock || this.configStore.appearance?.dock === 'off') {
|
||||||
|
// not docked, visible
|
||||||
|
setTimeout(() => {
|
||||||
|
this.window.show()
|
||||||
|
this.window.focus()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (this.configStore.appearance?.dockAlwaysOnTop) {
|
||||||
|
// docked, visible, on top
|
||||||
|
this.window.hide()
|
||||||
|
} else {
|
||||||
|
// docked, visible, not on top
|
||||||
|
this.window.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSecondInstance (argv: string[], cwd: string): void {
|
||||||
|
if (!this.configStore.appearance?.dock) {
|
||||||
|
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setupWindowManagement () {
|
private setupWindowManagement () {
|
||||||
this.window.on('show', () => {
|
this.window.on('show', () => {
|
||||||
this.visible.next(true)
|
this.visible.next(true)
|
||||||
@@ -326,6 +386,8 @@ export class Window {
|
|||||||
|
|
||||||
private destroy () {
|
private destroy () {
|
||||||
this.window = null
|
this.window = null
|
||||||
|
this.closed.next()
|
||||||
this.visible.complete()
|
this.visible.complete()
|
||||||
|
this.closed.complete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,34 +13,35 @@
|
|||||||
"watch": "webpack --progress --color --watch"
|
"watch": "webpack --progress --color --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "7.2.8",
|
"@angular/animations": "9.1.9",
|
||||||
"@angular/common": "7.2.8",
|
"@angular/common": "9.1.9",
|
||||||
"@angular/compiler": "7.2.8",
|
"@angular/compiler": "9.1.9",
|
||||||
"@angular/core": "7.2.8",
|
"@angular/core": "9.1.9",
|
||||||
"@angular/forms": "7.2.8",
|
"@angular/forms": "9.1.9",
|
||||||
"@angular/platform-browser": "7.2.8",
|
"@angular/platform-browser": "9.1.9",
|
||||||
"@angular/platform-browser-dynamic": "7.2.8",
|
"@angular/platform-browser-dynamic": "9.1.9",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^4.2.2",
|
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
|
||||||
"devtron": "1.4.0",
|
"devtron": "1.4.0",
|
||||||
"electron-config": "2.0.0",
|
"electron-config": "2.0.0",
|
||||||
"electron-debug": "^3.0.1",
|
"electron-debug": "^3.0.1",
|
||||||
"electron-is-dev": "1.1.0",
|
"electron-is-dev": "1.1.0",
|
||||||
"electron-updater": "^4.2.0",
|
"electron-updater": "^4.3.1",
|
||||||
"fontmanager-redux": "0.4.0",
|
"fontmanager-redux": "0.4.0",
|
||||||
"js-yaml": "3.13.1",
|
"js-yaml": "3.14.0",
|
||||||
"keytar": "^5.2.0",
|
"keytar": "^5.6.0",
|
||||||
"mz": "^2.7.0",
|
"mz": "^2.7.0",
|
||||||
"ngx-toastr": "^10.2.0",
|
"ngx-toastr": "^12.0.1",
|
||||||
"node-pty": "^0.10.0-beta2",
|
"node-pty": "^0.10.0-beta9",
|
||||||
"npm": "6.9.0",
|
"npm": "6.9.0",
|
||||||
"path": "0.12.7",
|
"path": "0.12.7",
|
||||||
"rxjs": "^6.5.4",
|
"rxjs": "^6.5.5",
|
||||||
"rxjs-compat": "^6.5.4",
|
"rxjs-compat": "^6.5.5",
|
||||||
"yargs": "^15.1.0",
|
"yargs": "^15.3.1",
|
||||||
"zone.js": "^0.8.29"
|
"zone.js": "^0.10.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"macos-native-processlist": "^1.0.2",
|
"macos-native-processlist": "^1.0.2",
|
||||||
|
"serialport": "^9.0.0",
|
||||||
"windows-blurbehind": "^1.0.1",
|
"windows-blurbehind": "^1.0.1",
|
||||||
"windows-native-registry": "^1.0.17",
|
"windows-native-registry": "^1.0.17",
|
||||||
"windows-process-tree": "^0.2.4",
|
"windows-process-tree": "^0.2.4",
|
||||||
@@ -49,6 +50,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mz": "0.0.32",
|
"@types/mz": "0.0.32",
|
||||||
"@types/node": "12.7.12",
|
"@types/node": "12.7.12",
|
||||||
"node-abi": "^2.15.0"
|
"node-abi": "^2.17.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { BrowserModule } from '@angular/platform-browser'
|
import { BrowserModule } from '@angular/platform-browser'
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
@@ -7,7 +8,7 @@ export function getRootModule (plugins: any[]) {
|
|||||||
const imports = [
|
const imports = [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
...plugins,
|
...plugins,
|
||||||
NgbModule.forRoot(),
|
NgbModule,
|
||||||
ToastrModule.forRoot({
|
ToastrModule.forRoot({
|
||||||
positionClass: 'toast-bottom-center',
|
positionClass: 'toast-bottom-center',
|
||||||
toastClass: 'toast',
|
toastClass: 'toast',
|
||||||
|
352
app/yarn.lock
352
app/yarn.lock
@@ -2,61 +2,111 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@angular/animations@7.2.8":
|
"@angular/animations@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.8.tgz#0285364c839c660a934ab0f753ec21424bfb292e"
|
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.1.9.tgz#de54334ea195189402487855c9a98f5618605da4"
|
||||||
integrity sha512-dJn9koYukyz15TouBc+z5z9fdThDk+bKgdlij25eYSu5Mpmtk04gB4eIMQA97K0UDh1d4YukgSJ5w3ZIk0m8DQ==
|
integrity sha512-qWVi0TxmU6HeXAgEsfpQvFFygh+a0kH2kGe6bWij4XvG6dWfV3xZjlaFwSIYGk+yK4yL0+9+PAXH+ENfxNw+Cw==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/common@7.2.8":
|
"@angular/common@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.8.tgz#660c816b6f08cd2919a6efb7465397e4ff14d265"
|
resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.1.9.tgz#16e77b2db675b80e32f1788a20c538150fd09294"
|
||||||
integrity sha512-LgOhf68+LPndGZhtnUlGFd2goReXYmHzaFZW8gCEi9aC+H+Io8bjYh0gkH3xDreevEOe3f0z6coXNFLIxSmTuA==
|
integrity sha512-y/tJtkuOJhV2kcaXZyrLZH84i4uQ1r+vaaEHvXj+JZYfYfcMMd/TDqMiPcIkUb3RxqghtZ+q0ZNW5D1Nlru3Pw==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/compiler@7.2.8":
|
"@angular/compiler@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.8.tgz#9d9c1515e99914399e6915c1c90484b1d255560b"
|
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.9.tgz#cbf678ee28a0811a8ef3ee7be565d4911ff28ec7"
|
||||||
integrity sha512-PrU97cTsOdofpaDkxK0rWUA/CGd0u6ESOI6XvFVm5xH9zJInsdY8ShSHklnr1JJnss70e1dGKZbZq32OChxWMw==
|
integrity sha512-kjFgaTB2ckr9lgmkS1dOGRT7kmzpQueydxsxXSHWgICNVE6F/u1PHyeSOyJRpxW0GnrkLq3QM2EUFnQGGga5bg==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/core@7.2.8":
|
"@angular/core@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.8.tgz#6586d9b6c6321c80119b3f3e2bd0edbb32d0b649"
|
resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.9.tgz#db4241f867d6e14b81ed6e7c50334813c6ebfc10"
|
||||||
integrity sha512-QKwug2kWJC00zm2rvmD9mCJzsOkMVhSu8vqPWf83poWTh8+F9aIVWcy29W0VoGpBkSchOnK8hf9DnKVv28j9nw==
|
integrity sha512-q/DERgVU6vK2LtTcdVCGGBcoO424WsEfImh3Vcuy+P/ZVmthlDUC/+q+tSKt8MMf4hLpxFDQJE8vUSkktj7QEw==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/forms@7.2.8":
|
"@angular/forms@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.8.tgz#adf194088495822d55dcf3e5bf69196dcf19465d"
|
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.1.9.tgz#20c9a79d1dcb2cace45df9e2f304b658e02c1687"
|
||||||
integrity sha512-lbSX4IHFHz/c4e2RHiPpL8MJlzDkCuQEHnqsujDaV2X9o9fApS6+C1X4x7Z2XDKqonmeX+aHQwv9+SLejX6OyQ==
|
integrity sha512-r675yImnb/0pY7K5W3V2ITa7YETu1I2AS+bRfII6UQ6gthyeFFOHb5noa7YneC2yqQiM6E4DQmF5ig3daPuFNg==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/platform-browser-dynamic@7.2.8":
|
"@angular/platform-browser-dynamic@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.8.tgz#e82768900cedfa75bf453263f931a9f90f7aaab2"
|
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.9.tgz#12f8b05d3c9ef0844df88f3833e29ea1e49ec5e0"
|
||||||
integrity sha512-nOJt28A5pRn4mdL8y98V7bA6OOdMRjsQAcWCr/isGYF0l1yDC0ijUGWkHuRtj3z1/9tmERN0BLXx+xs1h4JhCQ==
|
integrity sha512-b9MG5MWne+IuL3uLm8jwPhlJzqYaGBGk/qibOqb17T24j1iyrlO7T5bZ8zO6pUy5iT/TahVfHPnPJC1qTK5OmA==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@angular/platform-browser@7.2.8":
|
"@angular/platform-browser@9.1.9":
|
||||||
version "7.2.8"
|
version "9.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.8.tgz#11096727b99bf3d7fd82a00a3a468b933c9713bd"
|
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.1.9.tgz#c2fcc50aebfdc268521b407e32dc0d967cb40411"
|
||||||
integrity sha512-SizCRMc7Or27g2CugcqWnaAikRPfgLgRvb9GFFGpcgoq8CRfOVwkyR5dFZuqN39H+uwtwuTMP5OUYhZcrFNKug==
|
integrity sha512-V861X3MxJp1AlMTnkUPldpBLIJbApXF3ka0A5Dq2nVJCyOFeteGkaRWSBgqe2jxmq+LVpJbzcNvtDFXw6mQ0jA==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
"@ng-bootstrap/ng-bootstrap@^4.2.2":
|
"@ng-bootstrap/ng-bootstrap@^6.1.0":
|
||||||
version "4.2.2"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.2.2.tgz#a1c3a9576656cb4f793bbc3df56dfbdeb098f2fb"
|
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-6.1.0.tgz#fce7550a095aeac42108f76ac1ebd63caf8304e9"
|
||||||
integrity sha512-v8QmC17bv9he5Ep6zutaI9aQ2w/2NqySP0fejOKe7cacKpGUqsLIakpyd2FD7mfZu7pSCCtHYpRWR+h6yq+Ngg==
|
integrity sha512-2GzkNJBKdeHkaUqaCAqSILPft0IzzHjMfAlAuGY6/ZLlVQ0glt5MTbIXtIhSbjR+OvlrljoXFLrvzs1LGdmE+A==
|
||||||
|
|
||||||
|
"@serialport/binding-abstract@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/binding-abstract/-/binding-abstract-8.0.6.tgz#78e6d7995a95c46d480445303e6f32ca4d53edcd"
|
||||||
|
integrity sha512-1swwUVoRyQ9ubxrkJ8JPppykohUpTAP4jkGr36e9NjbVocSPfqeX6tFZFwl/IdUlwJwxGdbKDqq7FvXniCQUMw==
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
debug "^4.1.1"
|
||||||
|
|
||||||
|
"@serialport/binding-mock@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/binding-mock/-/binding-mock-8.0.6.tgz#41a8f827269c6a0e58546513a274e12023134155"
|
||||||
|
integrity sha512-BIbY5/PsDDo0QWDNCCxDgpowAdks+aZR8BOsEtK2GoASTTcJCy1fBwPIfH870o7rnbH901wY3C+yuTfdOvSO9A==
|
||||||
|
dependencies:
|
||||||
|
"@serialport/binding-abstract" "^8.0.6"
|
||||||
|
debug "^4.1.1"
|
||||||
|
|
||||||
|
"@serialport/bindings@^8.0.7":
|
||||||
|
version "8.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/bindings/-/bindings-8.0.7.tgz#2a58f60f1e24ee4549be6f9e0e37b3359d038a1c"
|
||||||
|
integrity sha512-IqudDL8ne2Y2S0W5fKA6wdgHCIA2e2OIaPVYhGy6duE6legNHFY+05CLicHAyAeTocXmHU7rVNxzVQrOG5tM4g==
|
||||||
|
dependencies:
|
||||||
|
"@serialport/binding-abstract" "^8.0.6"
|
||||||
|
"@serialport/parser-readline" "^8.0.6"
|
||||||
|
bindings "^1.5.0"
|
||||||
|
debug "^4.1.1"
|
||||||
|
nan "^2.14.0"
|
||||||
|
prebuild-install "^5.3.0"
|
||||||
|
|
||||||
|
"@serialport/parser-byte-length@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-byte-length/-/parser-byte-length-8.0.6.tgz#efb6195692b1088e6c095fd43bae196fc30674d0"
|
||||||
|
integrity sha512-92mrFxFEvq3gRvSM7ANK/jfbmHslz91a5oYJy/nbSn4H/MCRXjxR2YOkQgVXuN+zLt+iyDoW3pcOP4Sc1nWdqQ==
|
||||||
|
|
||||||
|
"@serialport/parser-cctalk@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-cctalk/-/parser-cctalk-8.0.6.tgz#4134a3c479d465df3b152a21e16b8ecf1bc818c3"
|
||||||
|
integrity sha512-pqtCYQPgxnxHygiXUPCfgX7sEx+fdR/ObjpscidynEULUq2fFrC5kBkrxRbTfHRtTaU2ii9DyjFq0JVRCbhI0Q==
|
||||||
|
|
||||||
|
"@serialport/parser-delimiter@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-delimiter/-/parser-delimiter-8.0.6.tgz#0e467cb07a40bd3006835c48e488666bd7de22cc"
|
||||||
|
integrity sha512-ogKOcPisPMlVtirkuDu3SFTF0+xT0ijxoH7XjpZiYL41EVi367MwuCnEmXG+dEKKnF0j9EPqOyD2LGSJxaFmhQ==
|
||||||
|
|
||||||
|
"@serialport/parser-readline@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-readline/-/parser-readline-8.0.6.tgz#8a6a296a1bec08a4855bf7a62bc6335d52972e4a"
|
||||||
|
integrity sha512-OYBT2mpczh9QUI3MTw8j0A0tIlPVjpVipvuVnjRkYwxrxPeq04RaLFhaDpuRzua5rTKMt89c1y3btYeoDXMjAA==
|
||||||
|
dependencies:
|
||||||
|
"@serialport/parser-delimiter" "^8.0.6"
|
||||||
|
|
||||||
|
"@serialport/parser-ready@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-ready/-/parser-ready-8.0.6.tgz#d6e95e53ee70d298ae0b4147995007f4ba62651c"
|
||||||
|
integrity sha512-xcEqv4rc119WR5JzAuu8UeJOlAwET2PTdNb6aIrrLlmTxhvuBbuRFcsnF3BpH9jUL30Kh7a6QiNXIwVG+WR/1Q==
|
||||||
|
|
||||||
|
"@serialport/parser-regex@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/parser-regex/-/parser-regex-8.0.6.tgz#70aa1abe31899d1b986f44cfb6777a76e26755bf"
|
||||||
|
integrity sha512-J8KY75Azz5ZyExmyM5YfUxbXOWBkZCytKgCCmZ966ttwZS0bUZOuoCaZj2Zp4VILJAiLuxHoqc0foi67Fri5+g==
|
||||||
|
|
||||||
|
"@serialport/stream@^8.0.6":
|
||||||
|
version "8.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-8.0.6.tgz#3395dbac788c00797c2435c61c2ecb4e99fbf41d"
|
||||||
|
integrity sha512-ym1PwM0rwLrj90vRBB66I1hwMXbuMw9wGTxqns75U3N/tuNFOH85mxXaYVF2TpI66aM849NoI1jMm50fl9equg==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
|
||||||
"@types/color-name@^1.1.1":
|
"@types/color-name@^1.1.1":
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
@@ -80,10 +130,12 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
|
||||||
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
|
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
|
||||||
|
|
||||||
"@types/semver@^6.0.2":
|
"@types/semver@^7.1.0":
|
||||||
version "6.2.0"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
|
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
|
||||||
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
|
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
JSONStream@^1.3.4, JSONStream@^1.3.5:
|
JSONStream@^1.3.4, JSONStream@^1.3.5:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
@@ -238,6 +290,11 @@ asynckit@^0.4.0:
|
|||||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||||
|
|
||||||
|
at-least-node@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||||
|
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||||
|
|
||||||
aws-sign2@~0.7.0:
|
aws-sign2@~0.7.0:
|
||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||||
@@ -271,6 +328,13 @@ bin-links@^1.1.2:
|
|||||||
graceful-fs "^4.1.11"
|
graceful-fs "^4.1.11"
|
||||||
write-file-atomic "^2.3.0"
|
write-file-atomic "^2.3.0"
|
||||||
|
|
||||||
|
bindings@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||||
|
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||||
|
dependencies:
|
||||||
|
file-uri-to-path "1.0.0"
|
||||||
|
|
||||||
bl@^3.0.0:
|
bl@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
|
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
|
||||||
@@ -316,10 +380,10 @@ buffer-from@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||||
|
|
||||||
builder-util-runtime@8.4.0:
|
builder-util-runtime@8.7.0:
|
||||||
version "8.4.0"
|
version "8.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.4.0.tgz#3163fffc078e6b8f3dd5b6eb12a8345573590682"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d"
|
||||||
integrity sha512-CJB/eKfPf2vHrkmirF5eicVnbDCkMBbwd5tRYlTlgud16zFeqD7QmrVUAOEXdnsrcNkiLg9dbuUsQKtl/AwsYQ==
|
integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
@@ -798,19 +862,18 @@ electron-localshortcut@^3.1.0:
|
|||||||
keyboardevent-from-electron-accelerator "^1.1.0"
|
keyboardevent-from-electron-accelerator "^1.1.0"
|
||||||
keyboardevents-areequal "^0.2.1"
|
keyboardevents-areequal "^0.2.1"
|
||||||
|
|
||||||
electron-updater@^4.2.0:
|
electron-updater@^4.3.1:
|
||||||
version "4.2.0"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.2.0.tgz#f9ecfc657f65ead737d42b9efecf628d3756b550"
|
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.1.tgz#9d485b6262bc56fcf7ee62b1dc1b3b105a3e96a7"
|
||||||
integrity sha512-GuS3g7HDh17x/SaFjxjswlWUaKHczksYkV2Xc5CKj/bZH0YCvTSHtOmnBAdAmCk99u/71p3zP8f0jIqDfGcjww==
|
integrity sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/semver" "^6.0.2"
|
"@types/semver" "^7.1.0"
|
||||||
builder-util-runtime "8.4.0"
|
builder-util-runtime "8.7.0"
|
||||||
fs-extra "^8.1.0"
|
fs-extra "^9.0.0"
|
||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
lazy-val "^1.0.4"
|
lazy-val "^1.0.4"
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
pako "^1.0.10"
|
semver "^7.1.3"
|
||||||
semver "^6.3.0"
|
|
||||||
|
|
||||||
emoji-regex@^8.0.0:
|
emoji-regex@^8.0.0:
|
||||||
version "8.0.0"
|
version "8.0.0"
|
||||||
@@ -925,6 +988,11 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
|
|||||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
||||||
integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
|
integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
|
||||||
|
|
||||||
|
file-uri-to-path@1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||||
|
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||||
|
|
||||||
find-npm-prefix@^1.0.2:
|
find-npm-prefix@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
|
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
|
||||||
@@ -1000,14 +1068,15 @@ fs-constants@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||||
|
|
||||||
fs-extra@^8.1.0:
|
fs-extra@^9.0.0:
|
||||||
version "8.1.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
|
||||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
at-least-node "^1.0.0"
|
||||||
graceful-fs "^4.2.0"
|
graceful-fs "^4.2.0"
|
||||||
jsonfile "^4.0.0"
|
jsonfile "^6.0.1"
|
||||||
universalify "^0.1.0"
|
universalify "^1.0.0"
|
||||||
|
|
||||||
fs-minipass@^1.2.5:
|
fs-minipass@^1.2.5:
|
||||||
version "1.2.6"
|
version "1.2.6"
|
||||||
@@ -1420,10 +1489,10 @@ isstream@~0.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||||
|
|
||||||
js-yaml@3.13.1, js-yaml@^3.13.1:
|
js-yaml@3.14.0, js-yaml@^3.13.1:
|
||||||
version "3.13.1"
|
version "3.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
|
||||||
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
@@ -1453,10 +1522,12 @@ json-stringify-safe@~5.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||||
|
|
||||||
jsonfile@^4.0.0:
|
jsonfile@^6.0.1:
|
||||||
version "4.0.0"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
|
||||||
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
|
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
|
||||||
|
dependencies:
|
||||||
|
universalify "^1.0.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
@@ -1485,12 +1556,12 @@ keyboardevents-areequal@^0.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
|
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
|
||||||
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
|
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
|
||||||
|
|
||||||
keytar@^5.2.0:
|
keytar@^5.6.0:
|
||||||
version "5.2.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.2.0.tgz#7543190be98e2a751466096ce3ca1b1a4b8f39fe"
|
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.6.0.tgz#7b5d4bd043d17211163640be6c4a27a49b12bb39"
|
||||||
integrity sha512-vsIX6n2BgTwzbKOSPIiJ8YduwHlPEE/G5dkmZWXaQK9qiGZMQyhxlFA4O6vrvM5fsXTMgUOrODYAqgpfNSRLDw==
|
integrity sha512-ueulhshHSGoryfRXaIvTj0BV1yB0KddBGhGoqCxSN9LR1Ks1GKuuCdVhF+2/YOs5fMl6MlTI9On1a4DHDXoTow==
|
||||||
dependencies:
|
dependencies:
|
||||||
nan "2.14.0"
|
nan "2.14.1"
|
||||||
prebuild-install "5.3.3"
|
prebuild-install "5.3.3"
|
||||||
|
|
||||||
latest-version@^3.0.0:
|
latest-version@^3.0.0:
|
||||||
@@ -1908,27 +1979,25 @@ mz@^2.7.0:
|
|||||||
object-assign "^4.0.1"
|
object-assign "^4.0.1"
|
||||||
thenify-all "^1.0.0"
|
thenify-all "^1.0.0"
|
||||||
|
|
||||||
nan@2.14.0, nan@^2.13.2, nan@^2.14.0:
|
nan@2.14.1, nan@^2.13.2, nan@^2.14.0:
|
||||||
version "2.14.0"
|
version "2.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
|
||||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
|
||||||
|
|
||||||
napi-build-utils@^1.0.1:
|
napi-build-utils@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
|
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
|
||||||
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
|
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
|
||||||
|
|
||||||
ngx-toastr@^10.2.0:
|
ngx-toastr@^12.0.1:
|
||||||
version "10.2.0"
|
version "12.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-10.2.0.tgz#8a79008de0b1c013f90120a53e0355af5762e969"
|
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-12.0.1.tgz#288c8ef505f1216aa4952cd2a8c6fa7c57a54ccc"
|
||||||
integrity sha512-6ASr5bcvQmtNKb4D2VEsQjCXyROq6GwberBWO0bVt+xcBYPUea4aRTgX8in9apX9buaTafzG+h3HlnIraspoPg==
|
integrity sha512-PABtbn2dyHweVSbo/py1W3veXzcmZO7uVItfTW9AykSSeAUju3gOCgauAw89km0aJ9EBcPOieaoI+9tAR7Pfug==
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
node-abi@^2.15.0, node-abi@^2.7.0:
|
node-abi@^2.16.0, node-abi@^2.7.0:
|
||||||
version "2.15.0"
|
version "2.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.15.0.tgz#51d55cc711bd9e4a24a572ace13b9231945ccb10"
|
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.16.0.tgz#7df94e9c0a7a189f4197ab84bac8089ef5894992"
|
||||||
integrity sha512-FeLpTS0F39U7hHZU1srAK4Vx+5AHNVOTP+hxBNQknR/54laTHSFIJkDWDqiquY1LeLUgTfPN7sLPhMubx0PLAg==
|
integrity sha512-+sa0XNlWDA6T+bDLmkCUYn6W5k5W6BPRL6mqzSCs6H/xUgtl4D5x2fORKDzopKiU6wsyn/+wXlRXwXeSp+mtoA==
|
||||||
dependencies:
|
dependencies:
|
||||||
semver "^5.4.1"
|
semver "^5.4.1"
|
||||||
|
|
||||||
@@ -1976,10 +2045,10 @@ node-gyp@^4.0.0:
|
|||||||
tar "^4.4.8"
|
tar "^4.4.8"
|
||||||
which "1"
|
which "1"
|
||||||
|
|
||||||
node-pty@^0.10.0-beta2:
|
node-pty@^0.10.0-beta9:
|
||||||
version "0.10.0-beta3"
|
version "0.10.0-beta9"
|
||||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta3.tgz#a33c9fc67c9e4d4f124111e1da2a72b0783008e7"
|
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta9.tgz#e5a795f9b53948346803cb71bac4ffc02e7909f0"
|
||||||
integrity sha512-j7MoJ3K999jrT9gAVs7JvM/skAQXQITrZK/PhL9B4W4GAPkANKwdu9uEtNvYionQ9dV8gRGte7lg9D2cRDdAiA==
|
integrity sha512-Qm6uSH30FUcAhJ9s76C+lgvTsOW2cHUbkIGjCdOVCL0c7S4DxsmKBRgjcr+guUK9d9KwfuZHeSjXYWjpJFPe4w==
|
||||||
dependencies:
|
dependencies:
|
||||||
nan "^2.14.0"
|
nan "^2.14.0"
|
||||||
|
|
||||||
@@ -2395,11 +2464,6 @@ pacote@^9.1.0, pacote@^9.2.3, pacote@^9.5.0:
|
|||||||
unique-filename "^1.1.1"
|
unique-filename "^1.1.1"
|
||||||
which "^1.3.1"
|
which "^1.3.1"
|
||||||
|
|
||||||
pako@^1.0.10:
|
|
||||||
version "1.0.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
|
|
||||||
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
|
|
||||||
|
|
||||||
parallel-transform@^1.1.0:
|
parallel-transform@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
||||||
@@ -2464,7 +2528,7 @@ pkg-up@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
find-up "^2.1.0"
|
find-up "^2.1.0"
|
||||||
|
|
||||||
prebuild-install@5.3.3:
|
prebuild-install@5.3.3, prebuild-install@^5.3.0:
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e"
|
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e"
|
||||||
integrity sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==
|
integrity sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==
|
||||||
@@ -2801,15 +2865,15 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
aproba "^1.1.1"
|
aproba "^1.1.1"
|
||||||
|
|
||||||
rxjs-compat@^6.5.4:
|
rxjs-compat@^6.5.5:
|
||||||
version "6.5.4"
|
version "6.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.4.tgz#03825692af3fe363e04c43f41ff4113d76bbd305"
|
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.5.tgz#073c40510f29c45a2a5fc02dde87f8c3ad75f2c2"
|
||||||
integrity sha512-rkn+lbOHUQOurdd74J/hjmDsG9nFx0z66fvnbs8M95nrtKvNqCKdk7iZqdY51CGmDemTQk+kUPy4s8HVOHtkfA==
|
integrity sha512-F42sssVbUyWH4vJswEo6m+Eh02xHv3q93n8S7nUJO58R7sbc3CvJIOts605zdaBhWa1xMB9aVSyqPqhQ5q3eXg==
|
||||||
|
|
||||||
rxjs@^6.5.4:
|
rxjs@^6.5.5:
|
||||||
version "6.5.4"
|
version "6.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec"
|
||||||
integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
|
integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
@@ -2840,16 +2904,32 @@ semver-diff@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||||
|
|
||||||
semver@^6.3.0:
|
semver@^7.1.3:
|
||||||
version "6.3.0"
|
version "7.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
|
||||||
|
|
||||||
semver@~5.3.0:
|
semver@~5.3.0:
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||||
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
|
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
|
||||||
|
|
||||||
|
serialport@^8.0.7:
|
||||||
|
version "8.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/serialport/-/serialport-8.0.7.tgz#9f28b1b7c47333a0962f5505a1c3feb1d90f89a9"
|
||||||
|
integrity sha512-R9bfNebs2dblYf5sD/Aaa7j8+siP4X7TGT02lqHM9DF5fyjlrPGXmsLw9+LKOz1AvjGjkxf2NzBVnDpqRX7clQ==
|
||||||
|
dependencies:
|
||||||
|
"@serialport/binding-mock" "^8.0.6"
|
||||||
|
"@serialport/bindings" "^8.0.7"
|
||||||
|
"@serialport/parser-byte-length" "^8.0.6"
|
||||||
|
"@serialport/parser-cctalk" "^8.0.6"
|
||||||
|
"@serialport/parser-delimiter" "^8.0.6"
|
||||||
|
"@serialport/parser-readline" "^8.0.6"
|
||||||
|
"@serialport/parser-ready" "^8.0.6"
|
||||||
|
"@serialport/parser-regex" "^8.0.6"
|
||||||
|
"@serialport/stream" "^8.0.6"
|
||||||
|
debug "^4.1.1"
|
||||||
|
|
||||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||||
@@ -3263,10 +3343,10 @@ unique-string@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
crypto-random-string "^1.0.0"
|
crypto-random-string "^1.0.0"
|
||||||
|
|
||||||
universalify@^0.1.0:
|
universalify@^1.0.0:
|
||||||
version "0.1.2"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
|
||||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
|
||||||
|
|
||||||
unpipe@~1.0.0:
|
unpipe@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@@ -3486,10 +3566,10 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
|
||||||
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
|
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
|
||||||
|
|
||||||
yargs-parser@^16.1.0:
|
yargs-parser@^18.1.1:
|
||||||
version "16.1.0"
|
version "18.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.1.tgz#bf7407b915427fc760fcbbccc6c82b4f0ffcbd37"
|
||||||
integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==
|
integrity sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA==
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase "^5.0.0"
|
camelcase "^5.0.0"
|
||||||
decamelize "^1.2.0"
|
decamelize "^1.2.0"
|
||||||
@@ -3519,10 +3599,10 @@ yargs@^11.0.0:
|
|||||||
y18n "^3.2.1"
|
y18n "^3.2.1"
|
||||||
yargs-parser "^9.0.2"
|
yargs-parser "^9.0.2"
|
||||||
|
|
||||||
yargs@^15.1.0:
|
yargs@^15.3.1:
|
||||||
version "15.1.0"
|
version "15.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219"
|
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b"
|
||||||
integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==
|
integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==
|
||||||
dependencies:
|
dependencies:
|
||||||
cliui "^6.0.0"
|
cliui "^6.0.0"
|
||||||
decamelize "^1.2.0"
|
decamelize "^1.2.0"
|
||||||
@@ -3534,9 +3614,9 @@ yargs@^15.1.0:
|
|||||||
string-width "^4.2.0"
|
string-width "^4.2.0"
|
||||||
which-module "^2.0.0"
|
which-module "^2.0.0"
|
||||||
y18n "^4.0.0"
|
y18n "^4.0.0"
|
||||||
yargs-parser "^16.1.0"
|
yargs-parser "^18.1.1"
|
||||||
|
|
||||||
zone.js@^0.8.29:
|
zone.js@^0.10.3:
|
||||||
version "0.8.29"
|
version "0.10.3"
|
||||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12"
|
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16"
|
||||||
integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==
|
integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==
|
||||||
|
16
build/mac/afterBuildHook.js
Normal file
16
build/mac/afterBuildHook.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const signHook = require('./afterSignHook')
|
||||||
|
|
||||||
|
module.exports = async function (params) {
|
||||||
|
// notarize the app on Mac OS only.
|
||||||
|
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('afterBuild hook triggered')
|
||||||
|
|
||||||
|
let pkgName = fs.readdirSync('dist').find(x => x.endsWith('.pkg'))
|
||||||
|
signHook({
|
||||||
|
appOutDir: 'dist',
|
||||||
|
_pathOverride: pkgName,
|
||||||
|
})
|
||||||
|
}
|
@@ -6,14 +6,14 @@ const notarizer = require('electron-notarize')
|
|||||||
|
|
||||||
module.exports = async function (params) {
|
module.exports = async function (params) {
|
||||||
// notarize the app on Mac OS only.
|
// notarize the app on Mac OS only.
|
||||||
if (process.platform !== 'darwin' || process.env.GITHUB_REF !== 'refs/heads/master' || process.env.GITHUB_REF && !process.env.GITHUB_REF.startsWith('refs/tags/')) {
|
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('afterSign hook triggered', params)
|
console.log('afterSign hook triggered', params)
|
||||||
|
|
||||||
let appId = 'org.terminus'
|
let appId = 'org.terminus'
|
||||||
|
|
||||||
let appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`)
|
let appPath = path.join(params.appOutDir, params._pathOverride || `${params.packager.appInfo.productFilename}.app`)
|
||||||
if (!fs.existsSync(appPath)) {
|
if (!fs.existsSync(appPath)) {
|
||||||
throw new Error(`Cannot find application at: ${appPath}`)
|
throw new Error(`Cannot find application at: ${appPath}`)
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ appId: org.terminus
|
|||||||
productName: Terminus
|
productName: Terminus
|
||||||
compression: normal
|
compression: normal
|
||||||
afterSign: "./build/mac/afterSignHook.js"
|
afterSign: "./build/mac/afterSignHook.js"
|
||||||
|
afterAllArtifactBuild: "./build/mac/afterBuildHook.js"
|
||||||
files:
|
files:
|
||||||
- "**/*"
|
- "**/*"
|
||||||
- dist
|
- dist
|
||||||
@@ -48,6 +49,7 @@ deb:
|
|||||||
depends:
|
depends:
|
||||||
- gconf2
|
- gconf2
|
||||||
- gconf-service
|
- gconf-service
|
||||||
|
- gnome-keyring
|
||||||
- libnotify4
|
- libnotify4
|
||||||
- libsecret-1-0
|
- libsecret-1-0
|
||||||
- libappindicator1
|
- libappindicator1
|
||||||
@@ -57,4 +59,4 @@ deb:
|
|||||||
rpm:
|
rpm:
|
||||||
depends:
|
depends:
|
||||||
- screen
|
- screen
|
||||||
- gnome-python2-gnomekeyring
|
- gnome-keyring
|
||||||
|
BIN
extras/ssh-keygen/libcrypto.dll
Normal file
BIN
extras/ssh-keygen/libcrypto.dll
Normal file
Binary file not shown.
BIN
extras/ssh-keygen/ssh-keygen.exe
Normal file
BIN
extras/ssh-keygen/ssh-keygen.exe
Normal file
Binary file not shown.
58
package.json
58
package.json
@@ -1,35 +1,35 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.12.1",
|
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||||
"@sentry/cli": "^1.49.0",
|
"@sentry/cli": "^1.52.3",
|
||||||
"@sentry/electron": "^1.0.0",
|
"@sentry/electron": "^1.2.1",
|
||||||
"@types/electron-config": "^3.2.2",
|
"@types/electron-config": "^3.2.2",
|
||||||
"@types/electron-debug": "^2.1.0",
|
"@types/electron-debug": "^2.1.0",
|
||||||
"@types/js-yaml": "^3.12.1",
|
"@types/js-yaml": "^3.12.4",
|
||||||
"@types/node": "12.7.12",
|
"@types/node": "12.7.12",
|
||||||
"@types/webpack-env": "1.15.0",
|
"@types/webpack-env": "^1.15.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.13.0",
|
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||||
"@typescript-eslint/parser": "^2.19.2",
|
"@typescript-eslint/parser": "^2.34.0",
|
||||||
"apply-loader": "2.0.0",
|
"apply-loader": "2.0.0",
|
||||||
"awesome-typescript-loader": "^5.0.0",
|
"awesome-typescript-loader": "^5.0.0",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.5",
|
||||||
"cross-env": "7.0.0",
|
"cross-env": "7.0.2",
|
||||||
"css-loader": "3.4.2",
|
"css-loader": "3.4.2",
|
||||||
"electron": "^8.0.0",
|
"electron": "^8.2.5",
|
||||||
"electron-builder": "22.3.2",
|
"electron-builder": "22.6.1",
|
||||||
"electron-download": "^4.1.1",
|
"electron-download": "^4.1.1",
|
||||||
"electron-installer-snap": "^5.0.0",
|
"electron-installer-snap": "^5.0.0",
|
||||||
"electron-notarize": "^0.1.1",
|
"electron-notarize": "^0.1.1",
|
||||||
"electron-rebuild": "^1.9.0",
|
"electron-rebuild": "^1.10.1",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-plugin-import": "^2.20.0",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
"file-loader": "^5.0.2",
|
"file-loader": "^5.0.2",
|
||||||
"graceful-fs": "^4.2.2",
|
"graceful-fs": "^4.2.4",
|
||||||
"html-loader": "0.5.5",
|
"html-loader": "0.5.5",
|
||||||
"json-loader": "0.5.7",
|
"json-loader": "0.5.7",
|
||||||
"node-abi": "^2.15.0",
|
"node-abi": "^2.16.0",
|
||||||
"node-gyp": "^6.1.0",
|
"node-gyp": "^6.1.0",
|
||||||
"node-sass": "^4.13.0",
|
"node-sass": "^4.14.1",
|
||||||
"npmlog": "4.1.2",
|
"npmlog": "4.1.2",
|
||||||
"npx": "^10.2.0",
|
"npx": "^10.2.0",
|
||||||
"pug": "^2.0.4",
|
"pug": "^2.0.4",
|
||||||
@@ -37,29 +37,29 @@
|
|||||||
"pug-lint": "^2.6.0",
|
"pug-lint": "^2.6.0",
|
||||||
"pug-loader": "^2.4.0",
|
"pug-loader": "^2.4.0",
|
||||||
"pug-static-loader": "2.0.0",
|
"pug-static-loader": "2.0.0",
|
||||||
"raw-loader": "4.0.0",
|
"raw-loader": "4.0.1",
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"shelljs": "0.8.3",
|
"shelljs": "0.8.4",
|
||||||
"source-code-pro": "^2.30.2",
|
"source-code-pro": "^2.30.2",
|
||||||
"source-sans-pro": "3.6.0",
|
"source-sans-pro": "3.6.0",
|
||||||
"style-loader": "^1.1.3",
|
"style-loader": "^1.1.4",
|
||||||
"svg-inline-loader": "^0.8.0",
|
"svg-inline-loader": "^0.8.0",
|
||||||
"to-string-loader": "1.1.6",
|
"to-string-loader": "1.1.6",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^2.0.0",
|
||||||
"typedoc": "^0.16.7",
|
"typedoc": "^0.17.6",
|
||||||
"typescript": "^3.7.5",
|
"typescript": "^3.9.3",
|
||||||
"url-loader": "^3.0.0",
|
"url-loader": "^3.0.0",
|
||||||
"val-loader": "2.1.0",
|
"val-loader": "2.1.1",
|
||||||
"webpack": "^5.0.0-beta.12",
|
"webpack": "^5.0.0-beta.16",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.10",
|
||||||
"yaml-loader": "0.5.0"
|
"yaml-loader": "0.6.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"*/node-abi": "^2.14.0"
|
"*/node-abi": "^2.14.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"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",
|
"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": "tsc --project terminus-core/tsconfig.typings.json && tsc --project terminus-settings/tsconfig.typings.json && tsc --project terminus-terminal/tsconfig.typings.json && tsc --project terminus-plugin-manager/tsconfig.typings.json && tsc --project terminus-ssh/tsconfig.typings.json",
|
"build:typings": "node scripts/build-typings.js",
|
||||||
"watch": "cross-env TERMINUS_DEV=1 webpack --progress --color --watch",
|
"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",
|
||||||
"prod": "cross-env TERMINUS_DEV=1 electron app",
|
"prod": "cross-env TERMINUS_DEV=1 electron app",
|
||||||
@@ -67,5 +67,7 @@
|
|||||||
"lint": "eslint --ext ts */src */lib",
|
"lint": "eslint --ext ts */src */lib",
|
||||||
"postinstall": "node ./scripts/install-deps.js"
|
"postinstall": "node ./scripts/install-deps.js"
|
||||||
},
|
},
|
||||||
"repository": "eugeny/terminus"
|
"repository": "eugeny/terminus",
|
||||||
|
"author": "Eugene Pankov",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const builder = require('electron-builder').build
|
const builder = require('electron-builder').build
|
||||||
const vars = require('./vars')
|
const vars = require('./vars')
|
||||||
|
const fs = require('fs')
|
||||||
|
const signHook = require('../build/mac/afterSignHook')
|
||||||
|
|
||||||
const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
|
const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
|
||||||
const isCI = !!process.env.GITHUB_REF
|
|
||||||
|
|
||||||
builder({
|
builder({
|
||||||
dir: true,
|
dir: true,
|
||||||
@@ -14,4 +15,7 @@ builder({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
publish: isTag ? 'always' : 'onTag',
|
publish: isTag ? 'always' : 'onTag',
|
||||||
}).catch(() => process.exit(1))
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
9
scripts/build-typings.js
Executable file
9
scripts/build-typings.js
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const sh = require('shelljs')
|
||||||
|
const vars = require('./vars')
|
||||||
|
const log = require('npmlog')
|
||||||
|
|
||||||
|
vars.builtinPlugins.forEach(plugin => {
|
||||||
|
log.info('typings', plugin)
|
||||||
|
sh.exec(`npx tsc --project ${plugin}/tsconfig.typings.json`)
|
||||||
|
})
|
@@ -21,6 +21,7 @@ exports.builtinPlugins = [
|
|||||||
'terminus-community-color-schemes',
|
'terminus-community-color-schemes',
|
||||||
'terminus-plugin-manager',
|
'terminus-plugin-manager',
|
||||||
'terminus-ssh',
|
'terminus-ssh',
|
||||||
|
'terminus-serial',
|
||||||
]
|
]
|
||||||
exports.bundledModules = [
|
exports.bundledModules = [
|
||||||
'@angular',
|
'@angular',
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-community-color-schemes",
|
"name": "terminus-community-color-schemes",
|
||||||
"version": "1.0.99-nightly.0",
|
"version": "1.0.104-nightly.0",
|
||||||
"description": "Community color schemes for Terminus",
|
"description": "Community color schemes for Terminus",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"terminus-builtin-plugin"
|
"terminus-builtin-plugin"
|
||||||
|
14
terminus-community-color-schemes/tsconfig.typings.json
Normal file
14
terminus-community-color-schemes/tsconfig.typings.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"exclude": ["node_modules", "dist", "typings"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationDir": "./typings",
|
||||||
|
"paths": {
|
||||||
|
"terminus-*": ["../../terminus-*"],
|
||||||
|
"*": ["../../app/node_modules/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-core",
|
"name": "terminus-core",
|
||||||
"version": "1.0.99-nightly.0",
|
"version": "1.0.104-nightly.0",
|
||||||
"description": "Terminus core",
|
"description": "Terminus core",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"terminus-builtin-plugin"
|
"terminus-builtin-plugin"
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"ng2-dnd": "^5.0.2",
|
"ng2-dnd": "^5.0.2",
|
||||||
"ngx-perfect-scrollbar": "^8.0.0",
|
"ngx-perfect-scrollbar": "^8.0.0",
|
||||||
"shell-escape": "^0.2.0",
|
"shell-escape": "^0.2.0",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^8.0.0",
|
||||||
"winston": "^3.2.1"
|
"winston": "^3.2.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
|
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
|
||||||
export { TabHeaderComponent } from '../components/tabHeader.component'
|
export { TabHeaderComponent } from '../components/tabHeader.component'
|
||||||
export { SplitTabComponent, SplitContainer } from '../components/splitTab.component'
|
export { SplitTabComponent, SplitContainer } from '../components/splitTab.component'
|
||||||
export { TabRecoveryProvider, RecoveredTab } from './tabRecovery'
|
export { TabRecoveryProvider, RecoveredTab, RecoveryToken } from './tabRecovery'
|
||||||
export { ToolbarButtonProvider, ToolbarButton } from './toolbarButtonProvider'
|
export { ToolbarButtonProvider, ToolbarButton } from './toolbarButtonProvider'
|
||||||
export { ConfigProvider } from './configProvider'
|
export { ConfigProvider } from './configProvider'
|
||||||
export { HotkeyProvider, HotkeyDescription } from './hotkeyProvider'
|
export { HotkeyProvider, HotkeyDescription } from './hotkeyProvider'
|
||||||
export { Theme } from './theme'
|
export { Theme } from './theme'
|
||||||
export { TabContextMenuItemProvider } from './tabContextMenuProvider'
|
export { TabContextMenuItemProvider } from './tabContextMenuProvider'
|
||||||
|
export { SelectorOption } from './selector'
|
||||||
|
|
||||||
export { AppService } from '../services/app.service'
|
export { AppService } from '../services/app.service'
|
||||||
export { ConfigService } from '../services/config.service'
|
export { ConfigService } from '../services/config.service'
|
||||||
|
8
terminus-core/src/api/selector.ts
Normal file
8
terminus-core/src/api/selector.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface SelectorOption<T> {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
result?: T
|
||||||
|
icon?: string
|
||||||
|
freeInputPattern?: string
|
||||||
|
callback?: (string?) => void
|
||||||
|
}
|
@@ -12,6 +12,12 @@ export interface RecoveredTab {
|
|||||||
options?: any
|
options?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RecoveryToken {
|
||||||
|
[_: string]: any
|
||||||
|
type: string
|
||||||
|
tabColor?: string|null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend to enable recovery for your custom tab.
|
* Extend to enable recovery for your custom tab.
|
||||||
* This works in conjunction with [[getRecoveryToken()]]
|
* This works in conjunction with [[getRecoveryToken()]]
|
||||||
@@ -34,5 +40,5 @@ export abstract class TabRecoveryProvider {
|
|||||||
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
|
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
|
||||||
* or `null` if this token is from a different tab type or is not supported
|
* or `null` if this token is from a different tab type or is not supported
|
||||||
*/
|
*/
|
||||||
abstract async recover (recoveryToken: any): Promise<RecoveredTab|null>
|
abstract async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null>
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Inject, Input, HostListener, HostBinding } from '@angular/core'
|
import { Component, Inject, Input, HostListener, HostBinding } from '@angular/core'
|
||||||
import { trigger, style, animate, transition, state } from '@angular/animations'
|
import { trigger, style, animate, transition, state } from '@angular/animations'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
@@ -113,6 +114,9 @@ export class AppRootComponent {
|
|||||||
if (hotkey === 'move-tab-right') {
|
if (hotkey === 'move-tab-right') {
|
||||||
this.app.moveSelectedTabRight()
|
this.app.moveSelectedTabRight()
|
||||||
}
|
}
|
||||||
|
if (hotkey === 'reopen-tab') {
|
||||||
|
this.app.reopenLastTab()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hotkey === 'toggle-fullscreen') {
|
if (hotkey === 'toggle-fullscreen') {
|
||||||
this.hostApp.toggleFullscreen()
|
this.hostApp.toggleFullscreen()
|
||||||
@@ -124,17 +128,8 @@ export class AppRootComponent {
|
|||||||
this.docking.dock()
|
this.docking.dock()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.hostApp.secondInstance$.subscribe(() => {
|
|
||||||
this.presentWindow()
|
|
||||||
})
|
|
||||||
this.hotkeys.globalHotkey.subscribe(() => {
|
|
||||||
this.onGlobalHotkey()
|
|
||||||
})
|
|
||||||
|
|
||||||
this.hostApp.windowCloseRequest$.subscribe(async () => {
|
this.hostApp.windowCloseRequest$.subscribe(async () => {
|
||||||
if (await this.app.closeAllTabs()) {
|
this.app.closeWindow()
|
||||||
this.hostApp.closeWindow()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (window['safeModeReason']) {
|
if (window['safeModeReason']) {
|
||||||
@@ -173,41 +168,6 @@ export class AppRootComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onGlobalHotkey () {
|
|
||||||
if (this.hostApp.getWindow().isFocused()) {
|
|
||||||
this.hideWindow()
|
|
||||||
} else {
|
|
||||||
this.presentWindow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
presentWindow () {
|
|
||||||
if (!this.hostApp.getWindow().isVisible()) {
|
|
||||||
// unfocused, invisible
|
|
||||||
this.hostApp.getWindow().show()
|
|
||||||
this.hostApp.getWindow().focus()
|
|
||||||
} else {
|
|
||||||
if (this.config.store.appearance.dock === 'off') {
|
|
||||||
// not docked, visible
|
|
||||||
setTimeout(() => {
|
|
||||||
this.hostApp.getWindow().show()
|
|
||||||
this.hostApp.getWindow().focus()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// docked, visible
|
|
||||||
this.hostApp.getWindow().hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hideWindow () {
|
|
||||||
this.electron.loseFocus()
|
|
||||||
this.hostApp.getWindow().blur()
|
|
||||||
if (this.hostApp.platform !== Platform.macOS) {
|
|
||||||
this.hostApp.getWindow().hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
this.ready = true
|
this.ready = true
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { Observable, Subject } from 'rxjs'
|
import { Observable, Subject } from 'rxjs'
|
||||||
import { ViewRef } from '@angular/core'
|
import { ViewRef } from '@angular/core'
|
||||||
|
import { RecoveryToken } from '../api/tabRecovery'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an active "process" inside a tab,
|
* Represents an active "process" inside a tab,
|
||||||
@@ -13,6 +14,11 @@ export interface BaseTabProcess {
|
|||||||
* Abstract base class for custom tab components
|
* Abstract base class for custom tab components
|
||||||
*/
|
*/
|
||||||
export abstract class BaseTabComponent {
|
export abstract class BaseTabComponent {
|
||||||
|
/**
|
||||||
|
* Parent tab (usually a SplitTabComponent)
|
||||||
|
*/
|
||||||
|
parent: BaseTabComponent|null = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current tab title
|
* Current tab title
|
||||||
*/
|
*/
|
||||||
@@ -62,7 +68,7 @@ export abstract class BaseTabComponent {
|
|||||||
get destroyed$ (): Observable<void> { return this.destroyed }
|
get destroyed$ (): Observable<void> { return this.destroyed }
|
||||||
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
|
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
|
||||||
|
|
||||||
constructor () {
|
protected constructor () {
|
||||||
this.focused$.subscribe(() => {
|
this.focused$.subscribe(() => {
|
||||||
this.hasFocus = true
|
this.hasFocus = true
|
||||||
})
|
})
|
||||||
@@ -71,7 +77,7 @@ export abstract class BaseTabComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setTitle (title: string) {
|
setTitle (title: string): void {
|
||||||
this.title = title
|
this.title = title
|
||||||
if (!this.customTitle) {
|
if (!this.customTitle) {
|
||||||
this.titleChange.next(title)
|
this.titleChange.next(title)
|
||||||
@@ -83,7 +89,7 @@ export abstract class BaseTabComponent {
|
|||||||
*
|
*
|
||||||
* @param {type} progress: value between 0 and 1, or `null` to remove
|
* @param {type} progress: value between 0 and 1, or `null` to remove
|
||||||
*/
|
*/
|
||||||
setProgress (progress: number|null) {
|
setProgress (progress: number|null): void {
|
||||||
this.progress.next(progress)
|
this.progress.next(progress)
|
||||||
if (progress) {
|
if (progress) {
|
||||||
if (this.progressClearTimeout) {
|
if (this.progressClearTimeout) {
|
||||||
@@ -118,7 +124,7 @@ export abstract class BaseTabComponent {
|
|||||||
* @return JSON serializable tab state representation
|
* @return JSON serializable tab state representation
|
||||||
* for your [[TabRecoveryProvider]] to parse
|
* for your [[TabRecoveryProvider]] to parse
|
||||||
*/
|
*/
|
||||||
async getRecoveryToken (): Promise<any> {
|
async getRecoveryToken (): Promise<RecoveryToken|null> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +142,11 @@ export abstract class BaseTabComponent {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
emitFocused () {
|
emitFocused (): void {
|
||||||
this.focused.next()
|
this.focused.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
emitBlurred () {
|
emitBlurred (): void {
|
||||||
this.blurred.next()
|
this.blurred.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { NgZone, Component, Input, HostBinding, HostListener } from '@angular/core'
|
import { NgZone, Component, Input, HostBinding, HostListener } from '@angular/core'
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input, ElementRef, ViewChild } from '@angular/core'
|
import { Component, Input, ElementRef, ViewChild } from '@angular/core'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ export class SafeModeModalComponent {
|
|||||||
this.error = window['safeModeReason']
|
this.error = window['safeModeReason']
|
||||||
}
|
}
|
||||||
|
|
||||||
close () {
|
close (): void {
|
||||||
this.modalInstance.dismiss()
|
this.modalInstance.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
terminus-core/src/components/selectorModal.component.pug
Normal file
26
terminus-core/src/components/selectorModal.component.pug
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.modal-body
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
[(ngModel)]='filter',
|
||||||
|
autofocus,
|
||||||
|
[placeholder]='name',
|
||||||
|
(ngModelChange)='onFilterChange()'
|
||||||
|
)
|
||||||
|
|
||||||
|
.list-group.mt-3(*ngIf='filteredOptions.length')
|
||||||
|
a.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||||
|
#item,
|
||||||
|
(click)='selectOption(option)',
|
||||||
|
[class.active]='selectedIndex == i',
|
||||||
|
*ngFor='let option of filteredOptions; let i = index'
|
||||||
|
)
|
||||||
|
i.icon(
|
||||||
|
class='fa-fw fas fa-{{option.icon}}',
|
||||||
|
*ngIf='!iconIsSVG(option.icon)'
|
||||||
|
)
|
||||||
|
.icon(
|
||||||
|
[fastHtmlBind]='option.icon',
|
||||||
|
*ngIf='iconIsSVG(option.icon)'
|
||||||
|
)
|
||||||
|
.mr-2.title {{getOptionText(option)}}
|
||||||
|
.text-muted {{option.description}}
|
13
terminus-core/src/components/selectorModal.component.scss
Normal file
13
terminus-core/src/components/selectorModal.component.scss
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.list-group {
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 1.25rem;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
78
terminus-core/src/components/selectorModal.component.ts
Normal file
78
terminus-core/src/components/selectorModal.component.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core'
|
||||||
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { SelectorOption } from '../api/selector'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Component({
|
||||||
|
template: require('./selectorModal.component.pug'),
|
||||||
|
styles: [require('./selectorModal.component.scss')],
|
||||||
|
})
|
||||||
|
export class SelectorModalComponent<T> {
|
||||||
|
@Input() options: SelectorOption<T>[]
|
||||||
|
@Input() filteredOptions: SelectorOption<T>[]
|
||||||
|
@Input() filter = ''
|
||||||
|
@Input() name: string
|
||||||
|
@Input() selectedIndex = 0
|
||||||
|
@ViewChildren('item') itemChildren: QueryList<ElementRef>
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
public modalInstance: NgbActiveModal,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit (): void {
|
||||||
|
this.onFilterChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'ArrowUp') {
|
||||||
|
this.selectedIndex--
|
||||||
|
}
|
||||||
|
if (event.key === 'ArrowDown') {
|
||||||
|
this.selectedIndex++
|
||||||
|
}
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.selectOption(this.filteredOptions[this.selectedIndex])
|
||||||
|
}
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
||||||
|
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'nearest',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onFilterChange (): void {
|
||||||
|
const f = this.filter.trim().toLowerCase()
|
||||||
|
if (!f) {
|
||||||
|
this.filteredOptions = this.options.filter(x => !x.freeInputPattern)
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||||
|
this.filteredOptions = this.options.filter(x => x.freeInputPattern || (x.name + (x.description || '')).toLowerCase().includes(f))
|
||||||
|
}
|
||||||
|
this.selectedIndex = Math.max(0, this.selectedIndex)
|
||||||
|
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptionText (option: SelectorOption<T>): string {
|
||||||
|
if (option.freeInputPattern) {
|
||||||
|
return option.freeInputPattern.replace('%s', this.filter)
|
||||||
|
}
|
||||||
|
return option.name
|
||||||
|
}
|
||||||
|
|
||||||
|
selectOption (option: SelectorOption<T>): void {
|
||||||
|
option.callback?.(this.filter)
|
||||||
|
this.modalInstance.close(option.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
close (): void {
|
||||||
|
this.modalInstance.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
iconIsSVG (icon: string): boolean {
|
||||||
|
return icon?.startsWith('<')
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
import { Observable, Subject, Subscription } from 'rxjs'
|
import { Observable, Subject, Subscription } from 'rxjs'
|
||||||
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, OnInit, OnDestroy } from '@angular/core'
|
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy } from '@angular/core'
|
||||||
import { BaseTabComponent, BaseTabProcess } from './baseTab.component'
|
import { BaseTabComponent, BaseTabProcess } from './baseTab.component'
|
||||||
import { TabRecoveryProvider, RecoveredTab } from '../api/tabRecovery'
|
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from '../api/tabRecovery'
|
||||||
import { TabsService } from '../services/tabs.service'
|
import { TabsService } from '../services/tabs.service'
|
||||||
import { HotkeysService } from '../services/hotkeys.service'
|
import { HotkeysService } from '../services/hotkeys.service'
|
||||||
import { TabRecoveryService } from '../services/tabRecovery.service'
|
import { TabRecoveryService } from '../services/tabRecovery.service'
|
||||||
@@ -48,7 +48,7 @@ export class SplitContainer {
|
|||||||
/**
|
/**
|
||||||
* Remove unnecessarily nested child containers and renormalizes [[ratios]]
|
* Remove unnecessarily nested child containers and renormalizes [[ratios]]
|
||||||
*/
|
*/
|
||||||
normalize () {
|
normalize (): void {
|
||||||
for (let i = 0; i < this.children.length; i++) {
|
for (let i = 0; i < this.children.length; i++) {
|
||||||
const child = this.children[i]
|
const child = this.children[i]
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ export class SplitContainer {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
async serialize () {
|
async serialize (): Promise<RecoveryToken> {
|
||||||
const children: any[] = []
|
const children: any[] = []
|
||||||
for (const child of this.children) {
|
for (const child of this.children) {
|
||||||
if (child instanceof SplitContainer) {
|
if (child instanceof SplitContainer) {
|
||||||
@@ -140,7 +140,7 @@ export interface SplitSpannerInfo {
|
|||||||
`,
|
`,
|
||||||
styles: [require('./splitTab.component.scss')],
|
styles: [require('./splitTab.component.scss')],
|
||||||
})
|
})
|
||||||
export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
|
export class SplitTabComponent extends BaseTabComponent implements AfterViewInit, OnDestroy {
|
||||||
static DIRECTIONS: SplitDirection[] = ['t', 'r', 'b', 'l']
|
static DIRECTIONS: SplitDirection[] = ['t', 'r', 'b', 'l']
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@@ -166,6 +166,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
private tabRemoved = new Subject<BaseTabComponent>()
|
private tabRemoved = new Subject<BaseTabComponent>()
|
||||||
private splitAdjusted = new Subject<SplitSpannerInfo>()
|
private splitAdjusted = new Subject<SplitSpannerInfo>()
|
||||||
private focusChanged = new Subject<BaseTabComponent>()
|
private focusChanged = new Subject<BaseTabComponent>()
|
||||||
|
private initialized = new Subject<void>()
|
||||||
|
|
||||||
get tabAdded$ (): Observable<BaseTabComponent> { return this.tabAdded }
|
get tabAdded$ (): Observable<BaseTabComponent> { return this.tabAdded }
|
||||||
get tabRemoved$ (): Observable<BaseTabComponent> { return this.tabRemoved }
|
get tabRemoved$ (): Observable<BaseTabComponent> { return this.tabRemoved }
|
||||||
@@ -180,6 +181,11 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
*/
|
*/
|
||||||
get focusChanged$ (): Observable<BaseTabComponent> { return this.focusChanged }
|
get focusChanged$ (): Observable<BaseTabComponent> { return this.focusChanged }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once tab layout is created and child tabs can be added
|
||||||
|
*/
|
||||||
|
get initialized$ (): Observable<void> { return this.initialized }
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
constructor (
|
||||||
private hotkeys: HotkeysService,
|
private hotkeys: HotkeysService,
|
||||||
@@ -244,7 +250,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
async ngOnInit () {
|
async ngAfterViewInit (): Promise<void> {
|
||||||
if (this._recoveredState) {
|
if (this._recoveredState) {
|
||||||
await this.recoverContainer(this.root, this._recoveredState)
|
await this.recoverContainer(this.root, this._recoveredState)
|
||||||
this.layout()
|
this.layout()
|
||||||
@@ -255,15 +261,17 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
this.initialized.next()
|
||||||
|
this.initialized.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
ngOnDestroy () {
|
ngOnDestroy (): void {
|
||||||
this.hotkeysSubscription.unsubscribe()
|
this.hotkeysSubscription.unsubscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns Flat list of all sub-tabs */
|
/** @returns Flat list of all sub-tabs */
|
||||||
getAllTabs () {
|
getAllTabs (): BaseTabComponent[] {
|
||||||
return this.root.getAllTabs()
|
return this.root.getAllTabs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +283,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
return this.maximizedTab
|
return this.maximizedTab
|
||||||
}
|
}
|
||||||
|
|
||||||
focus (tab: BaseTabComponent) {
|
focus (tab: BaseTabComponent): void {
|
||||||
this.focusedTab = tab
|
this.focusedTab = tab
|
||||||
for (const x of this.getAllTabs()) {
|
for (const x of this.getAllTabs()) {
|
||||||
if (x !== tab) {
|
if (x !== tab) {
|
||||||
@@ -293,7 +301,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
this.layout()
|
this.layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
maximize (tab: BaseTabComponent|null) {
|
maximize (tab: BaseTabComponent|null): void {
|
||||||
this.maximizedTab = tab
|
this.maximizedTab = tab
|
||||||
this.layout()
|
this.layout()
|
||||||
}
|
}
|
||||||
@@ -301,7 +309,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
/**
|
/**
|
||||||
* Focuses the first available tab inside the given [[SplitContainer]]
|
* Focuses the first available tab inside the given [[SplitContainer]]
|
||||||
*/
|
*/
|
||||||
focusAnyIn (parent: BaseTabComponent | SplitContainer) {
|
focusAnyIn (parent: BaseTabComponent | SplitContainer): void {
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -315,7 +323,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
/**
|
/**
|
||||||
* Inserts a new `tab` to the `side` of the `relative` tab
|
* Inserts a new `tab` to the `side` of the `relative` tab
|
||||||
*/
|
*/
|
||||||
addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection) {
|
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
|
let insertIndex = relative ? target.children.indexOf(relative) : -1
|
||||||
|
|
||||||
@@ -345,6 +355,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
target.children.splice(insertIndex, 0, tab)
|
target.children.splice(insertIndex, 0, tab)
|
||||||
|
|
||||||
this.recoveryStateChangedHint.next()
|
this.recoveryStateChangedHint.next()
|
||||||
|
|
||||||
|
await this.initialized$.toPromise()
|
||||||
|
|
||||||
this.attachTabView(tab)
|
this.attachTabView(tab)
|
||||||
|
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
@@ -354,7 +367,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTab (tab: BaseTabComponent) {
|
removeTab (tab: BaseTabComponent): void {
|
||||||
const parent = this.getParentOf(tab)
|
const parent = this.getParentOf(tab)
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return
|
return
|
||||||
@@ -364,11 +377,11 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
parent.children.splice(index, 1)
|
parent.children.splice(index, 1)
|
||||||
|
|
||||||
this.detachTabView(tab)
|
this.detachTabView(tab)
|
||||||
|
tab.parent = null
|
||||||
|
|
||||||
this.layout()
|
this.layout()
|
||||||
|
|
||||||
this.tabRemoved.next(tab)
|
this.tabRemoved.next(tab)
|
||||||
|
|
||||||
if (this.root.children.length === 0) {
|
if (this.root.children.length === 0) {
|
||||||
this.destroy()
|
this.destroy()
|
||||||
} else {
|
} else {
|
||||||
@@ -379,7 +392,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
/**
|
/**
|
||||||
* Moves focus in the given direction
|
* Moves focus in the given direction
|
||||||
*/
|
*/
|
||||||
navigate (dir: SplitDirection) {
|
navigate (dir: SplitDirection): void {
|
||||||
let rel: BaseTabComponent | SplitContainer = this.focusedTab
|
let rel: BaseTabComponent | SplitContainer = this.focusedTab
|
||||||
let parent = this.getParentOf(rel)
|
let parent = this.getParentOf(rel)
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
@@ -412,11 +425,12 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async splitTab (tab: BaseTabComponent, dir: SplitDirection) {
|
async splitTab (tab: BaseTabComponent, dir: SplitDirection): Promise<BaseTabComponent|null> {
|
||||||
const newTab = await this.tabsService.duplicate(tab)
|
const newTab = await this.tabsService.duplicate(tab)
|
||||||
if (newTab) {
|
if (newTab) {
|
||||||
this.addTab(newTab, tab, dir)
|
this.addTab(newTab, tab, dir)
|
||||||
}
|
}
|
||||||
|
return newTab
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -454,12 +468,12 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
onSpannerAdjusted (spanner: SplitSpannerInfo) {
|
onSpannerAdjusted (spanner: SplitSpannerInfo): void {
|
||||||
this.layout()
|
this.layout()
|
||||||
this.splitAdjusted.next(spanner)
|
this.splitAdjusted.next(spanner)
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy () {
|
destroy (): void {
|
||||||
super.destroy()
|
super.destroy()
|
||||||
for (const x of this.getAllTabs()) {
|
for (const x of this.getAllTabs()) {
|
||||||
x.destroy()
|
x.destroy()
|
||||||
@@ -515,21 +529,24 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
if (child instanceof SplitContainer) {
|
if (child instanceof SplitContainer) {
|
||||||
this.layoutInternal(child, childX, childY, childW, childH)
|
this.layoutInternal(child, childX, childY, childW, childH)
|
||||||
} else {
|
} else {
|
||||||
const element = this.viewRefs.get(child)!.rootNodes[0]
|
const viewRef = this.viewRefs.get(child)
|
||||||
element.classList.toggle('child', true)
|
if (viewRef) {
|
||||||
element.classList.toggle('maximized', child === this.maximizedTab)
|
const element = viewRef.rootNodes[0]
|
||||||
element.classList.toggle('minimized', this.maximizedTab && child !== this.maximizedTab)
|
element.classList.toggle('child', true)
|
||||||
element.classList.toggle('focused', child === this.focusedTab)
|
element.classList.toggle('maximized', child === this.maximizedTab)
|
||||||
element.style.left = `${childX}%`
|
element.classList.toggle('minimized', this.maximizedTab && child !== this.maximizedTab)
|
||||||
element.style.top = `${childY}%`
|
element.classList.toggle('focused', child === this.focusedTab)
|
||||||
element.style.width = `${childW}%`
|
element.style.left = `${childX}%`
|
||||||
element.style.height = `${childH}%`
|
element.style.top = `${childY}%`
|
||||||
|
element.style.width = `${childW}%`
|
||||||
|
element.style.height = `${childH}%`
|
||||||
|
|
||||||
if (child === this.maximizedTab) {
|
if (child === this.maximizedTab) {
|
||||||
element.style.left = '5%'
|
element.style.left = '5%'
|
||||||
element.style.top = '5%'
|
element.style.top = '5%'
|
||||||
element.style.width = '90%'
|
element.style.width = '90%'
|
||||||
element.style.height = '90%'
|
element.style.height = '90%'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += sizes[i]
|
offset += sizes[i]
|
||||||
@@ -558,6 +575,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
if (recovered) {
|
if (recovered) {
|
||||||
const tab = this.tabsService.create(recovered.type, recovered.options)
|
const tab = this.tabsService.create(recovered.type, recovered.options)
|
||||||
children.push(tab)
|
children.push(tab)
|
||||||
|
tab.parent = this
|
||||||
this.attachTabView(tab)
|
this.attachTabView(tab)
|
||||||
} else {
|
} else {
|
||||||
state.ratios.splice(state.children.indexOf(childState), 0)
|
state.ratios.splice(state.children.indexOf(childState), 0)
|
||||||
@@ -574,7 +592,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
|||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
|
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
|
||||||
async recover (recoveryToken: any): Promise<RecoveredTab|null> {
|
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
|
||||||
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
|
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
|
||||||
return {
|
return {
|
||||||
type: SplitTabComponent,
|
type: SplitTabComponent,
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input, HostBinding, ElementRef, Output, EventEmitter } from '@angular/core'
|
import { Component, Input, HostBinding, ElementRef, Output, EventEmitter } from '@angular/core'
|
||||||
import { SplitContainer } from './splitTab.component'
|
import { SplitContainer } from './splitTab.component'
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ import { ToolbarButton, ToolbarButtonProvider } from '../api'
|
|||||||
export class StartPageComponent {
|
export class StartPageComponent {
|
||||||
version: string
|
version: string
|
||||||
|
|
||||||
constructor (
|
private constructor (
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
private domSanitizer: DomSanitizer,
|
private domSanitizer: DomSanitizer,
|
||||||
public homeBase: HomeBaseService,
|
public homeBase: HomeBaseService,
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input, ViewChild, HostBinding, ViewContainerRef, OnChanges } from '@angular/core'
|
import { Component, Input, ViewChild, HostBinding, ViewContainerRef, OnChanges } from '@angular/core'
|
||||||
import { BaseTabComponent } from '../components/baseTab.component'
|
import { BaseTabComponent } from '../components/baseTab.component'
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
|
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
|
||||||
import { SortableComponent } from 'ng2-dnd'
|
import { SortableComponent } from 'ng2-dnd'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
@@ -48,14 +49,17 @@ export class TabHeaderComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
if (this.hostApp.platform === Platform.macOS) {
|
|
||||||
this.parentDraggable.setDragHandle(this.handle.nativeElement)
|
|
||||||
}
|
|
||||||
this.tab.progress$.subscribe(progress => {
|
this.tab.progress$.subscribe(progress => {
|
||||||
this.progress = progress
|
this.progress = progress
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit () {
|
||||||
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
|
this.parentDraggable.setDragHandle(this.handle.nativeElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showRenameTabModal (): void {
|
showRenameTabModal (): void {
|
||||||
const modal = this.ngbModal.open(RenameTabModalComponent)
|
const modal = this.ngbModal.open(RenameTabModalComponent)
|
||||||
modal.componentInstance.value = this.tab.customTitle || this.tab.title
|
modal.componentInstance.value = this.tab.customTitle || this.tab.title
|
||||||
|
@@ -1,19 +1,29 @@
|
|||||||
.mb-4
|
.container.mt-5.mb-5
|
||||||
.terminus-logo
|
.mb-4
|
||||||
h1.terminus-title Terminus
|
.terminus-logo
|
||||||
sup α
|
h1.terminus-title Terminus
|
||||||
|
sup α
|
||||||
|
|
||||||
.container
|
|
||||||
.text-center.mb-5 Thank you for downloading Terminus!
|
.text-center.mb-5 Thank you for downloading Terminus!
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title Enable analytics
|
.title Enable analytics
|
||||||
.description Help us track the number of Terminus installs across the world!
|
.description Help us track the number of Terminus installs across the world!
|
||||||
toggle(
|
toggle([(ngModel)]='config.store.enableAnalytics')
|
||||||
[(ngModel)]='config.store.enableAnalytics',
|
|
||||||
(ngModelChange)='config.save(); config.requestRestart()',
|
.form-line
|
||||||
)
|
.header
|
||||||
|
.title Enable SSH plugin
|
||||||
|
.description Adds an SSH connection manager UI to Terminus
|
||||||
|
toggle([(ngModel)]='enableSSH')
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Enable Serial plugin
|
||||||
|
.description Allows attaching Terminus to serial ports
|
||||||
|
toggle([(ngModel)]='enableSerial')
|
||||||
|
|
||||||
|
|
||||||
.text-center.mt-5
|
.text-center.mt-5
|
||||||
button.btn.btn-primary((click)='closeAndDisable()') Close and never show again
|
button.btn.btn-primary((click)='closeAndDisable()') Close and never show again
|
||||||
|
@@ -2,5 +2,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
flex: 0 1 500px;
|
flex: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { BaseTabComponent } from './baseTab.component'
|
import { BaseTabComponent } from './baseTab.component'
|
||||||
import { ConfigService } from '../services/config.service'
|
import { ConfigService } from '../services/config.service'
|
||||||
import { AppService } from '../services/app.service'
|
import { HostAppService } from '../services/hostApp.service'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Component({
|
@Component({
|
||||||
@@ -10,17 +11,29 @@ import { AppService } from '../services/app.service'
|
|||||||
styles: [require('./welcomeTab.component.scss')],
|
styles: [require('./welcomeTab.component.scss')],
|
||||||
})
|
})
|
||||||
export class WelcomeTabComponent extends BaseTabComponent {
|
export class WelcomeTabComponent extends BaseTabComponent {
|
||||||
|
enableSSH = false
|
||||||
|
enableSerial = false
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private app: AppService,
|
private hostApp: HostAppService,
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.setTitle('Welcome')
|
this.setTitle('Welcome')
|
||||||
|
this.enableSSH = !config.store.pluginBlacklist.includes('ssh')
|
||||||
|
this.enableSerial = !config.store.pluginBlacklist.includes('serial')
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAndDisable () {
|
closeAndDisable () {
|
||||||
this.config.store.enableWelcomeTab = false
|
this.config.store.enableWelcomeTab = false
|
||||||
|
this.config.store.pluginBlacklist = []
|
||||||
|
if (!this.enableSSH) {
|
||||||
|
this.config.store.pluginBlacklist.push('ssh')
|
||||||
|
}
|
||||||
|
if (!this.enableSerial) {
|
||||||
|
this.config.store.pluginBlacklist.push('serial')
|
||||||
|
}
|
||||||
this.config.save()
|
this.config.save()
|
||||||
this.app.closeTab(this)
|
this.hostApp.getWindow().reload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { HostAppService } from '../services/hostApp.service'
|
import { HostAppService } from '../services/hostApp.service'
|
||||||
import { AppService } from '../services/app.service'
|
import { AppService } from '../services/app.service'
|
||||||
@@ -9,11 +10,9 @@ import { AppService } from '../services/app.service'
|
|||||||
styles: [require('./windowControls.component.scss')],
|
styles: [require('./windowControls.component.scss')],
|
||||||
})
|
})
|
||||||
export class WindowControlsComponent {
|
export class WindowControlsComponent {
|
||||||
constructor (public hostApp: HostAppService, public app: AppService) { }
|
private constructor (public hostApp: HostAppService, public app: AppService) { }
|
||||||
|
|
||||||
async closeWindow () {
|
async closeWindow () {
|
||||||
if (await this.app.closeAllTabs()) {
|
this.app.closeWindow()
|
||||||
this.hostApp.closeWindow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,8 @@ hotkeys:
|
|||||||
- 'F11'
|
- 'F11'
|
||||||
close-tab:
|
close-tab:
|
||||||
- 'Ctrl-Shift-W'
|
- 'Ctrl-Shift-W'
|
||||||
|
reopen-tab:
|
||||||
|
- 'Ctrl-Shift-T'
|
||||||
toggle-last-tab: []
|
toggle-last-tab: []
|
||||||
rename-tab:
|
rename-tab:
|
||||||
- 'Ctrl-Shift-R'
|
- 'Ctrl-Shift-R'
|
||||||
|
@@ -7,6 +7,8 @@ hotkeys:
|
|||||||
- 'Ctrl+⌘+F'
|
- 'Ctrl+⌘+F'
|
||||||
close-tab:
|
close-tab:
|
||||||
- '⌘-W'
|
- '⌘-W'
|
||||||
|
reopen-tab:
|
||||||
|
- '⌘-Shift-T'
|
||||||
toggle-last-tab: []
|
toggle-last-tab: []
|
||||||
rename-tab:
|
rename-tab:
|
||||||
- '⌘-R'
|
- '⌘-R'
|
||||||
|
@@ -8,6 +8,8 @@ hotkeys:
|
|||||||
- 'Alt-Enter'
|
- 'Alt-Enter'
|
||||||
close-tab:
|
close-tab:
|
||||||
- 'Ctrl-Shift-W'
|
- 'Ctrl-Shift-W'
|
||||||
|
reopen-tab:
|
||||||
|
- 'Ctrl-Shift-T'
|
||||||
toggle-last-tab: []
|
toggle-last-tab: []
|
||||||
rename-tab:
|
rename-tab:
|
||||||
- 'Ctrl-Shift-R'
|
- 'Ctrl-Shift-R'
|
||||||
|
@@ -2,6 +2,8 @@ appearance:
|
|||||||
dock: off
|
dock: off
|
||||||
dockScreen: current
|
dockScreen: current
|
||||||
dockFill: 0.5
|
dockFill: 0.5
|
||||||
|
dockHideOnBlur: false
|
||||||
|
dockAlwaysOnTop: true
|
||||||
tabsLocation: top
|
tabsLocation: top
|
||||||
cycleTabs: true
|
cycleTabs: true
|
||||||
theme: Standard
|
theme: Standard
|
||||||
|
@@ -7,7 +7,7 @@ import { Directive, AfterViewInit, ElementRef } from '@angular/core'
|
|||||||
export class AutofocusDirective implements AfterViewInit {
|
export class AutofocusDirective implements AfterViewInit {
|
||||||
constructor (private el: ElementRef) { }
|
constructor (private el: ElementRef) { }
|
||||||
|
|
||||||
ngAfterViewInit () {
|
ngAfterViewInit (): void {
|
||||||
this.el.nativeElement.blur()
|
this.el.nativeElement.blur()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.el.nativeElement.focus()
|
this.el.nativeElement.focus()
|
||||||
|
@@ -8,7 +8,7 @@ export class FastHtmlBindDirective implements OnChanges {
|
|||||||
@Input() fastHtmlBind: string
|
@Input() fastHtmlBind: string
|
||||||
constructor (private el: ElementRef) { }
|
constructor (private el: ElementRef) { }
|
||||||
|
|
||||||
ngOnChanges () {
|
ngOnChanges (): void {
|
||||||
this.el.nativeElement.innerHTML = this.fastHtmlBind || ''
|
this.el.nativeElement.innerHTML = this.fastHtmlBind || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
|||||||
id: 'close-tab',
|
id: 'close-tab',
|
||||||
name: 'Close tab',
|
name: 'Close tab',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'reopen-tab',
|
||||||
|
name: 'Reopen last tab',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'toggle-last-tab',
|
id: 'toggle-last-tab',
|
||||||
name: 'Toggle last tab',
|
name: 'Toggle last tab',
|
||||||
|
@@ -16,6 +16,7 @@ import { TitleBarComponent } from './components/titleBar.component'
|
|||||||
import { ToggleComponent } from './components/toggle.component'
|
import { ToggleComponent } from './components/toggle.component'
|
||||||
import { WindowControlsComponent } from './components/windowControls.component'
|
import { WindowControlsComponent } from './components/windowControls.component'
|
||||||
import { RenameTabModalComponent } from './components/renameTabModal.component'
|
import { RenameTabModalComponent } from './components/renameTabModal.component'
|
||||||
|
import { SelectorModalComponent } from './components/selectorModal.component'
|
||||||
import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component'
|
import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component'
|
||||||
import { SplitTabSpannerComponent } from './components/splitTabSpanner.component'
|
import { SplitTabSpannerComponent } from './components/splitTabSpanner.component'
|
||||||
import { WelcomeTabComponent } from './components/welcomeTab.component'
|
import { WelcomeTabComponent } from './components/welcomeTab.component'
|
||||||
@@ -35,7 +36,7 @@ import { ConfigService } from './services/config.service'
|
|||||||
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
|
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
|
||||||
import { CoreConfigProvider } from './config'
|
import { CoreConfigProvider } from './config'
|
||||||
import { AppHotkeyProvider } from './hotkeys'
|
import { AppHotkeyProvider } from './hotkeys'
|
||||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu'
|
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu } from './tabContextMenu'
|
||||||
|
|
||||||
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
import 'perfect-scrollbar/css/perfect-scrollbar.css'
|
||||||
import 'ng2-dnd/bundles/style.css'
|
import 'ng2-dnd/bundles/style.css'
|
||||||
@@ -53,7 +54,7 @@ const PROVIDERS = [
|
|||||||
{ provide: Theme, useClass: PaperTheme, multi: true },
|
{ provide: Theme, useClass: PaperTheme, multi: true },
|
||||||
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
||||||
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
|
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
|
||||||
{ provide: TabContextMenuItemProvider, useClass: CloseContextMenu, multi: true },
|
{ provide: TabContextMenuItemProvider, useClass: TabManagementContextMenu, multi: true },
|
||||||
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
|
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
|
||||||
{ provide: TabRecoveryProvider, useClass: SplitTabRecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useClass: SplitTabRecoveryProvider, multi: true },
|
||||||
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } },
|
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } },
|
||||||
@@ -65,7 +66,7 @@ const PROVIDERS = [
|
|||||||
BrowserModule,
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgbModule.forRoot(),
|
NgbModule,
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
DndModule.forRoot(),
|
DndModule.forRoot(),
|
||||||
],
|
],
|
||||||
@@ -82,6 +83,7 @@ const PROVIDERS = [
|
|||||||
SafeModeModalComponent,
|
SafeModeModalComponent,
|
||||||
AutofocusDirective,
|
AutofocusDirective,
|
||||||
FastHtmlBindDirective,
|
FastHtmlBindDirective,
|
||||||
|
SelectorModalComponent,
|
||||||
SplitTabComponent,
|
SplitTabComponent,
|
||||||
SplitTabSpannerComponent,
|
SplitTabSpannerComponent,
|
||||||
WelcomeTabComponent,
|
WelcomeTabComponent,
|
||||||
@@ -89,6 +91,7 @@ const PROVIDERS = [
|
|||||||
entryComponents: [
|
entryComponents: [
|
||||||
RenameTabModalComponent,
|
RenameTabModalComponent,
|
||||||
SafeModeModalComponent,
|
SafeModeModalComponent,
|
||||||
|
SelectorModalComponent,
|
||||||
SplitTabComponent,
|
SplitTabComponent,
|
||||||
WelcomeTabComponent,
|
WelcomeTabComponent,
|
||||||
],
|
],
|
||||||
|
@@ -2,9 +2,13 @@
|
|||||||
import { Observable, Subject, AsyncSubject } from 'rxjs'
|
import { Observable, Subject, AsyncSubject } from 'rxjs'
|
||||||
import { takeUntil } from 'rxjs/operators'
|
import { takeUntil } from 'rxjs/operators'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
import { BaseTabComponent } from '../components/baseTab.component'
|
import { BaseTabComponent } from '../components/baseTab.component'
|
||||||
import { SplitTabComponent } from '../components/splitTab.component'
|
import { SplitTabComponent } from '../components/splitTab.component'
|
||||||
|
import { SelectorModalComponent } from '../components/selectorModal.component'
|
||||||
|
import { SelectorOption } from '../api/selector'
|
||||||
|
import { RecoveryToken } from '../api/tabRecovery'
|
||||||
|
|
||||||
import { ConfigService } from './config.service'
|
import { ConfigService } from './config.service'
|
||||||
import { HostAppService } from './hostApp.service'
|
import { HostAppService } from './hostApp.service'
|
||||||
@@ -46,6 +50,7 @@ export class AppService {
|
|||||||
|
|
||||||
private lastTabIndex = 0
|
private lastTabIndex = 0
|
||||||
private _activeTab: BaseTabComponent
|
private _activeTab: BaseTabComponent
|
||||||
|
private closedTabsStack: RecoveryToken[] = []
|
||||||
|
|
||||||
private activeTabChange = new Subject<BaseTabComponent>()
|
private activeTabChange = new Subject<BaseTabComponent>()
|
||||||
private tabsChanged = new Subject<void>()
|
private tabsChanged = new Subject<void>()
|
||||||
@@ -64,41 +69,47 @@ export class AppService {
|
|||||||
get ready$ (): Observable<void> { return this.ready }
|
get ready$ (): Observable<void> { return this.ready }
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
private tabRecovery: TabRecoveryService,
|
private tabRecovery: TabRecoveryService,
|
||||||
private tabsService: TabsService,
|
private tabsService: TabsService,
|
||||||
|
private ngbModal: NgbModal,
|
||||||
) {
|
) {
|
||||||
if (hostApp.getWindow().id === 1) {
|
|
||||||
if (config.store.terminal.recoverTabs) {
|
|
||||||
this.tabRecovery.recoverTabs().then(tabs => {
|
|
||||||
for (const tab of tabs) {
|
|
||||||
this.openNewTabRaw(tab.type, tab.options)
|
|
||||||
}
|
|
||||||
this.startTabStorage()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
/** Continue to store the tabs even if the setting is currently off */
|
|
||||||
this.startTabStorage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hostApp.windowFocused$.subscribe(() => {
|
|
||||||
this._activeTab?.emitFocused()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
startTabStorage () {
|
|
||||||
this.tabsChanged$.subscribe(() => {
|
this.tabsChanged$.subscribe(() => {
|
||||||
this.tabRecovery.saveTabs(this.tabs)
|
this.tabRecovery.saveTabs(this.tabs)
|
||||||
})
|
})
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.tabRecovery.saveTabs(this.tabs)
|
this.tabRecovery.saveTabs(this.tabs)
|
||||||
}, 30000)
|
}, 30000)
|
||||||
|
|
||||||
|
if (hostApp.getWindow().id === 1) {
|
||||||
|
if (config.store.terminal.recoverTabs) {
|
||||||
|
this.tabRecovery.recoverTabs().then(tabs => {
|
||||||
|
for (const tab of tabs) {
|
||||||
|
this.openNewTabRaw(tab.type, tab.options)
|
||||||
|
}
|
||||||
|
this.tabRecovery.enabled = true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/** Continue to store the tabs even if the setting is currently off */
|
||||||
|
this.tabRecovery.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hostApp.windowFocused$.subscribe(() => {
|
||||||
|
this._activeTab?.emitFocused()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.tabClosed$.subscribe(async tab => {
|
||||||
|
const token = await tab.getRecoveryToken()
|
||||||
|
if (token) {
|
||||||
|
this.closedTabsStack.push(token)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
addTabRaw (tab: BaseTabComponent, index: number|null = null) {
|
addTabRaw (tab: BaseTabComponent, index: number|null = null): void {
|
||||||
if (index !== null) {
|
if (index !== null) {
|
||||||
this.tabs.splice(index, 0, tab)
|
this.tabs.splice(index, 0, tab)
|
||||||
} else {
|
} else {
|
||||||
@@ -141,7 +152,7 @@ export class AppService {
|
|||||||
* Adds a new tab **without** wrapping it in a SplitTabComponent
|
* Adds a new tab **without** wrapping it in a SplitTabComponent
|
||||||
* @param inputs Properties to be assigned on the new tab component instance
|
* @param inputs Properties to be assigned on the new tab component instance
|
||||||
*/
|
*/
|
||||||
openNewTabRaw (type: TabComponentType, inputs?: any): BaseTabComponent {
|
openNewTabRaw (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
|
||||||
const tab = this.tabsService.create(type, inputs)
|
const tab = this.tabsService.create(type, inputs)
|
||||||
this.addTabRaw(tab)
|
this.addTabRaw(tab)
|
||||||
return tab
|
return tab
|
||||||
@@ -151,7 +162,7 @@ export class AppService {
|
|||||||
* Adds a new tab while wrapping it in a SplitTabComponent
|
* Adds a new tab while wrapping it in a SplitTabComponent
|
||||||
* @param inputs Properties to be assigned on the new tab component instance
|
* @param inputs Properties to be assigned on the new tab component instance
|
||||||
*/
|
*/
|
||||||
openNewTab (type: TabComponentType, inputs?: any): BaseTabComponent {
|
openNewTab (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
|
||||||
const splitTab = this.tabsService.create(SplitTabComponent) as SplitTabComponent
|
const splitTab = this.tabsService.create(SplitTabComponent) as SplitTabComponent
|
||||||
const tab = this.tabsService.create(type, inputs)
|
const tab = this.tabsService.create(type, inputs)
|
||||||
splitTab.addTab(tab, null, 'r')
|
splitTab.addTab(tab, null, 'r')
|
||||||
@@ -159,7 +170,24 @@ export class AppService {
|
|||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
|
|
||||||
selectTab (tab: BaseTabComponent) {
|
async reopenLastTab (): Promise<BaseTabComponent|null> {
|
||||||
|
const token = this.closedTabsStack.pop()
|
||||||
|
if (token) {
|
||||||
|
const recoveredTab = await this.tabRecovery.recoverTab(token)
|
||||||
|
if (recoveredTab) {
|
||||||
|
const tab = this.tabsService.create(recoveredTab.type, recoveredTab.options)
|
||||||
|
if (this.activeTab) {
|
||||||
|
this.addTabRaw(tab, this.tabs.indexOf(this.activeTab) + 1)
|
||||||
|
} else {
|
||||||
|
this.addTabRaw(tab)
|
||||||
|
}
|
||||||
|
return tab
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTab (tab: BaseTabComponent): void {
|
||||||
if (this._activeTab === tab) {
|
if (this._activeTab === tab) {
|
||||||
this._activeTab.emitFocused()
|
this._activeTab.emitFocused()
|
||||||
return
|
return
|
||||||
@@ -195,14 +223,14 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Switches between the current tab and the previously active one */
|
/** Switches between the current tab and the previously active one */
|
||||||
toggleLastTab () {
|
toggleLastTab (): void {
|
||||||
if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
|
if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
|
||||||
this.lastTabIndex = 0
|
this.lastTabIndex = 0
|
||||||
}
|
}
|
||||||
this.selectTab(this.tabs[this.lastTabIndex])
|
this.selectTab(this.tabs[this.lastTabIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTab () {
|
nextTab (): void {
|
||||||
if (this.tabs.length > 1) {
|
if (this.tabs.length > 1) {
|
||||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||||
if (tabIndex < this.tabs.length - 1) {
|
if (tabIndex < this.tabs.length - 1) {
|
||||||
@@ -213,7 +241,7 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previousTab () {
|
previousTab (): void {
|
||||||
if (this.tabs.length > 1) {
|
if (this.tabs.length > 1) {
|
||||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||||
if (tabIndex > 0) {
|
if (tabIndex > 0) {
|
||||||
@@ -224,7 +252,7 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveSelectedTabLeft () {
|
moveSelectedTabLeft (): void {
|
||||||
if (this.tabs.length > 1) {
|
if (this.tabs.length > 1) {
|
||||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||||
if (tabIndex > 0) {
|
if (tabIndex > 0) {
|
||||||
@@ -235,7 +263,7 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveSelectedTabRight () {
|
moveSelectedTabRight (): void {
|
||||||
if (this.tabs.length > 1) {
|
if (this.tabs.length > 1) {
|
||||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||||
if (tabIndex < this.tabs.length - 1) {
|
if (tabIndex < this.tabs.length - 1) {
|
||||||
@@ -246,7 +274,7 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
swapTabs (a: BaseTabComponent, b: BaseTabComponent) {
|
swapTabs (a: BaseTabComponent, b: BaseTabComponent): void {
|
||||||
const i1 = this.tabs.indexOf(a)
|
const i1 = this.tabs.indexOf(a)
|
||||||
const i2 = this.tabs.indexOf(b)
|
const i2 = this.tabs.indexOf(b)
|
||||||
this.tabs[i1] = b
|
this.tabs[i1] = b
|
||||||
@@ -254,7 +282,7 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
emitTabsChanged () {
|
emitTabsChanged (): void {
|
||||||
this.tabsChanged.next()
|
this.tabsChanged.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,11 +296,12 @@ export class AppService {
|
|||||||
tab.destroy()
|
tab.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
async duplicateTab (tab: BaseTabComponent) {
|
async duplicateTab (tab: BaseTabComponent): Promise<BaseTabComponent|null> {
|
||||||
const dup = await this.tabsService.duplicate(tab)
|
const dup = await this.tabsService.duplicate(tab)
|
||||||
if (dup) {
|
if (dup) {
|
||||||
this.addTabRaw(dup, this.tabs.indexOf(tab) + 1)
|
this.addTabRaw(dup, this.tabs.indexOf(tab) + 1)
|
||||||
}
|
}
|
||||||
|
return dup
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -290,8 +319,18 @@ export class AppService {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async closeWindow (): Promise<void> {
|
||||||
|
this.tabRecovery.enabled = false
|
||||||
|
await this.tabRecovery.saveTabs(this.tabs)
|
||||||
|
if (await this.closeAllTabs()) {
|
||||||
|
this.hostApp.closeWindow()
|
||||||
|
} else {
|
||||||
|
this.tabRecovery.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
emitReady () {
|
emitReady (): void {
|
||||||
this.ready.next()
|
this.ready.next()
|
||||||
this.ready.complete()
|
this.ready.complete()
|
||||||
this.hostApp.emitReady()
|
this.hostApp.emitReady()
|
||||||
@@ -312,7 +351,15 @@ export class AppService {
|
|||||||
return this.completionObservers.get(tab)!.done$
|
return this.completionObservers.get(tab)!.done$
|
||||||
}
|
}
|
||||||
|
|
||||||
stopObservingTabCompletion (tab: BaseTabComponent) {
|
stopObservingTabCompletion (tab: BaseTabComponent): void {
|
||||||
this.completionObservers.delete(tab)
|
this.completionObservers.delete(tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showSelector <T> (name: string, options: SelectorOption<T>[]): Promise<T> {
|
||||||
|
const modal = this.ngbModal.open(SelectorModalComponent)
|
||||||
|
const instance: SelectorModalComponent<T> = modal.componentInstance
|
||||||
|
instance.name = name
|
||||||
|
instance.options = options
|
||||||
|
return modal.result as Promise<T>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ function isNonStructuralObjectMember (v): boolean {
|
|||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
export class ConfigProxy {
|
export class ConfigProxy {
|
||||||
constructor (real: any, defaults: any) {
|
constructor (real: Record<string, any>, defaults: Record<string, any>) {
|
||||||
for (const key in defaults) {
|
for (const key in defaults) {
|
||||||
if (isStructuralMember(defaults[key])) {
|
if (isStructuralMember(defaults[key])) {
|
||||||
if (!real[key]) {
|
if (!real[key]) {
|
||||||
@@ -71,8 +71,10 @@ export class ConfigProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue (_key: string): any { } // eslint-disable-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
|
||||||
setValue (_key: string, _value: any) { } // eslint-disable-line @typescript-eslint/no-empty-function
|
getValue (_key: string): any { }
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
|
||||||
|
setValue (_key: string, _value: any) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
@@ -100,7 +102,7 @@ export class ConfigService {
|
|||||||
get changed$ (): Observable<void> { return this.changed }
|
get changed$ (): Observable<void> { return this.changed }
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
electron: ElectronService,
|
electron: ElectronService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
@Inject(ConfigProvider) configProviders: ConfigProvider[],
|
@Inject(ConfigProvider) configProviders: ConfigProvider[],
|
||||||
@@ -124,7 +126,7 @@ export class ConfigService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaults () {
|
getDefaults (): Record<string, any> {
|
||||||
const cleanup = o => {
|
const cleanup = o => {
|
||||||
if (o instanceof Array) {
|
if (o instanceof Array) {
|
||||||
return o.map(cleanup)
|
return o.map(cleanup)
|
||||||
@@ -153,9 +155,11 @@ export class ConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save (): void {
|
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.safeDump(this._store), 'utf8')
|
||||||
this.emitChange()
|
this.emitChange()
|
||||||
this.hostApp.broadcastConfigChange()
|
this.hostApp.broadcastConfigChange(this.store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,11 +192,11 @@ export class ConfigService {
|
|||||||
enabledServices<T extends object> (services: T[]): T[] {
|
enabledServices<T extends object> (services: T[]): T[] {
|
||||||
if (!this.servicesCache) {
|
if (!this.servicesCache) {
|
||||||
this.servicesCache = {}
|
this.servicesCache = {}
|
||||||
const ngModule = window['rootModule'].ngInjectorDef
|
const ngModule = window['rootModule'].ɵinj
|
||||||
for (const imp of ngModule.imports) {
|
for (const imp of ngModule.imports) {
|
||||||
const module = imp['ngModule'] || imp
|
const module = imp['ngModule'] || imp
|
||||||
if (module.ngInjectorDef && module.ngInjectorDef.providers) {
|
if (module.ɵinj?.providers) {
|
||||||
this.servicesCache[module['pluginName']] = module.ngInjectorDef.providers.map(provider => {
|
this.servicesCache[module['pluginName']] = module.ɵinj.providers.map(provider => {
|
||||||
return provider['useClass'] || provider
|
return provider['useClass'] || provider
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ import { HostAppService, Bounds } from '../services/hostApp.service'
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class DockingService {
|
export class DockingService {
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
@@ -15,7 +15,7 @@ export class DockingService {
|
|||||||
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
|
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
|
||||||
}
|
}
|
||||||
|
|
||||||
dock () {
|
dock (): void {
|
||||||
const dockSide = this.config.store.appearance.dock
|
const dockSide = this.config.store.appearance.dock
|
||||||
|
|
||||||
if (dockSide === 'off') {
|
if (dockSide === 'off') {
|
||||||
@@ -53,22 +53,25 @@ export class DockingService {
|
|||||||
newBounds.y = display.bounds.y
|
newBounds.y = display.bounds.y
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hostApp.setAlwaysOnTop(true)
|
const alwaysOnTop = this.config.store.appearance.dockAlwaysOnTop
|
||||||
|
|
||||||
|
this.hostApp.setAlwaysOnTop(alwaysOnTop)
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this.hostApp.setBounds(newBounds)
|
this.hostApp.setBounds(newBounds)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentScreen () {
|
getCurrentScreen (): Electron.Display {
|
||||||
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
|
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
getScreens () {
|
getScreens (): Electron.Display[] {
|
||||||
const primaryDisplayID = this.electron.screen.getPrimaryDisplay().id
|
const primaryDisplayID = this.electron.screen.getPrimaryDisplay().id
|
||||||
return this.electron.screen.getAllDisplays().sort((a, b) =>
|
return this.electron.screen.getAllDisplays().sort((a, b) =>
|
||||||
a.bounds.x === b.bounds.x ? a.bounds.y - b.bounds.y : a.bounds.x - b.bounds.x
|
a.bounds.x === b.bounds.x ? a.bounds.y - b.bounds.y : a.bounds.x - b.bounds.x
|
||||||
).map((display,index) => {
|
).map((display, index) => {
|
||||||
return {
|
return {
|
||||||
|
...display,
|
||||||
id: display.id,
|
id: display.id,
|
||||||
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index +1}`,
|
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index +1}`,
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ export class ElectronService {
|
|||||||
private electron: any
|
private electron: any
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor () {
|
private constructor () {
|
||||||
this.electron = require('electron')
|
this.electron = require('electron')
|
||||||
this.remote = this.electron.remote
|
this.remote = this.electron.remote
|
||||||
this.app = this.remote.app
|
this.app = this.remote.app
|
||||||
@@ -43,15 +43,6 @@ export class ElectronService {
|
|||||||
this.MenuItem = this.remote.MenuItem
|
this.MenuItem = this.remote.MenuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes OS focus from Terminus' window
|
|
||||||
*/
|
|
||||||
loseFocus () {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
this.remote.Menu.sendActionToFirstResponder('hide:')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async showMessageBox (
|
async showMessageBox (
|
||||||
browserWindow: Electron.BrowserWindow,
|
browserWindow: Electron.BrowserWindow,
|
||||||
options: Electron.MessageBoxOptions
|
options: Electron.MessageBoxOptions
|
||||||
|
@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'
|
|||||||
import { ElectronService } from './electron.service'
|
import { ElectronService } from './electron.service'
|
||||||
import { ConfigService } from './config.service'
|
import { ConfigService } from './config.service'
|
||||||
import * as mixpanel from 'mixpanel'
|
import * as mixpanel from 'mixpanel'
|
||||||
import * as uuidv4 from 'uuid/v4'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class HomeBaseService {
|
export class HomeBaseService {
|
||||||
@@ -11,7 +11,7 @@ export class HomeBaseService {
|
|||||||
mixpanel: any
|
mixpanel: any
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
) {
|
) {
|
||||||
@@ -22,11 +22,11 @@ export class HomeBaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openGitHub () {
|
openGitHub (): void {
|
||||||
this.electron.shell.openExternal('https://github.com/eugeny/terminus')
|
this.electron.shell.openExternal('https://github.com/eugeny/terminus')
|
||||||
}
|
}
|
||||||
|
|
||||||
reportBug () {
|
reportBug (): void {
|
||||||
let body = `Version: ${this.appVersion}\n`
|
let body = `Version: ${this.appVersion}\n`
|
||||||
body += `Platform: ${os.platform()} ${os.release()}\n`
|
body += `Platform: ${os.platform()} ${os.release()}\n`
|
||||||
const label = {
|
const label = {
|
||||||
@@ -44,7 +44,7 @@ export class HomeBaseService {
|
|||||||
this.electron.shell.openExternal(`https://github.com/eugeny/terminus/issues/new?body=${encodeURIComponent(body)}&labels=${label}`)
|
this.electron.shell.openExternal(`https://github.com/eugeny/terminus/issues/new?body=${encodeURIComponent(body)}&labels=${label}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
enableAnalytics () {
|
enableAnalytics (): void {
|
||||||
if (!window.localStorage.analyticsUserID) {
|
if (!window.localStorage.analyticsUserID) {
|
||||||
window.localStorage.analyticsUserID = uuidv4()
|
window.localStorage.analyticsUserID = uuidv4()
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ export class HomeBaseService {
|
|||||||
this.mixpanel.track('launch', this.getAnalyticsProperties())
|
this.mixpanel.track('launch', this.getAnalyticsProperties())
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnalyticsProperties () {
|
getAnalyticsProperties (): Record<string, string> {
|
||||||
return {
|
return {
|
||||||
distinct_id: window.localStorage.analyticsUserID, // eslint-disable-line @typescript-eslint/camelcase
|
distinct_id: window.localStorage.analyticsUserID, // eslint-disable-line @typescript-eslint/camelcase
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
|
@@ -166,7 +166,6 @@ export class HostAppService {
|
|||||||
this.configChangeBroadcast.next()
|
this.configChangeBroadcast.next()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED) &&
|
isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED) &&
|
||||||
!isWindowsBuild(WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED)
|
!isWindowsBuild(WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED)
|
||||||
@@ -178,48 +177,48 @@ export class HostAppService {
|
|||||||
/**
|
/**
|
||||||
* Returns the current remote [[BrowserWindow]]
|
* Returns the current remote [[BrowserWindow]]
|
||||||
*/
|
*/
|
||||||
getWindow () {
|
getWindow (): Electron.BrowserWindow {
|
||||||
return this.electron.BrowserWindow.fromId(this.windowId)
|
return this.electron.BrowserWindow.fromId(this.windowId)
|
||||||
}
|
}
|
||||||
|
|
||||||
newWindow () {
|
newWindow (): void {
|
||||||
this.electron.ipcRenderer.send('app:new-window')
|
this.electron.ipcRenderer.send('app:new-window')
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFullscreen () {
|
toggleFullscreen (): void {
|
||||||
const window = this.getWindow()
|
const window = this.getWindow()
|
||||||
window.setFullScreen(!this.isFullScreen)
|
window.setFullScreen(!this.isFullScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
openDevTools () {
|
openDevTools (): void {
|
||||||
this.getWindow().webContents.openDevTools({ mode: 'undocked' })
|
this.getWindow().webContents.openDevTools({ mode: 'undocked' })
|
||||||
}
|
}
|
||||||
|
|
||||||
focusWindow () {
|
focusWindow (): void {
|
||||||
this.electron.ipcRenderer.send('window-focus')
|
this.electron.ipcRenderer.send('window-focus')
|
||||||
}
|
}
|
||||||
|
|
||||||
minimize () {
|
minimize (): void {
|
||||||
this.electron.ipcRenderer.send('window-minimize')
|
this.electron.ipcRenderer.send('window-minimize')
|
||||||
}
|
}
|
||||||
|
|
||||||
maximize () {
|
maximize (): void {
|
||||||
this.electron.ipcRenderer.send('window-maximize')
|
this.electron.ipcRenderer.send('window-maximize')
|
||||||
}
|
}
|
||||||
|
|
||||||
unmaximize () {
|
unmaximize (): void {
|
||||||
this.electron.ipcRenderer.send('window-unmaximize')
|
this.electron.ipcRenderer.send('window-unmaximize')
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleMaximize () {
|
toggleMaximize (): void {
|
||||||
this.electron.ipcRenderer.send('window-toggle-maximize')
|
this.electron.ipcRenderer.send('window-toggle-maximize')
|
||||||
}
|
}
|
||||||
|
|
||||||
setBounds (bounds: Bounds) {
|
setBounds (bounds: Bounds): void {
|
||||||
this.electron.ipcRenderer.send('window-set-bounds', bounds)
|
this.electron.ipcRenderer.send('window-set-bounds', bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
setAlwaysOnTop (flag: boolean) {
|
setAlwaysOnTop (flag: boolean): void {
|
||||||
this.electron.ipcRenderer.send('window-set-always-on-top', flag)
|
this.electron.ipcRenderer.send('window-set-always-on-top', flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +227,7 @@ export class HostAppService {
|
|||||||
*
|
*
|
||||||
* @param type `null`, or `fluent` when supported (Windowd only)
|
* @param type `null`, or `fluent` when supported (Windowd only)
|
||||||
*/
|
*/
|
||||||
setVibrancy (enable: boolean, type: string|null) {
|
setVibrancy (enable: boolean, type: string|null): void {
|
||||||
if (!isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
if (!isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||||
type = null
|
type = null
|
||||||
}
|
}
|
||||||
@@ -236,38 +235,42 @@ export class HostAppService {
|
|||||||
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
|
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTitle (title: string) {
|
setTitle (title: string): void {
|
||||||
this.electron.ipcRenderer.send('window-set-title', title)
|
this.electron.ipcRenderer.send('window-set-title', title)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTouchBar (touchBar: Electron.TouchBar) {
|
setTouchBar (touchBar: Electron.TouchBar): void {
|
||||||
this.getWindow().setTouchBar(touchBar)
|
this.getWindow().setTouchBar(touchBar)
|
||||||
}
|
}
|
||||||
|
|
||||||
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]) {
|
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]): void {
|
||||||
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
|
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies other windows of config file changes
|
* Notifies other windows of config file changes
|
||||||
*/
|
*/
|
||||||
broadcastConfigChange () {
|
broadcastConfigChange (configStore: {[k: string]: any}): void {
|
||||||
this.electron.ipcRenderer.send('app:config-change')
|
this.electron.ipcRenderer.send('app:config-change', configStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitReady () {
|
emitReady (): void {
|
||||||
this.electron.ipcRenderer.send('app:ready')
|
this.electron.ipcRenderer.send('app:ready')
|
||||||
}
|
}
|
||||||
|
|
||||||
bringToFront () {
|
bringToFront (): void {
|
||||||
this.electron.ipcRenderer.send('window-bring-to-front')
|
this.electron.ipcRenderer.send('window-bring-to-front')
|
||||||
}
|
}
|
||||||
|
|
||||||
closeWindow () {
|
closeWindow (): void {
|
||||||
this.electron.ipcRenderer.send('window-close')
|
this.electron.ipcRenderer.send('window-close')
|
||||||
}
|
}
|
||||||
|
|
||||||
relaunch () {
|
registerGlobalHotkey (specs: string[]): void {
|
||||||
|
this.electron.ipcRenderer.send('app:register-global-hotkey', specs)
|
||||||
|
}
|
||||||
|
|
||||||
|
relaunch (): void {
|
||||||
if (this.isPortable) {
|
if (this.isPortable) {
|
||||||
this.electron.app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE })
|
this.electron.app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE })
|
||||||
} else {
|
} else {
|
||||||
@@ -276,7 +279,7 @@ export class HostAppService {
|
|||||||
this.electron.app.exit()
|
this.electron.app.exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
quit () {
|
quit (): void {
|
||||||
this.logger.info('Quitting')
|
this.logger.info('Quitting')
|
||||||
this.electron.app.quit()
|
this.electron.app.quit()
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,9 @@ import { Injectable, Inject, NgZone, EventEmitter } from '@angular/core'
|
|||||||
import { Observable, Subject } from 'rxjs'
|
import { Observable, Subject } from 'rxjs'
|
||||||
import { HotkeyDescription, HotkeyProvider } from '../api/hotkeyProvider'
|
import { HotkeyDescription, HotkeyProvider } from '../api/hotkeyProvider'
|
||||||
import { stringifyKeySequence } from './hotkeys.util'
|
import { stringifyKeySequence } from './hotkeys.util'
|
||||||
import { ConfigService } from '../services/config.service'
|
import { ConfigService } from './config.service'
|
||||||
import { ElectronService } from '../services/electron.service'
|
import { ElectronService } from './electron.service'
|
||||||
|
import { HostAppService } from './hostApp.service'
|
||||||
|
|
||||||
export interface PartialHotkeyMatch {
|
export interface PartialHotkeyMatch {
|
||||||
id: string
|
id: string
|
||||||
@@ -30,7 +31,6 @@ export class HotkeysService {
|
|||||||
*/
|
*/
|
||||||
get hotkey$ (): Observable<string> { return this._hotkey }
|
get hotkey$ (): Observable<string> { return this._hotkey }
|
||||||
|
|
||||||
globalHotkey = new EventEmitter<void>()
|
|
||||||
private _hotkey = new Subject<string>()
|
private _hotkey = new Subject<string>()
|
||||||
private currentKeystrokes: EventBufferEntry[] = []
|
private currentKeystrokes: EventBufferEntry[] = []
|
||||||
private disabledLevel = 0
|
private disabledLevel = 0
|
||||||
@@ -38,6 +38,7 @@ export class HotkeysService {
|
|||||||
|
|
||||||
private constructor (
|
private constructor (
|
||||||
private zone: NgZone,
|
private zone: NgZone,
|
||||||
|
private hostApp: HostAppService,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
@Inject(HotkeyProvider) private hotkeyProviders: HotkeyProvider[],
|
@Inject(HotkeyProvider) private hotkeyProviders: HotkeyProvider[],
|
||||||
@@ -70,7 +71,7 @@ export class HotkeysService {
|
|||||||
* @param name DOM event name
|
* @param name DOM event name
|
||||||
* @param nativeEvent event object
|
* @param nativeEvent event object
|
||||||
*/
|
*/
|
||||||
pushKeystroke (name: string, nativeEvent: KeyboardEvent) {
|
pushKeystroke (name: string, nativeEvent: KeyboardEvent): void {
|
||||||
(nativeEvent as any).event = name
|
(nativeEvent as any).event = name
|
||||||
this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
|
this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,7 @@ export class HotkeysService {
|
|||||||
/**
|
/**
|
||||||
* Check the buffer for new complete keystrokes
|
* Check the buffer for new complete keystrokes
|
||||||
*/
|
*/
|
||||||
processKeystrokes () {
|
processKeystrokes (): void {
|
||||||
if (this.isEnabled()) {
|
if (this.isEnabled()) {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
const matched = this.getCurrentFullyMatchedHotkey()
|
const matched = this.getCurrentFullyMatchedHotkey()
|
||||||
@@ -91,13 +92,13 @@ export class HotkeysService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitKeyEvent (nativeEvent: KeyboardEvent) {
|
emitKeyEvent (nativeEvent: KeyboardEvent): void {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
this.key.emit(nativeEvent)
|
this.key.emit(nativeEvent)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCurrentKeystrokes () {
|
clearCurrentKeystrokes (): void {
|
||||||
this.currentKeystrokes = []
|
this.currentKeystrokes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,15 +156,15 @@ export class HotkeysService {
|
|||||||
return this.hotkeyDescriptions.filter((x) => x.id === id)[0]
|
return this.hotkeyDescriptions.filter((x) => x.id === id)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
enable () {
|
enable (): void {
|
||||||
this.disabledLevel--
|
this.disabledLevel--
|
||||||
}
|
}
|
||||||
|
|
||||||
disable () {
|
disable (): void {
|
||||||
this.disabledLevel++
|
this.disabledLevel++
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled () {
|
isEnabled (): boolean {
|
||||||
return this.disabledLevel === 0
|
return this.disabledLevel === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +183,7 @@ export class HotkeysService {
|
|||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
value = [value]
|
value = [value]
|
||||||
}
|
}
|
||||||
|
const specs: string[] = []
|
||||||
value.forEach((item: string | string[]) => {
|
value.forEach((item: string | string[]) => {
|
||||||
item = typeof item === 'string' ? [item] : item
|
item = typeof item === 'string' ? [item] : item
|
||||||
|
|
||||||
@@ -190,13 +192,13 @@ export class HotkeysService {
|
|||||||
electronKeySpec = electronKeySpec.replace('⌘', 'Command')
|
electronKeySpec = electronKeySpec.replace('⌘', 'Command')
|
||||||
electronKeySpec = electronKeySpec.replace('⌥', 'Alt')
|
electronKeySpec = electronKeySpec.replace('⌥', 'Alt')
|
||||||
electronKeySpec = electronKeySpec.replace(/-/g, '+')
|
electronKeySpec = electronKeySpec.replace(/-/g, '+')
|
||||||
this.electron.globalShortcut.register(electronKeySpec, () => {
|
specs.push(electronKeySpec)
|
||||||
this.globalHotkey.emit()
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Could not register the global hotkey:', err)
|
console.error('Could not register the global hotkey:', err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.hostApp.registerGlobalHotkey(specs)
|
||||||
}
|
}
|
||||||
|
|
||||||
private getHotkeysConfig () {
|
private getHotkeysConfig () {
|
||||||
@@ -216,6 +218,9 @@ export class HotkeysService {
|
|||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
value = [value]
|
value = [value]
|
||||||
}
|
}
|
||||||
|
if (!(value instanceof Array)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
|
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
|
||||||
keys[key] = value
|
keys[key] = value
|
||||||
|
@@ -32,27 +32,27 @@ export class Logger {
|
|||||||
private name: string,
|
private name: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
debug (...args: any[]) {
|
debug (...args: any[]): void {
|
||||||
this.doLog('debug', ...args)
|
this.doLog('debug', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
info (...args: any[]) {
|
info (...args: any[]): void {
|
||||||
this.doLog('info', ...args)
|
this.doLog('info', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
warn (...args: any[]) {
|
warn (...args: any[]): void {
|
||||||
this.doLog('warn', ...args)
|
this.doLog('warn', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
error (...args: any[]) {
|
error (...args: any[]): void {
|
||||||
this.doLog('error', ...args)
|
this.doLog('error', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
log (...args: any[]) {
|
log (...args: any[]): void {
|
||||||
this.doLog('log', ...args)
|
this.doLog('log', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
private doLog (level: string, ...args: any[]) {
|
private doLog (level: string, ...args: any[]): void {
|
||||||
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
|
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
|
||||||
if (this.winstonLogger) {
|
if (this.winstonLogger) {
|
||||||
this.winstonLogger[level](...args)
|
this.winstonLogger[level](...args)
|
||||||
@@ -65,7 +65,7 @@ export class LogService {
|
|||||||
private log: any
|
private log: any
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (electron: ElectronService) {
|
private constructor (electron: ElectronService) {
|
||||||
this.log = initializeWinston(electron)
|
this.log = initializeWinston(electron)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ export class ShellIntegrationService {
|
|||||||
command: 'paste "%V"',
|
command: 'paste "%V"',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
constructor (
|
private constructor (
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
) {
|
) {
|
||||||
@@ -58,7 +58,7 @@ export class ShellIntegrationService {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async install () {
|
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) {
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
for (const wf of this.automatorWorkflows) {
|
for (const wf of this.automatorWorkflows) {
|
||||||
@@ -82,7 +82,7 @@ export class ShellIntegrationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove () {
|
async remove (): Promise<void> {
|
||||||
if (this.hostApp.platform === Platform.macOS) {
|
if (this.hostApp.platform === Platform.macOS) {
|
||||||
for (const wf of this.automatorWorkflows) {
|
for (const wf of this.automatorWorkflows) {
|
||||||
await exec(`rm -rf "${this.automatorWorkflowsDestination}/${wf}"`)
|
await exec(`rm -rf "${this.automatorWorkflowsDestination}/${wf}"`)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable, Inject } from '@angular/core'
|
import { Injectable, Inject } from '@angular/core'
|
||||||
import { TabRecoveryProvider, RecoveredTab } from '../api/tabRecovery'
|
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from '../api/tabRecovery'
|
||||||
import { BaseTabComponent } from '../components/baseTab.component'
|
import { BaseTabComponent } from '../components/baseTab.component'
|
||||||
import { Logger, LogService } from '../services/log.service'
|
import { Logger, LogService } from '../services/log.service'
|
||||||
import { ConfigService } from '../services/config.service'
|
import { ConfigService } from '../services/config.service'
|
||||||
@@ -8,8 +8,9 @@ import { ConfigService } from '../services/config.service'
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class TabRecoveryService {
|
export class TabRecoveryService {
|
||||||
logger: Logger
|
logger: Logger
|
||||||
|
enabled = false
|
||||||
|
|
||||||
constructor (
|
private constructor (
|
||||||
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
|
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
log: LogService
|
log: LogService
|
||||||
@@ -17,7 +18,10 @@ export class TabRecoveryService {
|
|||||||
this.logger = log.create('tabRecovery')
|
this.logger = log.create('tabRecovery')
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveTabs (tabs: BaseTabComponent[]) {
|
async saveTabs (tabs: BaseTabComponent[]): Promise<void> {
|
||||||
|
if (!this.enabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
window.localStorage.tabsRecovery = JSON.stringify(
|
window.localStorage.tabsRecovery = JSON.stringify(
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
tabs
|
tabs
|
||||||
@@ -26,7 +30,10 @@ export class TabRecoveryService {
|
|||||||
if (token) {
|
if (token) {
|
||||||
token = token.then(r => {
|
token = token.then(r => {
|
||||||
if (r) {
|
if (r) {
|
||||||
r.tabColor = tab.color
|
r.tabTitle = tab.title
|
||||||
|
if (tab.color) {
|
||||||
|
r.tabColor = tab.color
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
})
|
})
|
||||||
@@ -38,13 +45,14 @@ export class TabRecoveryService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async recoverTab (token: any): Promise<RecoveredTab|null> {
|
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
|
||||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
|
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
|
||||||
try {
|
try {
|
||||||
const tab = await provider.recover(token)
|
const tab = await provider.recover(token)
|
||||||
if (tab !== null) {
|
if (tab !== null) {
|
||||||
tab.options = tab.options || {}
|
tab.options = tab.options || {}
|
||||||
tab.options.color = token.tabColor || null
|
tab.options.color = token.tabColor || null
|
||||||
|
tab.options.title = token.tabTitle || ''
|
||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -8,7 +8,7 @@ export type TabComponentType = new (...args: any[]) => BaseTabComponent
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class TabsService {
|
export class TabsService {
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private injector: Injector,
|
private injector: Injector,
|
||||||
private tabRecovery: TabRecoveryService,
|
private tabRecovery: TabRecoveryService,
|
||||||
@@ -17,7 +17,7 @@ export class TabsService {
|
|||||||
/**
|
/**
|
||||||
* Instantiates a tab component and assigns given inputs
|
* Instantiates a tab component and assigns given inputs
|
||||||
*/
|
*/
|
||||||
create (type: TabComponentType, inputs?: any): BaseTabComponent {
|
create (type: TabComponentType, inputs?: Record<string, any>): BaseTabComponent {
|
||||||
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type)
|
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type)
|
||||||
const componentRef = componentFactory.create(this.injector)
|
const componentRef = componentFactory.create(this.injector)
|
||||||
const tab = componentRef.instance
|
const tab = componentRef.instance
|
||||||
|
@@ -7,7 +7,7 @@ export class ThemesService {
|
|||||||
private styleElement: HTMLElement|null = null
|
private styleElement: HTMLElement|null = null
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
constructor (
|
private constructor (
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
@Inject(Theme) private themes: Theme[],
|
@Inject(Theme) private themes: Theme[],
|
||||||
) {
|
) {
|
||||||
|
@@ -14,7 +14,7 @@ export class TouchbarService {
|
|||||||
private tabSegments: SegmentedControlSegment[] = []
|
private tabSegments: SegmentedControlSegment[] = []
|
||||||
private nsImageCache: {[id: string]: Electron.NativeImage} = {}
|
private nsImageCache: {[id: string]: Electron.NativeImage} = {}
|
||||||
|
|
||||||
constructor (
|
private constructor (
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||||
@@ -48,7 +48,7 @@ export class TouchbarService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTabs () {
|
updateTabs (): void {
|
||||||
this.tabSegments = this.app.tabs.map(tab => ({
|
this.tabSegments = this.app.tabs.map(tab => ({
|
||||||
label: this.shortenTitle(tab.title),
|
label: this.shortenTitle(tab.title),
|
||||||
}))
|
}))
|
||||||
@@ -56,7 +56,7 @@ export class TouchbarService {
|
|||||||
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab)
|
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab)
|
||||||
}
|
}
|
||||||
|
|
||||||
update () {
|
update (): void {
|
||||||
if (this.hostApp.platform !== Platform.macOS) {
|
if (this.hostApp.platform !== Platform.macOS) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ export class UpdaterService {
|
|||||||
private updateURL: string
|
private updateURL: string
|
||||||
private autoUpdater: AppUpdater
|
private autoUpdater: AppUpdater
|
||||||
|
|
||||||
constructor (
|
private constructor (
|
||||||
log: LogService,
|
log: LogService,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
@@ -80,7 +80,7 @@ export class UpdaterService {
|
|||||||
return this.downloaded
|
return this.downloaded
|
||||||
}
|
}
|
||||||
|
|
||||||
async update () {
|
async update (): Promise<void> {
|
||||||
if (!this.electronUpdaterAvailable) {
|
if (!this.electronUpdaterAvailable) {
|
||||||
this.electron.shell.openExternal(this.updateURL)
|
this.electron.shell.openExternal(this.updateURL)
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,14 +1,16 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Injectable, NgZone } from '@angular/core'
|
import { Injectable, NgZone } from '@angular/core'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { AppService } from './services/app.service'
|
import { AppService } from './services/app.service'
|
||||||
import { BaseTabComponent } from './components/baseTab.component'
|
import { BaseTabComponent } from './components/baseTab.component'
|
||||||
import { TabHeaderComponent } from './components/tabHeader.component'
|
import { TabHeaderComponent } from './components/tabHeader.component'
|
||||||
|
import { SplitTabComponent, SplitDirection } from './components/splitTab.component'
|
||||||
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CloseContextMenu extends TabContextMenuItemProvider {
|
export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||||
weight = -5
|
weight = 99
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
@@ -18,7 +20,7 @@ export class CloseContextMenu extends TabContextMenuItemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||||
let items = [
|
let items: Electron.MenuItemConstructorOptions[] = [
|
||||||
{
|
{
|
||||||
label: 'Close',
|
label: 'Close',
|
||||||
click: () => this.zone.run(() => {
|
click: () => this.zone.run(() => {
|
||||||
@@ -58,6 +60,24 @@ export class CloseContextMenu extends TabContextMenuItemProvider {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
} else {
|
||||||
|
if (tab.parent instanceof SplitTabComponent) {
|
||||||
|
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||||
|
items.push({
|
||||||
|
label: 'Split',
|
||||||
|
submenu: directions.map(dir => ({
|
||||||
|
label: {
|
||||||
|
r: 'Right',
|
||||||
|
b: 'Down',
|
||||||
|
l: 'Left',
|
||||||
|
t: 'Up',
|
||||||
|
}[dir],
|
||||||
|
click: () => this.zone.run(() => {
|
||||||
|
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||||
|
}),
|
||||||
|
})) as Electron.MenuItemConstructorOptions[],
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
@@ -86,8 +106,10 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||||
|
let items: Electron.MenuItemConstructorOptions[] = []
|
||||||
if (tabHeader) {
|
if (tabHeader) {
|
||||||
return [
|
items = [
|
||||||
|
...items,
|
||||||
{
|
{
|
||||||
label: 'Rename',
|
label: 'Rename',
|
||||||
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
|
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
|
||||||
@@ -110,7 +132,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
return []
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,4 +20,8 @@ app-root {
|
|||||||
ssh-tab .content {
|
ssh-tab .content {
|
||||||
margin: 5px !important;
|
margin: 5px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serial-tab .content {
|
||||||
|
margin: 5px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -246,7 +246,7 @@ ngb-tabset .tab-content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
transition: 0.25s background;
|
transition: 0.0625s background;
|
||||||
|
|
||||||
i + * {
|
i + * {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
@@ -262,6 +262,29 @@ ngb-tabset .tab-content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-light {
|
||||||
|
.list-group-item {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, .1);
|
||||||
|
|
||||||
|
&:not(.combi) {
|
||||||
|
padding: $list-group-item-padding-y $list-group-item-padding-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.list-group-item-action {
|
||||||
|
&:hover, &.active {
|
||||||
|
background: $list-group-hover-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkbox i.on {
|
checkbox i.on {
|
||||||
color: $blue;
|
color: $blue;
|
||||||
}
|
}
|
||||||
@@ -392,3 +415,7 @@ search-panel {
|
|||||||
border-color: $nav-tabs-link-active-border-color;
|
border-color: $nav-tabs-link-active-border-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: $list-group-border-color;
|
||||||
|
}
|
||||||
|
@@ -10,6 +10,7 @@ export function isWindowsBuild (build: number): boolean {
|
|||||||
return process.platform === 'win32' && parseFloat(os.release()) >= 10 && parseInt(os.release().split('.')[2]) >= build
|
return process.platform === 'win32' && parseFloat(os.release()) >= 10 && parseInt(os.release().split('.')[2]) >= build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export function getCSSFontFamily (config: any): string {
|
export function getCSSFontFamily (config: any): string {
|
||||||
let fonts: string[] = config.terminal.font.split(',').map(x => x.trim().replace(/"/g, ''))
|
let fonts: string[] = config.terminal.font.split(',').map(x => x.trim().replace(/"/g, ''))
|
||||||
if (config.terminal.fallbackFont) {
|
if (config.terminal.fallbackFont) {
|
||||||
|
@@ -3,14 +3,21 @@
|
|||||||
|
|
||||||
|
|
||||||
"@types/js-yaml@^3.9.0":
|
"@types/js-yaml@^3.9.0":
|
||||||
version "3.12.1"
|
version "3.12.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656"
|
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.4.tgz#7d3b534ec35a0585128e2d332db1403ebe057e25"
|
||||||
integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==
|
integrity sha512-fYMgzN+9e28R81weVN49inn/u798ruU91En1ZnGvSZzCRc5jXx9B2EDhlRaWmcO1RIxFHL8AajRXzxDuJu93+A==
|
||||||
|
|
||||||
"@types/semver@^6.0.2":
|
"@types/node@*":
|
||||||
version "6.2.0"
|
version "13.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
|
||||||
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
|
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
|
||||||
|
|
||||||
|
"@types/semver@^7.1.0":
|
||||||
|
version "7.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
|
||||||
|
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/shell-escape@^0.2.0":
|
"@types/shell-escape@^0.2.0":
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
@@ -45,6 +52,11 @@ async@^2.6.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
|
|
||||||
|
at-least-node@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||||
|
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||||
|
|
||||||
axios@^0.19.0:
|
axios@^0.19.0:
|
||||||
version "0.19.2"
|
version "0.19.2"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||||
@@ -57,10 +69,10 @@ bootstrap@^4.1.3:
|
|||||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
|
||||||
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
|
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
|
||||||
|
|
||||||
builder-util-runtime@8.4.0:
|
builder-util-runtime@8.7.0:
|
||||||
version "8.4.0"
|
version "8.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.4.0.tgz#3163fffc078e6b8f3dd5b6eb12a8345573590682"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d"
|
||||||
integrity sha512-CJB/eKfPf2vHrkmirF5eicVnbDCkMBbwd5tRYlTlgud16zFeqD7QmrVUAOEXdnsrcNkiLg9dbuUsQKtl/AwsYQ==
|
integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
@@ -117,9 +129,9 @@ colorspace@1.1.x:
|
|||||||
text-hex "1.0.x"
|
text-hex "1.0.x"
|
||||||
|
|
||||||
core-js@^3.1.2:
|
core-js@^3.1.2:
|
||||||
version "3.6.4"
|
version "3.6.5"
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
|
||||||
integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
|
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
|
||||||
|
|
||||||
core-util-is@~1.0.0:
|
core-util-is@~1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -162,18 +174,17 @@ diagnostics@^1.1.1:
|
|||||||
kuler "1.0.x"
|
kuler "1.0.x"
|
||||||
|
|
||||||
electron-updater@^4.0.6:
|
electron-updater@^4.0.6:
|
||||||
version "4.2.0"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.2.0.tgz#f9ecfc657f65ead737d42b9efecf628d3756b550"
|
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.1.tgz#9d485b6262bc56fcf7ee62b1dc1b3b105a3e96a7"
|
||||||
integrity sha512-GuS3g7HDh17x/SaFjxjswlWUaKHczksYkV2Xc5CKj/bZH0YCvTSHtOmnBAdAmCk99u/71p3zP8f0jIqDfGcjww==
|
integrity sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/semver" "^6.0.2"
|
"@types/semver" "^7.1.0"
|
||||||
builder-util-runtime "8.4.0"
|
builder-util-runtime "8.7.0"
|
||||||
fs-extra "^8.1.0"
|
fs-extra "^9.0.0"
|
||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
lazy-val "^1.0.4"
|
lazy-val "^1.0.4"
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
pako "^1.0.10"
|
semver "^7.1.3"
|
||||||
semver "^6.3.0"
|
|
||||||
|
|
||||||
enabled@1.0.x:
|
enabled@1.0.x:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -221,14 +232,15 @@ follow-redirects@1.5.10:
|
|||||||
dependencies:
|
dependencies:
|
||||||
debug "=3.1.0"
|
debug "=3.1.0"
|
||||||
|
|
||||||
fs-extra@^8.1.0:
|
fs-extra@^9.0.0:
|
||||||
version "8.1.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
|
||||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
at-least-node "^1.0.0"
|
||||||
graceful-fs "^4.2.0"
|
graceful-fs "^4.2.0"
|
||||||
jsonfile "^4.0.0"
|
jsonfile "^6.0.1"
|
||||||
universalify "^0.1.0"
|
universalify "^1.0.0"
|
||||||
|
|
||||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||||
version "4.2.2"
|
version "4.2.2"
|
||||||
@@ -264,17 +276,19 @@ isarray@~1.0.0:
|
|||||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||||
|
|
||||||
js-yaml@^3.13.1, js-yaml@^3.9.0:
|
js-yaml@^3.13.1, js-yaml@^3.9.0:
|
||||||
version "3.13.1"
|
version "3.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
|
||||||
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
jsonfile@^4.0.0:
|
jsonfile@^6.0.1:
|
||||||
version "4.0.0"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
|
||||||
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
|
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
|
||||||
|
dependencies:
|
||||||
|
universalify "^1.0.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
@@ -346,11 +360,6 @@ one-time@0.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
|
resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
|
||||||
integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
|
integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
|
||||||
|
|
||||||
pako@^1.0.10:
|
|
||||||
version "1.0.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
|
|
||||||
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
|
|
||||||
|
|
||||||
perfect-scrollbar@^1.4.0:
|
perfect-scrollbar@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.4.0.tgz#5d014ef9775e1f43058a1dbae9ed1daf0e7091f1"
|
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.4.0.tgz#5d014ef9775e1f43058a1dbae9ed1daf0e7091f1"
|
||||||
@@ -398,10 +407,10 @@ sax@^1.2.4:
|
|||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||||
|
|
||||||
semver@^6.3.0:
|
semver@^7.1.3:
|
||||||
version "6.3.0"
|
version "7.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
|
||||||
|
|
||||||
shell-escape@^0.2.0:
|
shell-escape@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
@@ -449,20 +458,20 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
|
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
|
||||||
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
|
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
|
||||||
|
|
||||||
universalify@^0.1.0:
|
universalify@^1.0.0:
|
||||||
version "0.1.2"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
|
||||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
|
||||||
|
|
||||||
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||||
|
|
||||||
uuid@^3.3.2:
|
uuid@^8.0.0:
|
||||||
version "3.4.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
|
||||||
|
|
||||||
winston-transport@^4.3.0:
|
winston-transport@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "terminus-plugin-manager",
|
"name": "terminus-plugin-manager",
|
||||||
"version": "1.0.99-nightly.0",
|
"version": "1.0.104-nightly.0",
|
||||||
"description": "Terminus' plugin manager",
|
"description": "Terminus' plugin manager",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"terminus-builtin-plugin"
|
"terminus-builtin-plugin"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"author": "Eugene Pankov",
|
"author": "Eugene Pankov",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/semver": "^6.0.0",
|
"@types/semver": "^7.1.0",
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.19.0",
|
||||||
"mz": "^2.6.0",
|
"mz": "^2.6.0",
|
||||||
"semver": "^7.1.1"
|
"semver": "^7.1.1"
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { BehaviorSubject, Observable } from 'rxjs'
|
import { BehaviorSubject, Observable } from 'rxjs'
|
||||||
import { debounceTime, distinctUntilChanged, first, tap, flatMap, map } from 'rxjs/operators'
|
import { debounceTime, distinctUntilChanged, first, tap, flatMap, map } from 'rxjs/operators'
|
||||||
import * as semver from 'semver'
|
import semverGt from 'semver/functions/gt'
|
||||||
|
|
||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { ConfigService, ElectronService } from 'terminus-core'
|
import { ConfigService, ElectronService } from 'terminus-core'
|
||||||
@@ -48,7 +49,7 @@ export class PluginsSettingsTabComponent {
|
|||||||
return plugins
|
return plugins
|
||||||
})).subscribe(available => {
|
})).subscribe(available => {
|
||||||
for (const plugin of this.pluginManager.installedPlugins) {
|
for (const plugin of this.pluginManager.installedPlugins) {
|
||||||
this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semver.gt(x.version, plugin.version)) || null
|
this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semverGt(x.version, plugin.version)) || null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -34,13 +34,13 @@ export class PluginManagerService {
|
|||||||
private npmReady: Promise<void>
|
private npmReady: Promise<void>
|
||||||
private npm: any
|
private npm: any
|
||||||
|
|
||||||
constructor (
|
private constructor (
|
||||||
log: LogService,
|
log: LogService,
|
||||||
) {
|
) {
|
||||||
this.logger = log.create('pluginManager')
|
this.logger = log.create('pluginManager')
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNPM () {
|
async getNPM (): Promise<any> {
|
||||||
if (!this.npm) {
|
if (!this.npm) {
|
||||||
if (!this.npmReady) {
|
if (!this.npmReady) {
|
||||||
this.npmReady = new Promise(resolve => {
|
this.npmReady = new Promise(resolve => {
|
||||||
@@ -83,7 +83,7 @@ export class PluginManagerService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async installPlugin (plugin: PluginInfo) {
|
async installPlugin (plugin: PluginInfo): Promise<void> {
|
||||||
(await this.getNPM()).commands.install([`${plugin.packageName}@${plugin.version}`], err => {
|
(await this.getNPM()).commands.install([`${plugin.packageName}@${plugin.version}`], err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.logger.error(err)
|
this.logger.error(err)
|
||||||
@@ -93,7 +93,7 @@ export class PluginManagerService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async uninstallPlugin (plugin: PluginInfo) {
|
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
|
||||||
(await this.getNPM()).commands.remove([plugin.packageName], err => {
|
(await this.getNPM()).commands.remove([plugin.packageName], err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.logger.error(err)
|
this.logger.error(err)
|
||||||
|
@@ -2,10 +2,17 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@types/semver@^6.0.0":
|
"@types/node@*":
|
||||||
version "6.2.0"
|
version "13.7.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.0.tgz#d688d574400d96c5b0114968705366f431831e1a"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113"
|
||||||
integrity sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==
|
integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==
|
||||||
|
|
||||||
|
"@types/semver@^7.1.0":
|
||||||
|
version "7.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
|
||||||
|
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
any-promise@^1.0.0:
|
any-promise@^1.0.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
@@ -53,9 +60,9 @@ object-assign@^4.0.1:
|
|||||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||||
|
|
||||||
semver@^7.1.1:
|
semver@^7.1.1:
|
||||||
version "7.1.1"
|
version "7.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.2.tgz#d01432d74ed3010a20ffaf909d63a691520521cd"
|
||||||
integrity sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A==
|
integrity sha512-Zo84u6o2PebMSK3zjJ6Zp5wi8VnQZnEaCP13Ul/lt1ANsLACxnJxq4EEm1PY94/por1Hm9+7xpIswdS5AkieMA==
|
||||||
|
|
||||||
thenify-all@^1.0.0:
|
thenify-all@^1.0.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
|
37
terminus-serial/package.json
Normal file
37
terminus-serial/package.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "terminus-serial",
|
||||||
|
"version": "1.0.104-nightly.0",
|
||||||
|
"description": "Serial connection manager for Terminus",
|
||||||
|
"keywords": [
|
||||||
|
"terminus-builtin-plugin"
|
||||||
|
],
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"typings": "typings/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --progress --color",
|
||||||
|
"watch": "webpack --progress --color --watch"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"author": "Eugene Pankov",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "12.7.3",
|
||||||
|
"@types/ssh2": "^0.5.35",
|
||||||
|
"ansi-colors": "^4.1.1",
|
||||||
|
"cli-spinner": "^0.2.10",
|
||||||
|
"electron-rebuild": "^1.10.0",
|
||||||
|
"terminus-terminal": "^1.0.98-nightly.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "^7",
|
||||||
|
"@angular/core": "^7",
|
||||||
|
"@angular/forms": "^7",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "^1",
|
||||||
|
"rxjs": "^5",
|
||||||
|
"terminus-core": "*",
|
||||||
|
"terminus-settings": "*",
|
||||||
|
"terminus-terminal": "*"
|
||||||
|
}
|
||||||
|
}
|
156
terminus-serial/src/api.ts
Normal file
156
terminus-serial/src/api.ts
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import { BaseSession } from 'terminus-terminal'
|
||||||
|
import { SerialPort } from 'serialport'
|
||||||
|
import { Logger } from 'terminus-core'
|
||||||
|
import { Subject, Observable } from 'rxjs'
|
||||||
|
|
||||||
|
export interface LoginScript {
|
||||||
|
expect: string
|
||||||
|
send: string
|
||||||
|
isRegex?: boolean
|
||||||
|
optional?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SerialConnection {
|
||||||
|
name: string
|
||||||
|
port: string
|
||||||
|
baudrate: number
|
||||||
|
databits: number
|
||||||
|
stopbits: number
|
||||||
|
parity: string
|
||||||
|
rtscts: boolean
|
||||||
|
xon: boolean
|
||||||
|
xoff: boolean
|
||||||
|
xany: boolean
|
||||||
|
scripts?: LoginScript[]
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BAUD_RATES = [
|
||||||
|
110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600,
|
||||||
|
]
|
||||||
|
|
||||||
|
export interface SerialPortInfo {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SerialSession extends BaseSession {
|
||||||
|
scripts?: LoginScript[]
|
||||||
|
serial: SerialPort
|
||||||
|
logger: Logger
|
||||||
|
|
||||||
|
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||||
|
private serviceMessage = new Subject<string>()
|
||||||
|
|
||||||
|
constructor (public connection: SerialConnection) {
|
||||||
|
super()
|
||||||
|
this.scripts = connection.scripts || []
|
||||||
|
}
|
||||||
|
|
||||||
|
async start (): Promise<void> {
|
||||||
|
this.open = true
|
||||||
|
|
||||||
|
this.serial.on('data', data => {
|
||||||
|
const dataString = data.toString()
|
||||||
|
this.emitOutput(data)
|
||||||
|
|
||||||
|
if (this.scripts) {
|
||||||
|
let found = false
|
||||||
|
for (const script of this.scripts) {
|
||||||
|
let match = false
|
||||||
|
let cmd = ''
|
||||||
|
if (script.isRegex) {
|
||||||
|
const re = new RegExp(script.expect, 'g')
|
||||||
|
if (dataString.match(re)) {
|
||||||
|
cmd = dataString.replace(re, script.send)
|
||||||
|
match = true
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dataString.includes(script.expect)) {
|
||||||
|
cmd = script.send
|
||||||
|
match = true
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
this.logger.info('Executing script: "' + cmd + '"')
|
||||||
|
this.serial.write(cmd + '\n')
|
||||||
|
this.scripts = this.scripts.filter(x => x !== script)
|
||||||
|
} else {
|
||||||
|
if (script.optional) {
|
||||||
|
this.logger.debug('Skip optional script: ' + script.expect)
|
||||||
|
found = true
|
||||||
|
this.scripts = this.scripts.filter(x => x !== script)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
this.executeUnconditionalScripts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.serial.on('end', () => {
|
||||||
|
this.logger.info('Shell session ended')
|
||||||
|
if (this.open) {
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.executeUnconditionalScripts()
|
||||||
|
}
|
||||||
|
|
||||||
|
write (data: Buffer): void {
|
||||||
|
if (this.serial) {
|
||||||
|
this.serial.write(data.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy (): Promise<void> {
|
||||||
|
this.serviceMessage.complete()
|
||||||
|
await super.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
|
||||||
|
resize (_, __) { }
|
||||||
|
|
||||||
|
kill (_?: string): void {
|
||||||
|
this.serial.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getChildProcesses (): Promise<any[]> {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
async gracefullyKillProcess (): Promise<void> {
|
||||||
|
this.kill('TERM')
|
||||||
|
}
|
||||||
|
|
||||||
|
async getWorkingDirectory (): Promise<string|null> {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private executeUnconditionalScripts () {
|
||||||
|
if (this.scripts) {
|
||||||
|
for (const script of this.scripts) {
|
||||||
|
if (!script.expect) {
|
||||||
|
console.log('Executing script:', script.send)
|
||||||
|
this.serial.write(script.send + '\n')
|
||||||
|
this.scripts = this.scripts.filter(x => x !== script)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SerialConnectionGroup {
|
||||||
|
name: string
|
||||||
|
connections: SerialConnection[]
|
||||||
|
}
|
36
terminus-serial/src/buttonProvider.ts
Normal file
36
terminus-serial/src/buttonProvider.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Injectable, Injector } from '@angular/core'
|
||||||
|
import { HotkeysService, ToolbarButtonProvider, ToolbarButton } from 'terminus-core'
|
||||||
|
import { SerialService } from './services/serial.service'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class ButtonProvider extends ToolbarButtonProvider {
|
||||||
|
constructor (
|
||||||
|
private injector: Injector,
|
||||||
|
hotkeys: HotkeysService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
hotkeys.matchedHotkey.subscribe(async (hotkey: string) => {
|
||||||
|
if (hotkey === 'serial') {
|
||||||
|
this.activate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
activate () {
|
||||||
|
this.injector.get(SerialService).showConnectionSelector()
|
||||||
|
}
|
||||||
|
|
||||||
|
provide (): ToolbarButton[] {
|
||||||
|
return [{
|
||||||
|
icon: require('./icons/serial.svg'),
|
||||||
|
weight: 5,
|
||||||
|
title: 'Serial connections',
|
||||||
|
touchBarNSImage: 'NSTouchBarOpenInBrowserTemplate',
|
||||||
|
click: async () => {
|
||||||
|
this.activate()
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
134
terminus-serial/src/components/editConnectionModal.component.pug
Normal file
134
terminus-serial/src/components/editConnectionModal.component.pug
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
.modal-body
|
||||||
|
ngb-tabset([activeId]='basic')
|
||||||
|
ngb-tab(id='basic')
|
||||||
|
ng-template(ngbTabTitle) General
|
||||||
|
ng-template(ngbTabContent)
|
||||||
|
.form-group
|
||||||
|
label Name
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
autofocus,
|
||||||
|
[(ngModel)]='connection.name',
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-group
|
||||||
|
label Path
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
[(ngModel)]='connection.port',
|
||||||
|
[ngbTypeahead]='portsAutocomplete',
|
||||||
|
[resultFormatter]='portsFormatter',
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-group
|
||||||
|
label Baud Rate
|
||||||
|
select.form-control(
|
||||||
|
[(ngModel)]='connection.baudrate',
|
||||||
|
)
|
||||||
|
option([value]='x', *ngFor='let x of baudRates') {{x}}
|
||||||
|
|
||||||
|
ngb-tab(id='advanced')
|
||||||
|
ng-template(ngbTabTitle) Advanced
|
||||||
|
ng-template(ngbTabContent)
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Tab color
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
autofocus,
|
||||||
|
[(ngModel)]='connection.color',
|
||||||
|
placeholder='#000000'
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title DataBits
|
||||||
|
input.form-control(
|
||||||
|
type='number',
|
||||||
|
placeholder='8',
|
||||||
|
[(ngModel)]='connection.databits',
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title StopBits
|
||||||
|
input.form-control(
|
||||||
|
type='number',
|
||||||
|
placeholder='1',
|
||||||
|
[(ngModel)]='connection.stopbits',
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Parity
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
[(ngModel)]='connection.parity',
|
||||||
|
placeholder='none'
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title RTSCTS
|
||||||
|
toggle([(ngModel)]='connection.rtscts')
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Xon
|
||||||
|
toggle([(ngModel)]='connection.xon')
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Xoff
|
||||||
|
toggle([(ngModel)]='connection.xoff')
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title Xany
|
||||||
|
toggle([(ngModel)]='connection.xany')
|
||||||
|
|
||||||
|
ngb-tab(id='scripts')
|
||||||
|
ng-template(ngbTabTitle) Login scripts
|
||||||
|
ng-template(ngbTabContent)
|
||||||
|
table(*ngIf='connection.scripts.length > 0')
|
||||||
|
tr
|
||||||
|
th String to expect
|
||||||
|
th String to be sent
|
||||||
|
th.pl-2 Regex
|
||||||
|
th.pl-2 Optional
|
||||||
|
th.pl-2 Actions
|
||||||
|
tr(*ngFor='let script of connection.scripts')
|
||||||
|
td.pr-2
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
[(ngModel)]='script.expect'
|
||||||
|
)
|
||||||
|
td
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
[(ngModel)]='script.send'
|
||||||
|
)
|
||||||
|
td.pl-2
|
||||||
|
checkbox(
|
||||||
|
[(ngModel)]='script.isRegex',
|
||||||
|
)
|
||||||
|
td.pl-2
|
||||||
|
checkbox(
|
||||||
|
[(ngModel)]='script.optional',
|
||||||
|
)
|
||||||
|
td.pl-2
|
||||||
|
.input-group.flex-nowrap
|
||||||
|
button.btn.btn-outline-info.ml-0((click)='moveScriptUp(script)')
|
||||||
|
i.fas.fa-arrow-up
|
||||||
|
button.btn.btn-outline-info.ml-0((click)='moveScriptDown(script)')
|
||||||
|
i.fas.fa-arrow-down
|
||||||
|
button.btn.btn-outline-danger.ml-0((click)='deleteScript(script)')
|
||||||
|
i.fas.fa-trash
|
||||||
|
|
||||||
|
button.btn.btn-outline-info.mt-2((click)='addScript()')
|
||||||
|
i.fas.fa-plus
|
||||||
|
span New item
|
||||||
|
|
||||||
|
.modal-footer
|
||||||
|
button.btn.btn-outline-primary((click)='save()') Save
|
||||||
|
button.btn.btn-outline-danger((click)='cancel()') Cancel
|
@@ -0,0 +1,95 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Component } from '@angular/core'
|
||||||
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { map } from 'rxjs/operators'
|
||||||
|
import { ElectronService, HostAppService } from 'terminus-core'
|
||||||
|
import { SerialConnection, LoginScript, SerialPortInfo, BAUD_RATES } from '../api'
|
||||||
|
import { SerialService } from '../services/serial.service'
|
||||||
|
// import { PromptModalComponent } from './promptModal.component'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Component({
|
||||||
|
template: require('./editConnectionModal.component.pug'),
|
||||||
|
})
|
||||||
|
export class EditConnectionModalComponent {
|
||||||
|
connection: SerialConnection
|
||||||
|
foundPorts: SerialPortInfo[]
|
||||||
|
baudRates = BAUD_RATES
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private modalInstance: NgbActiveModal,
|
||||||
|
private electron: ElectronService,
|
||||||
|
private hostApp: HostAppService,
|
||||||
|
private serial: SerialService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
portsAutocomplete = text$ => text$.pipe(map(() => {
|
||||||
|
return this.foundPorts.map(x => x.name)
|
||||||
|
}))
|
||||||
|
|
||||||
|
portsFormatter = port => {
|
||||||
|
const p = this.foundPorts.find(x => x.name === port)
|
||||||
|
if (p?.description) {
|
||||||
|
return `${port} (${p.description})`
|
||||||
|
}
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit () {
|
||||||
|
this.connection.scripts = this.connection.scripts || []
|
||||||
|
this.foundPorts = await this.serial.listPorts()
|
||||||
|
}
|
||||||
|
|
||||||
|
save () {
|
||||||
|
this.modalInstance.close(this.connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel () {
|
||||||
|
this.modalInstance.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
moveScriptUp (script: LoginScript) {
|
||||||
|
if (!this.connection.scripts) {
|
||||||
|
this.connection.scripts = []
|
||||||
|
}
|
||||||
|
const index = this.connection.scripts.indexOf(script)
|
||||||
|
if (index > 0) {
|
||||||
|
this.connection.scripts.splice(index, 1)
|
||||||
|
this.connection.scripts.splice(index - 1, 0, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveScriptDown (script: LoginScript) {
|
||||||
|
if (!this.connection.scripts) {
|
||||||
|
this.connection.scripts = []
|
||||||
|
}
|
||||||
|
const index = this.connection.scripts.indexOf(script)
|
||||||
|
if (index >= 0 && index < this.connection.scripts.length - 1) {
|
||||||
|
this.connection.scripts.splice(index, 1)
|
||||||
|
this.connection.scripts.splice(index + 1, 0, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteScript (script: LoginScript) {
|
||||||
|
if (this.connection.scripts && (await this.electron.showMessageBox(
|
||||||
|
this.hostApp.getWindow(),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
message: 'Delete this script?',
|
||||||
|
detail: script.expect,
|
||||||
|
buttons: ['Keep', 'Delete'],
|
||||||
|
defaultId: 1,
|
||||||
|
}
|
||||||
|
)).response === 1) {
|
||||||
|
this.connection.scripts = this.connection.scripts.filter(x => x !== script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addScript () {
|
||||||
|
if (!this.connection.scripts) {
|
||||||
|
this.connection.scripts = []
|
||||||
|
}
|
||||||
|
this.connection.scripts.push({ expect: '', send: '' })
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
h3 Connections
|
||||||
|
|
||||||
|
.list-group.list-group-flush.mt-3.mb-3
|
||||||
|
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||||
|
*ngFor='let connection of connections',
|
||||||
|
(click)='editConnection(connection)'
|
||||||
|
)
|
||||||
|
.mr-auto
|
||||||
|
div {{connection.name}}
|
||||||
|
.text-muted {{connection.port}}
|
||||||
|
button.btn.btn-outline-danger.ml-1((click)='$event.stopPropagation(); deleteConnection(connection)')
|
||||||
|
i.fas.fa-trash
|
||||||
|
|
||||||
|
button.btn.btn-primary((click)='createConnection()')
|
||||||
|
i.fas.fa-fw.fa-plus
|
||||||
|
span.ml-2 Add connection
|
@@ -0,0 +1,80 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Component } from '@angular/core'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { ConfigService, ElectronService, HostAppService } from 'terminus-core'
|
||||||
|
import { SerialConnection } from '../api'
|
||||||
|
import { EditConnectionModalComponent } from './editConnectionModal.component'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Component({
|
||||||
|
template: require('./serialSettingsTab.component.pug'),
|
||||||
|
})
|
||||||
|
export class SerialSettingsTabComponent {
|
||||||
|
connections: SerialConnection[]
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
public config: ConfigService,
|
||||||
|
private electron: ElectronService,
|
||||||
|
private hostApp: HostAppService,
|
||||||
|
private ngbModal: NgbModal,
|
||||||
|
) {
|
||||||
|
this.connections = this.config.store.serial.connections
|
||||||
|
this.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
createConnection () {
|
||||||
|
const connection: SerialConnection = {
|
||||||
|
name: '',
|
||||||
|
port: '',
|
||||||
|
baudrate: 115200,
|
||||||
|
databits: 8,
|
||||||
|
parity: 'none',
|
||||||
|
rtscts: false,
|
||||||
|
stopbits: 1,
|
||||||
|
xany: false,
|
||||||
|
xoff: false,
|
||||||
|
xon: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const modal = this.ngbModal.open(EditConnectionModalComponent)
|
||||||
|
modal.componentInstance.connection = connection
|
||||||
|
modal.result.then(result => {
|
||||||
|
this.connections.push(result)
|
||||||
|
this.config.store.serial.connections = this.connections
|
||||||
|
this.config.save()
|
||||||
|
this.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
editConnection (connection: SerialConnection) {
|
||||||
|
const modal = this.ngbModal.open(EditConnectionModalComponent, { size: 'lg' })
|
||||||
|
modal.componentInstance.connection = Object.assign({}, connection)
|
||||||
|
modal.result.then(result => {
|
||||||
|
Object.assign(connection, result)
|
||||||
|
this.config.store.serial.connections = this.connections
|
||||||
|
this.config.save()
|
||||||
|
this.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteConnection (connection: SerialConnection) {
|
||||||
|
if ((await this.electron.showMessageBox(
|
||||||
|
this.hostApp.getWindow(),
|
||||||
|
{
|
||||||
|
type: 'warning',
|
||||||
|
message: `Delete "${connection.name}"?`,
|
||||||
|
buttons: ['Keep', 'Delete'],
|
||||||
|
defaultId: 1,
|
||||||
|
}
|
||||||
|
)).response === 1) {
|
||||||
|
this.connections = this.connections.filter(x => x !== connection)
|
||||||
|
this.config.store.serial.connections = this.connections
|
||||||
|
this.config.save()
|
||||||
|
this.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh () {
|
||||||
|
this.connections = this.config.store.serial.connections
|
||||||
|
}
|
||||||
|
}
|
16
terminus-serial/src/components/serialTab.component.pug
Normal file
16
terminus-serial/src/components/serialTab.component.pug
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.tab-toolbar
|
||||||
|
.btn.btn-outline-secondary.reveal-button
|
||||||
|
i.fas.fa-ellipsis-h
|
||||||
|
.toolbar(*ngIf='session', [class.show]='!session.open')
|
||||||
|
i.fas.fa-circle.text-success.mr-2(*ngIf='session.open')
|
||||||
|
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session.open')
|
||||||
|
strong(*ngIf='session') {{session.connection.port}} ({{session.connection.baudrate}})
|
||||||
|
|
||||||
|
.mr-auto
|
||||||
|
|
||||||
|
button.btn.btn-secondary.mr-3((click)='changeBaudRate()', *ngIf='session.open')
|
||||||
|
span Change baud rate
|
||||||
|
|
||||||
|
button.btn.btn-info((click)='reconnect()', *ngIf='!session.open')
|
||||||
|
i.fas.fa-reload
|
||||||
|
span Reconnect
|
7
terminus-serial/src/components/serialTab.component.scss
Normal file
7
terminus-serial/src/components/serialTab.component.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@import '../../../terminus-ssh/src/components/sshTab.component.scss';
|
||||||
|
|
||||||
|
:host {
|
||||||
|
select {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
118
terminus-serial/src/components/serialTab.component.ts
Normal file
118
terminus-serial/src/components/serialTab.component.ts
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import colors from 'ansi-colors'
|
||||||
|
import { Spinner } from 'cli-spinner'
|
||||||
|
import { Component, Injector } from '@angular/core'
|
||||||
|
import { first } from 'rxjs/operators'
|
||||||
|
import { BaseTerminalTabComponent } from 'terminus-terminal'
|
||||||
|
import { SerialService } from '../services/serial.service'
|
||||||
|
import { SerialConnection, SerialSession, BAUD_RATES } from '../api'
|
||||||
|
import { Subscription } from 'rxjs'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Component({
|
||||||
|
selector: 'serial-tab',
|
||||||
|
template: BaseTerminalTabComponent.template + require<string>('./serialTab.component.pug'),
|
||||||
|
styles: [require('./serialTab.component.scss'), ...BaseTerminalTabComponent.styles],
|
||||||
|
animations: BaseTerminalTabComponent.animations,
|
||||||
|
})
|
||||||
|
export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||||
|
connection: SerialConnection
|
||||||
|
session: SerialSession
|
||||||
|
serialPort: any
|
||||||
|
private homeEndSubscription: Subscription
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||||
|
constructor (
|
||||||
|
injector: Injector,
|
||||||
|
) {
|
||||||
|
super(injector)
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.logger = this.log.create('terminalTab')
|
||||||
|
|
||||||
|
this.homeEndSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||||
|
if (!this.hasFocus) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (hotkey) {
|
||||||
|
case 'home':
|
||||||
|
this.sendInput('\x1b[H' )
|
||||||
|
break
|
||||||
|
case 'end':
|
||||||
|
this.sendInput('\x1b[F' )
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.frontendReady$.pipe(first()).subscribe(() => {
|
||||||
|
this.initializeSession()
|
||||||
|
})
|
||||||
|
|
||||||
|
super.ngOnInit()
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
this.setTitle(this.connection.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async initializeSession () {
|
||||||
|
if (!this.connection) {
|
||||||
|
this.logger.error('No Serial connection info supplied')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.session = this.injector.get(SerialService).createSession(this.connection)
|
||||||
|
this.session.serviceMessage$.subscribe(msg => {
|
||||||
|
this.write('\r\n' + colors.black.bgWhite(' serial ') + ' ' + msg + '\r\n')
|
||||||
|
this.session.resize(this.size.columns, this.size.rows)
|
||||||
|
})
|
||||||
|
this.attachSessionHandlers()
|
||||||
|
this.write(`Connecting to `)
|
||||||
|
|
||||||
|
const spinner = new Spinner({
|
||||||
|
text: 'Connecting',
|
||||||
|
stream: {
|
||||||
|
write: x => this.write(x),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
spinner.setSpinnerString(6)
|
||||||
|
spinner.start()
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.serialPort = await this.injector.get(SerialService).connectSession(this.session)
|
||||||
|
spinner.stop(true)
|
||||||
|
} catch (e) {
|
||||||
|
spinner.stop(true)
|
||||||
|
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.session.start()
|
||||||
|
this.session.resize(this.size.columns, this.size.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRecoveryToken (): Promise<any> {
|
||||||
|
return {
|
||||||
|
type: 'app:serial-tab',
|
||||||
|
connection: this.connection,
|
||||||
|
savedState: this.frontend?.saveState(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnect () {
|
||||||
|
this.initializeSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
async changeBaudRate () {
|
||||||
|
const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({
|
||||||
|
name: x.toString(), result: x,
|
||||||
|
})))
|
||||||
|
this.serialPort.update({ baudRate: rate })
|
||||||
|
this.connection.baudrate = rate
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy () {
|
||||||
|
this.homeEndSubscription.unsubscribe()
|
||||||
|
super.ngOnDestroy()
|
||||||
|
}
|
||||||
|
}
|
19
terminus-serial/src/config.ts
Normal file
19
terminus-serial/src/config.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { ConfigProvider } from 'terminus-core'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
export class SerialConfigProvider extends ConfigProvider {
|
||||||
|
defaults = {
|
||||||
|
serial: {
|
||||||
|
connections: [],
|
||||||
|
options: {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hotkeys: {
|
||||||
|
serial: [
|
||||||
|
'Alt-K',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
platformDefaults = { }
|
||||||
|
}
|
17
terminus-serial/src/hotkeys.ts
Normal file
17
terminus-serial/src/hotkeys.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { HotkeyDescription, HotkeyProvider } from 'terminus-core'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class SerialHotkeyProvider extends HotkeyProvider {
|
||||||
|
hotkeys: HotkeyDescription[] = [
|
||||||
|
{
|
||||||
|
id: 'serial',
|
||||||
|
name: 'Show Serial connections',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
async provide (): Promise<HotkeyDescription[]> {
|
||||||
|
return this.hotkeys
|
||||||
|
}
|
||||||
|
}
|
27
terminus-serial/src/icons/serial.svg
Normal file
27
terminus-serial/src/icons/serial.svg
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="32"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 32 16"
|
||||||
|
version="1.1"
|
||||||
|
id="svg3749">
|
||||||
|
<defs
|
||||||
|
id="defs3753" />
|
||||||
|
<g
|
||||||
|
id="g3747"
|
||||||
|
transform="matrix(0.48599086,0,0,0.48599086,0.50191451,-0.299629)"
|
||||||
|
style="fill:none;fill-rule:evenodd">
|
||||||
|
<g
|
||||||
|
id="g3741"
|
||||||
|
transform="translate(-292.02353,-314.25882)"
|
||||||
|
style="fill:#ffffff">
|
||||||
|
<path
|
||||||
|
style="fill-rule:nonzero;stroke-width:0.10270619"
|
||||||
|
d="M 16.007812,0 3.2929688,0.03515625 2.2324219,0.40234375 C 0.91449728,1.1071083 0,2.575555 0,3.9863281 c 0,1.2651363 1.3074352,7.8137089 1.7402344,8.7167969 0.553077,1.153703 1.988134,2.456836 3.234375,2.9375 0.8530743,0.328933 1.4753185,0.348528 10.9804686,0.357422 9.789951,0.0091 10.106534,-0.002 11.087891,-0.369141 1.221173,-0.456851 2.835858,-1.955656 3.333984,-3.09375 0.336145,-0.767943 1.638672,-7.5615083 1.638672,-8.5488279 0,-1.4107731 -0.849384,-3.02258715 -2.234375,-3.58398435 L 28.791016,0 Z m -4.27539,4.890625 c 0.427942,0 0.812664,0.071135 1.152344,0.2128906 0.342354,0.1390812 0.631097,0.3382162 0.86914,0.5976563 0.243393,0.2674641 0.430211,0.5965523 0.558594,0.984375 0.131057,0.3878229 0.197266,0.8262256 0.197266,1.3183593 0,0.4921338 -0.06744,0.9337216 -0.201172,1.3242188 -0.131058,0.387823 -0.316645,0.711263 -0.554688,0.970703 -0.246067,0.270139 -0.536042,0.474922 -0.873047,0.611328 -0.33433,0.136407 -0.71782,0.203125 -1.148437,0.203125 -0.419919,0 -0.801456,-0.0699 -1.146484,-0.208984 C 10.243584,10.765216 9.9516549,10.563618 9.7109375,10.298828 9.4702197,10.034039 9.2834009,9.7093672 9.1523438,9.3242188 9.0239608,8.9390707 8.9609375,8.4987146 8.9609375,8.0039062 c 0,-0.4867846 0.063023,-0.9214925 0.1914063,-1.3066406 C 9.2807263,6.3094427 9.4687769,5.9766597 9.7148438,5.7011719 9.950212,5.4390572 10.242141,5.2386906 10.589844,5.0996094 10.940222,4.9605279 11.320527,4.890625 11.732422,4.890625 Z m 9.933594,0 c 0.427942,0 0.812664,0.071135 1.152343,0.2128906 0.342354,0.1390812 0.631098,0.3382162 0.869141,0.5976563 0.243392,0.2674641 0.430211,0.5965523 0.558594,0.984375 0.131057,0.3878229 0.197265,0.8262256 0.197265,1.3183593 0,0.4921338 -0.06744,0.9337216 -0.201171,1.3242188 -0.131058,0.387823 -0.316645,0.711263 -0.554688,0.970703 -0.246067,0.270139 -0.536042,0.474922 -0.873047,0.611328 -0.33433,0.136407 -0.71782,0.203125 -1.148437,0.203125 -0.419919,0 -0.801456,-0.0699 -1.146485,-0.208984 -0.342353,-0.139081 -0.634282,-0.340679 -0.875,-0.605469 C 19.403813,10.034039 19.216995,9.7093672 19.085938,9.3242188 18.957555,8.9390707 18.894531,8.4987146 18.894531,8.0039062 c 0,-0.4867846 0.06302,-0.9214925 0.191407,-1.3066406 0.128382,-0.3878229 0.316433,-0.7206059 0.5625,-0.9960937 0.235368,-0.2621147 0.527296,-0.4624813 0.875,-0.6015625 0.350377,-0.1390815 0.730683,-0.2089844 1.142578,-0.2089844 z m -16.0839848,0.125 h 2.359375 V 5.625 H 7.1582031 v 4.753906 h 0.7832031 v 0.611328 H 5.5820312 V 10.378906 H 6.3652344 V 5.625 H 5.5820312 Z m 9.9335938,0 H 17.875 V 5.625 h -0.783203 v 4.753906 H 17.875 v 0.611328 h -2.359375 v -0.611328 h 0.783203 V 5.625 h -0.783203 z m 9.933594,0 h 2.359375 V 5.625 h -0.783203 v 4.753906 h 0.783203 v 0.611328 h -2.359375 v -0.611328 h 0.783203 V 5.625 h -0.783203 z m -13.712891,0.5625 c -0.607143,0 -1.083937,0.2102191 -1.43164,0.6328125 -0.3450291,0.4199185 -0.5175786,1.0173231 -0.5175786,1.7929687 0,0.7836694 0.1762443,1.3854905 0.5292966,1.8027344 0.353053,0.4145694 0.826152,0.6210934 1.419922,0.6210934 0.59377,0 1.065638,-0.206524 1.416016,-0.6210934 0.353052,-0.4172439 0.529297,-1.019065 0.529297,-1.8027344 0,-0.7756456 -0.173782,-1.3730502 -0.521485,-1.7929687 C 12.812453,5.7883441 12.338122,5.578125 11.736328,5.578125 Z m 9.933594,0 c -0.607144,0 -1.083938,0.2102191 -1.431641,0.6328125 -0.345028,0.4199185 -0.517578,1.0173231 -0.517578,1.7929687 0,0.7836694 0.176244,1.3854905 0.529297,1.8027344 0.353052,0.4145694 0.826152,0.6210934 1.419922,0.6210934 0.59377,0 1.065638,-0.206524 1.416016,-0.6210934 0.353052,-0.4172439 0.529296,-1.019065 0.529296,-1.8027344 0,-0.7756456 -0.173781,-1.3730502 -0.521484,-1.7929687 C 22.746047,5.7883441 22.271716,5.578125 21.669922,5.578125 Z"
|
||||||
|
transform="matrix(2.0576519,0,0,2.0576519,290.99076,314.87535)"
|
||||||
|
id="path3739" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
48
terminus-serial/src/index.ts
Normal file
48
terminus-serial/src/index.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { CommonModule } from '@angular/common'
|
||||||
|
import { FormsModule } from '@angular/forms'
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { ToastrModule } from 'ngx-toastr'
|
||||||
|
import TerminusCoreModule, { ToolbarButtonProvider, ConfigProvider, TabRecoveryProvider, HotkeyProvider } from 'terminus-core'
|
||||||
|
import { SettingsTabProvider } from 'terminus-settings'
|
||||||
|
import TerminusTerminalModule from 'terminus-terminal'
|
||||||
|
|
||||||
|
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
||||||
|
import { SerialSettingsTabComponent } from './components/serialSettingsTab.component'
|
||||||
|
import { SerialTabComponent } from './components/serialTab.component'
|
||||||
|
|
||||||
|
import { ButtonProvider } from './buttonProvider'
|
||||||
|
import { SerialConfigProvider } from './config'
|
||||||
|
import { SerialSettingsTabProvider } from './settings'
|
||||||
|
import { RecoveryProvider } from './recoveryProvider'
|
||||||
|
import { SerialHotkeyProvider } from './hotkeys'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
NgbModule,
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
ToastrModule,
|
||||||
|
TerminusCoreModule,
|
||||||
|
TerminusTerminalModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||||
|
{ provide: ConfigProvider, useClass: SerialConfigProvider, multi: true },
|
||||||
|
{ provide: SettingsTabProvider, useClass: SerialSettingsTabProvider, multi: true },
|
||||||
|
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||||
|
{ provide: HotkeyProvider, useClass: SerialHotkeyProvider, multi: true },
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
EditConnectionModalComponent,
|
||||||
|
SerialSettingsTabComponent,
|
||||||
|
SerialTabComponent,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EditConnectionModalComponent,
|
||||||
|
SerialSettingsTabComponent,
|
||||||
|
SerialTabComponent,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export default class SerialModule { } // eslint-disable-line @typescript-eslint/no-extraneous-class
|
21
terminus-serial/src/recoveryProvider.ts
Normal file
21
terminus-serial/src/recoveryProvider.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from 'terminus-core'
|
||||||
|
|
||||||
|
import { SerialTabComponent } from './components/serialTab.component'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class RecoveryProvider extends TabRecoveryProvider {
|
||||||
|
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
|
||||||
|
if (recoveryToken?.type === 'app:serial-tab') {
|
||||||
|
return {
|
||||||
|
type: SerialTabComponent,
|
||||||
|
options: {
|
||||||
|
connection: recoveryToken['connection'],
|
||||||
|
savedState: recoveryToken['savedState'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
169
terminus-serial/src/services/serial.service.ts
Normal file
169
terminus-serial/src/services/serial.service.ts
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { Injectable, NgZone } from '@angular/core'
|
||||||
|
import SerialPort from 'serialport'
|
||||||
|
import { ToastrService } from 'ngx-toastr'
|
||||||
|
import { LogService, AppService, SelectorOption, ConfigService } from 'terminus-core'
|
||||||
|
import { SettingsTabComponent } from 'terminus-settings'
|
||||||
|
import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api'
|
||||||
|
import { SerialTabComponent } from '../components/serialTab.component'
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class SerialService {
|
||||||
|
private constructor (
|
||||||
|
private log: LogService,
|
||||||
|
private zone: NgZone,
|
||||||
|
private toastr: ToastrService,
|
||||||
|
private app: AppService,
|
||||||
|
private config: ConfigService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async listPorts (): Promise<SerialPortInfo[]> {
|
||||||
|
return (await SerialPort.list()).map(x => ({
|
||||||
|
name: x.path,
|
||||||
|
description: x.manufacturer || x.serialNumber ? `${x.manufacturer || ''} ${x.serialNumber || ''}` : undefined,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
createSession (connection: SerialConnection): SerialSession {
|
||||||
|
const session = new SerialSession(connection)
|
||||||
|
session.logger = this.log.create(`serial-${connection.port}`)
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectSession (session: SerialSession): Promise<SerialPort> {
|
||||||
|
const serial = new SerialPort(session.connection.port, { autoOpen: false, baudRate: session.connection.baudrate,
|
||||||
|
dataBits: session.connection.databits, stopBits: session.connection.stopbits, parity: session.connection.parity,
|
||||||
|
rtscts: session.connection.rtscts, xon: session.connection.xon, xoff: session.connection.xoff,
|
||||||
|
xany: session.connection.xany })
|
||||||
|
session.serial = serial
|
||||||
|
let connected = false
|
||||||
|
await new Promise(async (resolve, reject) => {
|
||||||
|
serial.on('open', () => {
|
||||||
|
connected = true
|
||||||
|
this.zone.run(resolve)
|
||||||
|
})
|
||||||
|
serial.on('error', error => {
|
||||||
|
this.zone.run(() => {
|
||||||
|
if (connected) {
|
||||||
|
this.toastr.error(error.toString())
|
||||||
|
} else {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
serial.open()
|
||||||
|
} catch (e) {
|
||||||
|
this.toastr.error(e.message)
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
return serial
|
||||||
|
}
|
||||||
|
|
||||||
|
async showConnectionSelector (): Promise<void> {
|
||||||
|
const options: SelectorOption<void>[] = []
|
||||||
|
const foundPorts = await this.listPorts()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const lastConnection = JSON.parse(window.localStorage.lastSerialConnection)
|
||||||
|
if (lastConnection) {
|
||||||
|
options.push({
|
||||||
|
name: lastConnection.name,
|
||||||
|
icon: 'history',
|
||||||
|
callback: () => this.connect(lastConnection),
|
||||||
|
})
|
||||||
|
options.push({
|
||||||
|
name: 'Clear last connection',
|
||||||
|
icon: 'eraser',
|
||||||
|
callback: () => {
|
||||||
|
window.localStorage.lastSerialConnection = null
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
for (const port of foundPorts) {
|
||||||
|
options.push({
|
||||||
|
name: port.name,
|
||||||
|
description: port.description,
|
||||||
|
icon: 'arrow-right',
|
||||||
|
callback: () => this.connectFoundPort(port),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const connection of this.config.store.serial.connections) {
|
||||||
|
options.push({
|
||||||
|
name: connection.name,
|
||||||
|
description: connection.port,
|
||||||
|
callback: () => this.connect(connection),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
options.push({
|
||||||
|
name: 'Manage connections',
|
||||||
|
icon: 'cog',
|
||||||
|
callback: () => this.app.openNewTab(SettingsTabComponent, { activeTab: 'serial' }),
|
||||||
|
})
|
||||||
|
|
||||||
|
options.push({
|
||||||
|
name: 'Quick connect',
|
||||||
|
freeInputPattern: 'Open device: %s...',
|
||||||
|
icon: 'arrow-right',
|
||||||
|
callback: query => this.quickConnect(query),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
await this.app.showSelector('Open a serial port', options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect (connection: SerialConnection): Promise<SerialTabComponent> {
|
||||||
|
try {
|
||||||
|
const tab = this.app.openNewTab(
|
||||||
|
SerialTabComponent,
|
||||||
|
{ connection }
|
||||||
|
) as SerialTabComponent
|
||||||
|
if (connection.color) {
|
||||||
|
(this.app.getParentTab(tab) || tab).color = connection.color
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.app.activeTab.emitFocused()
|
||||||
|
})
|
||||||
|
return tab
|
||||||
|
} catch (error) {
|
||||||
|
this.toastr.error(`Could not connect: ${error}`)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickConnect (query: string): Promise<SerialTabComponent> {
|
||||||
|
let path = query
|
||||||
|
let baudrate = 115200
|
||||||
|
if (query.includes('@')) {
|
||||||
|
baudrate = parseInt(path.split('@')[1])
|
||||||
|
path = path.split('@')[0]
|
||||||
|
}
|
||||||
|
const connection: SerialConnection = {
|
||||||
|
name: query,
|
||||||
|
port: path,
|
||||||
|
baudrate: baudrate,
|
||||||
|
databits: 8,
|
||||||
|
parity: 'none',
|
||||||
|
rtscts: false,
|
||||||
|
stopbits: 1,
|
||||||
|
xany: false,
|
||||||
|
xoff: false,
|
||||||
|
xon: false,
|
||||||
|
}
|
||||||
|
window.localStorage.lastSerialConnection = JSON.stringify(connection)
|
||||||
|
return this.connect(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectFoundPort (port: SerialPortInfo): Promise<SerialTabComponent> {
|
||||||
|
const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({
|
||||||
|
name: x.toString(), result: x,
|
||||||
|
})))
|
||||||
|
return this.quickConnect(`${port.name}@${rate}`)
|
||||||
|
}
|
||||||
|
}
|
16
terminus-serial/src/settings.ts
Normal file
16
terminus-serial/src/settings.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { SettingsTabProvider } from 'terminus-settings'
|
||||||
|
|
||||||
|
import { SerialSettingsTabComponent } from './components/serialSettingsTab.component'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class SerialSettingsTabProvider extends SettingsTabProvider {
|
||||||
|
id = 'serial'
|
||||||
|
icon = 'keyboard'
|
||||||
|
title = 'Serial'
|
||||||
|
|
||||||
|
getComponentType (): any {
|
||||||
|
return SerialSettingsTabComponent
|
||||||
|
}
|
||||||
|
}
|
7
terminus-serial/tsconfig.json
Normal file
7
terminus-serial/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"exclude": ["node_modules", "dist", "typings"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src"
|
||||||
|
}
|
||||||
|
}
|
15
terminus-serial/tsconfig.typings.json
Normal file
15
terminus-serial/tsconfig.typings.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"exclude": ["node_modules", "dist", "typings"],
|
||||||
|
"include": ["src"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationDir": "./typings",
|
||||||
|
"paths": {
|
||||||
|
"terminus-*": ["../../terminus-*"],
|
||||||
|
"*": ["../../app/node_modules/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
terminus-serial/webpack.config.js
Normal file
59
terminus-serial/webpack.config.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
target: 'node',
|
||||||
|
entry: 'src/index.ts',
|
||||||
|
context: __dirname,
|
||||||
|
devtool: 'source-map',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: 'index.js',
|
||||||
|
pathinfo: true,
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
devtoolModuleFilenameTemplate: 'webpack-terminus-serial:///[resource-path]',
|
||||||
|
},
|
||||||
|
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||||
|
optimization:{
|
||||||
|
minimize: false,
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||||
|
extensions: ['.ts', '.js', '.node'],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: {
|
||||||
|
loader: 'awesome-typescript-loader',
|
||||||
|
options: {
|
||||||
|
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||||
|
typeRoots: [
|
||||||
|
path.resolve(__dirname, 'node_modules/@types'),
|
||||||
|
path.resolve(__dirname, '../node_modules/@types'),
|
||||||
|
],
|
||||||
|
paths: {
|
||||||
|
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
|
||||||
|
"*": [path.resolve(__dirname, '../app/node_modules/*')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||||
|
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||||
|
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
externals: [
|
||||||
|
'fs',
|
||||||
|
'keytar',
|
||||||
|
'path',
|
||||||
|
'ngx-toastr',
|
||||||
|
'serialport',
|
||||||
|
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||||
|
/^rxjs/,
|
||||||
|
/^@angular/,
|
||||||
|
/^@ng-bootstrap/,
|
||||||
|
/^terminus-/,
|
||||||
|
],
|
||||||
|
}
|
1110
terminus-serial/yarn.lock
Normal file
1110
terminus-serial/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user