mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-19 07:41:53 +00:00
Compare commits
206 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f6d08af986 | ||
![]() |
7ddb67f28e | ||
![]() |
ff2c2031b5 | ||
![]() |
1ab528b05c | ||
![]() |
f4f52321f5 | ||
![]() |
286b6cfdde | ||
![]() |
b97149aa73 | ||
![]() |
2094c44992 | ||
![]() |
a8409a0aec | ||
![]() |
5c2ac72bac | ||
![]() |
be09e7829f | ||
![]() |
a9320a33c9 | ||
![]() |
0e881e47e2 | ||
![]() |
3b7f4be643 | ||
![]() |
8f361f841c | ||
![]() |
0e0d59f2c5 | ||
![]() |
ca9b8307c2 | ||
![]() |
d837a3d7fd | ||
![]() |
555e1e733d | ||
![]() |
2e546fb72e | ||
![]() |
a2d4b76070 | ||
![]() |
34edee2f37 | ||
![]() |
f17b7fb8ce | ||
![]() |
cbe5ea7fdd | ||
![]() |
c00405afff | ||
![]() |
555db7bef9 | ||
![]() |
94e9e7d439 | ||
![]() |
c4850f2172 | ||
![]() |
2d33a0030d | ||
![]() |
1f576edf85 | ||
![]() |
6d139434d7 | ||
![]() |
e9ba07c7a3 | ||
![]() |
4f083098c3 | ||
![]() |
03369da32c | ||
![]() |
edb2cf2b7b | ||
![]() |
91a1ae1cbe | ||
![]() |
4a9f17ace9 | ||
![]() |
d5babde1fa | ||
![]() |
902c1fceb1 | ||
![]() |
1d340e4666 | ||
![]() |
b922fe7776 | ||
![]() |
de3829a94c | ||
![]() |
964e0ad2bc | ||
![]() |
742affb88b | ||
![]() |
e9999ee883 | ||
![]() |
1c8288bfe1 | ||
![]() |
37044fbb01 | ||
![]() |
5507171fee | ||
![]() |
472b421484 | ||
![]() |
b076541962 | ||
![]() |
8201e0b9ef | ||
![]() |
6293a43571 | ||
![]() |
b61bc943ec | ||
![]() |
be668403c5 | ||
![]() |
90a173d8b7 | ||
![]() |
bbcc84e9b0 | ||
![]() |
b0a8832499 | ||
![]() |
8cd1c4a9af | ||
![]() |
1ada4338b7 | ||
![]() |
4a701fa7b4 | ||
![]() |
b718448904 | ||
![]() |
7770cf2573 | ||
![]() |
49755f855f | ||
![]() |
daa1b4572e | ||
![]() |
d48e22a9d2 | ||
![]() |
fc82010729 | ||
![]() |
4a8f3fbd7f | ||
![]() |
4c435672a5 | ||
![]() |
0311754ce0 | ||
![]() |
ff5da104c1 | ||
![]() |
b01b902829 | ||
![]() |
595707eed4 | ||
![]() |
441ee4fb6e | ||
![]() |
51827d6750 | ||
![]() |
9807bbe32a | ||
![]() |
181b55890d | ||
![]() |
c8c5f1a0fd | ||
![]() |
222c6a9f3c | ||
![]() |
0400c8fe63 | ||
![]() |
099d9b06d6 | ||
![]() |
ad26b39cca | ||
![]() |
f465c359ef | ||
![]() |
67aead225c | ||
![]() |
280c421ae4 | ||
![]() |
b6fc43faa2 | ||
![]() |
b5a985b8a3 | ||
![]() |
2f7dcf3339 | ||
![]() |
7e38f11c06 | ||
![]() |
86cd560089 | ||
![]() |
c0c4580461 | ||
![]() |
5cb65dfd84 | ||
![]() |
2b5f623b50 | ||
![]() |
a8d5cf469e | ||
![]() |
d261b89803 | ||
![]() |
21cb452d62 | ||
![]() |
b07a2113d2 | ||
![]() |
f545b3eacf | ||
![]() |
87fe8deaa8 | ||
![]() |
1068450ddd | ||
![]() |
b355fff0f8 | ||
![]() |
f80b0eb65b | ||
![]() |
285691326f | ||
![]() |
3ecffbfda6 | ||
![]() |
3d89a15d18 | ||
![]() |
491d4c3b3a | ||
![]() |
995f329835 | ||
![]() |
28f2ea595d | ||
![]() |
42b7c573ea | ||
![]() |
c40294628a | ||
![]() |
c11a10144e | ||
![]() |
7b6cdb274c | ||
![]() |
a3c74ecdba | ||
![]() |
94d91f8182 | ||
![]() |
e4f32c9ade | ||
![]() |
65fd7b05b1 | ||
![]() |
2150fab55b | ||
![]() |
644cb76fd3 | ||
![]() |
4106d97f6b | ||
![]() |
98103fd139 | ||
![]() |
9453e8ba7b | ||
![]() |
2f78575cd7 | ||
![]() |
500acee064 | ||
![]() |
42eb5f6b78 | ||
![]() |
ef19b92e85 | ||
![]() |
f263f954d4 | ||
![]() |
2ce0f03282 | ||
![]() |
150999d3a3 | ||
![]() |
8cc76555d2 | ||
![]() |
f0f8f06890 | ||
![]() |
176a55c91d | ||
![]() |
fc6dfc50dd | ||
![]() |
34d020f66a | ||
![]() |
fa0ef69c46 | ||
![]() |
e5c1e421f7 | ||
![]() |
f3994f1bd9 | ||
![]() |
6956ef9e0f | ||
![]() |
a080129882 | ||
![]() |
ef9bfe6120 | ||
![]() |
37d69e858f | ||
![]() |
ee594f5bcd | ||
![]() |
adf022de2c | ||
![]() |
c5a9b890c4 | ||
![]() |
2d1a96a12b | ||
![]() |
5289981485 | ||
![]() |
a89047b205 | ||
![]() |
a7b4496d22 | ||
![]() |
09cd9d0e18 | ||
![]() |
fb2a4d268d | ||
![]() |
9b61615701 | ||
![]() |
077d2421e1 | ||
![]() |
202ba18a8c | ||
![]() |
63f33f8f4b | ||
![]() |
3bd89a0194 | ||
![]() |
604bc28c9a | ||
![]() |
f81f5d122a | ||
![]() |
3633be750e | ||
![]() |
404fd72ea9 | ||
![]() |
402b76bcc9 | ||
![]() |
b6c97ffa49 | ||
![]() |
20aa1d814f | ||
![]() |
786daaac32 | ||
![]() |
0360ad2dd0 | ||
![]() |
0a451c5876 | ||
![]() |
5a9625424c | ||
![]() |
62c1f6463b | ||
![]() |
9fe82f2c0a | ||
![]() |
09838197a2 | ||
![]() |
27114797a2 | ||
![]() |
4dc77d11cf | ||
![]() |
245698b67d | ||
![]() |
017fabaf6f | ||
![]() |
6c11189b3e | ||
![]() |
dd70f5f5d8 | ||
![]() |
47277ac5aa | ||
![]() |
b69cbbcdd1 | ||
![]() |
efba980a1d | ||
![]() |
f31da67508 | ||
![]() |
2ba76cc0b9 | ||
![]() |
62d14ac0cb | ||
![]() |
c1b4ffd248 | ||
![]() |
87cacdb568 | ||
![]() |
2a11bc4fcc | ||
![]() |
f716baa7d4 | ||
![]() |
5b60daf366 | ||
![]() |
11f9f4e824 | ||
![]() |
0daf48f699 | ||
![]() |
8fb0ea4d75 | ||
![]() |
d9948cf6e2 | ||
![]() |
54b618cffc | ||
![]() |
690dde628e | ||
![]() |
3dfbcf9d41 | ||
![]() |
d91ba71ec0 | ||
![]() |
99698913a8 | ||
![]() |
0dbb16d859 | ||
![]() |
0f8cff2d5b | ||
![]() |
471f9effcf | ||
![]() |
04faf1a04a | ||
![]() |
656f5c2561 | ||
![]() |
99bc2c1c65 | ||
![]() |
87837bf66b | ||
![]() |
c8735243f3 | ||
![]() |
b197a16e5c | ||
![]() |
1a361e67b3 | ||
![]() |
fc471b2c16 | ||
![]() |
ae17faa7e5 | ||
![]() |
4dd0a5951f |
@@ -225,6 +225,24 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "LeSeulArtichaut",
|
||||
"name": "LeSeulArtichaut",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/38361244?v=4",
|
||||
"profile": "https://github.com/LeSeulArtichaut",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "CyrilTaylor",
|
||||
"name": "Cyril Taylor",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/12631466?v=4",
|
||||
"profile": "https://github.com/CyrilTaylor",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
@@ -232,5 +250,6 @@
|
||||
"projectOwner": "Eugeny",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"commitConvention": "none"
|
||||
"commitConvention": "none",
|
||||
"skipCi": true
|
||||
}
|
||||
|
@@ -97,3 +97,4 @@ rules:
|
||||
'@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors
|
||||
'@typescript-eslint/restrict-template-expressions': off
|
||||
'@typescript-eslint/no-dynamic-delete': off
|
||||
'@typescript-eslint/prefer-nullish-coalescing': off
|
||||
|
59
README.md
59
README.md
@@ -13,12 +13,13 @@
|
||||
|
||||
**Terminus** is a highly configurable terminal emulator for Windows, macOS and Linux
|
||||
|
||||
* Integrated SSH client and connection manager
|
||||
* Theming and color schemes
|
||||
* Fully configurable shortcuts
|
||||
* Split panes
|
||||
* Remembers your tabs
|
||||
* PowerShell (and PS Core), WSL, Git-Bash, Cygwin, Cmder and CMD support
|
||||
* Integrated SSH client and connection manager
|
||||
* Direct file transfer from/to SSH sessions via Zmodem
|
||||
* Full Unicode support including double-width characters
|
||||
* Doesn't choke on fast-flowing outputs
|
||||
* Proper shell experience on Windows including tab completion (via Clink)
|
||||
@@ -39,7 +40,6 @@
|
||||
Plugins and themes can be installed directly from the Settings view inside Terminus.
|
||||
|
||||
* [clickable-links](https://github.com/Eugeny/terminus-clickable-links) - makes paths and URLs in the terminal clickable
|
||||
* [shell-selector](https://github.com/Eugeny/terminus-shell-selector) - a quick shell selector pane
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - allows modifying the title of the terminal tabs by providing a prefix, suffix, and/or strings to be removed
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - quickly send commands to one or all terminal tabs
|
||||
* [save-output](https://github.com/Eugeny/terminus-save-output) - record terminal output into a file
|
||||
@@ -66,42 +66,47 @@ See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) and
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt="Russell Myers"/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt="Austin Warren"/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt="Felicia Hummel"/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt="Mike MacCana"/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt="Yacine Kanzari"/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt="BBJip"/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt="Futagirl"/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt="Levin Rickert"/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt="OJ Kwon"/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt="domain"/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt="James Brumond"/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt="Daniel Imms"/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt="Florian Bachmann"/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt="Michael Kühnel"/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt="Tilmann Meyer"/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt="PM Extra"/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt="Jonathan"/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt="Hans Koch"/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt="Dak Smyth"/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt="Wang Zhi"/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt="jack1142"/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt="Howie Douglas"/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt="Chris Kaczor"/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt="Johannes Kadak"/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
@@ -13,9 +13,12 @@ export class Application {
|
||||
})
|
||||
|
||||
const configData = loadConfig()
|
||||
if (process.platform === 'linux' && ((configData.appearance || {}).opacity || 1) !== 1) {
|
||||
app.commandLine.appendSwitch('enable-transparent-visuals')
|
||||
app.disableHardwareAcceleration()
|
||||
if (process.platform === 'linux') {
|
||||
app.commandLine.appendSwitch('no-sandbox')
|
||||
if (((configData.appearance || {}).opacity || 1) !== 1) {
|
||||
app.commandLine.appendSwitch('enable-transparent-visuals')
|
||||
app.disableHardwareAcceleration()
|
||||
}
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch('disable-http-cache')
|
||||
|
@@ -4,6 +4,8 @@ import { app, ipcMain, Menu } from 'electron'
|
||||
import { parseArgs } from './cli'
|
||||
import { Application } from './app'
|
||||
import electronDebug = require('electron-debug')
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
if (!process.env.TERMINUS_PLUGINS) {
|
||||
process.env.TERMINUS_PLUGINS = ''
|
||||
@@ -11,6 +13,14 @@ if (!process.env.TERMINUS_PLUGINS) {
|
||||
|
||||
const application = new Application()
|
||||
|
||||
if (process.env.PORTABLE_EXECUTABLE_DIR) {
|
||||
const portableData = path.join(process.env.PORTABLE_EXECUTABLE_DIR, 'terminus-data')
|
||||
if (!fs.existsSync(portableData)) {
|
||||
fs.mkdirSync(portableData)
|
||||
}
|
||||
app.setPath('userData', portableData)
|
||||
}
|
||||
|
||||
ipcMain.on('app:new-window', () => {
|
||||
application.newWindow()
|
||||
})
|
||||
|
@@ -1,4 +1,5 @@
|
||||
const { init } = process.type === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
|
||||
import * as isDev from 'electron-is-dev'
|
||||
|
||||
|
||||
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
|
||||
@@ -9,7 +10,12 @@ try {
|
||||
release = require('electron').remote.app.getVersion()
|
||||
}
|
||||
|
||||
init({
|
||||
dsn: SENTRY_DSN,
|
||||
release,
|
||||
})
|
||||
if (!isDev) {
|
||||
init({
|
||||
dsn: SENTRY_DSN,
|
||||
release,
|
||||
integrations (integrations) {
|
||||
return integrations.filter(integration => integration.name !== 'Breadcrumbs')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@@ -202,6 +202,10 @@ export class Window {
|
||||
}
|
||||
})
|
||||
|
||||
this.window.on('focus', () => {
|
||||
this.send('host:window-focused')
|
||||
})
|
||||
|
||||
ipcMain.on('window-focus', event => {
|
||||
if (!this.window || event.sender !== this.window.webContents) {
|
||||
return
|
||||
|
@@ -34,21 +34,21 @@
|
||||
"node-pty": "^0.10.0-beta2",
|
||||
"npm": "6.9.0",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "^6.5.3",
|
||||
"rxjs-compat": "^6.5.3",
|
||||
"yargs": "^15.0.2",
|
||||
"rxjs": "^6.5.4",
|
||||
"rxjs-compat": "^6.5.4",
|
||||
"yargs": "^15.1.0",
|
||||
"zone.js": "^0.8.29"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"macos-native-processlist": "^1.0.2",
|
||||
"windows-blurbehind": "^1.0.1",
|
||||
"windows-native-registry": "^1.0.16",
|
||||
"windows-native-registry": "^1.0.17",
|
||||
"windows-process-tree": "^0.2.4",
|
||||
"windows-swca": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mz": "0.0.32",
|
||||
"@types/node": "12.7.12",
|
||||
"node-abi": "^2.12.0"
|
||||
"node-abi": "^2.13.0"
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,8 @@ import * as isDev from 'electron-is-dev'
|
||||
import './global.scss'
|
||||
import './toastr.scss'
|
||||
|
||||
import { enableProdMode, NgModuleRef } from '@angular/core'
|
||||
import { enableProdMode, NgModuleRef, ApplicationRef } from '@angular/core'
|
||||
import { enableDebugTools } from '@angular/platform-browser'
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
|
||||
import { getRootModule } from './app.module'
|
||||
@@ -37,7 +38,14 @@ async function bootstrap (plugins: PluginInfo[], safeMode = false): Promise<NgMo
|
||||
})
|
||||
const module = getRootModule(pluginsModules)
|
||||
window['rootModule'] = module
|
||||
return platformBrowserDynamic().bootstrapModule(module)
|
||||
return platformBrowserDynamic().bootstrapModule(module).then(moduleRef => {
|
||||
if (isDev) {
|
||||
const applicationRef = moduleRef.injector.get(ApplicationRef)
|
||||
const componentRef = applicationRef.components[0]
|
||||
enableDebugTools(componentRef)
|
||||
}
|
||||
return moduleRef
|
||||
})
|
||||
}
|
||||
|
||||
findPlugins().then(async plugins => {
|
||||
|
@@ -10,6 +10,10 @@
|
||||
background-image: none;
|
||||
width: auto;
|
||||
|
||||
&.toast-error {
|
||||
background-color: #BD362F;
|
||||
}
|
||||
|
||||
&.toast-info {
|
||||
background-color: #555;
|
||||
}
|
||||
|
@@ -1925,10 +1925,10 @@ ngx-toastr@^10.2.0:
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
node-abi@^2.12.0, node-abi@^2.7.0:
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.12.0.tgz#40e9cfabdda1837863fa825e7dfa0b15686adf6f"
|
||||
integrity sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw==
|
||||
node-abi@^2.13.0, node-abi@^2.7.0:
|
||||
version "2.13.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.13.0.tgz#e2f2ec444d0aca3ea1b3874b6de41d1665828f63"
|
||||
integrity sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
@@ -2801,15 +2801,15 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
dependencies:
|
||||
aproba "^1.1.1"
|
||||
|
||||
rxjs-compat@^6.5.3:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.3.tgz#18440949b2678bf87a78a754009676b2c49183dc"
|
||||
integrity sha512-BIJX2yovz3TBpjJoAZyls2QYuU6ZiCaZ+U96SmxQpuSP/qDUfiXPKOVLbThBB2WZijNHkdTTJXKRwvv5Y48H7g==
|
||||
rxjs-compat@^6.5.4:
|
||||
version "6.5.4"
|
||||
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.5.4.tgz#03825692af3fe363e04c43f41ff4113d76bbd305"
|
||||
integrity sha512-rkn+lbOHUQOurdd74J/hjmDsG9nFx0z66fvnbs8M95nrtKvNqCKdk7iZqdY51CGmDemTQk+kUPy4s8HVOHtkfA==
|
||||
|
||||
rxjs@^6.5.3:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
|
||||
integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
|
||||
rxjs@^6.5.4:
|
||||
version "6.5.4"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
|
||||
integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
@@ -3397,10 +3397,10 @@ windows-blurbehind@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/windows-blurbehind/-/windows-blurbehind-1.0.1.tgz#ff098713873304e38330b2c54cc41bb369b587b9"
|
||||
integrity sha512-1HzHfCiM1ayrbACJu5qE9zELV24uX/tINT6kxaZwLY3rtQAoeav6x9z7LFHWoLaGDN/sYbnK+9Vk0cz7fsk5HQ==
|
||||
|
||||
windows-native-registry@^1.0.16:
|
||||
version "1.0.16"
|
||||
resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.16.tgz#761f21b7dfa6cdb28479cf9bc66b705592e3ae6a"
|
||||
integrity sha512-RROB5VPEafEJLK93vdttfq4BGWaMWI/OHjAE2cqA31eMjmPShD2KaerlhEfUgqa5THsaAbYUK0LQKc4UQTjIMg==
|
||||
windows-native-registry@^1.0.17:
|
||||
version "1.0.17"
|
||||
resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.17.tgz#d8cce48b364703a55c226690431b325114405022"
|
||||
integrity sha512-u9Fp9TyDo5dvhlW6hYBOdHPETtAahXKxo3jeW5EXwNK7qa+nSNopQycN1drtBVWe3jpJXvyKpt9zrjiDd+u4JQ==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
@@ -3519,10 +3519,10 @@ yargs@^11.0.0:
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^9.0.2"
|
||||
|
||||
yargs@^15.0.2:
|
||||
version "15.0.2"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.0.2.tgz#4248bf218ef050385c4f7e14ebdf425653d13bd3"
|
||||
integrity sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==
|
||||
yargs@^15.1.0:
|
||||
version "15.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219"
|
||||
integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==
|
||||
dependencies:
|
||||
cliui "^6.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#!/bin/bash
|
||||
cat > '/usr/bin/${executable}' << END
|
||||
#!/bin/sh
|
||||
'/opt/${productFilename}/${executable}' --no-sandbox $@
|
||||
END
|
||||
|
||||
# Link to the binary
|
||||
ln -sf '/opt/${productFilename}/${executable}' '/usr/bin/${executable}'
|
||||
chmod +x '/usr/bin/${executable}'
|
||||
|
45
package.json
45
package.json
@@ -1,32 +1,34 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.11.2",
|
||||
"@fortawesome/fontawesome-free": "^5.12.0",
|
||||
"@sentry/cli": "^1.49.0",
|
||||
"@sentry/electron": "^1.0.0",
|
||||
"@types/electron-config": "^3.2.2",
|
||||
"@types/electron-debug": "^2.1.0",
|
||||
"@types/js-yaml": "^3.12.1",
|
||||
"@types/node": "12.7.12",
|
||||
"@types/webpack-env": "1.14.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.8.0",
|
||||
"@typescript-eslint/parser": "^2.8.0",
|
||||
"@types/webpack-env": "1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.13.0",
|
||||
"@typescript-eslint/parser": "^2.17.0",
|
||||
"apply-loader": "2.0.0",
|
||||
"awesome-typescript-loader": "^5.0.0",
|
||||
"core-js": "^3.4.2",
|
||||
"core-js": "^3.6.4",
|
||||
"cross-env": "6.0.3",
|
||||
"css-loader": "3.2.0",
|
||||
"electron": "^7.1.2",
|
||||
"css-loader": "3.4.2",
|
||||
"electron": "^7.1.10",
|
||||
"electron-builder": "22.1.0",
|
||||
"electron-installer-snap": "^4.1.0",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.0.0",
|
||||
"electron-notarize": "^0.1.1",
|
||||
"electron-rebuild": "^1.8.5",
|
||||
"eslint": "^6.7.1",
|
||||
"file-loader": "^4.3.0",
|
||||
"electron-rebuild": "^1.9.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-import": "^2.20.0",
|
||||
"file-loader": "^5.0.2",
|
||||
"graceful-fs": "^4.2.2",
|
||||
"html-loader": "0.5.5",
|
||||
"json-loader": "0.5.7",
|
||||
"node-abi": "^2.12.0",
|
||||
"node-gyp": "^6.0.1",
|
||||
"node-gyp": "^6.1.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"npmlog": "4.1.2",
|
||||
"npx": "^10.2.0",
|
||||
@@ -35,23 +37,21 @@
|
||||
"pug-lint": "^2.6.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-static-loader": "2.0.0",
|
||||
"raw-loader": "3.1.0",
|
||||
"raw-loader": "4.0.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"shelljs": "0.8.3",
|
||||
"source-code-pro": "^2.30.2",
|
||||
"source-sans-pro": "3.6.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"style-loader": "^1.1.2",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"to-string-loader": "1.1.6",
|
||||
"tslib": "^1.10.0",
|
||||
"typedoc": "^0.15.3",
|
||||
"typescript": "^3.6.4",
|
||||
"url-loader": "^2.3.0",
|
||||
"val-loader": "2.0.1",
|
||||
"webpack": "^5.0.0-beta.7",
|
||||
"typedoc": "^0.16.7",
|
||||
"typescript": "^3.7.4",
|
||||
"url-loader": "^3.0.0",
|
||||
"val-loader": "2.1.0",
|
||||
"webpack": "^5.0.0-beta.12",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"electron-download": "^4.1.1",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"yaml-loader": "0.5.0"
|
||||
},
|
||||
"resolutions": {
|
||||
@@ -107,6 +107,9 @@
|
||||
"icon": "./build/icons",
|
||||
"artifactName": "terminus-${version}-linux.${ext}"
|
||||
},
|
||||
"snap": {
|
||||
"plugs": ["default", "system-files", "system-observe"]
|
||||
},
|
||||
"deb": {
|
||||
"depends": [
|
||||
"gconf2",
|
||||
|
@@ -25,8 +25,5 @@ if (['darwin', 'linux'].includes(process.platform)) {
|
||||
for (let x of vars.builtinPlugins) {
|
||||
sh.ln('-fs', '../' + x, x)
|
||||
}
|
||||
for (let x of vars.bundledModules) {
|
||||
sh.ln('-fs', '../app/node_modules/' + x, x)
|
||||
}
|
||||
sh.cd('..')
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-community-color-schemes",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "Community color schemes for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-core",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "Terminus core",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
|
@@ -1,4 +1,5 @@
|
||||
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
|
||||
export { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
export { SplitTabComponent, SplitContainer } from '../components/splitTab.component'
|
||||
export { TabRecoveryProvider, RecoveredTab } from './tabRecovery'
|
||||
export { ToolbarButtonProvider, ToolbarButton } from './toolbarButtonProvider'
|
||||
|
@@ -38,7 +38,7 @@ title-bar(
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
[title]='button.title',
|
||||
(click)='button.click && button.click()',
|
||||
[innerHTML]='sanitizeIcon(button.icon)',
|
||||
[fastHtmlBind]='button.icon',
|
||||
ngbDropdownToggle,
|
||||
)
|
||||
div(*ngIf='button.submenu', ngbDropdownMenu)
|
||||
@@ -47,8 +47,11 @@ title-bar(
|
||||
(click)='item.click()',
|
||||
ngbDropdownItem,
|
||||
)
|
||||
.icon-wrapper([innerHTML]='sanitizeIcon(item.icon)')
|
||||
.ml-3 {{item.title}}
|
||||
.icon-wrapper(
|
||||
*ngIf='hasIcons(button.submenuItems)',
|
||||
[fastHtmlBind]='item.icon'
|
||||
)
|
||||
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
|
||||
|
||||
.drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
|
||||
|
||||
@@ -61,7 +64,7 @@ title-bar(
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
[title]='button.title',
|
||||
(click)='button.click && button.click()',
|
||||
[innerHTML]='sanitizeIcon(button.icon)',
|
||||
[fastHtmlBind]='button.icon',
|
||||
ngbDropdownToggle,
|
||||
)
|
||||
div(*ngIf='button.submenu', ngbDropdownMenu)
|
||||
@@ -70,14 +73,17 @@ title-bar(
|
||||
(click)='item.click()',
|
||||
ngbDropdownItem,
|
||||
)
|
||||
.icon-wrapper([innerHTML]='sanitizeIcon(item.icon)')
|
||||
.ml-3 {{item.title}}
|
||||
.icon-wrapper(
|
||||
*ngIf='hasIcons(button.submenuItems)',
|
||||
[fastHtmlBind]='item.icon'
|
||||
)
|
||||
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
|
||||
|
||||
button.btn.btn-secondary.btn-tab-bar.btn-update(
|
||||
*ngIf='updatesAvailable',
|
||||
title='Update available - Click to install',
|
||||
(click)='updateApp()',
|
||||
[innerHTML]='sanitizeIcon(updateIcon)'
|
||||
[fastHtmlBind]='updateIcon'
|
||||
)
|
||||
|
||||
window-controls.background(
|
||||
|
@@ -64,6 +64,7 @@ $tab-border-radius: 4px;
|
||||
&>.drag-space {
|
||||
min-width: 1px;
|
||||
flex: 1 0 1%;
|
||||
margin-top: 2px; // for window resizing
|
||||
-webkit-app-region: drag;
|
||||
|
||||
&.persistent {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { Component, Inject, Input, HostListener, HostBinding } from '@angular/core'
|
||||
import { trigger, style, animate, transition, state } from '@angular/animations'
|
||||
import { DomSanitizer } from '@angular/platform-browser'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
@@ -75,7 +74,6 @@ export class AppRootComponent {
|
||||
public hostApp: HostAppService,
|
||||
public config: ConfigService,
|
||||
public app: AppService,
|
||||
private domSanitizer: DomSanitizer,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
log: LogService,
|
||||
ngbModal: NgbModal,
|
||||
@@ -250,8 +248,8 @@ export class AppRootComponent {
|
||||
}
|
||||
}
|
||||
|
||||
sanitizeIcon (icon: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
|
||||
hasIcons (submenuItems: ToolbarButton[]): boolean {
|
||||
return submenuItems.some(x => !!x.icon)
|
||||
}
|
||||
|
||||
private getToolbarButtons (aboveZero: boolean): ToolbarButton[] {
|
||||
|
@@ -1,4 +0,0 @@
|
||||
.icon(tabindex='0', [class.active]='model', (keyup.space)='click()')
|
||||
i.fas.fa-square.off
|
||||
i.fas.fa-check-square.on
|
||||
.text {{text}}
|
@@ -1,55 +0,0 @@
|
||||
:host {
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
|
||||
&:focus {
|
||||
background: rgba(255,255,255,.05);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(255,255,255,.1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.off {
|
||||
color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
flex: none;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -2px;
|
||||
transition: 0.25s opacity;
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
i.on, &.active i.off {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
i.off, &.active i.on {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: auto;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
@@ -4,8 +4,12 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'checkbox',
|
||||
template: require('./checkbox.component.pug'),
|
||||
styles: [require('./checkbox.component.scss')],
|
||||
template: `
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" [(ngModel)]='model'>
|
||||
<label class="custom-control-label">{{text}}</label>
|
||||
</div>
|
||||
`,
|
||||
providers: [
|
||||
{ provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true },
|
||||
],
|
||||
|
@@ -3,3 +3,24 @@
|
||||
position: relative;
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
::ng-deep split-tab > .child {
|
||||
position: absolute;
|
||||
transition: 0.125s all;
|
||||
opacity: .75;
|
||||
|
||||
&.focused {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.minimized {
|
||||
opacity: .1;
|
||||
}
|
||||
|
||||
&.maximized {
|
||||
z-index: 2;
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0px 0px 30px;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
@@ -141,6 +141,8 @@ export interface SplitSpannerInfo {
|
||||
styles: [require('./splitTab.component.scss')],
|
||||
})
|
||||
export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
|
||||
static DIRECTIONS: SplitDirection[] = ['t', 'r', 'b', 'l']
|
||||
|
||||
/** @hidden */
|
||||
@ViewChild('vc', { read: ViewContainerRef }) viewContainer: ViewContainerRef
|
||||
|
||||
@@ -156,6 +158,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
_spanners: SplitSpannerInfo[] = []
|
||||
|
||||
private focusedTab: BaseTabComponent
|
||||
private maximizedTab: BaseTabComponent|null = null
|
||||
private hotkeysSubscription: Subscription
|
||||
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
|
||||
|
||||
@@ -226,6 +229,13 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
case 'pane-nav-down':
|
||||
this.navigate('b')
|
||||
break
|
||||
case 'pane-maximize':
|
||||
if (this.maximizedTab) {
|
||||
this.maximize(null)
|
||||
} else if (this.getAllTabs().length > 1) {
|
||||
this.maximize(this.focusedTab)
|
||||
}
|
||||
break
|
||||
case 'close-pane':
|
||||
this.removeTab(this.focusedTab)
|
||||
break
|
||||
@@ -261,6 +271,10 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
return this.focusedTab
|
||||
}
|
||||
|
||||
getMaximizedTab (): BaseTabComponent|null {
|
||||
return this.maximizedTab
|
||||
}
|
||||
|
||||
focus (tab: BaseTabComponent) {
|
||||
this.focusedTab = tab
|
||||
for (const x of this.getAllTabs()) {
|
||||
@@ -272,6 +286,15 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
tab.emitFocused()
|
||||
this.focusChanged.next(tab)
|
||||
}
|
||||
|
||||
if (this.maximizedTab !== tab) {
|
||||
this.maximizedTab = null
|
||||
}
|
||||
this.layout()
|
||||
}
|
||||
|
||||
maximize (tab: BaseTabComponent|null) {
|
||||
this.maximizedTab = tab
|
||||
this.layout()
|
||||
}
|
||||
|
||||
@@ -436,6 +459,13 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
this.splitAdjusted.next(spanner)
|
||||
}
|
||||
|
||||
destroy () {
|
||||
super.destroy()
|
||||
for (const x of this.getAllTabs()) {
|
||||
x.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
private attachTabView (tab: BaseTabComponent) {
|
||||
const ref = this.viewContainer.insert(tab.hostView) as EmbeddedViewRef<any> // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
this.viewRefs.set(tab, ref)
|
||||
@@ -486,13 +516,21 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
|
||||
this.layoutInternal(child, childX, childY, childW, childH)
|
||||
} else {
|
||||
const element = this.viewRefs.get(child)!.rootNodes[0]
|
||||
element.style.position = 'absolute'
|
||||
element.classList.toggle('child', true)
|
||||
element.classList.toggle('maximized', child === this.maximizedTab)
|
||||
element.classList.toggle('minimized', this.maximizedTab && child !== this.maximizedTab)
|
||||
element.classList.toggle('focused', child === this.focusedTab)
|
||||
element.style.left = `${childX}%`
|
||||
element.style.top = `${childY}%`
|
||||
element.style.width = `${childW}%`
|
||||
element.style.height = `${childH}%`
|
||||
|
||||
element.style.opacity = child === this.focusedTab ? 1 : 0.75
|
||||
if (child === this.maximizedTab) {
|
||||
element.style.left = '5%'
|
||||
element.style.top = '5%'
|
||||
element.style.width = '90%'
|
||||
element.style.height = '90%'
|
||||
}
|
||||
}
|
||||
offset += sizes[i]
|
||||
|
||||
|
@@ -16,13 +16,17 @@ export class SplitTabSpannerComponent {
|
||||
@HostBinding('class.v') isVertical = true
|
||||
@HostBinding('style.left') cssLeft: string
|
||||
@HostBinding('style.top') cssTop: string
|
||||
@HostBinding('style.width') cssWidth: string
|
||||
@HostBinding('style.height') cssHeight: string
|
||||
@HostBinding('style.width') cssWidth: string | null
|
||||
@HostBinding('style.height') cssHeight: string | null
|
||||
private marginOffset = -5
|
||||
|
||||
constructor (private element: ElementRef) { }
|
||||
|
||||
ngAfterViewInit () {
|
||||
this.element.nativeElement.addEventListener('dblclick', () => {
|
||||
this.reset()
|
||||
})
|
||||
|
||||
this.element.nativeElement.addEventListener('mousedown', (e: MouseEvent) => {
|
||||
this.isActive = true
|
||||
const start = this.isVertical ? e.pageY : e.pageX
|
||||
@@ -49,14 +53,16 @@ export class SplitTabSpannerComponent {
|
||||
diff = Math.max(diff, -this.container.ratios[this.index - 1] + 0.1)
|
||||
diff = Math.min(diff, this.container.ratios[this.index] - 0.1)
|
||||
|
||||
this.container.ratios[this.index - 1] += diff
|
||||
this.container.ratios[this.index] -= diff
|
||||
this.change.emit()
|
||||
if (diff) {
|
||||
this.container.ratios[this.index - 1] += diff
|
||||
this.container.ratios[this.index] -= diff
|
||||
this.change.emit()
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', offHandler)
|
||||
document.addEventListener('mouseup', offHandler, { passive: true })
|
||||
this.element.nativeElement.parentElement.addEventListener('mousemove', dragHandler)
|
||||
})
|
||||
}, { passive: true })
|
||||
}
|
||||
|
||||
ngOnChanges () {
|
||||
@@ -79,10 +85,17 @@ export class SplitTabSpannerComponent {
|
||||
}
|
||||
}
|
||||
|
||||
reset () {
|
||||
const ratio = (this.container.ratios[this.index - 1] + this.container.ratios[this.index]) / 2
|
||||
this.container.ratios[this.index - 1] = ratio
|
||||
this.container.ratios[this.index] = ratio
|
||||
this.change.emit()
|
||||
}
|
||||
|
||||
private setDimensions (x: number, y: number, w: number, h: number) {
|
||||
this.cssLeft = `${x}%`
|
||||
this.cssTop = `${y}%`
|
||||
this.cssWidth = w ? `${w}%` : 'initial'
|
||||
this.cssHeight = h ? `${h}%` : 'initial'
|
||||
this.cssWidth = w ? `${w}%` : null
|
||||
this.cssHeight = h ? `${h}%` : null
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ $tabs-height: 38px;
|
||||
cursor: -webkit-grab;
|
||||
|
||||
margin-left: 10px;
|
||||
width: 20px;
|
||||
width: 22px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
transition: 0.25s all;
|
||||
@@ -48,7 +48,7 @@ $tabs-height: 38px;
|
||||
width: $button-size;
|
||||
height: $button-size;
|
||||
border-radius: $button-size / 2;
|
||||
line-height: $button-size * 0.9;
|
||||
line-height: $button-size;
|
||||
align-self: center;
|
||||
margin-right: 10px;
|
||||
|
||||
|
@@ -16,55 +16,8 @@
|
||||
padding-left: 10px;
|
||||
margin-left: -10px;
|
||||
|
||||
&:focus {
|
||||
background: rgba(255,255,255,.05);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.body {
|
||||
$border-width: 2px;
|
||||
border-radius: 5px;
|
||||
border: $border-width solid rgba(255, 255, 255, .2);
|
||||
padding: $padding;
|
||||
height: $toggle-size + $border-width * 2 + $padding * 2;
|
||||
width: $toggle-size * 2 + $border-width * 2 + $padding * 2;
|
||||
|
||||
position: relative;
|
||||
|
||||
.toggle {
|
||||
position: absolute;
|
||||
border-radius: 2px;
|
||||
width: $toggle-size;
|
||||
height: $toggle-size;
|
||||
background: #475158;
|
||||
top: $padding;
|
||||
left: $padding;
|
||||
transition: 0.25s left;
|
||||
line-height: 19px;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
|
||||
i {
|
||||
opacity: 0;
|
||||
transition: 0.25s opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active .body .toggle {
|
||||
left: $toggle-size + $padding;
|
||||
|
||||
i {
|
||||
color: white;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(255,255,255,.1);
|
||||
}
|
||||
}
|
||||
|
@@ -6,13 +6,10 @@ import { CheckboxComponent } from './checkbox.component'
|
||||
@Component({
|
||||
selector: 'toggle',
|
||||
template: `
|
||||
<div class="switch">
|
||||
<div class="body">
|
||||
<div class="toggle" [class.bg-primary]='model'>
|
||||
<i class="fa fa-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" [(ngModel)]='model'>
|
||||
<label class="custom-control-label"></label>
|
||||
</div>
|
||||
`,
|
||||
styles: [require('./toggle.component.scss')],
|
||||
providers: [
|
||||
|
@@ -50,5 +50,7 @@ hotkeys:
|
||||
- 'Ctrl-Alt-Up'
|
||||
pane-nav-left:
|
||||
- 'Ctrl-Alt-Left'
|
||||
pane-maximize:
|
||||
- 'Ctrl-Alt-Enter'
|
||||
close-pane: []
|
||||
pluginBlacklist: ['ssh']
|
||||
|
@@ -48,6 +48,8 @@ hotkeys:
|
||||
- '⌘-⌥-Up'
|
||||
pane-nav-left:
|
||||
- '⌘-⌥-Left'
|
||||
pane-maximize:
|
||||
- '⌘-⌥-Enter'
|
||||
close-pane:
|
||||
- '⌘-Shift-W'
|
||||
pluginBlacklist: ['ssh']
|
||||
|
@@ -5,6 +5,7 @@ hotkeys:
|
||||
- 'Ctrl+Space'
|
||||
toggle-fullscreen:
|
||||
- 'F11'
|
||||
- 'Alt-Enter'
|
||||
close-tab:
|
||||
- 'Ctrl-Shift-W'
|
||||
toggle-last-tab: []
|
||||
@@ -50,5 +51,7 @@ hotkeys:
|
||||
- 'Ctrl-Alt-Up'
|
||||
pane-nav-left:
|
||||
- 'Ctrl-Alt-Left'
|
||||
pane-maximize:
|
||||
- 'Ctrl-Alt-Enter'
|
||||
close-pane: []
|
||||
pluginBlacklist: []
|
||||
|
@@ -8,7 +8,7 @@ appearance:
|
||||
frame: thin
|
||||
css: '/* * { color: blue !important; } */'
|
||||
opacity: 1.0
|
||||
vibrancy: false
|
||||
vibrancy: true
|
||||
vibrancyType: 'blur'
|
||||
enableAnalytics: true
|
||||
enableWelcomeTab: true
|
||||
|
14
terminus-core/src/directives/fastHtmlBind.directive.ts
Normal file
14
terminus-core/src/directives/fastHtmlBind.directive.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Directive, Input, ElementRef, OnChanges } from '@angular/core'
|
||||
|
||||
/** @hidden */
|
||||
@Directive({
|
||||
selector: '[fastHtmlBind]',
|
||||
})
|
||||
export class FastHtmlBindDirective implements OnChanges {
|
||||
@Input() fastHtmlBind: string
|
||||
constructor (private el: ElementRef) { }
|
||||
|
||||
ngOnChanges () {
|
||||
this.el.nativeElement.innerHTML = this.fastHtmlBind || ''
|
||||
}
|
||||
}
|
@@ -93,6 +93,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
id: 'split-top',
|
||||
name: 'Split to the top',
|
||||
},
|
||||
{
|
||||
id: 'pane-maximize',
|
||||
name: 'Maximize the active pane',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-up',
|
||||
name: 'Focus the pane above',
|
||||
|
@@ -21,6 +21,7 @@ import { SplitTabSpannerComponent } from './components/splitTabSpanner.component
|
||||
import { WelcomeTabComponent } from './components/welcomeTab.component'
|
||||
|
||||
import { AutofocusDirective } from './directives/autofocus.directive'
|
||||
import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
||||
|
||||
import { HotkeyProvider } from './api/hotkeyProvider'
|
||||
import { ConfigProvider } from './api/configProvider'
|
||||
@@ -80,6 +81,7 @@ const PROVIDERS = [
|
||||
RenameTabModalComponent,
|
||||
SafeModeModalComponent,
|
||||
AutofocusDirective,
|
||||
FastHtmlBindDirective,
|
||||
SplitTabComponent,
|
||||
SplitTabSpannerComponent,
|
||||
WelcomeTabComponent,
|
||||
|
@@ -83,6 +83,10 @@ export class AppService {
|
||||
this.startTabStorage()
|
||||
}
|
||||
}
|
||||
|
||||
hostApp.windowFocused$.subscribe(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
})
|
||||
}
|
||||
|
||||
startTabStorage () {
|
||||
@@ -94,8 +98,13 @@ export class AppService {
|
||||
}, 30000)
|
||||
}
|
||||
|
||||
addTabRaw (tab: BaseTabComponent) {
|
||||
this.tabs.push(tab)
|
||||
addTabRaw (tab: BaseTabComponent, index: number|null = null) {
|
||||
if (index !== null) {
|
||||
this.tabs.splice(index, 0, tab)
|
||||
} else {
|
||||
this.tabs.push(tab)
|
||||
}
|
||||
|
||||
this.selectTab(tab)
|
||||
this.tabsChanged.next()
|
||||
this.tabOpened.next(tab)
|
||||
@@ -121,6 +130,11 @@ export class AppService {
|
||||
this.tabsChanged.next()
|
||||
this.tabClosed.next(tab)
|
||||
})
|
||||
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
tab.tabAdded$.subscribe(() => this.emitTabsChanged())
|
||||
tab.tabRemoved$.subscribe(() => this.emitTabsChanged())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,6 +183,17 @@ export class AppService {
|
||||
}
|
||||
}
|
||||
|
||||
getParentTab (tab: BaseTabComponent): SplitTabComponent|null {
|
||||
for (const topLevelTab of this.tabs) {
|
||||
if (topLevelTab instanceof SplitTabComponent) {
|
||||
if (topLevelTab.getAllTabs().includes(tab)) {
|
||||
return topLevelTab
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** Switches between the current tab and the previously active one */
|
||||
toggleLastTab () {
|
||||
if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
|
||||
@@ -217,7 +242,7 @@ export class AppService {
|
||||
async duplicateTab (tab: BaseTabComponent) {
|
||||
const dup = await this.tabsService.duplicate(tab)
|
||||
if (dup) {
|
||||
this.addTabRaw(dup)
|
||||
this.addTabRaw(dup, this.tabs.indexOf(tab) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -125,7 +125,22 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
getDefaults () {
|
||||
return this.defaults
|
||||
const cleanup = o => {
|
||||
if (o instanceof Array) {
|
||||
return o.map(cleanup)
|
||||
} else if (o instanceof Object) {
|
||||
const r = {}
|
||||
for (const k of Object.keys(o)) {
|
||||
if (k !== '__nonStructural') {
|
||||
r[k] = cleanup(o[k])
|
||||
}
|
||||
}
|
||||
return r
|
||||
} else {
|
||||
return o
|
||||
}
|
||||
}
|
||||
return cleanup(this.defaults)
|
||||
}
|
||||
|
||||
load (): void {
|
||||
|
@@ -30,9 +30,14 @@ export class HomeBaseService {
|
||||
let body = `Version: ${this.appVersion}\n`
|
||||
body += `Platform: ${os.platform()} ${os.release()}\n`
|
||||
const label = {
|
||||
aix: 'OS: IBM AIX',
|
||||
android: 'OS: Android',
|
||||
darwin: 'OS: macOS',
|
||||
windows: 'OS: Windows',
|
||||
freebsd: 'OS: FreeBSD',
|
||||
linux: 'OS: Linux',
|
||||
openbsd: 'OS: OpenBSD',
|
||||
sunos: 'OS: Solaris',
|
||||
win32: 'OS: Windows',
|
||||
}[os.platform()]
|
||||
const plugins = (window as any).installedPlugins.filter(x => !x.isBuiltin).map(x => x.name)
|
||||
body += `Plugins: ${plugins.join(', ') || 'none'}\n\n`
|
||||
|
@@ -39,6 +39,7 @@ export class HostAppService {
|
||||
private configChangeBroadcast = new Subject<void>()
|
||||
private windowCloseRequest = new Subject<void>()
|
||||
private windowMoved = new Subject<void>()
|
||||
private windowFocused = new Subject<void>()
|
||||
private displayMetricsChanged = new Subject<void>()
|
||||
private logger: Logger
|
||||
private windowId: number
|
||||
@@ -85,6 +86,8 @@ export class HostAppService {
|
||||
|
||||
get windowMoved$ (): Observable<void> { return this.windowMoved }
|
||||
|
||||
get windowFocused$ (): Observable<void> { return this.windowFocused }
|
||||
|
||||
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
|
||||
|
||||
private constructor (
|
||||
@@ -128,6 +131,10 @@ export class HostAppService {
|
||||
this.zone.run(() => this.windowMoved.next())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:window-focused', () => {
|
||||
this.zone.run(() => this.windowFocused.next())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:display-metrics-changed', () => {
|
||||
this.zone.run(() => this.displayMetricsChanged.next())
|
||||
})
|
||||
|
@@ -18,11 +18,18 @@ export class ShellIntegrationService {
|
||||
private automatorWorkflowsDestination: string
|
||||
private registryKeys = [
|
||||
{
|
||||
path: 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here',
|
||||
path: 'Software\\Classes\\Directory\\Background\\shell\\Terminus',
|
||||
value: 'Open Terminus here',
|
||||
command: 'open "%V"',
|
||||
},
|
||||
{
|
||||
path: 'Software\\Classes\\*\\shell\\Paste path into Terminus',
|
||||
path: 'SOFTWARE\\Classes\\Directory\\shell\\Terminus',
|
||||
value: 'Open Terminus here',
|
||||
command: 'open "%V"',
|
||||
},
|
||||
{
|
||||
path: 'Software\\Classes\\*\\shell\\Terminus',
|
||||
value: 'Paste path into Terminus',
|
||||
command: 'paste "%V"',
|
||||
},
|
||||
]
|
||||
@@ -61,9 +68,17 @@ export class ShellIntegrationService {
|
||||
for (const registryKey of this.registryKeys) {
|
||||
wnr.createRegistryKey(wnr.HK.CU, registryKey.path)
|
||||
wnr.createRegistryKey(wnr.HK.CU, registryKey.path + '\\command')
|
||||
wnr.setRegistryValue(wnr.HK.CU, registryKey.path, '', wnr.REG.SZ, registryKey.value)
|
||||
wnr.setRegistryValue(wnr.HK.CU, registryKey.path, 'Icon', wnr.REG.SZ, exe)
|
||||
wnr.setRegistryValue(wnr.HK.CU, registryKey.path + '\\command', '', wnr.REG.SZ, exe + ' ' + registryKey.command)
|
||||
}
|
||||
|
||||
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
|
||||
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')
|
||||
}
|
||||
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
|
||||
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -27,12 +27,18 @@ export class UpdaterService {
|
||||
) {
|
||||
this.logger = log.create('updater')
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
this.electronUpdaterAvailable = false
|
||||
return
|
||||
}
|
||||
|
||||
this.autoUpdater = electron.remote.require('electron-updater').autoUpdater
|
||||
|
||||
this.autoUpdater.autoInstallOnAppQuit = !!config.store.enableAutomaticUpdates
|
||||
|
||||
this.autoUpdater.on('update-available', () => {
|
||||
this.logger.info('Update available')
|
||||
this.autoUpdater.downloadUpdate()
|
||||
})
|
||||
this.autoUpdater.once('update-not-available', () => {
|
||||
this.logger.info('No updates')
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { AppService } from './services/app.service'
|
||||
import { BaseTabComponent } from './components/baseTab.component'
|
||||
import { TabHeaderComponent } from './components/tabHeader.component'
|
||||
@@ -16,39 +17,49 @@ export class CloseContextMenu extends TabContextMenuItemProvider {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
return [
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
let items = [
|
||||
{
|
||||
label: 'Close',
|
||||
click: () => this.zone.run(() => {
|
||||
this.app.closeTab(tab, true)
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Close other tabs',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Close tabs to the right',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Close tabs to the left',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
if (this.app.tabs.includes(tab)) {
|
||||
this.app.closeTab(tab, true)
|
||||
} else {
|
||||
tab.destroy()
|
||||
}
|
||||
}),
|
||||
},
|
||||
]
|
||||
if (tabHeader) {
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: 'Close other tabs',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Close tabs to the right',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Close tabs to the left',
|
||||
click: () => this.zone.run(() => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,28 +86,31 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
return [
|
||||
{
|
||||
label: 'Rename',
|
||||
click: () => this.zone.run(() => tabHeader && tabHeader.showRenameTabModal()),
|
||||
},
|
||||
{
|
||||
label: 'Duplicate',
|
||||
click: () => this.zone.run(() => this.app.duplicateTab(tab)),
|
||||
},
|
||||
{
|
||||
label: 'Color',
|
||||
sublabel: COLORS.find(x => x.value === tab.color)!.name,
|
||||
submenu: COLORS.map(color => ({
|
||||
label: color.name,
|
||||
type: 'radio',
|
||||
checked: tab.color === color.value,
|
||||
click: () => this.zone.run(() => {
|
||||
tab.color = color.value
|
||||
}),
|
||||
})) as Electron.MenuItemConstructorOptions[],
|
||||
},
|
||||
]
|
||||
if (tabHeader) {
|
||||
return [
|
||||
{
|
||||
label: 'Rename',
|
||||
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
|
||||
},
|
||||
{
|
||||
label: 'Duplicate',
|
||||
click: () => this.zone.run(() => this.app.duplicateTab(tab)),
|
||||
},
|
||||
{
|
||||
label: 'Color',
|
||||
sublabel: COLORS.find(x => x.value === tab.color)!.name,
|
||||
submenu: COLORS.map(color => ({
|
||||
label: color.name,
|
||||
type: 'radio',
|
||||
checked: tab.color === color.value,
|
||||
click: () => this.zone.run(() => {
|
||||
tab.color = color.value
|
||||
}),
|
||||
})) as Electron.MenuItemConstructorOptions[],
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,36 +126,61 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
const process = await tab.getCurrentProcess()
|
||||
if (process) {
|
||||
return [
|
||||
{
|
||||
id: 'process-name',
|
||||
enabled: false,
|
||||
label: 'Current process: ' + process.name,
|
||||
},
|
||||
{
|
||||
label: 'Notify when done',
|
||||
type: 'checkbox',
|
||||
checked: (tab as any).__completionNotificationEnabled,
|
||||
click: () => this.zone.run(() => {
|
||||
(tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
|
||||
let items: Electron.MenuItemConstructorOptions[] = []
|
||||
|
||||
if ((tab as any).__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||
new Notification('Process completed', {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
;(tab as any).__completionNotificationEnabled = false
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
|
||||
|
||||
if (process) {
|
||||
items.push({
|
||||
id: 'process-name',
|
||||
enabled: false,
|
||||
label: 'Current process: ' + process.name,
|
||||
})
|
||||
items.push({
|
||||
label: 'Notify when done',
|
||||
type: 'checkbox',
|
||||
checked: extTab.__completionNotificationEnabled,
|
||||
click: () => this.zone.run(() => {
|
||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||
|
||||
if (extTab.__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||
new Notification('Process completed', {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(tab)
|
||||
}
|
||||
}),
|
||||
},
|
||||
]
|
||||
extTab.__completionNotificationEnabled = false
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(tab)
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
return []
|
||||
items.push({
|
||||
label: 'Notify on activity',
|
||||
type: 'checkbox',
|
||||
checked: !!extTab.__outputNotificationSubscription,
|
||||
click: () => this.zone.run(() => {
|
||||
if (extTab.__outputNotificationSubscription) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
} else {
|
||||
extTab.__outputNotificationSubscription = tab.activity$.subscribe(active => {
|
||||
if (extTab.__outputNotificationSubscription && active) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
new Notification('Tab activity', {
|
||||
body: tab.title,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}),
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
@@ -16,4 +16,8 @@ app-root {
|
||||
terminaltab .content {
|
||||
margin: 5px !important;
|
||||
}
|
||||
|
||||
ssh-tab .content {
|
||||
margin: 5px !important;
|
||||
}
|
||||
}
|
||||
|
@@ -1,103 +1,11 @@
|
||||
$tab-border-radius: 5px;
|
||||
@import "./theme.vars";
|
||||
|
||||
// ---------
|
||||
|
||||
|
||||
$button-hover-bg: rgba(0, 0, 0, .25);
|
||||
$button-active-bg: rgba(0, 0, 0, .5);
|
||||
|
||||
|
||||
$white: #fff !default;
|
||||
$black: #000 !default;
|
||||
$red: #d9534f !default;
|
||||
$orange: #f0ad4e !default;
|
||||
$yellow: #ffd500 !default;
|
||||
$green: #5cb85c !default;
|
||||
$blue: #0275d8 !default;
|
||||
$teal: #5bc0de !default;
|
||||
$pink: #ff5b77 !default;
|
||||
$purple: #613d7c !default;
|
||||
|
||||
$theme-colors: (
|
||||
"primary": $blue,
|
||||
"secondary": #394b5d
|
||||
);
|
||||
|
||||
$content-bg: rgba(39, 49, 60, 0.65); //#1D272D;
|
||||
$content-bg-solid: #1D272D;
|
||||
$body-bg: #131d27;
|
||||
$body-bg2: #20333e;
|
||||
|
||||
$body-color: #ccc;
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$font-family-monospace: "Source Code Pro";
|
||||
$font-size-base: 14rem / 16;
|
||||
|
||||
$btn-border-radius: 0;
|
||||
$btn-secondary-color: #ccc;
|
||||
$btn-secondary-bg: #222;
|
||||
$btn-secondary-border: #444;
|
||||
|
||||
//$btn-warning-bg: rgba($orange, .5);
|
||||
|
||||
|
||||
$nav-tabs-border-width: 0;
|
||||
$nav-tabs-border-radius: 0;
|
||||
$nav-tabs-link-hover-border-color: $body-bg;
|
||||
$nav-tabs-active-link-hover-color: $white;
|
||||
$nav-tabs-active-link-hover-bg: $blue;
|
||||
$nav-tabs-active-link-hover-border-color: darken($blue, 30%);
|
||||
$nav-pills-border-radius: 0;
|
||||
|
||||
$input-bg: #111;
|
||||
$input-disabled-bg: #333;
|
||||
|
||||
$input-color: $body-color;
|
||||
$input-color-placeholder: #333;
|
||||
$input-border-color: #344;
|
||||
$input-border-width: 1px;
|
||||
//$input-box-shadow: inset 0 1px 1px rgba($black,.075);
|
||||
$input-border-radius: 0;
|
||||
$custom-select-border-radius: 0;
|
||||
$input-bg-focus: $input-bg;
|
||||
$input-border-focus: lighten($blue, 25%);
|
||||
$input-focus-box-shadow: none;
|
||||
$input-color-focus: $input-color;
|
||||
$input-group-addon-bg: $body-bg;
|
||||
$input-group-addon-border-color: $input-border-color;
|
||||
|
||||
$modal-content-bg: $content-bg-solid;
|
||||
$modal-content-border-color: $body-bg;
|
||||
$modal-header-border-color: transparent;
|
||||
$modal-footer-border-color: transparent;
|
||||
|
||||
$popover-bg: $body-bg;
|
||||
|
||||
$dropdown-bg: $body-bg;
|
||||
$dropdown-link-color: $body-color;
|
||||
$dropdown-link-hover-color: white;
|
||||
$dropdown-link-hover-bg: $body-bg2;
|
||||
//$dropdown-link-active-color: $component-active-color;
|
||||
//$dropdown-link-active-bg: $component-active-bg;
|
||||
$dropdown-link-disabled-color: #333;
|
||||
$dropdown-header-color: #333;
|
||||
|
||||
$list-group-color: $body-color;
|
||||
$list-group-bg: rgba(255,255,255,.05);
|
||||
$list-group-border-color: rgba(255,255,255,.1);
|
||||
$list-group-hover-bg: rgba(255,255,255,.1);
|
||||
$list-group-link-active-bg: rgba(255,255,255,.2);
|
||||
|
||||
$list-group-action-color: $body-color;
|
||||
$list-group-action-bg: rgba(255,255,255,.05);
|
||||
$list-group-action-active-bg: $list-group-link-active-bg;
|
||||
|
||||
$pre-bg: $dropdown-bg;
|
||||
$pre-color: $dropdown-link-color;
|
||||
|
||||
$alert-danger-bg: $body-bg;
|
||||
$alert-danger-text: $red;
|
||||
$alert-danger-border: $red;
|
||||
|
||||
$headings-font-weight: lighter;
|
||||
$headings-color: #eee;
|
||||
|
||||
@import '~bootstrap/scss/bootstrap.scss';
|
||||
|
||||
window-controls {
|
||||
@@ -236,13 +144,14 @@ settings-tab > ngb-tabset {
|
||||
border: none;
|
||||
padding: 10px 50px 10px 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 0;
|
||||
|
||||
&:not(.active) {
|
||||
color: $body-color;
|
||||
color: $body-color;
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,14 +219,6 @@ hotkey-input-modal {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
background: $btn-secondary-bg;
|
||||
.nav-link {
|
||||
transition: 0.25s all;
|
||||
border-bottom-color: $nav-tabs-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
ngb-tabset .tab-content {
|
||||
padding-top: 20px;
|
||||
}
|
||||
@@ -361,22 +262,10 @@ ngb-tabset .tab-content {
|
||||
}
|
||||
}
|
||||
|
||||
select.form-control {
|
||||
-webkit-appearance: none;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='#444' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
|
||||
background-position: 100% 50%;
|
||||
background-repeat: no-repeat;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
checkbox i.on {
|
||||
color: $blue;
|
||||
}
|
||||
|
||||
toggle.active .body .toggle {
|
||||
background: $blue;
|
||||
}
|
||||
|
||||
.modal .modal-footer {
|
||||
background: rgba(0, 0, 0, .25);
|
||||
|
||||
@@ -405,3 +294,101 @@ toggle.active .body .toggle {
|
||||
*::-webkit-resizer {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
search-panel {
|
||||
background: rgba(39, 49, 60, 0.65) !important;
|
||||
}
|
||||
|
||||
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.btn.btn-outline-secondary {
|
||||
@include button-outline-variant(#9badb9, #fff);
|
||||
&:hover:not([disabled]), &:active:not([disabled]), &.active:not([disabled]) {
|
||||
background-color: #3f484e;
|
||||
border-color: darken(#9badb9, 25%);
|
||||
}
|
||||
|
||||
border-color: darken(#9badb9, 25%);
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: #9badb9;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-warning:not(:disabled):not(.disabled) {
|
||||
&.active, &:active {
|
||||
color: $gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-secondary:not(:disabled):not(.disabled) {
|
||||
&.active, &:active {
|
||||
background: #191e23;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
&:hover, &[aria-expanded=true], &:active, &.active {
|
||||
color: $link-hover-color;
|
||||
border-radius: $btn-border-radius;
|
||||
}
|
||||
|
||||
&[aria-expanded=true], &:active, &.active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group .btn.active {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
margin-bottom: 10px;
|
||||
|
||||
&.nav-justified .nav-link {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
border: none;
|
||||
border-bottom: $nav-tabs-border-width solid transparent;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
padding: 5px 0;
|
||||
margin-right: 20px;
|
||||
|
||||
uib-tab-heading > i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
@include hover-focus {
|
||||
color: $nav-tabs-link-active-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $nav-link-disabled-color;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item:last-child .nav-link {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-item.show .nav-link {
|
||||
color: $nav-tabs-link-active-color;
|
||||
border-color: $nav-tabs-link-active-border-color;
|
||||
}
|
||||
}
|
||||
|
187
terminus-core/src/theme.vars.scss
Normal file
187
terminus-core/src/theme.vars.scss
Normal file
@@ -0,0 +1,187 @@
|
||||
$white: #fff;
|
||||
$gray-100: #f8f9fa;
|
||||
$gray-200: #e9ecef;
|
||||
$gray-300: #dee2e6;
|
||||
$gray-400: #ced4da;
|
||||
$gray-500: #adb5bd;
|
||||
$gray-600: #6c757d;
|
||||
$gray-700: #495057;
|
||||
$gray-800: #343a40;
|
||||
$gray-900: #212529;
|
||||
$black: #000;
|
||||
|
||||
|
||||
$red: #d9534f !default;
|
||||
$orange: #f0ad4e !default;
|
||||
$yellow: #ffd500 !default;
|
||||
$green: #5cb85c !default;
|
||||
$blue: #0275d8 !default;
|
||||
$teal: #5bc0de !default;
|
||||
$pink: #ff5b77 !default;
|
||||
$purple: #613d7c !default;
|
||||
|
||||
|
||||
@import "~bootstrap/scss/functions";
|
||||
|
||||
$content-bg: rgba(39, 49, 60, 0.65); //#1D272D;
|
||||
$content-bg-solid: #1D272D;
|
||||
|
||||
$table-bg: rgba(255,255,255,.05);
|
||||
$table-bg-hover: rgba(255,255,255,.1);
|
||||
$table-border-color: rgba(255,255,255,.1);
|
||||
|
||||
$theme-colors: (
|
||||
primary: $blue,
|
||||
secondary: #38434e,
|
||||
success: $green,
|
||||
info: $blue,
|
||||
warning: $orange,
|
||||
danger: $red,
|
||||
light: $gray-300,
|
||||
dark: $gray-800,
|
||||
rare: $purple
|
||||
);
|
||||
|
||||
$body-color: #ccc;
|
||||
$body-bg: #131d27;
|
||||
$body-bg2: #20333e;
|
||||
|
||||
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$font-family-monospace: "Source Code Pro";
|
||||
$font-size-base: 14rem / 16;
|
||||
$font-size-lg: 1.28rem;
|
||||
$font-size-sm: .85rem;
|
||||
|
||||
$line-height-base: 1.6;
|
||||
|
||||
$headings-color: #ced9e2;
|
||||
$headings-font-weight: lighter;
|
||||
|
||||
$input-btn-padding-y: .3rem;
|
||||
$input-btn-padding-x: .9rem;
|
||||
$input-btn-line-height: 1.6;
|
||||
$input-btn-line-height-sm: 1.8;
|
||||
$input-btn-line-height-lg: 1.8;
|
||||
|
||||
$btn-link-disabled-color: $gray-600;
|
||||
$btn-focus-box-shadow: none;
|
||||
|
||||
$h4-font-size: 18px;
|
||||
|
||||
$link-color: $gray-400;
|
||||
$link-hover-color: $white;
|
||||
$link-hover-decoration: none;
|
||||
|
||||
$component-active-color: $white;
|
||||
$component-active-bg: #2f3a42;
|
||||
|
||||
$list-group-bg: $table-bg;
|
||||
$list-group-border-color: $table-border-color;
|
||||
|
||||
$list-group-item-padding-y: 0.8rem;
|
||||
$list-group-item-padding-x: 1rem;
|
||||
|
||||
$list-group-hover-bg: $table-bg-hover;
|
||||
$list-group-active-bg: rgba(255,255,255,.2);
|
||||
$list-group-active-color: $component-active-color;
|
||||
$list-group-active-border-color: translate;
|
||||
|
||||
$list-group-action-color: $body-color;
|
||||
$list-group-action-hover-color: white;
|
||||
|
||||
$list-group-action-active-color: $component-active-color;
|
||||
$list-group-action-active-bg: $list-group-active-bg;
|
||||
|
||||
$alert-padding-y: 0.9rem;
|
||||
$alert-padding-x: 1.25rem;
|
||||
|
||||
$input-box-shadow: none;
|
||||
|
||||
$transition-base: all .15s ease-in-out;
|
||||
$transition-fade: opacity .1s linear;
|
||||
$transition-collapse: height .35s ease;
|
||||
$btn-transition: all .15s ease-in-out;
|
||||
|
||||
$popover-bg: $body-bg;
|
||||
$popover-body-color: $body-color;
|
||||
$popover-header-bg: $table-bg-hover;
|
||||
$popover-header-color: $headings-color;
|
||||
$popover-arrow-color: $popover-bg;
|
||||
$popover-max-width: 360px;
|
||||
|
||||
$btn-border-width: 2px;
|
||||
|
||||
$input-bg: #181e23;
|
||||
$input-disabled-bg: #2e3235;
|
||||
|
||||
$input-color: #ddd;
|
||||
$input-border-color: $input-bg;
|
||||
$input-border-width: 2px;
|
||||
|
||||
$input-focus-bg: $input-bg;
|
||||
$input-focus-border-color: rgba(171, 171, 171, 0.61);
|
||||
$input-focus-color: $input-color;
|
||||
|
||||
$input-btn-focus-color: var(--focus-color);
|
||||
$input-btn-focus-box-shadow: 0 0 0 2px $input-btn-focus-color;
|
||||
|
||||
$input-group-addon-color: $input-color;
|
||||
$input-group-addon-bg: $input-bg;
|
||||
$input-group-addon-border-color: transparent;
|
||||
$input-group-btn-border-color: $input-bg;
|
||||
|
||||
$nav-tabs-border-radius: 0;
|
||||
$nav-tabs-border-color: transparent;
|
||||
$nav-tabs-border-width: 2px;
|
||||
$nav-tabs-link-hover-border-color: transparent;
|
||||
$nav-tabs-link-active-color: #eee;
|
||||
$nav-tabs-link-active-bg: transparent;
|
||||
$nav-tabs-link-active-border-color: #eee;
|
||||
|
||||
$navbar-padding-y: 0;
|
||||
$navbar-padding-x: 0;
|
||||
|
||||
$dropdown-bg: $content-bg-solid;
|
||||
$dropdown-color: $body-color;
|
||||
$dropdown-border-width: 1px;
|
||||
$dropdown-box-shadow: 0 .5rem 1rem rgba($black,.175);
|
||||
$dropdown-header-color: $gray-500;
|
||||
|
||||
$dropdown-link-color: $body-color;
|
||||
$dropdown-link-hover-color: #eee;
|
||||
$dropdown-link-hover-bg: rgba(255,255,255,.04);
|
||||
$dropdown-link-active-color: white;
|
||||
$dropdown-link-active-bg: rgba(0, 0, 0, .2);
|
||||
$dropdown-item-padding-y: 0.5rem;
|
||||
$dropdown-item-padding-x: 1.5rem;
|
||||
|
||||
|
||||
$code-color: $orange;
|
||||
$code-bg: rgba(0, 0, 0, .25);
|
||||
$code-padding-y: 3px;
|
||||
$code-padding-x: 5px;
|
||||
$pre-bg: $dropdown-bg;
|
||||
$pre-color: $dropdown-link-color;
|
||||
|
||||
$badge-font-size: 0.75rem;
|
||||
$badge-font-weight: bold;
|
||||
$badge-padding-y: 4px;
|
||||
$badge-padding-x: 6px;
|
||||
|
||||
|
||||
$custom-control-indicator-size: 1.2rem;
|
||||
$custom-control-indicator-bg: $body-bg;
|
||||
$custom-control-indicator-border-color: lighten($body-bg, 25%);
|
||||
$custom-control-indicator-checked-bg: theme-color("primary");
|
||||
$custom-control-indicator-checked-color: $body-bg;
|
||||
$custom-control-indicator-checked-border-color: transparent;
|
||||
$custom-control-indicator-active-bg: rgba(255, 255, 0, 0.5);
|
||||
|
||||
|
||||
$modal-content-bg: $content-bg-solid;
|
||||
$modal-content-border-color: $body-bg;
|
||||
$modal-header-border-width: 0;
|
||||
$modal-footer-border-color: #222;
|
||||
$modal-footer-border-width: 1px;
|
||||
$modal-content-border-width: 0;
|
@@ -46,17 +46,16 @@ async@^2.6.1:
|
||||
lodash "^4.17.11"
|
||||
|
||||
axios@^0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
|
||||
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.1.tgz#8a6a04eed23dfe72747e1dd43c604b8f1677b5aa"
|
||||
integrity sha512-Yl+7nfreYKaLRvAvjNPkvfjnQHJM1yLBY3zhqAwcJSwR/6ETkanUgylgtIvkvz0xJ+p/vZuNw8X7Hnb7Whsbpw==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
is-buffer "^2.0.2"
|
||||
|
||||
bootstrap@^4.1.3:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
|
||||
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
|
||||
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
|
||||
|
||||
builder-util-runtime@8.4.0:
|
||||
version "8.4.0"
|
||||
@@ -118,9 +117,9 @@ colorspace@1.1.x:
|
||||
text-hex "1.0.x"
|
||||
|
||||
core-js@^3.1.2:
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.4.2.tgz#ee2b1a60b50388d8ddcda8cdb44a92c7a9ea76df"
|
||||
integrity sha512-bUTfqFWtNKWp73oNIfRkqwYZJeNT3lstzZcAkhhiuvDraRSgOH1/+F9ZklbpR4zpdKuo4cpXN8tKP7s61yjX+g==
|
||||
version "3.6.4"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
|
||||
integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -254,11 +253,6 @@ is-arrayish@^0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-buffer@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
|
||||
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
@@ -466,9 +460,9 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
winston-transport@^4.3.0:
|
||||
version "4.3.0"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-plugin-manager",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "Terminus' plugin manager",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -20,7 +20,7 @@
|
||||
"@types/semver": "^6.0.0",
|
||||
"axios": "^0.19.0",
|
||||
"mz": "^2.6.0",
|
||||
"semver": "^6.1.0"
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7",
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
.d-flex
|
||||
h3.mb-1 Installed
|
||||
button.btn.btn-outline-info.btn-sm.ml-auto((click)='openPluginsFolder()')
|
||||
button.btn.btn-outline-secondary.btn-sm.ml-auto((click)='openPluginsFolder()')
|
||||
i.fas.fa-folder
|
||||
span Plugins folder
|
||||
|
||||
@@ -28,19 +28,19 @@
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
|
||||
span Upgrade ({{knownUpgrades[plugin.name].version}})
|
||||
|
||||
button.btn.btn-primary.ml-2(
|
||||
button.btn.btn-link.text-primary.ml-2(
|
||||
*ngIf='config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='enablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-play
|
||||
|
||||
button.btn.btn-secondary.ml-2(
|
||||
button.btn.btn-link.ml-2(
|
||||
*ngIf='!config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='disablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-pause
|
||||
|
||||
button.btn.btn-danger.ml-2(
|
||||
button.btn.btn-link.text-danger.ml-2(
|
||||
(click)='uninstallPlugin(plugin)',
|
||||
*ngIf='!plugin.isBuiltin',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
|
@@ -8,6 +8,10 @@ const NAME_PREFIX = 'terminus-'
|
||||
const KEYWORD = 'terminus-plugin'
|
||||
const OFFICIAL_NPM_ACCOUNT = 'eugenepankov'
|
||||
|
||||
const BLACKLIST = [
|
||||
'terminus-shell-selector', // superseded by profiles
|
||||
]
|
||||
|
||||
export interface PluginInfo {
|
||||
name: string
|
||||
description: string
|
||||
@@ -75,6 +79,7 @@ export class PluginManagerService {
|
||||
isOfficial: item.package.publisher.username === OFFICIAL_NPM_ACCOUNT,
|
||||
}))),
|
||||
map(plugins => plugins.filter(x => x.packageName.startsWith(NAME_PREFIX))),
|
||||
map(plugins => plugins.filter(x => !BLACKLIST.includes(x.packageName))),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -13,12 +13,11 @@ any-promise@^1.0.0:
|
||||
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||
|
||||
axios@^0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
|
||||
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.1.tgz#8a6a04eed23dfe72747e1dd43c604b8f1677b5aa"
|
||||
integrity sha512-Yl+7nfreYKaLRvAvjNPkvfjnQHJM1yLBY3zhqAwcJSwR/6ETkanUgylgtIvkvz0xJ+p/vZuNw8X7Hnb7Whsbpw==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
is-buffer "^2.0.2"
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
@@ -34,11 +33,6 @@ follow-redirects@1.5.10:
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
|
||||
is-buffer@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
|
||||
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -58,10 +52,10 @@ object-assign@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
semver@^6.1.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
semver@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667"
|
||||
integrity sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A==
|
||||
|
||||
thenify-all@^1.0.0:
|
||||
version "1.6.0"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-settings",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "Terminus terminal settings page",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-ssh",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "SSH connection manager for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -20,7 +20,9 @@
|
||||
"@types/node": "12.7.3",
|
||||
"@types/ssh2": "^0.5.35",
|
||||
"ssh2": "^0.8.2",
|
||||
"ssh2-streams": "^0.4.2"
|
||||
"ssh2-streams": "^0.4.2",
|
||||
"sshpk": "^1.16.1",
|
||||
"terminus-terminal": "^1.0.98-nightly.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7",
|
||||
|
@@ -1,4 +1,8 @@
|
||||
import { BaseSession } from 'terminus-terminal'
|
||||
import { Server, Socket, createServer, createConnection } from 'net'
|
||||
import { Client, ClientChannel } from 'ssh2'
|
||||
import { Logger } from 'terminus-core'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
|
||||
export interface LoginScript {
|
||||
expect: string
|
||||
@@ -26,25 +30,82 @@ export interface SSHConnection {
|
||||
keepaliveInterval?: number
|
||||
keepaliveCountMax?: number
|
||||
readyTimeout?: number
|
||||
color?: string
|
||||
x11?: boolean
|
||||
|
||||
algorithms?: {[t: string]: string[]}
|
||||
}
|
||||
|
||||
export enum PortForwardType {
|
||||
Local, Remote
|
||||
}
|
||||
|
||||
export class ForwardedPort {
|
||||
type: PortForwardType
|
||||
host = '127.0.0.1'
|
||||
port: number
|
||||
targetAddress: string
|
||||
targetPort: number
|
||||
|
||||
private listener: Server
|
||||
|
||||
async startLocalListener (callback: (Socket) => void): Promise<void> {
|
||||
this.listener = createServer(callback)
|
||||
return new Promise((resolve, reject) => {
|
||||
this.listener.listen(this.port, '127.0.0.1')
|
||||
this.listener.on('error', reject)
|
||||
this.listener.on('listening', resolve)
|
||||
})
|
||||
}
|
||||
|
||||
stopLocalListener () {
|
||||
this.listener.close()
|
||||
}
|
||||
|
||||
toString () {
|
||||
if (this.type === PortForwardType.Local) {
|
||||
return `(local) ${this.host}:${this.port} → (remote) ${this.targetAddress}:${this.targetPort}`
|
||||
} else {
|
||||
return `(remote) ${this.host}:${this.port} → (local) ${this.targetAddress}:${this.targetPort}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SSHSession extends BaseSession {
|
||||
scripts?: LoginScript[]
|
||||
shell: any
|
||||
shell: ClientChannel
|
||||
ssh: Client
|
||||
forwardedPorts: ForwardedPort[] = []
|
||||
logger: Logger
|
||||
|
||||
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||
private serviceMessage = new Subject<string>()
|
||||
|
||||
constructor (public connection: SSHConnection) {
|
||||
super()
|
||||
this.scripts = connection.scripts || []
|
||||
}
|
||||
|
||||
start () {
|
||||
async start () {
|
||||
this.open = true
|
||||
|
||||
try {
|
||||
this.shell = await this.openShellChannel({ x11: this.connection.x11 })
|
||||
} catch (err) {
|
||||
this.emitServiceMessage(`Remote rejected opening a shell channel: ${err}`)
|
||||
}
|
||||
|
||||
this.shell.on('greeting', greeting => {
|
||||
this.emitServiceMessage(`Shell greeting: ${greeting}`)
|
||||
})
|
||||
|
||||
this.shell.on('banner', banner => {
|
||||
this.emitServiceMessage(`Shell banner: ${banner}`)
|
||||
})
|
||||
|
||||
this.shell.on('data', data => {
|
||||
const dataString = data.toString()
|
||||
this.emitOutput(dataString)
|
||||
this.emitOutput(data)
|
||||
|
||||
if (this.scripts) {
|
||||
let found = false
|
||||
@@ -67,12 +128,12 @@ export class SSHSession extends BaseSession {
|
||||
}
|
||||
|
||||
if (match) {
|
||||
console.log('Executing script: "' + cmd + '"')
|
||||
this.logger.info('Executing script: "' + cmd + '"')
|
||||
this.shell.write(cmd + '\n')
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
if (script.optional) {
|
||||
console.log('Skip optional script: ' + script.expect)
|
||||
this.logger.debug('Skip optional script: ' + script.expect)
|
||||
found = true
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
@@ -88,17 +149,140 @@ export class SSHSession extends BaseSession {
|
||||
})
|
||||
|
||||
this.shell.on('end', () => {
|
||||
this.logger.info('Shell session ended')
|
||||
if (this.open) {
|
||||
this.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
this.ssh.on('tcp connection', (details, accept, reject) => {
|
||||
this.logger.info(`Incoming forwarded connection: (remote) ${details.srcIP}:${details.srcPort} -> (local) ${details.destIP}:${details.destPort}`)
|
||||
const forward = this.forwardedPorts.find(x => x.port === details.destPort)
|
||||
if (!forward) {
|
||||
this.emitServiceMessage(`Rejected incoming forwarded connection for unrecognized port ${details.destPort}`)
|
||||
return reject()
|
||||
}
|
||||
const socket = new Socket()
|
||||
socket.connect(forward.targetPort, forward.targetAddress)
|
||||
socket.on('error', e => {
|
||||
this.emitServiceMessage(`Could not forward the remote connection to ${forward.targetAddress}:${forward.targetPort}: ${e}`)
|
||||
reject()
|
||||
})
|
||||
socket.on('connect', () => {
|
||||
this.logger.info('Connection forwarded')
|
||||
const stream = accept()
|
||||
stream.pipe(socket)
|
||||
socket.pipe(stream)
|
||||
stream.on('close', () => {
|
||||
socket.destroy()
|
||||
})
|
||||
socket.on('close', () => {
|
||||
stream.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.ssh.on('x11', (details, accept, reject) => {
|
||||
this.logger.info(`Incoming X11 connection from ${details.srcIP}:${details.srcPort}`)
|
||||
let displaySpec = process.env.DISPLAY || ':0'
|
||||
this.logger.debug(`Trying display ${displaySpec}`)
|
||||
let xHost = displaySpec.split(':')[0]
|
||||
let xDisplay = parseInt(displaySpec.split(':')[1].split('.')[0] || '0')
|
||||
let xPort = xDisplay < 100 ? xDisplay + 6000 : xDisplay
|
||||
|
||||
const socket = displaySpec.startsWith('/') ? createConnection(displaySpec) : new Socket()
|
||||
if (!displaySpec.startsWith('/')) {
|
||||
socket.connect(xPort, xHost)
|
||||
}
|
||||
socket.on('error', e => {
|
||||
this.emitServiceMessage(`Could not connect to the X server ${xHost}:${xPort}: ${e}`)
|
||||
reject()
|
||||
})
|
||||
socket.on('connect', () => {
|
||||
this.logger.info('Connection forwarded')
|
||||
const stream = accept()
|
||||
stream.pipe(socket)
|
||||
socket.pipe(stream)
|
||||
stream.on('close', () => {
|
||||
socket.destroy()
|
||||
})
|
||||
socket.on('close', () => {
|
||||
stream.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.executeUnconditionalScripts()
|
||||
}
|
||||
|
||||
emitServiceMessage (msg: string) {
|
||||
this.serviceMessage.next(msg)
|
||||
this.logger.info(msg)
|
||||
}
|
||||
|
||||
async addPortForward (fw: ForwardedPort) {
|
||||
if (fw.type === PortForwardType.Local) {
|
||||
await fw.startLocalListener((socket: Socket) => {
|
||||
this.logger.info(`New connection on ${fw}`)
|
||||
this.ssh.forwardOut(
|
||||
socket.remoteAddress || '127.0.0.1',
|
||||
socket.remotePort || 0,
|
||||
fw.targetAddress,
|
||||
fw.targetPort,
|
||||
(err, stream) => {
|
||||
if (err) {
|
||||
this.emitServiceMessage(`Remote has rejected the forwaded connection via ${fw}: ${err}`)
|
||||
socket.destroy()
|
||||
return
|
||||
}
|
||||
stream.pipe(socket)
|
||||
socket.pipe(stream)
|
||||
stream.on('close', () => {
|
||||
socket.destroy()
|
||||
})
|
||||
socket.on('close', () => {
|
||||
stream.close()
|
||||
})
|
||||
}
|
||||
)
|
||||
}).then(() => {
|
||||
this.emitServiceMessage(`Forwaded ${fw}`)
|
||||
this.forwardedPorts.push(fw)
|
||||
}).catch(e => {
|
||||
this.emitServiceMessage(`Failed to forward port ${fw}: ${e}`)
|
||||
throw e
|
||||
})
|
||||
}
|
||||
if (fw.type === PortForwardType.Remote) {
|
||||
await new Promise((resolve, reject) => {
|
||||
this.ssh.forwardIn(fw.host, fw.port, err => {
|
||||
if (err) {
|
||||
this.emitServiceMessage(`Remote rejected port forwarding for ${fw}: ${err}`)
|
||||
return reject(err)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
this.emitServiceMessage(`Forwaded ${fw}`)
|
||||
this.forwardedPorts.push(fw)
|
||||
}
|
||||
}
|
||||
|
||||
async removePortForward (fw: ForwardedPort) {
|
||||
if (fw.type === PortForwardType.Local) {
|
||||
fw.stopLocalListener()
|
||||
this.forwardedPorts = this.forwardedPorts.filter(x => x !== fw)
|
||||
}
|
||||
if (fw.type === PortForwardType.Remote) {
|
||||
this.ssh.unforwardIn(fw.host, fw.port)
|
||||
this.forwardedPorts = this.forwardedPorts.filter(x => x !== fw)
|
||||
}
|
||||
this.emitServiceMessage(`Stopped forwarding ${fw}`)
|
||||
}
|
||||
|
||||
resize (columns, rows) {
|
||||
if (this.shell) {
|
||||
this.shell.setWindow(rows, columns)
|
||||
this.shell.setWindow(rows, columns, rows, columns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +298,11 @@ export class SSHSession extends BaseSession {
|
||||
}
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
this.serviceMessage.complete()
|
||||
await super.destroy()
|
||||
}
|
||||
|
||||
async getChildProcesses (): Promise<any[]> {
|
||||
return []
|
||||
}
|
||||
@@ -126,6 +315,18 @@ export class SSHSession extends BaseSession {
|
||||
return null
|
||||
}
|
||||
|
||||
private openShellChannel (options): Promise<ClientChannel> {
|
||||
return new Promise<ClientChannel>((resolve, reject) => {
|
||||
this.ssh.shell({ term: 'xterm-256color' }, options, (err, shell) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(shell)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private executeUnconditionalScripts () {
|
||||
if (this.scripts) {
|
||||
for (const script of this.scripts) {
|
||||
|
@@ -1,118 +1,147 @@
|
||||
.modal-body
|
||||
ngb-tabset(type='pills', [activeId]='basic')
|
||||
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',
|
||||
type='text',
|
||||
autofocus,
|
||||
[(ngModel)]='connection.name',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Group
|
||||
input.form-control(
|
||||
type='text',
|
||||
type='text',
|
||||
placeholder='Ungrouped',
|
||||
[(ngModel)]='connection.group',
|
||||
[(ngModel)]='connection.group',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Host
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.host',
|
||||
type='text',
|
||||
[(ngModel)]='connection.host',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Port
|
||||
input.form-control(
|
||||
type='number',
|
||||
placeholder='22',
|
||||
[(ngModel)]='connection.port',
|
||||
placeholder='22',
|
||||
[(ngModel)]='connection.port',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Username
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.user',
|
||||
type='text',
|
||||
[(ngModel)]='connection.user',
|
||||
)
|
||||
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Password
|
||||
.description(*ngIf='!hasSavedPassword') Save a password in the keychain
|
||||
.description(*ngIf='hasSavedPassword') There is a saved password for this connection
|
||||
button.btn.btn-outline-success.ml-4(*ngIf='!hasSavedPassword', (click)='setPassword()')
|
||||
i.fas.fa-key
|
||||
button.btn.btn-outline-success.ml-4(*ngIf='!hasSavedPassword', (click)='setPassword()')
|
||||
i.fas.fa-key
|
||||
span Set password
|
||||
button.btn.btn-danger.ml-4(*ngIf='hasSavedPassword', (click)='clearSavedPassword()')
|
||||
button.btn.btn-danger.ml-4(*ngIf='hasSavedPassword', (click)='clearSavedPassword()')
|
||||
i.fas.fa-trash-alt
|
||||
span Forget
|
||||
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Private key
|
||||
.title Private key
|
||||
.description Path to the private key file
|
||||
.input-group
|
||||
input.form-control(
|
||||
type='text',
|
||||
placeholder='Key file path',
|
||||
type='text',
|
||||
placeholder='Key file path',
|
||||
[(ngModel)]='connection.privateKey'
|
||||
)
|
||||
.input-group-btn
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='selectPrivateKey()')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
ngb-tab(id='advanced')
|
||||
ng-template(ngbTabTitle) Advanced
|
||||
ng-template(ngbTabContent)
|
||||
.form-group
|
||||
label Keep Alive Interval (Milliseconds)
|
||||
.form-line
|
||||
.header
|
||||
.title X11 forwarding
|
||||
toggle([(ngModel)]='connection.x11')
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Tab color
|
||||
input.form-control(
|
||||
type='number',
|
||||
placeholder='0',
|
||||
[(ngModel)]='connection.keepaliveInterval',
|
||||
type='text',
|
||||
autofocus,
|
||||
[(ngModel)]='connection.color',
|
||||
placeholder='#000000'
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Max Keep Alive Count
|
||||
.form-line
|
||||
.header
|
||||
.title Keep Alive Interval (Milliseconds)
|
||||
input.form-control(
|
||||
type='number',
|
||||
placeholder='3',
|
||||
[(ngModel)]='connection.keepaliveCountMax',
|
||||
type='number',
|
||||
placeholder='0',
|
||||
[(ngModel)]='connection.keepaliveInterval',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Ready Timeout (Milliseconds)
|
||||
.form-line
|
||||
.header
|
||||
.title Max Keep Alive Count
|
||||
input.form-control(
|
||||
type='number',
|
||||
placeholder='20000',
|
||||
[(ngModel)]='connection.readyTimeout',
|
||||
type='number',
|
||||
placeholder='3',
|
||||
[(ngModel)]='connection.keepaliveCountMax',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Ciphers
|
||||
div(*ngFor='let alg of supportedAlgorithms.cipher')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.cipher[alg]')
|
||||
|
||||
.form-group
|
||||
label Key exchange
|
||||
div(*ngFor='let alg of supportedAlgorithms.kex')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.kex[alg]')
|
||||
.form-line
|
||||
.header
|
||||
.title Ready Timeout (Milliseconds)
|
||||
input.form-control(
|
||||
type='number',
|
||||
placeholder='20000',
|
||||
[(ngModel)]='connection.readyTimeout',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label HMAC
|
||||
div(*ngFor='let alg of supportedAlgorithms.hmac')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.hmac[alg]')
|
||||
ngb-tab(id='ciphers')
|
||||
ng-template(ngbTabTitle) Ciphers
|
||||
ng-template(ngbTabContent)
|
||||
.form-line.align-items-start
|
||||
.header
|
||||
.title Ciphers
|
||||
.w-50
|
||||
div(*ngFor='let alg of supportedAlgorithms.cipher')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.cipher[alg]')
|
||||
|
||||
.form-group
|
||||
label Host key
|
||||
div(*ngFor='let alg of supportedAlgorithms.serverHostKey')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.serverHostKey[alg]')
|
||||
.form-line.align-items-start
|
||||
.header
|
||||
.title Key exchange
|
||||
.w-50
|
||||
div(*ngFor='let alg of supportedAlgorithms.kex')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.kex[alg]')
|
||||
|
||||
.form-line.align-items-start
|
||||
.header
|
||||
.title HMAC
|
||||
.w-50
|
||||
div(*ngFor='let alg of supportedAlgorithms.hmac')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.hmac[alg]')
|
||||
|
||||
.form-line.align-items-start
|
||||
.header
|
||||
.title Host key
|
||||
.w-50
|
||||
div(*ngFor='let alg of supportedAlgorithms.serverHostKey')
|
||||
checkbox([text]='alg', [(ngModel)]='algorithms.serverHostKey[alg]')
|
||||
|
||||
|
||||
ngb-tab(id='scripts')
|
||||
@@ -128,12 +157,12 @@
|
||||
tr(*ngFor='let script of connection.scripts')
|
||||
td.pr-2
|
||||
input.form-control(
|
||||
type='text',
|
||||
type='text',
|
||||
[(ngModel)]='script.expect'
|
||||
)
|
||||
td
|
||||
input.form-control(
|
||||
type='text',
|
||||
type='text',
|
||||
[(ngModel)]='script.send'
|
||||
)
|
||||
td.pl-2
|
||||
@@ -152,11 +181,11 @@
|
||||
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
|
||||
|
@@ -66,7 +66,7 @@ export class EditConnectionModalComponent {
|
||||
modal.componentInstance.password = true
|
||||
try {
|
||||
const result = await modal.result
|
||||
if (result && result.value) {
|
||||
if (result?.value) {
|
||||
this.passwordStorage.savePassword(this.connection, result.value)
|
||||
this.hasSavedPassword = true
|
||||
}
|
||||
|
@@ -0,0 +1,48 @@
|
||||
.modal-header
|
||||
h5.m-0 Port forwarding
|
||||
|
||||
.modal-body.pt-0
|
||||
.list-group-light.mb-3
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of session.forwardedPorts')
|
||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
||||
.ml-3 {{fw.host}}:{{fw.port}} → {{fw.targetAddress}}:{{fw.targetPort}}
|
||||
button.btn.btn-link.ml-auto((click)='remove(fw)')
|
||||
i.fas.fa-trash-alt.mr-2
|
||||
span Remove
|
||||
|
||||
.input-group.mb-2
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
.input-group-append
|
||||
.input-group-text →
|
||||
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
|
||||
|
||||
.d-flex
|
||||
.btn-group.mr-auto(
|
||||
[(ngModel)]='newForward.type',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Local'
|
||||
)
|
||||
| Local
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Remote'
|
||||
)
|
||||
| Remote
|
||||
|
||||
button.btn.btn-primary((click)='addForward()')
|
||||
i.fas.fa-check.mr-2
|
||||
span Forward port
|
@@ -0,0 +1,42 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ForwardedPort, PortForwardType, SSHSession } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./sshPortForwardingModal.component.pug'),
|
||||
// styles: [require('./sshPortForwardingModal.component.scss')],
|
||||
})
|
||||
export class SSHPortForwardingModalComponent {
|
||||
@Input() session: SSHSession
|
||||
newForward = new ForwardedPort()
|
||||
PortForwardType = PortForwardType
|
||||
|
||||
constructor (
|
||||
public modalInstance: NgbActiveModal,
|
||||
) {
|
||||
this.reset()
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.newForward = new ForwardedPort()
|
||||
this.newForward.type = PortForwardType.Local
|
||||
this.newForward.host = '127.0.0.1'
|
||||
this.newForward.port = 8000
|
||||
this.newForward.targetAddress = '127.0.0.1'
|
||||
this.newForward.targetPort = 80
|
||||
}
|
||||
|
||||
async addForward () {
|
||||
try {
|
||||
await this.session.addPortForward(this.newForward)
|
||||
this.reset()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
remove (fw: ForwardedPort) {
|
||||
this.session.removePortForward(fw)
|
||||
}
|
||||
}
|
15
terminus-ssh/src/components/sshTab.component.pug
Normal file
15
terminus-ssh/src/components/sshTab.component.pug
Normal file
@@ -0,0 +1,15 @@
|
||||
.ssh-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.mr-auto(*ngIf='session') {{session.connection.user}}@{{session.connection.host}}:{{session.connection.port}}
|
||||
|
||||
button.btn.btn-secondary((click)='showPortForwarding()', *ngIf='session.open')
|
||||
i.fas.fa-plug
|
||||
span Ports
|
||||
|
||||
button.btn.btn-info((click)='reconnect()', *ngIf='!session.open')
|
||||
i.fas.fa-reload
|
||||
span Reconnect
|
@@ -3,6 +3,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&> .content {
|
||||
flex: auto;
|
||||
@@ -11,4 +12,60 @@
|
||||
overflow: hidden;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.ssh-tab-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 4;
|
||||
pointer-events: none;
|
||||
|
||||
.reveal-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 30px;
|
||||
border-radius: 50%;
|
||||
width: 35px;
|
||||
padding: 0;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
transition: 0.125s opacity;
|
||||
opacity: .5;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&:hover .reveal-button {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover .toolbar {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
opacity: 0;
|
||||
background: rgba(0, 0, 0, .75);
|
||||
padding: 10px 20px;
|
||||
transition: 0.25s opacity;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
will-change: transform;
|
||||
|
||||
&>* {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
&.show {
|
||||
.reveal-button {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,15 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { first } from 'rxjs/operators'
|
||||
import { BaseTerminalTabComponent } from 'terminus-terminal'
|
||||
import { SSHService } from '../services/ssh.service'
|
||||
import { SSHConnection, SSHSession } from '../api'
|
||||
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: BaseTerminalTabComponent.template,
|
||||
selector: 'ssh-tab',
|
||||
template: BaseTerminalTabComponent.template + require<string>('./sshTab.component.pug'),
|
||||
styles: [require('./sshTab.component.scss'), ...BaseTerminalTabComponent.styles],
|
||||
animations: BaseTerminalTabComponent.animations,
|
||||
})
|
||||
@@ -14,8 +17,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
connection: SSHConnection
|
||||
ssh: SSHService
|
||||
session: SSHSession
|
||||
private ngbModal: NgbModal
|
||||
|
||||
ngOnInit () {
|
||||
this.ngbModal = this.injector.get<NgbModal>(NgbModal)
|
||||
|
||||
this.logger = this.log.create('terminalTab')
|
||||
this.ssh = this.injector.get(SSHService)
|
||||
this.frontendReady$.pipe(first()).subscribe(() => {
|
||||
@@ -35,7 +41,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this.session = new SSHSession(this.connection)
|
||||
this.session = this.ssh.createSession(this.connection)
|
||||
this.session.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n[SSH] ${msg}\r\n`)
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
this.attachSessionHandlers()
|
||||
this.write(`Connecting to ${this.connection.host}`)
|
||||
const interval = setInterval(() => this.write('.'), 500)
|
||||
@@ -51,8 +61,8 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
clearInterval(interval)
|
||||
this.write('\r\n')
|
||||
}
|
||||
await this.session.start()
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
this.session.start()
|
||||
}
|
||||
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
@@ -61,4 +71,13 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
connection: this.connection,
|
||||
}
|
||||
}
|
||||
|
||||
showPortForwarding () {
|
||||
const modal = this.ngbModal.open(SSHPortForwardingModalComponent).componentInstance as SSHPortForwardingModalComponent
|
||||
modal.session = this.session
|
||||
}
|
||||
|
||||
reconnect () {
|
||||
this.initializeSession()
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import TerminusTerminalModule from 'terminus-terminal'
|
||||
|
||||
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
||||
import { SSHModalComponent } from './components/sshModal.component'
|
||||
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
@@ -40,6 +41,7 @@ import { SSHHotkeyProvider } from './hotkeys'
|
||||
EditConnectionModalComponent,
|
||||
PromptModalComponent,
|
||||
SSHModalComponent,
|
||||
SSHPortForwardingModalComponent,
|
||||
SSHSettingsTabComponent,
|
||||
SSHTabComponent,
|
||||
],
|
||||
@@ -47,6 +49,7 @@ import { SSHHotkeyProvider } from './hotkeys'
|
||||
EditConnectionModalComponent,
|
||||
PromptModalComponent,
|
||||
SSHModalComponent,
|
||||
SSHPortForwardingModalComponent,
|
||||
SSHSettingsTabComponent,
|
||||
SSHTabComponent,
|
||||
],
|
||||
|
@@ -3,6 +3,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Client } from 'ssh2'
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import * as sshpk from 'sshpk'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { AppService, HostAppService, Platform, Logger, LogService } from 'terminus-core'
|
||||
import { SSHConnection, SSHSession } from '../api'
|
||||
@@ -20,7 +21,7 @@ export class SSHService {
|
||||
private logger: Logger
|
||||
|
||||
private constructor (
|
||||
log: LogService,
|
||||
private log: LogService,
|
||||
private app: AppService,
|
||||
private zone: NgZone,
|
||||
private ngbModal: NgbModal,
|
||||
@@ -32,15 +33,24 @@ export class SSHService {
|
||||
}
|
||||
|
||||
async openTab (connection: SSHConnection): Promise<SSHTabComponent> {
|
||||
return this.zone.run(() => this.app.openNewTab(
|
||||
const tab = this.zone.run(() => this.app.openNewTab(
|
||||
SSHTabComponent,
|
||||
{ connection }
|
||||
) as SSHTabComponent)
|
||||
if (connection.color) {
|
||||
(this.app.getParentTab(tab) || tab).color = connection.color
|
||||
}
|
||||
return tab
|
||||
}
|
||||
|
||||
createSession (connection: SSHConnection): SSHSession {
|
||||
const session = new SSHSession(connection)
|
||||
session.logger = this.log.create(`ssh-${connection.host}-${connection.port}`)
|
||||
return session
|
||||
}
|
||||
|
||||
async connectSession (session: SSHSession, logCallback?: (s: any) => void): Promise<void> {
|
||||
let privateKey: string|null = null
|
||||
let privateKeyPassphrase: string|null = null
|
||||
let privateKeyPath = session.connection.privateKey
|
||||
|
||||
if (!logCallback) {
|
||||
@@ -61,6 +71,7 @@ export class SSHService {
|
||||
}
|
||||
|
||||
if (privateKeyPath) {
|
||||
log(`Loading private key from ${privateKeyPath}`)
|
||||
try {
|
||||
privateKey = (await fs.readFile(privateKeyPath)).toString()
|
||||
} catch (error) {
|
||||
@@ -69,28 +80,36 @@ export class SSHService {
|
||||
}
|
||||
|
||||
if (privateKey) {
|
||||
log(`Loading private key from ${privateKeyPath}`)
|
||||
let parsedKey: any = null
|
||||
try {
|
||||
parsedKey = sshpk.parsePrivateKey(privateKey, 'auto')
|
||||
} catch (e) {
|
||||
if (e instanceof sshpk.KeyEncryptedError) {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
log('Key requires passphrase')
|
||||
modal.componentInstance.prompt = 'Private key passphrase'
|
||||
modal.componentInstance.password = true
|
||||
let passphrase = ''
|
||||
try {
|
||||
const result = await modal.result
|
||||
passphrase = result?.value
|
||||
} catch (e) { }
|
||||
parsedKey = sshpk.parsePrivateKey(
|
||||
privateKey,
|
||||
'auto',
|
||||
{ passphrase: passphrase }
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
let encrypted = privateKey.includes('ENCRYPTED')
|
||||
if (privateKeyPath.toLowerCase().endsWith('.ppk')) {
|
||||
encrypted = encrypted || privateKey.includes('Encryption:') && !privateKey.includes('Encryption: none')
|
||||
}
|
||||
if (encrypted) {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
log('Key requires passphrase')
|
||||
modal.componentInstance.prompt = 'Private key passphrase'
|
||||
modal.componentInstance.password = true
|
||||
try {
|
||||
const result = await modal.result
|
||||
if (result) {
|
||||
privateKeyPassphrase = result.value
|
||||
}
|
||||
} catch (e) { }
|
||||
}
|
||||
privateKey = parsedKey!.toString('ssh')
|
||||
}
|
||||
}
|
||||
|
||||
const ssh = new Client()
|
||||
session.ssh = ssh
|
||||
let connected = false
|
||||
let savedPassword: string|null = null
|
||||
await new Promise(async (resolve, reject) => {
|
||||
@@ -156,7 +175,6 @@ export class SSHService {
|
||||
username: session.connection.user,
|
||||
password: session.connection.privateKey ? undefined : '',
|
||||
privateKey: privateKey || undefined,
|
||||
passphrase: privateKeyPassphrase || undefined,
|
||||
tryKeyboard: true,
|
||||
agent: agent || undefined,
|
||||
agentForward: !!agent,
|
||||
@@ -210,31 +228,6 @@ export class SSHService {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
try {
|
||||
const shell: any = await new Promise<any>((resolve, reject) => {
|
||||
ssh.shell({ term: 'xterm-256color' }, (err, shell) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(shell)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
session.shell = shell
|
||||
|
||||
shell.on('greeting', greeting => {
|
||||
log(`Shell Greeting: ${greeting}`)
|
||||
})
|
||||
|
||||
shell.on('banner', banner => {
|
||||
log(`Shell Banner: ${banner}`)
|
||||
})
|
||||
} catch (error) {
|
||||
this.toastr.error(error.message)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -27,47 +27,99 @@
|
||||
"@types/node" "*"
|
||||
"@types/ssh2-streams" "*"
|
||||
|
||||
asn1@~0.2.0:
|
||||
asn1@~0.2.0, asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
bcrypt-pbkdf@^1.0.2:
|
||||
assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
safer-buffer@~2.1.0:
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
ssh2-streams@^0.4.2, ssh2-streams@~0.4.7:
|
||||
version "0.4.7"
|
||||
resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.7.tgz#093b89069de9cf5f06feff0601a5301471b01611"
|
||||
integrity sha512-JhF8BNfeguOqVHOLhXjzLlRKlUP8roAEhiT/y+NcBQCqpRUupLNrRf2M+549OPNVGx21KgKktug4P3MY/IvTig==
|
||||
ssh2-streams@^0.4.2, ssh2-streams@~0.4.8:
|
||||
version "0.4.8"
|
||||
resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.8.tgz#2ff92df2e0063fef86cf934eaea197967deda715"
|
||||
integrity sha512-auxXfgYySz2vYw7TMU7PK7vFI7EPvhvTH8/tZPgGaWocK4p/vwCMiV3icz9AEkb0R40kOKZtFtqYIxDJyJiytw==
|
||||
dependencies:
|
||||
asn1 "~0.2.0"
|
||||
bcrypt-pbkdf "^1.0.2"
|
||||
streamsearch "~0.1.2"
|
||||
|
||||
ssh2@^0.8.2:
|
||||
version "0.8.6"
|
||||
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.6.tgz#dcc62e1d3b9e58a21f711f5186f043e4e792e6da"
|
||||
integrity sha512-T0cPmEtmtC8WxSupicFDjx3vVUdNXO8xu2a/D5bjt8ixOUCe387AgvxU3mJgEHpu7+Sq1ZYx4d3P2pl/yxMH+w==
|
||||
version "0.8.7"
|
||||
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.7.tgz#2dc15206f493010b98027201cf399b90bab79c89"
|
||||
integrity sha512-/u1BO12kb0lDVxJXejWB9pxyF3/ncgRqI9vPCZuPzo05pdNDzqUeQRavScwSPsfMGK+5H/VRqp1IierIx0Bcxw==
|
||||
dependencies:
|
||||
ssh2-streams "~0.4.7"
|
||||
ssh2-streams "~0.4.8"
|
||||
|
||||
sshpk@^1.16.1:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
getpass "^0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
streamsearch@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||
|
||||
tweetnacl@^0.14.3:
|
||||
terminus-terminal@^1.0.98-nightly.0:
|
||||
version "1.0.98-nightly.0"
|
||||
resolved "https://registry.yarnpkg.com/terminus-terminal/-/terminus-terminal-1.0.98-nightly.0.tgz#10df71b0a81adf76a076fb21a91c859dd2f8bef7"
|
||||
integrity sha512-JLxkeoQkORcfe6cRW6BJF5ZPSbvKA8IWUAb7fzBONVmNfRKj2Mq/uYPy76UXsdmb9F1n+rYIg+DShNp57asMKA==
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-terminal",
|
||||
"version": "1.0.93-nightly.0",
|
||||
"version": "1.0.99-nightly.0",
|
||||
"description": "Terminus' terminal emulation core",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -25,13 +25,14 @@
|
||||
"mz": "^2.6.0",
|
||||
"ps-node": "^0.1.6",
|
||||
"runes": "^0.4.2",
|
||||
"slug": "^1.1.0",
|
||||
"slug": "^2.0.0",
|
||||
"uuid": "^3.3.2",
|
||||
"xterm": "4.3.0-beta.30",
|
||||
"xterm": "^4.4.0-beta.15",
|
||||
"xterm-addon-fit": "^0.4.0-beta2",
|
||||
"xterm-addon-ligatures": "^0.2.1",
|
||||
"xterm-addon-search": "^0.4.0-beta5",
|
||||
"xterm-addon-webgl": "^0.4.0-beta.15"
|
||||
"xterm-addon-search": "^0.4.0",
|
||||
"xterm-addon-webgl": "^0.5.0-beta.7",
|
||||
"zmodem.js": "^0.1.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "^7",
|
||||
|
@@ -3,7 +3,7 @@ import { first } from 'rxjs/operators'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { NgZone, OnInit, OnDestroy, Inject, Injector, Optional, ViewChild, HostBinding, Input, ElementRef } from '@angular/core'
|
||||
import { trigger, transition, style, animate, AnimationTriggerMetadata } from '@angular/animations'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, Platform, LogService, Logger } from 'terminus-core'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, Platform, LogService, Logger, TabContextMenuItemProvider } from 'terminus-core'
|
||||
|
||||
import { BaseSession, SessionsService } from '../services/sessions.service'
|
||||
import { TerminalFrontendService } from '../services/terminalFrontend.service'
|
||||
@@ -11,7 +11,6 @@ import { TerminalFrontendService } from '../services/terminalFrontend.service'
|
||||
import { Frontend } from '../frontends/frontend'
|
||||
import { ResizeEvent } from './interfaces'
|
||||
import { TerminalDecorator } from './decorator'
|
||||
import { TerminalContextMenuItemProvider } from './contextMenuProvider'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@@ -22,8 +21,8 @@ export interface ToastrServiceProxy {
|
||||
* A class to base your custom terminal tabs on
|
||||
*/
|
||||
export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
|
||||
static template = require('../components/baseTerminalTab.component.pug')
|
||||
static styles = [require('../components/terminalTab.component.scss')]
|
||||
static template = require<string>('../components/baseTerminalTab.component.pug')
|
||||
static styles = [require<string>('../components/terminalTab.component.scss')]
|
||||
static animations: AnimationTriggerMetadata[] = [trigger('slideInOut', [
|
||||
transition(':enter', [
|
||||
style({ transform: 'translateY(-25%)' }),
|
||||
@@ -56,6 +55,11 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
frontendReady = new Subject<void>()
|
||||
size: ResizeEvent
|
||||
|
||||
/**
|
||||
* Enables normall passthrough from session output to terminal input
|
||||
*/
|
||||
enablePassthrough = true
|
||||
|
||||
protected logger: Logger
|
||||
protected output = new Subject<string>()
|
||||
private sessionCloseSubscription: Subscription
|
||||
@@ -63,7 +67,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
private bellPlayer: HTMLAudioElement
|
||||
private termContainerSubscriptions: Subscription[] = []
|
||||
|
||||
get input$ (): Observable<string> { return this.frontend.input$ }
|
||||
get input$ (): Observable<Buffer> { return this.frontend.input$ }
|
||||
get output$ (): Observable<string> { return this.output }
|
||||
get resize$ (): Observable<ResizeEvent> { return this.frontend.resize$ }
|
||||
get alternateScreenActive$ (): Observable<boolean> { return this.frontend.alternateScreenActive$ }
|
||||
@@ -83,7 +87,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
@Inject(ToastrService) protected toastr: ToastrServiceProxy,
|
||||
protected log: LogService,
|
||||
@Optional() @Inject(TerminalDecorator) protected decorators: TerminalDecorator[],
|
||||
@Optional() @Inject(TerminalContextMenuItemProvider) protected contextMenuProviders: TerminalContextMenuItemProvider[],
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
) {
|
||||
super()
|
||||
this.logger = log.create('baseTerminalTab')
|
||||
@@ -229,7 +233,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
/**
|
||||
* Feeds input into the active session
|
||||
*/
|
||||
sendInput (data: string) {
|
||||
sendInput (data: string|Buffer) {
|
||||
if (!(data instanceof Buffer)) {
|
||||
data = Buffer.from(data, 'utf-8')
|
||||
}
|
||||
this.session.write(data)
|
||||
if (this.config.store.terminal.scrollOnInput) {
|
||||
this.frontend.scrollToBottom()
|
||||
@@ -245,7 +252,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
const percentage = percentageMatch[3] ? parseFloat(percentageMatch[2]) : parseInt(percentageMatch[2])
|
||||
if (percentage > 0 && percentage <= 100) {
|
||||
this.setProgress(percentage)
|
||||
this.logger.debug('Detected progress:', percentage)
|
||||
// this.logger.debug('Detected progress:', percentage)
|
||||
}
|
||||
} else {
|
||||
this.setProgress(null)
|
||||
@@ -350,7 +357,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.frontend.mouseEvent$.subscribe(async event => {
|
||||
if (event.type === 'mousedown') {
|
||||
if (event.which === 2) {
|
||||
this.paste()
|
||||
if (this.config.store.terminal.pasteOnMiddleClick) {
|
||||
this.paste()
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
@@ -405,10 +414,12 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
protected attachSessionHandlers () {
|
||||
// this.session.output$.bufferTime(10).subscribe((datas) => {
|
||||
this.session.output$.subscribe(data => {
|
||||
this.zone.run(() => {
|
||||
this.output.next(data)
|
||||
this.write(data)
|
||||
})
|
||||
if (this.enablePassthrough) {
|
||||
this.zone.run(() => {
|
||||
this.output.next(data)
|
||||
this.write(data)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.sessionCloseSubscription = this.session.closed$.subscribe(() => {
|
||||
|
@@ -2,6 +2,7 @@ import { BaseTerminalTabComponent } from './baseTerminalTab.component'
|
||||
|
||||
/**
|
||||
* Extend to add more terminal context menu items
|
||||
* @deprecated
|
||||
*/
|
||||
export abstract class TerminalContextMenuItemProvider {
|
||||
weight: number
|
||||
|
@@ -16,8 +16,9 @@ export interface SessionOptions {
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
name: string,
|
||||
sessionOptions: SessionOptions,
|
||||
name: string
|
||||
color?: string
|
||||
sessionOptions: SessionOptions
|
||||
isBuiltin?: boolean
|
||||
icon?: string
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ module.exports = function patchPTYModule (mod) {
|
||||
mod.spawn = (file, args, opt) => {
|
||||
let terminal = oldSpawn(file, args, opt)
|
||||
let timeout = null
|
||||
let buffer = ''
|
||||
let buffer = Buffer.from('')
|
||||
let lastFlush = 0
|
||||
let nextTimeout = 0
|
||||
|
||||
@@ -19,11 +19,11 @@ module.exports = function patchPTYModule (mod) {
|
||||
const maxWindow = 100
|
||||
|
||||
function flush () {
|
||||
if (buffer) {
|
||||
if (buffer.length) {
|
||||
terminal.emit('data-buffered', buffer)
|
||||
}
|
||||
lastFlush = Date.now()
|
||||
buffer = ''
|
||||
buffer = Buffer.from('')
|
||||
}
|
||||
|
||||
function reschedule () {
|
||||
@@ -38,12 +38,15 @@ module.exports = function patchPTYModule (mod) {
|
||||
}
|
||||
|
||||
terminal.on('data', data => {
|
||||
buffer += data
|
||||
if (typeof data === 'string') {
|
||||
data = Buffer.from(data)
|
||||
}
|
||||
buffer = Buffer.concat([buffer, data])
|
||||
if (Date.now() - lastFlush > maxWindow) {
|
||||
// Taking too much time buffering, flush to keep things interactive
|
||||
flush()
|
||||
} else {
|
||||
if (Date.now() > nextTimeout - (maxWindow / 10)) {
|
||||
if (Date.now() > nextTimeout - maxWindow / 10) {
|
||||
// Extend the window if it's expiring
|
||||
reschedule()
|
||||
}
|
||||
|
@@ -1,24 +1,11 @@
|
||||
h3.mb-3 Appearance
|
||||
.d-flex
|
||||
.mr-5
|
||||
.form-line
|
||||
.header
|
||||
.title Frontend
|
||||
.description Switches terminal frontend implementation (experimental)
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='config.store.terminal.frontend',
|
||||
(ngModelChange)='config.save()',
|
||||
)
|
||||
option(value='hterm') hterm
|
||||
option(value='xterm') xterm
|
||||
option(value='xterm-webgl') xterm (WebGL)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Font
|
||||
|
||||
.d-flex.w-75
|
||||
.input-group.w-75
|
||||
input.form-control.w-75(
|
||||
type='text',
|
||||
[ngbTypeahead]='fontAutocomplete',
|
||||
@@ -52,9 +39,10 @@ h3.mb-3 Appearance
|
||||
)
|
||||
option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}}
|
||||
option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}}
|
||||
.input-group-btn
|
||||
button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit
|
||||
.input-group-btn
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)')
|
||||
i.fas.fa-pen
|
||||
.input-group-append
|
||||
button.btn.btn-outline-danger(
|
||||
(click)='deleteScheme(config.store.terminal.colorScheme)',
|
||||
*ngIf='isCustomScheme(config.store.terminal.colorScheme)'
|
||||
@@ -65,10 +53,12 @@ h3.mb-3 Appearance
|
||||
label Editing
|
||||
.input-group
|
||||
input.form-control(type='text', [(ngModel)]='editingColorScheme.name')
|
||||
.input-group-btn
|
||||
button.btn.btn-secondary((click)='saveScheme()') Save
|
||||
.input-group-btn
|
||||
button.btn.btn-secondary((click)='cancelEditing()') Cancel
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='saveScheme()')
|
||||
i.fas.fa-check
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='cancelEditing()')
|
||||
i.fas.fa-times
|
||||
|
||||
.form-group(*ngIf='editingColorScheme')
|
||||
color-picker(
|
||||
@@ -180,6 +170,19 @@ h3.mb-3 Appearance
|
||||
span rm -rf /
|
||||
span([style.background-color]='config.store.terminal.colorScheme.cursor')
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Frontend
|
||||
.description Switches terminal frontend implementation (experimental)
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='config.store.terminal.frontend',
|
||||
(ngModelChange)='config.save()',
|
||||
)
|
||||
option(value='hterm') hterm
|
||||
option(value='xterm') xterm
|
||||
option(value='xterm-webgl') xterm (WebGL)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Terminal background
|
||||
|
@@ -2,55 +2,64 @@
|
||||
.form-group
|
||||
label Name
|
||||
input.form-control(
|
||||
type='text',
|
||||
autofocus,
|
||||
[(ngModel)]='profile.name',
|
||||
type='text',
|
||||
autofocus,
|
||||
[(ngModel)]='profile.name',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Command
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.command',
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.command',
|
||||
)
|
||||
|
||||
|
||||
.form-group
|
||||
label Arguments
|
||||
.input-group(
|
||||
*ngFor='let arg of profile.sessionOptions.args; index as i; trackBy: trackByIndex',
|
||||
)
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.args[i]',
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.args[i]',
|
||||
)
|
||||
.input-group-btn
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='profile.sessionOptions.args.splice(i, 1)')
|
||||
i.fas.fa-trash
|
||||
|
||||
|
||||
.mt-2
|
||||
button.btn.btn-secondary((click)='profile.sessionOptions.args.push("")')
|
||||
i.fas.fa-plus.mr-2
|
||||
| Add
|
||||
|
||||
|
||||
.form-line(*ngIf='uac.isAvailable')
|
||||
.header
|
||||
.title Run as administrator
|
||||
toggle(
|
||||
[(ngModel)]='profile.sessionOptions.runAsAdministrator',
|
||||
)
|
||||
|
||||
|
||||
.form-group
|
||||
label Working directory
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.cwd',
|
||||
type='text',
|
||||
[(ngModel)]='profile.sessionOptions.cwd',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Environment
|
||||
environment-editor(
|
||||
type='text',
|
||||
[(model)]='profile.sessionOptions.env',
|
||||
type='text',
|
||||
[(model)]='profile.sessionOptions.env',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Tab color
|
||||
input.form-control(
|
||||
type='text',
|
||||
autofocus,
|
||||
[(ngModel)]='profile.color',
|
||||
placeholder='#000000'
|
||||
)
|
||||
|
||||
.modal-footer
|
||||
|
@@ -1,12 +1,13 @@
|
||||
.mb-2.d-flex.align-items-center(*ngFor='let pair of vars')
|
||||
.input-group.w-50
|
||||
input.form-control([(ngModel)]='pair.key', (blur)='emitUpdate()', placeholder='Variable name')
|
||||
.input-group-append
|
||||
.input-group
|
||||
input.form-control.w-25([(ngModel)]='pair.key', (blur)='emitUpdate()', placeholder='Variable name')
|
||||
.input-group-append
|
||||
.input-group-text =
|
||||
input.form-control.w-50.mr-1([(ngModel)]='pair.value', (blur)='emitUpdate()', placeholder='Value')
|
||||
button.btn.btn-secondary((click)='removeEnvironmentVar(pair.key)')
|
||||
i.fas.fa-trash
|
||||
|
||||
input.form-control.w-50([(ngModel)]='pair.value', (blur)='emitUpdate()', placeholder='Value')
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='removeEnvironmentVar(pair.key)')
|
||||
i.fas.fa-trash
|
||||
|
||||
button.btn.btn-secondary((click)='addEnvironmentVar()')
|
||||
i.fas.fa-plus.mr-2
|
||||
span Add
|
||||
|
@@ -2,7 +2,7 @@
|
||||
input.search-input.form-control(
|
||||
type='search',
|
||||
[(ngModel)]='query',
|
||||
(ngModelChange)='notFound = false',
|
||||
(ngModelChange)='onQueryChange()',
|
||||
[class.text-danger]='notFound',
|
||||
(click)='$event.stopPropagation()',
|
||||
(keyup.enter)='findNext()',
|
||||
@@ -10,31 +10,27 @@
|
||||
placeholder='Search...'
|
||||
)
|
||||
.input-group-append
|
||||
.btn-group
|
||||
button.btn.btn-outline-primary(
|
||||
.input-group-text
|
||||
a(
|
||||
(click)='options.caseSensitive = !options.caseSensitive',
|
||||
[class.active]='options.caseSensitive',
|
||||
[class.text-info]='options.caseSensitive',
|
||||
ngbTooltip='Case sensitivity',
|
||||
placement='bottom'
|
||||
)
|
||||
i.fa.fa-fw.fa-font
|
||||
button.btn.btn-outline-primary(
|
||||
a(
|
||||
(click)='options.regex = !options.regex',
|
||||
[class.active]='options.regex',
|
||||
[class.text-info]='options.regex',
|
||||
ngbTooltip='Regular expression',
|
||||
placement='bottom'
|
||||
)
|
||||
i.fa.fa-fw.fa-asterisk
|
||||
button.btn.btn-outline-primary(
|
||||
a(
|
||||
(click)='options.wholeWord = !options.wholeWord',
|
||||
[class.active]='options.wholeWord',
|
||||
[class.text-info]='options.wholeWord',
|
||||
ngbTooltip='Whole word',
|
||||
placement='bottom'
|
||||
)
|
||||
i.fa.fa-fw.fa-text-width
|
||||
button.btn.btn-outline(
|
||||
(click)='close.emit()',
|
||||
ngbTooltip='Close',
|
||||
placement='bottom'
|
||||
)
|
||||
i.fa.fa-fw.fa-times
|
||||
|
||||
button.close.text-light.pl-3.pr-2((click)='close.emit()') ×
|
||||
|
@@ -1,9 +1,20 @@
|
||||
:host {
|
||||
position: fixed;
|
||||
width: 400px;
|
||||
align-self: center;
|
||||
right: 50px;
|
||||
z-index: 5;
|
||||
padding: 10px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
background: rgba(0, 0, 0, .75);
|
||||
border: 1px solid rgba(0, 0, 0, .5);
|
||||
border-top: 0;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
padding-left: 10px;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,9 @@ export class SearchPanelComponent {
|
||||
@Input() query: string
|
||||
@Input() frontend: Frontend
|
||||
notFound = false
|
||||
options: SearchOptions = {}
|
||||
options: SearchOptions = {
|
||||
incremental: true,
|
||||
}
|
||||
|
||||
@Output() close = new EventEmitter()
|
||||
|
||||
@@ -19,8 +21,13 @@ export class SearchPanelComponent {
|
||||
private toastr: ToastrService,
|
||||
) { }
|
||||
|
||||
findNext () {
|
||||
if (!this.frontend.findNext(this.query, this.options)) {
|
||||
onQueryChange () {
|
||||
this.notFound = false
|
||||
this.findNext(true)
|
||||
}
|
||||
|
||||
findNext (incremental = false) {
|
||||
if (!this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })) {
|
||||
this.notFound = true
|
||||
this.toastr.error('Not found')
|
||||
}
|
||||
|
@@ -14,20 +14,20 @@ h3.mb-3 Shell
|
||||
[ngValue]='slug(profile.name).toLowerCase()'
|
||||
) {{profile.name}}
|
||||
|
||||
|
||||
|
||||
.form-line(*ngIf='isConPTYAvailable')
|
||||
.header
|
||||
.title Use ConPTY
|
||||
.description Enables the experimental Windows ConPTY API
|
||||
|
||||
|
||||
toggle(
|
||||
[(ngModel)]='config.store.terminal.useConPTY',
|
||||
(ngModelChange)='config.save()'
|
||||
)
|
||||
|
||||
|
||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.useConPTY && isConPTYAvailable && !isConPTYStable')
|
||||
.mr-auto Windows 10 build 18309 or above is recommended for ConPTY
|
||||
|
||||
|
||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.profile.startsWith("WSL") && (config.store.terminal.frontend != "hterm" || !config.store.terminal.useConPTY)')
|
||||
.mr-auto WSL terminal only supports TrueColor with ConPTY and the hterm frontend
|
||||
|
||||
@@ -50,15 +50,17 @@ h3.mb-3 Shell
|
||||
placeholder='Home directory',
|
||||
[(ngModel)]='config.store.terminal.workingDirectory',
|
||||
(ngModelChange)='config.save()',
|
||||
)
|
||||
.input-group-btn
|
||||
)
|
||||
.input-group-append
|
||||
button.btn.btn-secondary((click)='pickWorkingDirectory()')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Always Use Working Directory
|
||||
.description By default, new terminals will open where the previous terminal was working. Enabling this option will always launch new terminals in the working directory specified above.
|
||||
.description
|
||||
div By default, new terminals will open where the previous terminal was working.
|
||||
div Enabling this option will always launch new terminals in the working directory specified above.
|
||||
|
||||
toggle(
|
||||
[(ngModel)]='config.store.terminal.alwaysUseWorkingDirectory',
|
||||
@@ -69,7 +71,7 @@ h3.mb-3 Shell
|
||||
.header
|
||||
.title Environment
|
||||
.description Inject additional environment variables
|
||||
|
||||
|
||||
environment-editor([(model)]='this.config.store.terminal.environment')
|
||||
|
||||
h3.mt-3 Saved Profiles
|
||||
@@ -78,16 +80,16 @@ h3.mt-3 Saved Profiles
|
||||
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||
*ngFor='let profile of config.store.terminal.profiles',
|
||||
(click)='editProfile(profile)',
|
||||
)
|
||||
)
|
||||
.mr-auto
|
||||
div {{profile.name}}
|
||||
.text-muted {{profile.sessionOptions.command}}
|
||||
button.btn.btn-outline-danger.ml-1((click)='$event.stopPropagation(); deleteProfile(profile)')
|
||||
i.fas.fa-trash
|
||||
|
||||
|
||||
div(ngbDropdown, placement='top-left')
|
||||
button.btn.btn-primary(ngbDropdownToggle)
|
||||
button.btn.btn-primary(ngbDropdownToggle)
|
||||
i.fas.fa-fw.fa-plus
|
||||
| New profile
|
||||
| New profile
|
||||
div(ngbDropdownMenu)
|
||||
button.dropdown-item(*ngFor='let shell of shells', (click)='newProfile(shell)') {{shell.name}}
|
||||
|
@@ -42,6 +42,13 @@ h3.mb-3 Terminal
|
||||
(ngModelChange)='config.save()',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
value='off'
|
||||
)
|
||||
| Off
|
||||
label.btn.btn-secondary(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
@@ -57,6 +64,15 @@ h3.mb-3 Terminal
|
||||
)
|
||||
| Paste
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Paste on middle-click
|
||||
|
||||
toggle(
|
||||
[(ngModel)]='config.store.terminal.pasteOnMiddleClick',
|
||||
(ngModelChange)='config.save()',
|
||||
)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Auto-open a terminal on app start
|
||||
|
@@ -25,6 +25,7 @@ export class TerminalConfigProvider extends ConfigProvider {
|
||||
cursorBlink: true,
|
||||
customShell: '',
|
||||
rightClick: 'menu',
|
||||
pasteOnMiddleClick: true,
|
||||
copyOnSelect: false,
|
||||
scrollOnInput: true,
|
||||
workingDirectory: '',
|
||||
@@ -113,6 +114,7 @@ export class TerminalConfigProvider extends ConfigProvider {
|
||||
shell: 'clink',
|
||||
profile: 'cmd-clink',
|
||||
rightClick: 'paste',
|
||||
pasteOnMiddleClick: false,
|
||||
copyOnSelect: true,
|
||||
},
|
||||
hotkeys: {
|
||||
|
@@ -1,98 +0,0 @@
|
||||
import { NgZone, Injectable } from '@angular/core'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { ConfigService } from 'terminus-core'
|
||||
import { UACService } from './services/uac.service'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
|
||||
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class NewTabContextMenu extends TerminalContextMenuItemProvider {
|
||||
weight = 0
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private zone: NgZone,
|
||||
private terminalService: TerminalService,
|
||||
private uac: UACService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
const profiles = await this.terminalService.getProfiles()
|
||||
|
||||
const items: Electron.MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'New terminal',
|
||||
click: () => this.zone.run(() => {
|
||||
this.terminalService.openTabWithOptions((tab as any).sessionOptions)
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'New with profile',
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: () => this.zone.run(async () => {
|
||||
const workingDirectory = this.config.store.terminal.alwaysUseWorkingDirectory === true ?
|
||||
this.config.store.terminal.workingDirectory : await tab.session.getWorkingDirectory()
|
||||
await this.terminalService.openTab(profile, workingDirectory)
|
||||
}),
|
||||
})),
|
||||
},
|
||||
]
|
||||
|
||||
if (this.uac.isAvailable) {
|
||||
items.push({
|
||||
label: 'New admin tab',
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: () => this.zone.run(async () => {
|
||||
this.terminalService.openTabWithOptions({
|
||||
...profile.sessionOptions,
|
||||
runAsAdministrator: true,
|
||||
})
|
||||
}),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CopyPasteContextMenu extends TerminalContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
private zone: NgZone,
|
||||
private toastr: ToastrService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
return [
|
||||
{
|
||||
label: 'Copy',
|
||||
click: () => {
|
||||
this.zone.run(() => {
|
||||
setTimeout(() => {
|
||||
tab.frontend.copySelection()
|
||||
this.toastr.info('Copied')
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
click: () => {
|
||||
this.zone.run(() => tab.paste())
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@@ -6,6 +6,7 @@ export interface SearchOptions {
|
||||
regex?: boolean
|
||||
wholeWord?: boolean
|
||||
caseSensitive?: boolean
|
||||
incremental?: true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -23,7 +24,7 @@ export abstract class Frontend {
|
||||
protected mouseEvent = new Subject<MouseEvent>()
|
||||
protected bell = new Subject<void>()
|
||||
protected contentUpdated = new Subject<void>()
|
||||
protected input = new Subject<string>()
|
||||
protected input = new Subject<Buffer>()
|
||||
protected resize = new ReplaySubject<ResizeEvent>(1)
|
||||
protected dragOver = new Subject<DragEvent>()
|
||||
protected drop = new Subject<DragEvent>()
|
||||
@@ -34,7 +35,7 @@ export abstract class Frontend {
|
||||
get mouseEvent$ (): Observable<MouseEvent> { return this.mouseEvent }
|
||||
get bell$ (): Observable<void> { return this.bell }
|
||||
get contentUpdated$ (): Observable<void> { return this.contentUpdated }
|
||||
get input$ (): Observable<string> { return this.input }
|
||||
get input$ (): Observable<Buffer> { return this.input }
|
||||
get resize$ (): Observable<ResizeEvent> { return this.resize }
|
||||
get dragOver$ (): Observable<DragEvent> { return this.dragOver }
|
||||
get drop$ (): Observable<DragEvent> { return this.drop }
|
||||
|
@@ -182,7 +182,7 @@ export class HTermFrontend extends Frontend {
|
||||
this.term.installKeyboard()
|
||||
this.term.scrollPort_.setCtrlVPaste(true)
|
||||
this.io = this.term.io.push()
|
||||
this.io.onVTKeystroke = this.io.sendString = data => this.input.next(data)
|
||||
this.io.onVTKeystroke = this.io.sendString = data => this.input.next(Buffer.from(data, 'utf-8'))
|
||||
this.io.onTerminalResize = (columns, rows) => {
|
||||
this.resize.next({ columns, rows })
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ export class XTermFrontend extends Frontend {
|
||||
protected enableWebGL = false
|
||||
private xterm: Terminal
|
||||
private configuredFontSize = 0
|
||||
private configuredLinePadding = 0
|
||||
private zoom = 0
|
||||
private resizeHandler: () => void
|
||||
private configuredTheme: ITheme = {}
|
||||
@@ -39,8 +40,11 @@ export class XTermFrontend extends Frontend {
|
||||
})
|
||||
this.xtermCore = (this.xterm as any)._core
|
||||
|
||||
this.xterm.onBinary(data => {
|
||||
this.input.next(Buffer.from(data, 'binary'))
|
||||
})
|
||||
this.xterm.onData(data => {
|
||||
this.input.next(data)
|
||||
this.input.next(Buffer.from(data, 'utf-8'))
|
||||
})
|
||||
this.xterm.onResize(({ cols, rows }) => {
|
||||
this.resize.next({ rows, columns: cols })
|
||||
@@ -113,6 +117,8 @@ export class XTermFrontend extends Frontend {
|
||||
}
|
||||
|
||||
attach (host: HTMLElement): void {
|
||||
this.configure()
|
||||
|
||||
this.xterm.open(host)
|
||||
this.opened = true
|
||||
|
||||
@@ -203,13 +209,14 @@ export class XTermFrontend extends Frontend {
|
||||
this.xterm.setOption('macOptionIsMeta', config.terminal.altIsMeta)
|
||||
this.xterm.setOption('scrollback', 100000)
|
||||
this.configuredFontSize = config.terminal.fontSize
|
||||
this.configuredLinePadding = config.terminal.linePadding
|
||||
this.setFontSize()
|
||||
|
||||
this.copyOnSelect = config.terminal.copyOnSelect
|
||||
|
||||
const theme: ITheme = {
|
||||
foreground: config.terminal.colorScheme.foreground,
|
||||
background: config.terminal.background === 'colorScheme' ? config.terminal.colorScheme.background : config.appearance.vibrancy ? 'transparent' : this.themesService.findCurrentTheme().terminalBackground,
|
||||
background: config.terminal.background === 'colorScheme' ? config.terminal.colorScheme.background : '#00000000',
|
||||
cursor: config.terminal.colorScheme.cursor,
|
||||
}
|
||||
|
||||
@@ -242,7 +249,10 @@ export class XTermFrontend extends Frontend {
|
||||
}
|
||||
|
||||
private setFontSize () {
|
||||
this.xterm.setOption('fontSize', this.configuredFontSize * Math.pow(1.1, this.zoom))
|
||||
const scale = Math.pow(1.1, this.zoom)
|
||||
this.xterm.setOption('fontSize', this.configuredFontSize * scale)
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
this.xterm.setOption('lineHeight', (this.configuredFontSize + this.configuredLinePadding * 2) / this.configuredFontSize)
|
||||
this.resizeHandler()
|
||||
}
|
||||
|
||||
|
1
terminus-terminal/src/icons/alpine.svg
Normal file
1
terminus-terminal/src/icons/alpine.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 65 57" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" width="300" height="300" font-family="Roboto" font-size="14px" text-anchor="middle"><defs><style type="text/css"></style></defs><use xlink:href="#A" x=".5" y=".5"></use><symbol id="A" overflow="visible"><g stroke="none" fill="#0d597f" fill-rule="nonzero"><path d="M23.252 34.527v-6.745l-4.855 4.864c.474.333.968.635 1.48.906.463.243.87.434 1.303.58a7.97 7.97 0 0 0 1.13.304c.348.064.66.093.95.096m24.822-.562a1.17 1.17 0 0 0 .142.1c.123.078.252.145.385.203a2.93 2.93 0 0 0 .637.194c.296.06.598.088.9.087a5.84 5.84 0 0 0 .955-.087 7.24 7.24 0 0 0 1.138-.301c.453-.16.895-.354 1.32-.58.52-.274 1.02-.58 1.503-.918l-3.685-3.6-12.2-12.258-5.356 5.356-7.23-7.455L8.44 32.647c.48.337.98.644 1.5.918.47.246.9.434 1.317.58a7.18 7.18 0 0 0 1.135.301 5.53 5.53 0 0 0 .955.087 4.53 4.53 0 0 0 .9-.087 3.29 3.29 0 0 0 .637-.194c.134-.054.263-.12.385-.197l.145-.104 8.193-8.193 2.924-2.808 8.106 8.106 2.837 2.912c.046.037.094.07.145.1.122.078.25.145.385.2a3.49 3.49 0 0 0 .637.194c.255.052.556.087.903.087a5.84 5.84 0 0 0 .955-.087c.387-.068.768-.168 1.138-.3a9.94 9.94 0 0 0 1.32-.579c.52-.274 1.02-.58 1.503-.918l-6.508-6.37 1.2-1.2 5.63 5.63 3.283 3.254M47.996.02l15.998 27.714-15.99 27.694H15.998L0 27.714 15.998 0z"></path><path d="M38.022 26.367L33.76 22.11l.304-.304 4.3 4.244z"></path></g></symbol></svg>
|
After Width: | Height: | Size: 1.5 KiB |
1
terminus-terminal/src/icons/debian.svg
Normal file
1
terminus-terminal/src/icons/debian.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.3 KiB |
122
terminus-terminal/src/icons/linux.svg
Normal file
122
terminus-terminal/src/icons/linux.svg
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="295px" viewBox="0 0 256 295" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<defs>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="6.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
</filter>
|
||||
<linearGradient x1="48.5477412%" y1="115.276174%" x2="51.0473804%" y2="41.3637237%" id="linearGradient-2">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="54.4065463%" y1="2.40410545%" x2="46.1753957%" y2="90.5422349%" id="linearGradient-3">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.8" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="51.859653%" y1="88.2477484%" x2="47.9469396%" y2="9.74782136%" id="linearGradient-4">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9251097%" y1="85.4900173%" x2="49.9236843%" y2="13.8109272%" id="linearGradient-5">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="53.9014071%" y1="3.10177585%" x2="45.9555354%" y2="93.8949571%" id="linearGradient-6">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="45.5928761%" y1="5.47459052%" x2="54.811359%" y2="93.5235162%" id="linearGradient-7">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9844987%" y1="89.8452442%" x2="49.9844987%" y2="40.6316864%" id="linearGradient-8">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="53.5047131%" y1="99.97524%" x2="42.7455968%" y2="23.5451715%" id="linearGradient-9">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.8413363%" y1="13.2289558%" x2="50.2412612%" y2="94.6729694%" id="linearGradient-10">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.8" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9272298%" y1="37.3270337%" x2="50.7270446%" y2="92.7824735%" id="linearGradient-11">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.8755597%" y1="2.29900584%" x2="49.8755597%" y2="81.203617%" id="linearGradient-12">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.8334391%" y1="2.27189065%" x2="49.8240398%" y2="71.7989617%" id="linearGradient-13">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="53.4670683%" y1="48.9213861%" x2="38.9488708%" y2="98.0999776%" id="linearGradient-14">
|
||||
<stop stop-color="#FFA63F" offset="0%"></stop>
|
||||
<stop stop-color="#FFFF00" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="52.3731508%" y1="143.008909%" x2="47.57909%" y2="-64.6215389%" id="linearGradient-15">
|
||||
<stop stop-color="#FFEED7" offset="0%"></stop>
|
||||
<stop stop-color="#BDBFC2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="30.580815%" y1="34.0241079%" x2="65.8867024%" y2="89.175349%" id="linearGradient-16">
|
||||
<stop stop-color="#FFA63F" offset="0%"></stop>
|
||||
<stop stop-color="#FFFF00" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="59.5715091%" y1="-17.2155207%" x2="48.3608522%" y2="66.1184465%" id="linearGradient-17">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="47.7689553%" y1="1.56481301%" x2="51.3733028%" y2="104.312856%" id="linearGradient-18">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="43.5495626%" y1="4.5334861%" x2="57.1143288%" y2="92.8267174%" id="linearGradient-19">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.7328042%" y1="17.6085216%" x2="50.5582487%" y2="99.3854667%" id="linearGradient-20">
|
||||
<stop stop-color="#FFA63F" offset="0%"></stop>
|
||||
<stop stop-color="#FFFF00" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="50.1697217%" y1="2.89048531%" x2="49.6802359%" y2="94.1704279%" id="linearGradient-21">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.65" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g fill="none">
|
||||
<g transform="translate(10.000000, 0.000000)">
|
||||
<path d="M235.125423,249.358628 C235.125423,266.714271 182.507524,280.855905 117.584567,280.855905 C52.6616093,280.855905 0.0437105058,266.806099 0.0437105058,249.358628 L0.0437105058,249.358628 C0.0437105058,232.002986 52.6616093,217.861352 117.584567,217.861352 C182.507524,217.861352 235.033594,232.002986 235.125423,249.358628 L235.125423,249.358628 L235.125423,249.358628 Z" fill="#000" fill-opacity="0.2" filter="url(#filter-1)"></path>
|
||||
<path d="M53.2125821,215.473804 C41.8258117,199.128278 39.6219206,145.867578 66.160442,113.084699 C79.2919595,97.3819748 82.6896249,86.4543483 83.6997416,71.6699125 C84.434372,54.8652433 71.8538272,4.81855066 119.237485,1.05357012 C167.263944,-2.80323922 164.600909,44.5804184 164.325423,69.6496791 C164.141765,90.7703016 179.844489,102.799874 190.680286,119.329056 C210.607135,149.632558 208.954216,201.791313 186.915306,230.074582 C158.999353,265.428667 135.123866,250.093259 119.237485,251.378862 C89.4849556,253.123609 88.4748389,268.918162 53.2125821,215.473804 L53.2125821,215.473804 Z" fill="#000000"></path>
|
||||
<path d="M169.10052,122.451235 C177.365111,130.073025 198.76122,164.141508 164.876395,185.445788 C152.938652,192.88392 175.528535,221.167189 186.364333,207.484699 C205.556551,182.874582 193.343321,143.571858 181.772893,129.522053 C174.059275,119.604543 162.121532,115.747734 169.10052,122.451235 L169.10052,122.451235 Z" fill="url(#linearGradient-2)"></path>
|
||||
<path d="M166.8048,117.859796 C180.395461,128.879251 205.097407,167.447344 169.008691,192.608434 C157.162777,200.413881 179.477174,225.115827 192.057718,212.535282 C235.676395,168.641119 190.955773,118.227111 175.528535,100.871469 C161.754216,85.719718 149.540987,104.360963 166.8048,117.859796 L166.8048,117.859796 Z" stroke="#000000" stroke-width="0.9773" fill="#000000"></path>
|
||||
<path d="M147.245267,25.0208853 C146.786123,37.60143 132.919975,48.5290565 116.298963,49.5391732 C99.6779518,50.54929 86.638263,40.9990954 87.097407,28.4185507 L87.097407,28.4185507 C87.556551,15.8380059 101.422699,4.91037946 118.043711,3.90026272 C134.664722,2.98197479 147.704411,12.4403405 147.245267,25.0208853 L147.245267,25.0208853 L147.245267,25.0208853 Z" fill="url(#linearGradient-3)"></path>
|
||||
<path d="M107.483399,54.9570721 C107.942543,63.1298347 104.085734,70.0169942 98.7596638,70.2924806 C93.4335938,70.567967 88.7503253,64.2317802 88.2911813,56.0590176 L88.2911813,56.0590176 C87.8320374,47.8862549 91.6888467,40.9990954 97.0149167,40.723609 C102.340987,40.4481226 107.024255,46.7843094 107.483399,54.9570721 L107.483399,54.9570721 L107.483399,54.9570721 Z" fill="url(#linearGradient-4)"></path>
|
||||
<path d="M117.125423,55.5998736 C117.30908,65.0582394 123.461609,72.5882005 130.807913,72.4045429 C138.154216,72.2208853 143.93943,64.4154378 143.755773,54.8652433 L143.755773,54.8652433 C143.572115,45.4068775 137.419586,37.8769164 130.073282,38.060574 C122.726979,38.2442316 116.849936,46.1415079 117.125423,55.5998736 L117.125423,55.5998736 L117.125423,55.5998736 Z" fill="url(#linearGradient-5)"></path>
|
||||
<path d="M123.186123,57.7119359 C123.094294,62.9461771 125.6655,67.1703016 129.063166,67.1703016 C132.369002,67.1703016 135.215695,62.9461771 135.307524,57.8037647 L135.307524,57.8037647 C135.399353,52.5695234 132.828146,48.3453989 129.430481,48.3453989 C126.032816,48.3453989 123.277952,52.5695234 123.186123,57.7119359 L123.186123,57.7119359 L123.186123,57.7119359 Z" fill="#000000"></path>
|
||||
<path d="M101.973672,57.8037647 C102.432816,62.119718 100.779897,65.7928697 98.3923486,66.1601849 C96.0048,66.4356713 93.7090802,63.2216635 93.2499362,58.9057102 L93.2499362,58.9057102 C92.7907922,54.5897569 94.4437105,50.9166051 96.8312591,50.54929 C99.2188078,50.2738036 101.514528,53.4878114 101.973672,57.8037647 L101.973672,57.8037647 L101.973672,57.8037647 Z" fill="#000000"></path>
|
||||
<path d="M124.563555,54.7734145 C124.288068,57.7119359 125.6655,60.0994845 127.593905,60.2831421 C129.52231,60.4667997 131.358886,58.1710798 131.634372,55.3243872 L131.634372,55.3243872 C131.909858,52.3858658 130.532426,49.9983172 128.604022,49.8146596 C126.675617,49.631002 124.839041,51.9267219 124.563555,54.7734145 L124.563555,54.7734145 L124.563555,54.7734145 Z" fill="url(#linearGradient-6)"></path>
|
||||
<path d="M99.9534381,55.5080448 C100.228925,57.8955935 99.2188078,60.0076557 97.7495471,60.1913133 C96.2802864,60.3749709 94.9028545,58.538395 94.6273681,56.0590176 L94.6273681,56.0590176 C94.3518817,53.6714689 95.3619984,51.5594067 96.8312591,51.3757491 C98.3005198,51.1920915 99.6779518,53.1204962 99.9534381,55.5080448 L99.9534381,55.5080448 L99.9534381,55.5080448 Z" fill="url(#linearGradient-7)"></path>
|
||||
<path d="M71.0273681,145.68392 C77.5472125,130.899485 91.4133603,104.911936 91.6888467,84.80143 C91.6888467,68.8232199 139.531648,64.9664106 143.388458,80.9446207 C147.245267,96.9228308 156.979119,120.798317 163.223477,132.368745 C169.467835,143.847344 187.558107,180.487033 168.274061,212.443453 C150.918419,240.726722 98.3005198,263.132948 70.2009089,208.586644 C60.6507144,189.669913 62.3954615,166.25357 71.0273681,145.68392 L71.0273681,145.68392 Z" fill="url(#linearGradient-8)"></path>
|
||||
<path d="M65.1503253,134.664465 C59.5487689,145.224776 47.9783409,172.957072 76.2616093,188.108823 C106.65694,204.270691 106.565111,237.420885 70.0172514,221.626333 C36.5915704,207.39287 51.3760062,149.724387 60.7425432,135.950068 C66.8032436,126.308045 75.986123,114.46213 65.1503253,134.664465 L65.1503253,134.664465 Z" fill="url(#linearGradient-9)"></path>
|
||||
<path d="M69.9254226,122.726722 C61.0180296,137.235671 39.7137494,171.395983 68.2725043,189.210769 C106.65694,212.810769 95.8211424,236.31894 60.7425432,215.106488 C11.3386521,185.537617 54.7736716,125.848901 74.5168623,103.07536 C97.1067455,77.5469553 78.8328156,107.758628 69.9254226,122.726722 L69.9254226,122.726722 Z" stroke="#000000" stroke-width="1.25" fill="#000000"></path>
|
||||
<path d="M156.428146,151.285477 C156.428146,167.447344 140.90908,188.384309 114.27873,188.200652 C86.8219206,188.384309 75.1596638,167.447344 75.1596638,151.285477 C75.1596638,135.123609 93.341765,121.992092 115.747991,121.992092 C138.246045,122.08392 156.428146,135.123609 156.428146,151.285477 L156.428146,151.285477 Z" fill="url(#linearGradient-10)"></path>
|
||||
<path d="M141.919197,100.504154 C141.643711,117.216994 130.716084,121.165632 116.941765,121.165632 C103.167446,121.165632 93.1581074,118.686255 91.9643331,100.504154 C91.9643331,89.1173833 103.167446,82.5057102 116.941765,82.5057102 C130.716084,82.4138814 141.919197,89.0255546 141.919197,100.504154 L141.919197,100.504154 Z" fill="url(#linearGradient-11)"></path>
|
||||
<path d="M58.6304809,126.216216 C67.6297027,112.533726 86.638263,91.504932 62.2118039,129.154737 C42.3767844,160.19287 54.8655004,180.119718 61.293516,185.629446 C79.8429323,202.158628 79.1083019,213.269913 64.5075237,204.546177 C33.1939051,185.904932 39.7137494,154.499485 58.6304809,126.216216 L58.6304809,126.216216 Z" fill="url(#linearGradient-12)"></path>
|
||||
<path d="M188.935539,131.817772 C181.130092,115.747734 156.336318,74.9757491 190.129314,122.359407 C220.89196,165.243453 199.312193,195.087811 195.455384,198.026333 C191.598574,200.964854 178.650714,206.933726 182.415695,196.557072 C186.272504,186.180418 205.372893,166.529056 188.935539,131.817772 L188.935539,131.817772 Z" fill="url(#linearGradient-13)"></path>
|
||||
<path d="M51.8351502,258.541508 C31.2655004,247.613881 1.42114241,260.65357 12.2569401,231.084699 C14.4608311,224.381197 9.0429323,214.280029 12.5324265,207.760185 C16.6647222,199.77108 25.5721152,201.515827 30.8981852,196.189757 C36.1324265,190.680029 39.438263,181.129835 49.263944,182.599095 C58.9977961,184.068356 65.5176405,196.006099 72.3129712,210.698706 C77.3635549,221.167189 95.1783409,235.951625 93.9845665,247.70571 C92.5153058,265.704154 72.0374848,269.101819 51.8351502,258.541508 L51.8351502,258.541508 Z" stroke="#E68C3F" stroke-width="6.25" fill="url(#linearGradient-14)"></path>
|
||||
<path d="M201.607913,189.11894 C198.485734,194.995983 185.446045,204.454348 176.72231,201.974971 C167.906746,199.587422 163.866279,186.180418 165.611026,175.987422 C167.263944,164.600652 176.72231,163.95785 188.660053,169.651235 C201.516084,175.987422 205.372893,181.313492 201.607913,189.11894 L201.607913,189.11894 Z" fill="url(#linearGradient-15)"></path>
|
||||
<path d="M194.445267,253.490924 C209.505189,235.216994 243.022699,238.981975 220.432816,213.912714 C215.657718,208.494815 217.126979,196.924387 211.249936,191.965632 C204.362777,185.904932 196.740987,190.863687 189.761998,187.741508 C182.78301,184.343842 175.436707,177.823998 166.896629,182.415438 C158.356551,187.098706 157.438263,199.220107 156.611804,215.198317 C155.877174,226.676916 145.408691,245.869134 151.010247,256.429446 C159.091181,272.774971 180.119975,270.57108 194.445267,253.490924 L194.445267,253.490924 Z" stroke="#E68C3F" stroke-width="6.2507" fill="url(#linearGradient-16)"></path>
|
||||
<path d="M187.925423,229.064465 C211.249936,194.628667 193.894294,194.904154 188.017251,192.241119 C182.140209,189.486255 175.987679,184.068356 169.10052,187.833337 C162.21336,191.690146 161.846045,201.607656 161.662388,214.647344 C161.386901,224.013881 153.581454,239.716605 158.264722,248.440341 C163.958107,258.633337 177.732426,243.848901 187.925423,229.064465 L187.925423,229.064465 Z" fill="url(#linearGradient-17)"></path>
|
||||
<path d="M47.0600529,234.02322 C12.1651113,211.433337 28.5106366,203.719718 33.7448778,200.138395 C40.0810646,195.546955 40.1728934,186.731391 47.9783409,187.55785 C55.7837883,188.384309 60.375228,198.026333 65.6094693,209.964076 C69.4662786,218.504154 82.8732825,229.890924 81.8631658,239.716605 C80.5775626,251.287033 62.1199751,243.665243 47.0600529,234.02322 L47.0600529,234.02322 Z" fill="url(#linearGradient-18)"></path>
|
||||
<path d="M199.587679,188.843453 C196.832816,193.618551 185.629703,201.148512 178.19157,199.128278 C170.569781,197.199874 167.080286,186.455905 168.641376,178.374971 C170.018808,169.192092 178.19157,168.732948 188.476395,173.324387 C199.404022,178.283142 202.801687,182.507267 199.587679,188.843453 L199.587679,188.843453 Z" fill="#000000"></path>
|
||||
<path d="M192.057718,186.180418 C190.312971,189.486255 182.966668,194.720496 177.824255,193.343064 C172.681843,191.965632 170.110637,184.5275 170.937096,178.925944 C171.671726,172.589757 177.181454,172.222442 184.160442,175.344621 C191.690403,178.834115 194.077952,181.772636 192.057718,186.180418 L192.057718,186.180418 Z" fill="url(#linearGradient-19)"></path>
|
||||
<path d="M97.1067455,66.3438425 C100.779897,62.9461771 109.68729,52.5695234 126.583788,63.4053211 C129.705967,65.4255546 132.277174,65.6092121 138.246045,68.1804184 C150.275617,73.1391732 144.582232,85.0769164 131.726201,89.1173833 C126.216473,90.8621304 121.257718,97.5656324 111.340209,96.9228308 C102.800131,96.4636868 100.59624,90.8621304 95.3619984,87.8317802 C86.0872903,82.597539 84.7098584,75.5267219 89.760442,71.7617413 C94.8110257,67.9967608 96.7394304,66.6193289 97.1067455,66.3438425 L97.1067455,66.3438425 Z" stroke="#E68C3F" stroke-width="3.75" fill="url(#linearGradient-20)"></path>
|
||||
<path d="M138.429703,75.9858658 C133.379119,76.2613522 122.451493,87.1889787 110.972893,87.1889787 C99.4942942,87.1889787 92.6071346,76.5368386 90.8623875,76.5368386" stroke="#E68C3F" stroke-width="2.5"></path>
|
||||
<path d="M102.800131,65.4255546 C104.636707,63.7726363 110.421921,59.2730254 118.043711,63.8644651 C119.696629,64.782753 121.349547,65.7928697 123.737096,67.1703016 C128.604022,70.0169942 126.216473,74.14929 120.33943,76.7204962 C117.676395,77.8224417 113.268613,80.2099904 109.962777,80.0263328 C106.289625,79.6590176 103.810247,77.2714689 101.422699,75.7103795 C96.9230879,72.7718581 97.1985743,70.2924806 99.3106366,68.364076 C100.871726,66.8948153 102.616473,65.5173833 102.800131,65.4255546 L102.800131,65.4255546 Z" fill="url(#linearGradient-21)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 18 KiB |
47
terminus-terminal/src/icons/suse.svg
Normal file
47
terminus-terminal/src/icons/suse.svg
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 256 256.00001"
|
||||
height="256"
|
||||
width="256">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="matrix(6.9999999,0,0,6.9999736,16,-7617.6082)"
|
||||
id="layer1"
|
||||
style="fill:#73ba25;fill-opacity:1">
|
||||
<g
|
||||
style="fill:#73ba25;fill-opacity:1"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,-10.590624,-38.473045)"
|
||||
id="g838">
|
||||
<circle
|
||||
r="0"
|
||||
cy="3582.8301"
|
||||
cx="507.46362"
|
||||
id="path872"
|
||||
style="opacity:0.3;fill:#73ba25;fill-opacity:1;stroke:none;stroke-width:1.90573967;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path819"
|
||||
d="m 100.5002,4267.059 a 60.472077,60.472442 0 0 0 -47.607132,23.2988 c 7.375955,1.9706 12.596534,3.6642 14.160064,4.1895 0.0245,-0.9593 0.183589,-9.5391 0.183589,-9.5391 0,0 0.0202,-0.1964 0.124999,-0.2988 0.13497,-0.1318 0.330078,-0.092 0.330078,-0.092 1.939989,0.281 43.348482,6.4189 60.802382,16.5899 2.15548,1.261 3.21941,2.6017 4.5488,3.9609 4.82477,4.99 11.19998,25.7389 11.88469,30.0176 0.0269,0.1681 -0.18083,0.3507 -0.26953,0.4199 h -0.002 c -0.4957,0.3868 -1.03554,0.789 -1.57616,1.1484 -4.12998,2.7709 -13.64449,9.4312 -25.85142,8.3438 -10.96493,-0.97 -25.290388,-7.2597 -42.560284,-18.6387 1.69799,3.9756 3.371,7.9635 5.04489,11.9492 2.500985,1.299 26.640524,13.5997 38.554464,13.3594 9.59593,-0.1999 19.85892,-4.8804 23.96469,-7.3516 0,0 0.90227,-0.5436 1.29491,-0.2402 0.4295,0.3318 0.31068,0.8402 0.20898,1.3594 -0.25259,1.1786 -0.82764,3.3289 -1.21873,4.3496 l -0.33008,0.832 c -0.46999,1.2592 -0.92111,2.4296 -1.79101,3.1504 -2.41868,2.1993 -6.27908,3.9491 -12.32804,6.5781 -9.34995,4.09 -24.51938,6.6911 -38.603293,6.6016 -5.04437,-0.1123 -9.91781,-0.672 -14.197174,-1.1719 -8.782187,-0.9915 -15.927854,-1.7959 -20.285038,1.3555 a 60.472077,60.472442 0 0 0 45.517305,20.7734 60.472077,60.472442 0 0 0 60.47229,-60.4726 60.472077,60.472442 0 0 0 -60.47229,-60.4727 z m 13.4882,35.0879 c -4.73327,-0.1509 -9.24668,1.5194 -12.70695,4.75 -3.458684,3.2199 -5.437952,7.6097 -5.613251,12.3399 -0.326998,9.7581 7.334241,17.9803 17.083881,18.3398 4.75477,0.1596 9.25839,-1.5118 12.71867,-4.7617 3.44988,-3.2099 5.42915,-7.5999 5.61325,-12.3301 0.335,-9.7494 -7.33546,-17.9889 -17.0956,-18.3379 z m -0.14844,5.2188 c 6.82096,0.242 12.16127,5.972 11.93157,12.791 -0.1053,3.2885 -1.49253,6.3369 -3.90231,8.5976 -2.41329,2.2502 -5.56743,3.4203 -8.87691,3.3203 -6.80516,-0.251 -12.14564,-5.9877 -11.91594,-12.8085 0.1,-3.3008 1.51475,-6.3495 3.91403,-8.5997 2.39919,-2.2502 5.53828,-3.42 8.84956,-3.3007 z m 2.02147,6.2011 c -3.03067,0 -5.47848,1.631 -5.47848,3.6602 0,2.01 2.44781,3.6504 5.47848,3.6504 3.02888,0 5.4863,-1.6405 5.4863,-3.6504 0,-2.0292 -2.45572,-3.6602 -5.4863,-3.6602 z"
|
||||
style="opacity:1;fill:#73ba25;fill-opacity:1;stroke:none;stroke-width:1.90559804;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
7
terminus-terminal/src/icons/ubuntu.svg
Normal file
7
terminus-terminal/src/icons/ubuntu.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M255.637396,127.683191 C255.637396,198.196551 198.47207,255.363378 127.954205,255.363378 C57.4348387,255.363378 0.27026393,198.196551 0.27026393,127.683191 C0.27026393,57.1653255 57.4355894,0 127.954205,0 C198.472821,0 255.637396,57.1653255 255.637396,127.683191 L255.637396,127.683191 Z" fill="#DD4814"></path>
|
||||
<path d="M41.1334194,110.63254 C31.7139707,110.63254 24.0827683,118.264493 24.0827683,127.683191 C24.0827683,137.097384 31.7139707,144.728587 41.1334194,144.728587 C50.5476129,144.728587 58.1788152,137.097384 58.1788152,127.683191 C58.1788152,118.264493 50.5476129,110.63254 41.1334194,110.63254 L41.1334194,110.63254 Z M162.848282,188.111202 C154.694569,192.820551 151.898839,203.240727 156.608938,211.389935 C161.313032,219.543648 171.733208,222.338628 179.886921,217.629279 C188.039883,212.925185 190.835613,202.505009 186.126264,194.350545 C181.42217,186.202088 170.995988,183.407109 162.848282,188.111202 L162.848282,188.111202 Z M78.1618299,127.683191 C78.1618299,110.836739 86.5295015,95.9534545 99.3332551,86.9409032 L86.8703343,66.0667683 C71.9555191,76.0365044 60.8581818,91.271132 56.2464282,109.113806 C61.6276833,113.504845 65.0720469,120.189372 65.0720469,127.68244 C65.0720469,135.171003 61.6276833,141.855531 56.2464282,146.246569 C60.852176,164.094499 71.9495132,179.329877 86.8703343,189.299613 L99.3332551,168.420223 C86.5295015,159.412927 78.1618299,144.530393 78.1618299,127.683191 L78.1618299,127.683191 Z M127.954205,77.8855601 C153.967109,77.8855601 175.30895,97.8302874 177.549138,123.265877 L201.839859,122.907777 C200.644692,104.129689 192.441431,87.2719765 179.836622,74.875871 C173.354792,77.3247625 165.86773,76.9501466 159.396411,73.2197537 C152.91383,69.4788504 148.849361,63.1681877 147.738276,56.3177478 C141.438123,54.5790499 134.807648,53.6271202 127.952704,53.6271202 C116.168446,53.6271202 105.026815,56.3950733 95.1344047,61.2913548 L106.979472,82.5175836 C113.351695,79.5521877 120.460387,77.8855601 127.954205,77.8855601 L127.954205,77.8855601 Z M127.954205,177.475566 C120.460387,177.475566 113.351695,175.808188 106.980223,172.843543 L95.1351554,194.069021 C105.027566,198.971308 116.169196,201.740012 127.954205,201.740012 C134.80915,201.740012 141.439625,200.787331 147.739026,199.043378 C148.850111,192.192938 152.916082,185.888282 159.397161,182.140622 C165.872985,178.404223 173.355543,178.036364 179.837372,180.485255 C192.442182,168.08915 200.645443,151.231437 201.84061,132.453349 L177.543883,132.095249 C175.30895,157.537595 153.967859,177.475566 127.954205,177.475566 L127.954205,177.475566 Z M162.842276,67.2446686 C170.995988,71.9532669 181.416915,69.1642933 186.121009,61.0105806 C190.830358,52.856868 188.041384,42.4359413 179.886921,37.7258416 C171.733208,33.0217478 161.313032,35.8167273 156.602182,43.9704399 C151.898839,52.1196481 154.693818,62.5405748 162.842276,67.2446686 L162.842276,67.2446686 Z" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
@@ -35,8 +35,8 @@ import { PathDropDecorator } from './pathDrop'
|
||||
import { TerminalConfigProvider } from './config'
|
||||
import { TerminalHotkeyProvider } from './hotkeys'
|
||||
import { HyperColorSchemes } from './colorSchemes'
|
||||
import { NewTabContextMenu, CopyPasteContextMenu } from './contextMenu'
|
||||
import { SaveAsProfileContextMenu } from './tabContextMenu'
|
||||
import { NewTabContextMenu, CopyPasteContextMenu, SaveAsProfileContextMenu, LegacyContextMenu } from './tabContextMenu'
|
||||
import { ZModemDecorator } from './zmodem'
|
||||
|
||||
import { CmderShellProvider } from './shells/cmder'
|
||||
import { CustomShellProvider } from './shells/custom'
|
||||
@@ -76,6 +76,7 @@ import { XTermFrontend, XTermWebGLFrontend } from './frontends/xtermFrontend'
|
||||
{ provide: HotkeyProvider, useClass: TerminalHotkeyProvider, multi: true },
|
||||
{ provide: TerminalColorSchemeProvider, useClass: HyperColorSchemes, multi: true },
|
||||
{ provide: TerminalDecorator, useClass: PathDropDecorator, multi: true },
|
||||
{ provide: TerminalDecorator, useClass: ZModemDecorator, multi: true },
|
||||
|
||||
{ provide: ShellProvider, useClass: WindowsDefaultShellProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: MacOSDefaultShellProvider, multi: true },
|
||||
@@ -90,10 +91,10 @@ import { XTermFrontend, XTermWebGLFrontend } from './frontends/xtermFrontend'
|
||||
{ provide: ShellProvider, useClass: POSIXShellsProvider, multi: true },
|
||||
{ provide: ShellProvider, useClass: WSLShellProvider, multi: true },
|
||||
|
||||
{ provide: TerminalContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
|
||||
{ provide: TerminalContextMenuItemProvider, useClass: CopyPasteContextMenu, multi: true },
|
||||
|
||||
{ provide: TabContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: CopyPasteContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: SaveAsProfileContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: LegacyContextMenu, multi: true },
|
||||
|
||||
// For WindowsDefaultShellProvider
|
||||
PowerShellCoreShellProvider,
|
||||
|
@@ -30,8 +30,8 @@ export interface ChildProcess {
|
||||
|
||||
const windowsDirectoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi
|
||||
const catalinaDataVolumePrefix = '/System/Volumes/Data'
|
||||
const OSC1337Prefix = '\x1b]1337;'
|
||||
const OSC1337Suffix = '\x07'
|
||||
const OSC1337Prefix = Buffer.from('\x1b]1337;')
|
||||
const OSC1337Suffix = Buffer.from('\x07')
|
||||
|
||||
/**
|
||||
* A session object for a [[BaseTerminalTabComponent]]
|
||||
@@ -42,27 +42,31 @@ export abstract class BaseSession {
|
||||
name: string
|
||||
truePID: number
|
||||
protected output = new Subject<string>()
|
||||
protected binaryOutput = new Subject<Buffer>()
|
||||
protected closed = new Subject<void>()
|
||||
protected destroyed = new Subject<void>()
|
||||
private initialDataBuffer = ''
|
||||
private initialDataBuffer = Buffer.from('')
|
||||
private initialDataBufferReleased = false
|
||||
|
||||
get output$ (): Observable<string> { return this.output }
|
||||
get binaryOutput$ (): Observable<Buffer> { return this.binaryOutput }
|
||||
get closed$ (): Observable<void> { return this.closed }
|
||||
get destroyed$ (): Observable<void> { return this.destroyed }
|
||||
|
||||
emitOutput (data: string) {
|
||||
emitOutput (data: Buffer) {
|
||||
if (!this.initialDataBufferReleased) {
|
||||
this.initialDataBuffer += data
|
||||
this.initialDataBuffer = Buffer.concat([this.initialDataBuffer, data])
|
||||
} else {
|
||||
this.output.next(data)
|
||||
this.output.next(data.toString())
|
||||
this.binaryOutput.next(data)
|
||||
}
|
||||
}
|
||||
|
||||
releaseInitialDataBuffer () {
|
||||
this.initialDataBufferReleased = true
|
||||
this.output.next(this.initialDataBuffer)
|
||||
this.initialDataBuffer = ''
|
||||
this.output.next(this.initialDataBuffer.toString())
|
||||
this.binaryOutput.next(this.initialDataBuffer)
|
||||
this.initialDataBuffer = Buffer.from('')
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
@@ -71,13 +75,14 @@ export abstract class BaseSession {
|
||||
this.closed.next()
|
||||
this.destroyed.next()
|
||||
this.output.complete()
|
||||
this.binaryOutput.complete()
|
||||
await this.gracefullyKillProcess()
|
||||
}
|
||||
}
|
||||
|
||||
abstract start (options: SessionOptions): void
|
||||
abstract resize (columns: number, rows: number): void
|
||||
abstract write (data: string): void
|
||||
abstract write (data: Buffer): void
|
||||
abstract kill (signal?: string): void
|
||||
abstract async getChildProcesses (): Promise<ChildProcess[]>
|
||||
abstract async gracefullyKillProcess (): Promise<void>
|
||||
@@ -129,6 +134,7 @@ export class Session extends BaseSession {
|
||||
name: 'xterm-256color',
|
||||
cols: options.width || 80,
|
||||
rows: options.height || 30,
|
||||
encoding: null,
|
||||
cwd,
|
||||
env: env,
|
||||
// `1` instead of `true` forces ConPTY even if unstable
|
||||
@@ -150,11 +156,11 @@ export class Session extends BaseSession {
|
||||
|
||||
this.open = true
|
||||
|
||||
this.pty.on('data-buffered', data => {
|
||||
this.pty.on('data-buffered', (data: Buffer) => {
|
||||
data = this.processOSC1337(data)
|
||||
this.emitOutput(data)
|
||||
if (process.platform === 'win32') {
|
||||
this.guessWindowsCWD(data)
|
||||
this.guessWindowsCWD(data.toString())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -168,7 +174,7 @@ export class Session extends BaseSession {
|
||||
|
||||
this.pty.on('close', () => {
|
||||
if (this.pauseAfterExit) {
|
||||
this.emitOutput('\r\nPress any key to close\r\n')
|
||||
this.emitOutput(Buffer.from('\r\nPress any key to close\r\n'))
|
||||
} else if (this.open) {
|
||||
this.destroy()
|
||||
}
|
||||
@@ -177,19 +183,19 @@ export class Session extends BaseSession {
|
||||
this.pauseAfterExit = options.pauseAfterExit || false
|
||||
}
|
||||
|
||||
processOSC1337 (data: string) {
|
||||
processOSC1337 (data: Buffer) {
|
||||
if (data.includes(OSC1337Prefix)) {
|
||||
const preData = data.substring(0, data.indexOf(OSC1337Prefix))
|
||||
let params = data.substring(data.indexOf(OSC1337Prefix) + OSC1337Prefix.length)
|
||||
const postData = params.substring(params.indexOf(OSC1337Suffix) + OSC1337Suffix.length)
|
||||
params = params.substring(0, params.indexOf(OSC1337Suffix))
|
||||
const preData = data.subarray(0, data.indexOf(OSC1337Prefix))
|
||||
let params = data.subarray(data.indexOf(OSC1337Prefix) + OSC1337Prefix.length)
|
||||
const postData = params.subarray(params.indexOf(OSC1337Suffix) + OSC1337Suffix.length)
|
||||
const paramString = params.subarray(0, params.indexOf(OSC1337Suffix)).toString()
|
||||
|
||||
if (params.startsWith('CurrentDir=')) {
|
||||
this.reportedCWD = params.split('=')[1]
|
||||
if (paramString.startsWith('CurrentDir=')) {
|
||||
this.reportedCWD = paramString.split('=')[1]
|
||||
if (this.reportedCWD.startsWith('~')) {
|
||||
this.reportedCWD = os.homedir() + this.reportedCWD.substring(1)
|
||||
}
|
||||
data = preData + postData
|
||||
data = Buffer.concat([preData, postData])
|
||||
}
|
||||
}
|
||||
return data
|
||||
@@ -201,10 +207,10 @@ export class Session extends BaseSession {
|
||||
}
|
||||
}
|
||||
|
||||
write (data) {
|
||||
write (data: Buffer) {
|
||||
if (this.open) {
|
||||
if (this.pty._writable) {
|
||||
this.pty.write(Buffer.from(data, 'utf-8'))
|
||||
this.pty.write(data)
|
||||
} else {
|
||||
this.destroy()
|
||||
}
|
||||
@@ -255,15 +261,15 @@ export class Session extends BaseSession {
|
||||
await new Promise((resolve) => {
|
||||
this.kill('SIGTERM')
|
||||
setImmediate(() => {
|
||||
if (!this.open) {
|
||||
resolve()
|
||||
} else {
|
||||
try {
|
||||
process.kill(this.pty.pid, 0)
|
||||
// still alive
|
||||
setTimeout(() => {
|
||||
if (this.open) {
|
||||
this.kill('SIGKILL')
|
||||
}
|
||||
this.kill('SIGKILL')
|
||||
resolve()
|
||||
}, 1000)
|
||||
} catch {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -292,7 +298,7 @@ export class Session extends BaseSession {
|
||||
}
|
||||
if (process.platform === 'linux') {
|
||||
try {
|
||||
return await fs.readlink(`/proc/${this.truePID}/cwd`)
|
||||
return fs.readlink(`/proc/${this.truePID}/cwd`)
|
||||
} catch (exc) {
|
||||
console.error(exc)
|
||||
return null
|
||||
|
@@ -88,7 +88,11 @@ export class TerminalService {
|
||||
cwd: cwd || undefined,
|
||||
}
|
||||
|
||||
return this.openTabWithOptions(sessionOptions)
|
||||
const tab = this.openTabWithOptions(sessionOptions)
|
||||
if (profile?.color) {
|
||||
(this.app.getParentTab(tab) || tab).color = profile.color
|
||||
}
|
||||
return tab
|
||||
}
|
||||
|
||||
optionsFromShell (shell: Shell): SessionOptions {
|
||||
|
@@ -35,6 +35,7 @@ export class Cygwin32ShellProvider extends ShellProvider {
|
||||
id: 'cygwin32',
|
||||
name: 'Cygwin (32 bit)',
|
||||
command: path.join(cygwinPath, 'bin', 'bash.exe'),
|
||||
args: ['--login', '-i'],
|
||||
icon: require('../icons/cygwin.svg'),
|
||||
env: {
|
||||
TERM: 'cygwin',
|
||||
|
@@ -35,6 +35,7 @@ export class Cygwin64ShellProvider extends ShellProvider {
|
||||
id: 'cygwin64',
|
||||
name: 'Cygwin',
|
||||
command: path.join(cygwinPath, 'bin', 'bash.exe'),
|
||||
args: ['--login', '-i'],
|
||||
icon: require('../icons/cygwin.svg'),
|
||||
env: {
|
||||
TERM: 'cygwin',
|
||||
|
@@ -14,6 +14,19 @@ try {
|
||||
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
} catch { }
|
||||
|
||||
// WSL Distribution List
|
||||
// https://docs.microsoft.com/en-us/windows/wsl/install-win10#install-your-linux-distribution-of-choice
|
||||
var wslIconMap: { [key: string]: string } = {
|
||||
'Alpine': 'alpine.svg',
|
||||
'Debian': 'debian.svg',
|
||||
'kali-linux': 'linux.svg',
|
||||
'SLES-12': 'suse.svg',
|
||||
'openSUSE-Leap-15-1': 'suse.svg',
|
||||
'Ubuntu-18.04': 'ubuntu.svg',
|
||||
'Ubuntu': 'ubuntu.svg',
|
||||
'Linux': 'linux.svg',
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class WSLShellProvider extends ShellProvider {
|
||||
@@ -31,23 +44,35 @@ export class WSLShellProvider extends ShellProvider {
|
||||
const bashPath = `${process.env.windir}\\system32\\bash.exe`
|
||||
const wslPath = `${process.env.windir}\\system32\\wsl.exe`
|
||||
|
||||
const shells: Shell[] = [{
|
||||
id: 'wsl',
|
||||
name: 'WSL / Default distro',
|
||||
command: wslPath,
|
||||
env: {
|
||||
TERM: 'xterm-color',
|
||||
COLORTERM: 'truecolor',
|
||||
},
|
||||
}]
|
||||
|
||||
const lxssPath = 'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss'
|
||||
const lxss = wnr.getRegistryKey(wnr.HK.CU, lxssPath)
|
||||
const shells: Shell[] = []
|
||||
|
||||
if (null != lxss && null != lxss.DefaultDistribution) {
|
||||
const defaultDistKey = wnr.getRegistryKey(wnr.HK.CU, lxssPath + '\\' + String(lxss.DefaultDistribution.value))
|
||||
if (defaultDistKey.DistributionName) {
|
||||
const shell: Shell = {
|
||||
id: 'wsl',
|
||||
name: 'WSL / Default distro',
|
||||
command: wslPath,
|
||||
env: {
|
||||
TERM: 'xterm-color',
|
||||
COLORTERM: 'truecolor',
|
||||
},
|
||||
}
|
||||
if (wslIconMap.hasOwnProperty(defaultDistKey.DistributionName.value)) {
|
||||
shell['icon'] = require(`../icons/${wslIconMap[defaultDistKey.DistributionName.value]}`)
|
||||
}
|
||||
shells.push(shell)
|
||||
}
|
||||
}
|
||||
|
||||
if (!lxss || !lxss.DefaultDistribution || !isWindowsBuild(WIN_BUILD_WSL_EXE_DISTRO_FLAG)) {
|
||||
if (await fs.exists(bashPath)) {
|
||||
return [{
|
||||
id: 'wsl',
|
||||
name: 'WSL / Bash on Windows',
|
||||
icon: require(`../icons/${wslIconMap['linux']}`),
|
||||
command: bashPath,
|
||||
env: {
|
||||
TERM: 'xterm-color',
|
||||
@@ -64,7 +89,7 @@ export class WSLShellProvider extends ShellProvider {
|
||||
continue
|
||||
}
|
||||
const name = childKey.DistributionName.value
|
||||
shells.push({
|
||||
const shell: Shell = {
|
||||
id: `wsl-${slug(name)}`,
|
||||
name: `WSL / ${name}`,
|
||||
command: wslPath,
|
||||
@@ -74,7 +99,11 @@ export class WSLShellProvider extends ShellProvider {
|
||||
TERM: 'xterm-color',
|
||||
COLORTERM: 'truecolor',
|
||||
},
|
||||
})
|
||||
}
|
||||
if (wslIconMap.hasOwnProperty(name)) {
|
||||
shell['icon'] = require(`../icons/${wslIconMap[name]}`)
|
||||
}
|
||||
shells.push(shell)
|
||||
}
|
||||
|
||||
return shells
|
||||
|
@@ -1,7 +1,11 @@
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { Injectable, NgZone, Optional, Inject } from '@angular/core'
|
||||
import { ToastrService } from 'ngx-toastr'
|
||||
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider } from 'terminus-core'
|
||||
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent } from 'terminus-core'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
import { UACService } from './services/uac.service'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
@@ -14,11 +18,11 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
if (!(tab instanceof TerminalTabComponent)) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
const items: Electron.MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'Save as profile',
|
||||
click: () => this.zone.run(async () => {
|
||||
@@ -38,5 +42,141 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
|
||||
}),
|
||||
},
|
||||
]
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class NewTabContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private zone: NgZone,
|
||||
private terminalService: TerminalService,
|
||||
private uac: UACService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
const profiles = await this.terminalService.getProfiles()
|
||||
|
||||
const items: Electron.MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'New terminal',
|
||||
click: () => this.zone.run(() => {
|
||||
this.terminalService.openTabWithOptions((tab as any).sessionOptions)
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'New with profile',
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: () => this.zone.run(async () => {
|
||||
let workingDirectory = this.config.store.terminal.workingDirectory
|
||||
if (this.config.store.terminal.alwaysUseWorkingDirectory !== true && tab instanceof TerminalTabComponent) {
|
||||
workingDirectory = await tab.session.getWorkingDirectory()
|
||||
}
|
||||
await this.terminalService.openTab(profile, workingDirectory)
|
||||
}),
|
||||
})),
|
||||
},
|
||||
]
|
||||
|
||||
if (this.uac.isAvailable) {
|
||||
items.push({
|
||||
label: 'New admin tab',
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: () => this.zone.run(async () => {
|
||||
this.terminalService.openTabWithOptions({
|
||||
...profile.sessionOptions,
|
||||
runAsAdministrator: true,
|
||||
})
|
||||
}),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof TerminalTabComponent && tabHeader && this.uac.isAvailable) {
|
||||
items.push({
|
||||
label: 'Duplicate as administrator',
|
||||
click: () => this.zone.run(async () => {
|
||||
this.terminalService.openTabWithOptions({
|
||||
...(tab as TerminalTabComponent).sessionOptions,
|
||||
runAsAdministrator: true,
|
||||
})
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CopyPasteContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
private zone: NgZone,
|
||||
private toastr: ToastrService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
if (tabHeader) {
|
||||
return []
|
||||
}
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
return [
|
||||
{
|
||||
label: 'Copy',
|
||||
click: () => {
|
||||
this.zone.run(() => {
|
||||
setTimeout(() => {
|
||||
(tab as BaseTerminalTabComponent).frontend.copySelection()
|
||||
this.toastr.info('Copied')
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
click: () => {
|
||||
this.zone.run(() => (tab as BaseTerminalTabComponent).paste())
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class LegacyContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
@Optional() @Inject(TerminalContextMenuItemProvider) protected contextMenuProviders: TerminalContextMenuItemProvider[],
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
let items: Electron.MenuItemConstructorOptions[] = []
|
||||
for (const p of this.contextMenuProviders) {
|
||||
items = items.concat(await p.getItems(tab))
|
||||
}
|
||||
return items
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
179
terminus-terminal/src/zmodem.ts
Normal file
179
terminus-terminal/src/zmodem.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import * as ZModem from 'zmodem.js'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TerminalDecorator } from './api/decorator'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
import { LogService, Logger, ElectronService, HostAppService } from 'terminus-core'
|
||||
|
||||
const SPACER = ' '
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ZModemDecorator extends TerminalDecorator {
|
||||
private subscriptions: Subscription[] = []
|
||||
private logger: Logger
|
||||
private activeSession: any = null
|
||||
|
||||
constructor (
|
||||
log: LogService,
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
super()
|
||||
this.logger = log.create('zmodem')
|
||||
}
|
||||
|
||||
attach (terminal: TerminalTabComponent): void {
|
||||
const sentry = new ZModem.Sentry({
|
||||
to_terminal: data => {
|
||||
if (!terminal.enablePassthrough) {
|
||||
terminal.write(data)
|
||||
}
|
||||
},
|
||||
sender: data => terminal.session.write(Buffer.from(data)),
|
||||
on_detect: async detection => {
|
||||
try {
|
||||
terminal.enablePassthrough = false
|
||||
await this.process(terminal, detection)
|
||||
} finally {
|
||||
terminal.enablePassthrough = true
|
||||
}
|
||||
},
|
||||
on_retract: () => {
|
||||
this.showMessage(terminal, 'transfer cancelled')
|
||||
},
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.subscriptions = [
|
||||
terminal.session.binaryOutput$.subscribe(data => {
|
||||
const chunkSize = 1024
|
||||
for (let i = 0; i <= Math.floor(data.length / chunkSize); i++) {
|
||||
try {
|
||||
sentry.consume(data.subarray(i * chunkSize, (i + 1) * chunkSize))
|
||||
} catch (e) {
|
||||
this.logger.error('protocol error', e)
|
||||
this.activeSession.abort()
|
||||
this.activeSession = null
|
||||
terminal.enablePassthrough = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
async process (terminal, detection) {
|
||||
this.showMessage(terminal, '[Terminus] ZModem session started')
|
||||
const zsession = detection.confirm()
|
||||
this.activeSession = zsession
|
||||
this.logger.info('new session', zsession)
|
||||
|
||||
if (zsession.type === 'send') {
|
||||
const result = await this.electron.dialog.showOpenDialog(
|
||||
this.hostApp.getWindow(),
|
||||
{
|
||||
buttonLabel: 'Send',
|
||||
properties: ['multiSelections', 'openFile', 'treatPackageAsDirectory'],
|
||||
},
|
||||
)
|
||||
if (result.canceled) {
|
||||
zsession.close()
|
||||
return
|
||||
}
|
||||
|
||||
let filesRemaining = result.filePaths.length
|
||||
for (const filePath of result.filePaths) {
|
||||
await this.sendFile(terminal, zsession, filePath, filesRemaining)
|
||||
filesRemaining--
|
||||
}
|
||||
this.activeSession = null
|
||||
await zsession.close()
|
||||
} else {
|
||||
zsession.on('offer', xfer => {
|
||||
this.receiveFile(terminal, xfer)
|
||||
})
|
||||
|
||||
zsession.start()
|
||||
|
||||
await new Promise(resolve => zsession.on('session_end', resolve))
|
||||
this.activeSession = null
|
||||
}
|
||||
}
|
||||
|
||||
detach (_terminal: TerminalTabComponent): void {
|
||||
for (const s of this.subscriptions) {
|
||||
s.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
private async receiveFile (terminal, xfer) {
|
||||
const details = xfer.get_details()
|
||||
this.showMessage(terminal, `🟡 Offered ${details.name}`, true)
|
||||
this.logger.info('offered', xfer)
|
||||
const result = await this.electron.dialog.showSaveDialog(
|
||||
this.hostApp.getWindow(),
|
||||
{
|
||||
defaultPath: details.name,
|
||||
},
|
||||
)
|
||||
if (!result.filePath) {
|
||||
this.showMessage(terminal, `🔴 Rejected ${details.name}`)
|
||||
xfer.skip()
|
||||
return
|
||||
}
|
||||
const stream = fs.createWriteStream(result.filePath)
|
||||
let bytesSent = 0
|
||||
await xfer.accept({
|
||||
on_input: chunk => {
|
||||
stream.write(Buffer.from(chunk))
|
||||
bytesSent += chunk.length
|
||||
this.showMessage(terminal, `🟡 Receiving ${details.name}: ${Math.round(100 * bytesSent / details.size)}%`, true)
|
||||
},
|
||||
})
|
||||
this.showMessage(terminal, `✅ Received ${details.name}`)
|
||||
stream.end()
|
||||
}
|
||||
|
||||
private async sendFile (terminal, zsession, filePath, filesRemaining) {
|
||||
const stat = fs.statSync(filePath)
|
||||
const offer = {
|
||||
name: path.basename(filePath),
|
||||
size: stat.size,
|
||||
mode: stat.mode,
|
||||
mtime: Math.floor(stat.mtimeMs / 1000),
|
||||
files_remaining: filesRemaining,
|
||||
bytes_remaining: stat.size,
|
||||
}
|
||||
this.logger.info('offering', offer)
|
||||
this.showMessage(terminal, `🟡 Offering ${offer.name}`, true)
|
||||
|
||||
const xfer = await zsession.send_offer(offer)
|
||||
if (xfer) {
|
||||
let bytesSent = 0
|
||||
const stream = fs.createReadStream(filePath)
|
||||
stream.on('data', chunk => {
|
||||
xfer.send(chunk)
|
||||
bytesSent += chunk.length
|
||||
this.showMessage(terminal, `🟡 Sending ${offer.name}: ${Math.round(100 * bytesSent / offer.size)}%`, true)
|
||||
})
|
||||
await new Promise(resolve => stream.on('end', resolve))
|
||||
await xfer.end()
|
||||
stream.close()
|
||||
this.showMessage(terminal, `✅ Sent ${offer.name}`)
|
||||
} else {
|
||||
this.showMessage(terminal, `🔴 Other side rejected ${offer.name}`)
|
||||
this.logger.warn('rejected by the other side')
|
||||
}
|
||||
}
|
||||
|
||||
private showMessage (terminal, msg: string, overwrite = false) {
|
||||
terminal.write(Buffer.from(`\r${msg}${SPACER}`))
|
||||
if (!overwrite) {
|
||||
terminal.write(Buffer.from('\r\n'))
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,6 +22,14 @@ connected-domain@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/connected-domain/-/connected-domain-1.0.0.tgz#bfe77238c74be453a79f0cb6058deeb4f2358e93"
|
||||
integrity sha1-v+dyOMdL5FOnnwy2BY3utPI1jpM=
|
||||
|
||||
crc-32@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
|
||||
integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==
|
||||
dependencies:
|
||||
exit-on-epipe "~1.0.1"
|
||||
printj "~1.1.0"
|
||||
|
||||
dataurl@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/dataurl/-/dataurl-0.1.0.tgz#1f4734feddec05ffe445747978d86759c4b33199"
|
||||
@@ -46,6 +54,11 @@ define-properties@^1.1.2:
|
||||
dependencies:
|
||||
object-keys "^1.0.12"
|
||||
|
||||
exit-on-epipe@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
|
||||
integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
|
||||
|
||||
font-finder@^1.0.3, font-finder@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/font-finder/-/font-finder-1.0.4.tgz#2ca944954dd8d0e1b5bdc4c596cc08607761d89b"
|
||||
@@ -141,6 +154,11 @@ opentype.js@^0.8.0:
|
||||
dependencies:
|
||||
tiny-inflate "^1.0.2"
|
||||
|
||||
printj@~1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
|
||||
integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
|
||||
|
||||
promise-stream-reader@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/promise-stream-reader/-/promise-stream-reader-1.0.1.tgz#4e793a79c9d49a73ccd947c6da9c127f12923649"
|
||||
@@ -170,10 +188,10 @@ runes@^0.4.2:
|
||||
resolved "https://registry.yarnpkg.com/runes/-/runes-0.4.3.tgz#32f7738844bc767b65cc68171528e3373c7bb355"
|
||||
integrity sha512-K6p9y4ZyL9wPzA+PMDloNQPfoDGTiFYDvdlXznyGKgD10BJpcAosvATKrExRKOrNLgD8E7Um7WGW0lxsnOuNLg==
|
||||
|
||||
slug@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/slug/-/slug-1.1.0.tgz#73eef5710416f515077bdf70c683bde4915913c9"
|
||||
integrity sha512-NuIOjDQeTMPm+/AUIHJ5636mF3jOsYLFnoEErl9Tdpt4kpt4fOrAJxscH9mUgX1LtPaEqgPCawBg7A4yhoSWRg==
|
||||
slug@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/slug/-/slug-2.1.0.tgz#293f8d53de7e55c15871846fd1bc36114841a8c7"
|
||||
integrity sha512-Q4foEgcE7E8UB/BFg4kEzFUICoppzsbbfRjrdKiOM4Z4EFZF5tdn6amkgeaGur3kI4lMWP2BoMv7XJcKZvLg9Q==
|
||||
dependencies:
|
||||
unicode ">= 0.3.1"
|
||||
|
||||
@@ -209,9 +227,9 @@ tiny-inflate@^1.0.2:
|
||||
integrity sha512-+cHtykLb+eF1yrSLWTwcYBrqJkTfX7Quoyg7Juhe6uylF43ZbMdxMuSHNYlnyLT8T7POAvavgBthzUF9AIaQvQ==
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
xterm-addon-fit@^0.4.0-beta2:
|
||||
version "0.4.0-beta2"
|
||||
@@ -226,22 +244,29 @@ xterm-addon-ligatures@^0.2.1:
|
||||
font-finder "^1.0.4"
|
||||
font-ligatures "^1.3.2"
|
||||
|
||||
xterm-addon-search@^0.4.0-beta5:
|
||||
version "0.4.0-beta5"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta5.tgz#d7b7d35502cc5155d35175ab63e0465c1447eebd"
|
||||
integrity sha512-aA+WmoM6U8H9V4ofKLaZaTBFoRLdxVujWA2mQxbzXBF8FLLCDSJOK8kEor4BSb8OtGr0Nlfs1Qy9O0HBmXSQWA==
|
||||
xterm-addon-search@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1"
|
||||
integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg==
|
||||
|
||||
xterm-addon-webgl@^0.4.0-beta.15:
|
||||
version "0.4.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.4.0-beta.15.tgz#a85a6f2374e1d3c9227bb3a9741ae1f126bafa47"
|
||||
integrity sha512-zsD6av31hRQh1yeY3XjRZIvPZdrqAPixvKz2Rczi1ZVwGl1IrXdMeAN2gofNej5ao09v/jfnherCmqEpsVIISw==
|
||||
xterm-addon-webgl@^0.5.0-beta.7:
|
||||
version "0.5.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0-beta.7.tgz#b7b95a362e942ad6f86fa286d7b7bd8ee3e7cf67"
|
||||
integrity sha512-v6aCvhm1C6mvaurGwUYQfyhb2cAUyuVnzf3Ob/hy5ebtyzUj4wW0N9NbqDEJk67UeMi1lV2xZqrO5gNeTpVqFA==
|
||||
|
||||
xterm@4.3.0-beta.30:
|
||||
version "4.3.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0-beta.30.tgz#2cdb5e21fece98a5f4fe70d13ccebbb50c639bae"
|
||||
integrity sha512-3ojuqTigSwvfq607O5UAcdAt6Clg0Y5+Fq6u5qEWNjd69G84tOqJVVogqTn0QON87OeiQN3ibQiBdi/+4xZ2KA==
|
||||
xterm@^4.4.0-beta.15:
|
||||
version "4.4.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0-beta.15.tgz#5897bf79d29d1a2496ccd54665aded28c341b1cc"
|
||||
integrity sha512-Dvz1CMCYKeoxPF7uIDznbRgUA2Mct49Bq93K2nnrDU0pDMM3Sf1t9fkEyz59wxSx5XEHVdLS80jywsz4sjXBjQ==
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||
|
||||
zmodem.js@^0.1.9:
|
||||
version "0.1.9"
|
||||
resolved "https://registry.yarnpkg.com/zmodem.js/-/zmodem.js-0.1.9.tgz#8dda36d45091bbdf263819f961d3c1a20223daf7"
|
||||
integrity sha512-xixLjW1eML0uiWULsXDInyfwNW9mqESzz7ra+2MWHNG2F5JINEkE5vzF5MigpPcLvrYoHdnehPcJwQZlDph3hQ==
|
||||
dependencies:
|
||||
crc-32 "^1.1.1"
|
||||
|
565
yarn.lock
565
yarn.lock
@@ -46,10 +46,10 @@
|
||||
global-agent "^2.0.2"
|
||||
global-tunnel-ng "^2.7.1"
|
||||
|
||||
"@fortawesome/fontawesome-free@^5.11.2":
|
||||
version "5.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.11.2.tgz#8644bc25b19475779a7b7c1fc104bc0a794f4465"
|
||||
integrity sha512-XiUPoS79r1G7PcpnNtq85TJ7inJWe0v+b5oZJZKb0pGHNIV6+UiNeQWiFGmuQ0aj7GEhnD/v9iqxIsjuRKtEnQ==
|
||||
"@fortawesome/fontawesome-free@^5.12.0":
|
||||
version "5.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.12.0.tgz#8ceb9f09edfb85ea18a6c7bf098f6f5dd5ffd62b"
|
||||
integrity sha512-vKDJUuE2GAdBERaQWmmtsciAMzjwNrROXA5KTGSZvayAsmuTGjam5z6QNqNPCwDfVljLWuov1nEC3mEQf/n6fQ==
|
||||
|
||||
"@sentry/browser@~5.7.1":
|
||||
version "5.7.1"
|
||||
@@ -224,45 +224,54 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
|
||||
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
|
||||
|
||||
"@types/webpack-env@1.14.1":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7"
|
||||
integrity sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA==
|
||||
"@types/webpack-env@1.15.0":
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.15.0.tgz#bd9956d5044b1fb43e869a9ba9148862ff98d9fd"
|
||||
integrity sha512-TfcyNecCz8Z9/s90gBOBniyzZrTru8u2Vp0VZODq4KEBaQu8bfXvu7o/KUOecMpzjbFPUA7aqgSq628Iue5BQg==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.8.0.tgz#eca584d46094ebebc3cb3e9fb625bfbc904a534d"
|
||||
integrity sha512-ohqul5s6XEB0AzPWZCuJF5Fd6qC0b4+l5BGEnrlpmvXxvyymb8yw8Bs4YMF8usNAeuCJK87eFIHy8g8GFvOtGA==
|
||||
"@typescript-eslint/eslint-plugin@^2.13.0":
|
||||
version "2.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.13.0.tgz#57e933fe16a2fc66dbac059af0d6d85d921d748e"
|
||||
integrity sha512-QoiANo0MMGNa8ej/yX3BrW5dZj5d8HYcKiM2fyYUlezECqn8Xc7T/e4EUdiGinn8jhBrn+9X47E9TWaaup3u1g==
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "2.8.0"
|
||||
"@typescript-eslint/experimental-utils" "2.13.0"
|
||||
eslint-utils "^1.4.3"
|
||||
functional-red-black-tree "^1.0.1"
|
||||
regexpp "^3.0.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/experimental-utils@2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.8.0.tgz#208b4164d175587e9b03ce6fea97d55f19c30ca9"
|
||||
integrity sha512-jZ05E4SxCbbXseQGXOKf3ESKcsGxT8Ucpkp1jiVp55MGhOvZB2twmWKf894PAuVQTCgbPbJz9ZbRDqtUWzP8xA==
|
||||
"@typescript-eslint/experimental-utils@2.13.0":
|
||||
version "2.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.13.0.tgz#958614faa6f77599ee2b241740e0ea402482533d"
|
||||
integrity sha512-+Hss3clwa6aNiC8ZjA45wEm4FutDV5HsVXPl/rDug1THq6gEtOYRGLqS3JlTk7mSnL5TbJz0LpEbzbPnKvY6sw==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.8.0"
|
||||
"@typescript-eslint/typescript-estree" "2.13.0"
|
||||
eslint-scope "^5.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.8.0.tgz#e10f7c40c8cf2fb19920c879311e6c46ad17bacb"
|
||||
integrity sha512-NseXWzhkucq+JM2HgqAAoKEzGQMb5LuTRjFPLQzGIdLthXMNUfuiskbl7QSykvWW6mvzCtYbw1fYWGa2EIaekw==
|
||||
"@typescript-eslint/experimental-utils@2.17.0":
|
||||
version "2.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.17.0.tgz#12ed4a5d656e02ff47a93efc7d1ce1b8f1242351"
|
||||
integrity sha512-2bNf+mZ/3mj5/3CP56v+ldRK3vFy9jOvmCPs/Gr2DeSJh+asPZrhFniv4QmQsHWQFPJFWhFHgkGgJeRmK4m8iQ==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.17.0"
|
||||
eslint-scope "^5.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.17.0":
|
||||
version "2.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.17.0.tgz#627f79586d868edbab55f46a6b183cdc341aea1d"
|
||||
integrity sha512-k1g3gRQ4fwfJoIfgUpz78AovicSWKFANmvTfkAHP24MgJHjWfZI6ya7tsQZt1sLczvP4G9BE5G5MgADHdmJB/w==
|
||||
dependencies:
|
||||
"@types/eslint-visitor-keys" "^1.0.0"
|
||||
"@typescript-eslint/experimental-utils" "2.8.0"
|
||||
"@typescript-eslint/typescript-estree" "2.8.0"
|
||||
"@typescript-eslint/experimental-utils" "2.17.0"
|
||||
"@typescript-eslint/typescript-estree" "2.17.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.8.0":
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.8.0.tgz#fcc3fe6532840085d29b75432c8a59895876aeca"
|
||||
integrity sha512-ksvjBDTdbAQ04cR5JyFSDX113k66FxH1tAXmi+dj6hufsl/G0eMc/f1GgLjEVPkYClDbRKv+rnBFuE5EusomUw==
|
||||
"@typescript-eslint/typescript-estree@2.13.0":
|
||||
version "2.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.13.0.tgz#a2e746867da772c857c13853219fced10d2566bc"
|
||||
integrity sha512-t21Mg5cc8T3ADEUGwDisHLIubgXKjuNRbkpzDMLb7/JMmgCe/gHM9FaaujokLey+gwTuLF5ndSQ7/EfQqrQx4g==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
@@ -272,6 +281,19 @@
|
||||
semver "^6.3.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.17.0":
|
||||
version "2.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.17.0.tgz#2ce1531ec0925ef8d22d7026235917c2638a82af"
|
||||
integrity sha512-g0eVRULGnEEUakxRfJO0s0Hr1LLQqsI6OrkiCLpdHtdJJek+wyd8mb00vedqAoWldeDcOcP8plqw8/jx9Gr3Lw==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
glob "^7.1.6"
|
||||
is-glob "^4.0.1"
|
||||
lodash "^4.17.15"
|
||||
semver "^6.3.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@webassemblyjs/ast@1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
|
||||
@@ -694,6 +716,14 @@ array-unique@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
|
||||
|
||||
array.prototype.flat@^1.2.1:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
|
||||
integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.1"
|
||||
|
||||
asap@^2.0.0, asap@~2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
@@ -1556,10 +1586,10 @@ core-js@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
|
||||
|
||||
core-js@^3.3.3, core-js@^3.4.2:
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.4.2.tgz#ee2b1a60b50388d8ddcda8cdb44a92c7a9ea76df"
|
||||
integrity sha512-bUTfqFWtNKWp73oNIfRkqwYZJeNT3lstzZcAkhhiuvDraRSgOH1/+F9ZklbpR4zpdKuo4cpXN8tKP7s61yjX+g==
|
||||
core-js@^3.3.3, core-js@^3.6.4:
|
||||
version "3.6.4"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
|
||||
integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -1579,12 +1609,6 @@ cross-env@6.0.3:
|
||||
dependencies:
|
||||
cross-spawn "^7.0.0"
|
||||
|
||||
cross-spawn-promise@^0.10.1:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn-promise/-/cross-spawn-promise-0.10.1.tgz#db9cb4c50c60b72a15be049b78122ce382d87b10"
|
||||
dependencies:
|
||||
cross-spawn "^5.1.0"
|
||||
|
||||
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
@@ -1602,7 +1626,7 @@ cross-spawn@^3.0.0:
|
||||
lru-cache "^4.0.1"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
|
||||
cross-spawn@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||
dependencies:
|
||||
@@ -1619,6 +1643,15 @@ cross-spawn@^7.0.0:
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
|
||||
integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
cryptiles@2.x.x:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
|
||||
@@ -1629,23 +1662,23 @@ crypto-random-string@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
||||
|
||||
css-loader@3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2"
|
||||
integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ==
|
||||
css-loader@3.4.2:
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202"
|
||||
integrity sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==
|
||||
dependencies:
|
||||
camelcase "^5.3.1"
|
||||
cssesc "^3.0.0"
|
||||
icss-utils "^4.1.1"
|
||||
loader-utils "^1.2.3"
|
||||
normalize-path "^3.0.0"
|
||||
postcss "^7.0.17"
|
||||
postcss "^7.0.23"
|
||||
postcss-modules-extract-imports "^2.0.0"
|
||||
postcss-modules-local-by-default "^3.0.2"
|
||||
postcss-modules-scope "^2.1.0"
|
||||
postcss-modules-scope "^2.1.1"
|
||||
postcss-modules-values "^3.0.0"
|
||||
postcss-value-parser "^4.0.0"
|
||||
schema-utils "^2.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
schema-utils "^2.6.0"
|
||||
|
||||
css-selector-parser@^1.1.0:
|
||||
version "1.3.0"
|
||||
@@ -1952,35 +1985,32 @@ electron-fetch@1.3.0:
|
||||
dependencies:
|
||||
encoding "^0.1.12"
|
||||
|
||||
electron-installer-common@^0.7.0:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/electron-installer-common/-/electron-installer-common-0.7.3.tgz#95beedc4c6abd287a2f3ef60c545abdf804d90a0"
|
||||
integrity sha512-l4chYFTWr6uWODKYUXeC+Z4tqGa3b8e+Y2WUBf3F7Ruv6yYzZ+Ccic65oXreeotx09B7sUx1KTuwXRsRJHKlMw==
|
||||
electron-installer-common@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-installer-common/-/electron-installer-common-0.10.0.tgz#e57b9cac3637fc312d28f3e45f197f5c1743c931"
|
||||
integrity sha512-oWkkKSrBtsg9rEh1lscRoboNBvA/biZV1L86jwsv8AOhQ6WqMqWPI6xf2HFRNsVDdsHGIldJSpGR4F8ITclerQ==
|
||||
dependencies:
|
||||
asar "^2.0.1"
|
||||
cross-spawn-promise "^0.10.1"
|
||||
cross-spawn "^7.0.1"
|
||||
debug "^4.1.1"
|
||||
fs-extra "^8.0.1"
|
||||
glob "^7.1.4"
|
||||
lodash "^4.17.11"
|
||||
lodash "^4.17.15"
|
||||
parse-author "^2.0.0"
|
||||
semver "^6.0.0"
|
||||
semver "^7.1.1"
|
||||
tmp-promise "^2.0.1"
|
||||
|
||||
electron-installer-snap@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-installer-snap/-/electron-installer-snap-4.1.0.tgz#b36e5d0640144073707d6ce848f94b447beecdbe"
|
||||
integrity sha512-4h9o0/D4tSIj+jje5JlIoNn8zHggVYeNACtZ6w626E4bveoUeQjzq2DOuBiF0+OFo9qvvOGhRjoENMHfXBze4A==
|
||||
electron-installer-snap@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-installer-snap/-/electron-installer-snap-5.0.0.tgz#09553749b367aa6d00c1f92e57d3f3e05daced5a"
|
||||
integrity sha512-M5ADJ7MP3QX1bRfdMZer4B/t5p2fVWciCXkqUs1t3kBSyxEJw4N2jNMydAeJRLend9cbM1E2Jq5+bhPEES85Kg==
|
||||
dependencies:
|
||||
cross-spawn-promise "^0.10.1"
|
||||
debug "^4.1.1"
|
||||
electron-installer-common "^0.7.0"
|
||||
electron-installer-common "^0.10.0"
|
||||
fs-extra "^8.0.1"
|
||||
js-yaml "^3.10.0"
|
||||
lodash.filter "^4.6.0"
|
||||
lodash.merge "^4.6.0"
|
||||
lodash.pull "^4.1.0"
|
||||
semver "^6.1.0"
|
||||
lodash "^4.17.15"
|
||||
semver "^7.1.1"
|
||||
tmp-promise "^2.0.1"
|
||||
which "^2.0.1"
|
||||
yargs "^15.0.1"
|
||||
@@ -2039,25 +2069,25 @@ electron-publish@22.1.0:
|
||||
lazy-val "^1.0.4"
|
||||
mime "^2.4.4"
|
||||
|
||||
electron-rebuild@^1.8.5:
|
||||
version "1.8.6"
|
||||
resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.8.6.tgz#4454ef5517c0588aef9bca0d923ff5633000b949"
|
||||
integrity sha512-4BAPcNG0XP6stByqvFXggrjmf/C47P2L6HFFrWdR2ako1VLiTDIeZAOmU4WEBuWdaXYNqstleszVmcNHdRDojA==
|
||||
electron-rebuild@^1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.9.0.tgz#4ad9d9bc0816b7e52eaffd6520ff62e1d9376d0f"
|
||||
integrity sha512-lnHW+gJIhukqVhME2v+LRDldafWwP0kGOPEpPuj59+F4NHEfu/vOjk8OLBcgDGt72CSWZm7zFUDE07oZxQJbHw==
|
||||
dependencies:
|
||||
colors "^1.3.3"
|
||||
debug "^4.1.1"
|
||||
detect-libc "^1.0.3"
|
||||
fs-extra "^7.0.1"
|
||||
node-abi "^2.9.0"
|
||||
node-gyp "^5.0.1"
|
||||
fs-extra "^8.1.0"
|
||||
node-abi "^2.11.0"
|
||||
node-gyp "^6.0.1"
|
||||
ora "^3.4.0"
|
||||
spawn-rx "^3.0.0"
|
||||
yargs "^13.2.4"
|
||||
|
||||
electron@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-7.1.2.tgz#d1726b9e50b29e97f5f12b52feb225ba87e0640f"
|
||||
integrity sha512-7hjONYt2GlQfKuKgQrhhUL1P9lbGWLBfMUq+2QFU3yeLtCvM0ROfPJCRP4OF5pVp3KDyfFp4DtmhuVzAnxV3jA==
|
||||
electron@^7.1.10:
|
||||
version "7.1.10"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-7.1.10.tgz#35d5aa41ee3f233613e37ef4245b83c23001628b"
|
||||
integrity sha512-UDpS2CfBN3yufCrbET5Ozw1XrLhuANHn+Zs8Vgl/BcBT/MoNbkY79nRFcyxj6pCFrEde9IoNOf+DgNp6altNxw==
|
||||
dependencies:
|
||||
"@electron/get" "^1.0.1"
|
||||
"@types/node" "^12.0.12"
|
||||
@@ -2148,6 +2178,23 @@ es-abstract@^1.12.0, es-abstract@^1.7.0:
|
||||
is-regex "^1.0.4"
|
||||
object-keys "^1.0.12"
|
||||
|
||||
es-abstract@^1.17.0-next.1:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1"
|
||||
integrity sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==
|
||||
dependencies:
|
||||
es-to-primitive "^1.2.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
is-callable "^1.1.5"
|
||||
is-regex "^1.0.5"
|
||||
object-inspect "^1.7.0"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.0"
|
||||
string.prototype.trimleft "^2.1.1"
|
||||
string.prototype.trimright "^2.1.1"
|
||||
|
||||
es-abstract@^1.5.1:
|
||||
version "1.16.2"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.2.tgz#4e874331645e9925edef141e74fc4bd144669d34"
|
||||
@@ -2248,30 +2295,31 @@ eslint-import-resolver-node@^0.3.2:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.5.0"
|
||||
|
||||
eslint-module-utils@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a"
|
||||
integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==
|
||||
eslint-module-utils@^2.4.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz#cdf0b40d623032274ccd2abd7e64c4e524d6e19c"
|
||||
integrity sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==
|
||||
dependencies:
|
||||
debug "^2.6.8"
|
||||
debug "^2.6.9"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
eslint-plugin-import@^2.18.2:
|
||||
version "2.18.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6"
|
||||
integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==
|
||||
eslint-plugin-import@^2.20.0:
|
||||
version "2.20.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa"
|
||||
integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==
|
||||
dependencies:
|
||||
array-includes "^3.0.3"
|
||||
array.prototype.flat "^1.2.1"
|
||||
contains-path "^0.1.0"
|
||||
debug "^2.6.9"
|
||||
doctrine "1.5.0"
|
||||
eslint-import-resolver-node "^0.3.2"
|
||||
eslint-module-utils "^2.4.0"
|
||||
eslint-module-utils "^2.4.1"
|
||||
has "^1.0.3"
|
||||
minimatch "^3.0.4"
|
||||
object.values "^1.1.0"
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.11.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
eslint-scope@^5.0.0:
|
||||
version "5.0.0"
|
||||
@@ -2293,10 +2341,10 @@ eslint-visitor-keys@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
||||
|
||||
eslint@^6.7.1:
|
||||
version "6.7.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.1.tgz#269ccccec3ef60ab32358a44d147ac209154b919"
|
||||
integrity sha512-UWzBS79pNcsDSxgxbdjkmzn/B6BhsXMfUaOHnNwyE8nD+Q6pyT96ow2MccVayUTV4yMid4qLhMiQaywctRkBLA==
|
||||
eslint@^6.8.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
|
||||
integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
ajv "^6.10.0"
|
||||
@@ -2529,10 +2577,10 @@ file-entry-cache@^5.0.1:
|
||||
dependencies:
|
||||
flat-cache "^2.0.1"
|
||||
|
||||
file-loader@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af"
|
||||
integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==
|
||||
file-loader@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-5.0.2.tgz#7f3d8b4ac85a5e8df61338cfec95d7405f971caa"
|
||||
integrity sha512-QMiQ+WBkGLejKe81HU8SZ9PovsU/5uaLo0JdTCEXOYv7i7jfAjHZi1tcwp9tSASJPOmmHZtbdCervFmXMH/Dcg==
|
||||
dependencies:
|
||||
loader-utils "^1.2.3"
|
||||
schema-utils "^2.5.0"
|
||||
@@ -2546,10 +2594,10 @@ fill-range@^4.0.0:
|
||||
repeat-string "^1.6.1"
|
||||
to-regex-range "^2.1.0"
|
||||
|
||||
find-cache-dir@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.1.0.tgz#9935894999debef4cf9f677fdf646d002c4cdecb"
|
||||
integrity sha512-zw+EFiNBNPgI2NTrKkDd1xd7q0cs6wr/iWnr/oUkI0yF9K9GqQ+riIt4aiyFaaqpaWbxPrJXHI+QvmNUQbX+0Q==
|
||||
find-cache-dir@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874"
|
||||
integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==
|
||||
dependencies:
|
||||
commondir "^1.0.1"
|
||||
make-dir "^3.0.0"
|
||||
@@ -2692,15 +2740,6 @@ fs-extra@^4.0.1:
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-extra@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
|
||||
integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-extra@^8.0.1, fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||
@@ -2859,19 +2898,7 @@ glob@^6.0.4:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1, glob@~7.1.2:
|
||||
version "7.1.4"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
|
||||
integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.1.6:
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.2:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
@@ -3012,10 +3039,10 @@ graceful-fs@~4.1.11:
|
||||
version "4.1.15"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||
|
||||
handlebars@^4.5.3:
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
|
||||
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
|
||||
handlebars@^4.5.3, handlebars@^4.7.2:
|
||||
version "4.7.2"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.2.tgz#01127b3840156a0927058779482031afe0e730d7"
|
||||
integrity sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==
|
||||
dependencies:
|
||||
neo-async "^2.6.0"
|
||||
optimist "^0.6.1"
|
||||
@@ -3124,10 +3151,12 @@ he@1.2.x:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
highlight.js@^9.16.2:
|
||||
version "9.16.2"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.16.2.tgz#68368d039ffe1c6211bcc07e483daf95de3e403e"
|
||||
integrity sha512-feMUrVLZvjy0oC7FVJQcSQRqbBq9kwqnYE4+Kj9ZjbHh3g+BisiPgF49NyQbVLNdrL/qqZr3Ca9yOKwgn2i/tw==
|
||||
highlight.js@^9.17.1:
|
||||
version "9.17.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.17.1.tgz#14a4eded23fd314b05886758bb906e39dd627f9a"
|
||||
integrity sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==
|
||||
dependencies:
|
||||
handlebars "^4.5.3"
|
||||
|
||||
hoek@2.x.x:
|
||||
version "2.16.3"
|
||||
@@ -3415,6 +3444,11 @@ is-callable@^1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
|
||||
integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
|
||||
|
||||
is-callable@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
|
||||
integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
|
||||
|
||||
is-ci@^1.0.10:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
|
||||
@@ -3566,6 +3600,13 @@ is-regex@^1.0.3, is-regex@^1.0.4:
|
||||
dependencies:
|
||||
has "^1.0.1"
|
||||
|
||||
is-regex@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
|
||||
integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
is-retry-allowed@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
|
||||
@@ -3893,10 +3934,10 @@ load-json-file@^2.0.0:
|
||||
pify "^2.0.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
loader-runner@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-3.0.0.tgz#c86f303af2dacbd27eabd2ea3aaa957291562e23"
|
||||
integrity sha512-BlinBEAJYOUubaKH9hMxshD1FltYLTd3FA4DoxEh/82C0Rc4cmcqI61bEUj0/osbmW9FCTXTpMAO/jHZDZC5Fw==
|
||||
loader-runner@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-3.1.0.tgz#e9440e5875f2ad2f968489cd2c7b59a4f2847fcb"
|
||||
integrity sha512-wE/bOCdTKMR2rm7Xxh+eirDOmN7Vx7hntWgiTayuFPtF8MgsFDo49SP8kkYz8IVlEBTOtR7P+XI7bE1xjo/IkA==
|
||||
|
||||
loader-utils@1.2.3, loader-utils@^1.0.0, loader-utils@^1.1.0, loader-utils@^1.2.3:
|
||||
version "1.2.3"
|
||||
@@ -3968,19 +4009,6 @@ lodash.clonedeep@~4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
|
||||
lodash.filter@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
|
||||
|
||||
lodash.merge@^4.6.0:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
||||
lodash.pull@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pull/-/lodash.pull-4.1.0.tgz#60060cc6bd625b4d4567ec27dc45cd1be9eec012"
|
||||
|
||||
lodash.unescape@4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
|
||||
@@ -4112,10 +4140,10 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
marked@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
|
||||
integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==
|
||||
marked@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.8.0.tgz#ec5c0c9b93878dc52dd54be8d0e524097bd81a99"
|
||||
integrity sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==
|
||||
|
||||
matcher@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -4401,7 +4429,7 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1:
|
||||
neo-async@^2.6.0, neo-async@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
|
||||
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
|
||||
@@ -4420,7 +4448,7 @@ no-case@^2.2.0:
|
||||
dependencies:
|
||||
lower-case "^1.1.1"
|
||||
|
||||
node-abi@^2.12.0, node-abi@^2.8.0, node-abi@^2.9.0:
|
||||
node-abi@^2.11.0, node-abi@^2.12.0, node-abi@^2.8.0:
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.12.0.tgz#40e9cfabdda1837863fa825e7dfa0b15686adf6f"
|
||||
integrity sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw==
|
||||
@@ -4457,27 +4485,10 @@ node-gyp@^3.8.0:
|
||||
tar "^2.0.0"
|
||||
which "1"
|
||||
|
||||
node-gyp@^5.0.1:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.0.4.tgz#1de243f17b081a6e89f4330967900c816114f8fb"
|
||||
integrity sha512-PMYap4ekQckQDZ2lxoORUF/nX13haU1JdCAlmLgvrykLyN0LFkhfwPbWhYjTxwTruCWbTkeOxFo043kjhmKHZA==
|
||||
dependencies:
|
||||
env-paths "^1.0.0"
|
||||
glob "^7.0.3"
|
||||
graceful-fs "^4.1.2"
|
||||
mkdirp "^0.5.0"
|
||||
nopt "2 || 3"
|
||||
npmlog "0 || 1 || 2 || 3 || 4"
|
||||
request "^2.87.0"
|
||||
rimraf "2"
|
||||
semver "~5.3.0"
|
||||
tar "^4.4.12"
|
||||
which "1"
|
||||
|
||||
node-gyp@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-6.0.1.tgz#d59c4247df61bb343f56e2c41d9c8dc2bc361470"
|
||||
integrity sha512-udHG4hGe3Ji97AYJbJhaRwuSOuQO7KHnE4ZPH3Sox3tjRZ+bkBsDvfZ7eYA1qwD8eLWr//193x806ss3HFTPRw==
|
||||
node-gyp@^6.0.1, node-gyp@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-6.1.0.tgz#64e31c61a4695ad304c1d5b82cf6b7c79cc79f3f"
|
||||
integrity sha512-h4A2zDlOujeeaaTx06r4Vy+8MZ1679lU+wbCKDS4ZtvY2A37DESo37oejIw0mtmR3+rvNwts5B6Kpt1KrNYdNw==
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
glob "^7.1.4"
|
||||
@@ -5229,10 +5240,10 @@ postcss-modules-local-by-default@^3.0.2:
|
||||
postcss-selector-parser "^6.0.2"
|
||||
postcss-value-parser "^4.0.0"
|
||||
|
||||
postcss-modules-scope@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb"
|
||||
integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==
|
||||
postcss-modules-scope@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba"
|
||||
integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==
|
||||
dependencies:
|
||||
postcss "^7.0.6"
|
||||
postcss-selector-parser "^6.0.0"
|
||||
@@ -5254,15 +5265,15 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
|
||||
indexes-of "^1.0.1"
|
||||
uniq "^1.0.1"
|
||||
|
||||
postcss-value-parser@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d"
|
||||
integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==
|
||||
postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9"
|
||||
integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==
|
||||
|
||||
postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.5, postcss@^7.0.6:
|
||||
version "7.0.17"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
|
||||
integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==
|
||||
postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.5, postcss@^7.0.6:
|
||||
version "7.0.23"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.23.tgz#9f9759fad661b15964f3cfc3140f66f1e05eadc1"
|
||||
integrity sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ==
|
||||
dependencies:
|
||||
chalk "^2.4.2"
|
||||
source-map "^0.6.1"
|
||||
@@ -5567,13 +5578,13 @@ qs@~6.5.2:
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
raw-loader@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f"
|
||||
integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==
|
||||
raw-loader@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.0.tgz#d639c40fb9d72b5c7f8abc1fb2ddb25b29d3d540"
|
||||
integrity sha512-iINUOYvl1cGEmfoaLjnZXt4bKfT2LJnZZib5N/LLyAphC+Dd11vNP9CNVb38j+SAJpFI1uo8j9frmih53ASy7Q==
|
||||
dependencies:
|
||||
loader-utils "^1.1.0"
|
||||
schema-utils "^2.0.1"
|
||||
loader-utils "^1.2.3"
|
||||
schema-utils "^2.5.0"
|
||||
|
||||
rc@^1.0.1, rc@^1.1.6, rc@^1.2.1, rc@^1.2.8:
|
||||
version "1.2.8"
|
||||
@@ -5888,9 +5899,10 @@ resolve-url@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
|
||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.5.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
|
||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.5.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.1.tgz#9e018c540fcf0c427d678b9931cbf45e984bcaff"
|
||||
integrity sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
@@ -6035,10 +6047,10 @@ sax@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
|
||||
schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f"
|
||||
integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==
|
||||
schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f"
|
||||
integrity sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==
|
||||
dependencies:
|
||||
ajv "^6.10.2"
|
||||
ajv-keywords "^3.4.1"
|
||||
@@ -6066,11 +6078,16 @@ semver-diff@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.3.0:
|
||||
semver@^6.0.0, semver@^6.1.2, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667"
|
||||
integrity sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A==
|
||||
|
||||
semver@~5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||
@@ -6083,10 +6100,10 @@ serialize-error@^5.0.0:
|
||||
dependencies:
|
||||
type-fest "^0.8.0"
|
||||
|
||||
serialize-javascript@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.0.tgz#9310276819efd0eb128258bb341957f6eb2fc570"
|
||||
integrity sha512-a/mxFfU00QT88umAJQsNWOnUKckhNCqOl028N48e7wFmo2/EHpTo9Wso+iJJCMrQnmFvcjto5RJdAHEvVhcyUQ==
|
||||
serialize-javascript@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
|
||||
integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -6131,10 +6148,22 @@ shebang-command@^1.2.0:
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
||||
dependencies:
|
||||
shebang-regex "^3.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
|
||||
shebang-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
shelljs@0.8.3, shelljs@^0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
|
||||
@@ -6473,6 +6502,14 @@ string.prototype.trimleft@^2.1.0:
|
||||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string.prototype.trimleft@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74"
|
||||
integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string.prototype.trimright@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
|
||||
@@ -6481,6 +6518,14 @@ string.prototype.trimright@^2.1.0:
|
||||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string.prototype.trimright@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9"
|
||||
integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string_decoder@~0.10.x:
|
||||
version "0.10.31"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||
@@ -6554,10 +6599,10 @@ strip-json-comments@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
|
||||
integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
|
||||
|
||||
style-loader@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82"
|
||||
integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==
|
||||
style-loader@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.1.2.tgz#1b519c19faf548df6182b93e72ea1a4156022c2f"
|
||||
integrity sha512-0Mpq1ZHFDCNq1F+6avNBgv+7q8V+mWRuzehxyJT+aKgzyN/yfKTwjYqaYwBgx+11UpQxL21zNQfzzlz+JcGURw==
|
||||
dependencies:
|
||||
loader-utils "^1.2.3"
|
||||
schema-utils "^2.0.1"
|
||||
@@ -6612,10 +6657,10 @@ table@^5.2.3:
|
||||
slice-ansi "^2.1.0"
|
||||
string-width "^3.0.0"
|
||||
|
||||
tapable@2.0.0-beta.8, tapable@^2.0.0-beta.8:
|
||||
version "2.0.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.0.0-beta.8.tgz#0a8d42f6895d43d5a895de15d9a9e3e425f72a0a"
|
||||
integrity sha512-7qMajFcHb2O+aWufLoAvKhEehIwikXUTH1s8RP4R5gSYMIB0Tmypp+J90EtSNVbIlI7oB0Oz8ZlpJUJlZ5owxQ==
|
||||
tapable@2.0.0-beta.9, tapable@^2.0.0-beta.8:
|
||||
version "2.0.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.0.0-beta.9.tgz#638496fb27b53e69c21a0e6a4435afbe805845cb"
|
||||
integrity sha512-+VBUuZXh+WIHnKOeo+A27SB/1sHTVWozcKweDIAhB/XOGnr8cy6ULZjU+qpGxO/G4xEyWCCaWTX/HPEkGg3Xrg==
|
||||
|
||||
tapable@^1.0.0:
|
||||
version "1.1.3"
|
||||
@@ -6678,24 +6723,24 @@ term-size@^1.2.0:
|
||||
dependencies:
|
||||
execa "^0.7.0"
|
||||
|
||||
terser-webpack-plugin@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.2.1.tgz#5569e6c7d8be79e5e43d6da23acc3b6ba77d22bd"
|
||||
integrity sha512-jwdauV5Al7zopR6OAYvIIRcxXCSvLjZjr7uZE8l2tIWb/ryrGN48sJftqGf5k9z09tWhajx53ldp0XPI080YnA==
|
||||
terser-webpack-plugin@^2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.2.tgz#6d3d1b0590c8f729bfbaeb7fb2528b8b62db4c74"
|
||||
integrity sha512-SmvB/6gtEPv+CJ88MH5zDOsZdKXPS/Uzv2//e90+wM1IHFUhsguPKEILgzqrM1nQ4acRXN/SV4Obr55SXC+0oA==
|
||||
dependencies:
|
||||
cacache "^13.0.1"
|
||||
find-cache-dir "^3.0.0"
|
||||
find-cache-dir "^3.2.0"
|
||||
jest-worker "^24.9.0"
|
||||
schema-utils "^2.5.0"
|
||||
serialize-javascript "^2.1.0"
|
||||
schema-utils "^2.6.1"
|
||||
serialize-javascript "^2.1.2"
|
||||
source-map "^0.6.1"
|
||||
terser "^4.3.9"
|
||||
terser "^4.4.3"
|
||||
webpack-sources "^1.4.3"
|
||||
|
||||
terser@^4.3.9:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.0.tgz#22c46b4817cf4c9565434bfe6ad47336af259ac3"
|
||||
integrity sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA==
|
||||
terser@^4.4.3:
|
||||
version "4.6.3"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
|
||||
integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
|
||||
dependencies:
|
||||
commander "^2.20.0"
|
||||
source-map "~0.6.1"
|
||||
@@ -6899,37 +6944,37 @@ typedarray@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
typedoc-default-themes@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.6.1.tgz#e2e471188983df995f4f9df49f713044fced6802"
|
||||
integrity sha512-z5AWKqQDz7igl9WkUuafx8cEm4MPVQGMpbWE+3lwVOaq+U4UoLKBMnpFQWh/4fqQ3bGysXpOstMxy2OOzHezyw==
|
||||
typedoc-default-themes@^0.7.2:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.7.2.tgz#1e9896f920b58e6da0bba9d7e643738d02405a5a"
|
||||
integrity sha512-fiFKlFO6VTqjcno8w6WpTsbCgXmfPHVjnLfYkmByZE7moaz+E2DSpAT+oHtDHv7E0BM5kAhPrHJELP2J2Y2T9A==
|
||||
dependencies:
|
||||
backbone "^1.4.0"
|
||||
jquery "^3.4.1"
|
||||
lunr "^2.3.8"
|
||||
underscore "^1.9.1"
|
||||
|
||||
typedoc@^0.15.3:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.15.3.tgz#8f5a038cfc1160f70cbc57e37908653483dca689"
|
||||
integrity sha512-RGX+dgnm9fyg5KHj81/ZhMiee0FfvJnjBXedhedhMWlrtM4YRv3pn8sYCWRt5TMi1Jli3/JG224pbFo3/3uaGw==
|
||||
typedoc@^0.16.7:
|
||||
version "0.16.7"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.16.7.tgz#00975cbe37fba3a69ec4b42827683303d9c89da9"
|
||||
integrity sha512-sNrLlaZ/aZHxA2rCURGf3g5YabGVwrujiwC6SCV/rgx3LFfZh+goUCatAAyTEDk7evuu6pJ0APGDSde1mSYegw==
|
||||
dependencies:
|
||||
"@types/minimatch" "3.0.3"
|
||||
fs-extra "^8.1.0"
|
||||
handlebars "^4.5.3"
|
||||
highlight.js "^9.16.2"
|
||||
handlebars "^4.7.2"
|
||||
highlight.js "^9.17.1"
|
||||
lodash "^4.17.15"
|
||||
marked "^0.7.0"
|
||||
marked "^0.8.0"
|
||||
minimatch "^3.0.0"
|
||||
progress "^2.0.3"
|
||||
shelljs "^0.8.3"
|
||||
typedoc-default-themes "^0.6.1"
|
||||
typedoc-default-themes "^0.7.2"
|
||||
typescript "3.7.x"
|
||||
|
||||
typescript@3.7.x, typescript@^3.6.4:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
|
||||
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
|
||||
typescript@3.7.x, typescript@^3.7.4:
|
||||
version "3.7.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
|
||||
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
|
||||
|
||||
uglify-js@3.4.x:
|
||||
version "3.4.7"
|
||||
@@ -7084,10 +7129,10 @@ urix@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
|
||||
url-loader@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b"
|
||||
integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==
|
||||
url-loader@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-3.0.0.tgz#9f1f11b371acf6e51ed15a50db635e02eec18368"
|
||||
integrity sha512-a84JJbIA5xTFTWyjjcPdnsu+41o/SNE8SpXMdUvXs6Q+LuhCD9E2+0VCiuDWqgo3GGXVlFHzArDmBpj9PgWn4A==
|
||||
dependencies:
|
||||
loader-utils "^1.2.3"
|
||||
mime "^2.4.4"
|
||||
@@ -7154,13 +7199,13 @@ v8-compile-cache@^2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
||||
integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
|
||||
|
||||
val-loader@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-2.0.1.tgz#e50a88c7198e39b67c098ec78ec3e6721b33d0c4"
|
||||
integrity sha512-0bS1mLDnnoL85YM6PkE5082QOQVZAyRh7MkcW5Oqkh7gwqAgvaO58IGBjHdQYNDicN28yGVxtipHJkzO3NTqIw==
|
||||
val-loader@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-2.1.0.tgz#2e5f50b6d78b318a441f17fb680ec1ddc901a934"
|
||||
integrity sha512-eZmzjMSDiRJygGwEqMav043IJ6TjZE7ofMSRi6CDkeN/tSeTqObC/R43NkrkRTE9jlZO8oLPPJ8pONBf9PApPw==
|
||||
dependencies:
|
||||
loader-utils "^1.2.3"
|
||||
schema-utils "^2.5.0"
|
||||
schema-utils "^2.6.1"
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.4"
|
||||
@@ -7188,14 +7233,13 @@ void-elements@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
|
||||
|
||||
watchpack@2.0.0-beta.10:
|
||||
version "2.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.0.0-beta.10.tgz#6e4a5b16bda08a5a3ce9851f166a45a8860066bb"
|
||||
integrity sha512-JR/S6jbW/hC+xAHG+AxZjkIH/yCxC/yQfCJT8FnZDrZf//tCd6O3wtcEuCkgFmWVERC2IdnlYvmzwa1RJJKg0A==
|
||||
watchpack@2.0.0-beta.12:
|
||||
version "2.0.0-beta.12"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.0.0-beta.12.tgz#bed6878b020c8f43f5b88b7031dfb2b2092755f5"
|
||||
integrity sha512-vUJN6XQCBqrUkyX74WNopUvASMLqgicYGA5nO/FwSfdmLQgrfy44Z+Jl2YHHHXy/gDO6RlbArR26YQGeIWfoAg==
|
||||
dependencies:
|
||||
glob-to-regexp "^0.4.1"
|
||||
graceful-fs "^4.1.2"
|
||||
neo-async "^2.5.0"
|
||||
|
||||
wcwidth@^1.0.0, wcwidth@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -7245,10 +7289,10 @@ webpack-sources@^1.4.3:
|
||||
source-list-map "^2.0.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
webpack@^5.0.0-beta.7:
|
||||
version "5.0.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.0.0-beta.7.tgz#e2dc0ed0543c71e97524be0fcb68a80de50aa898"
|
||||
integrity sha512-ghllYmUzrCJi0Z2dohBXkEqvm7zkd2c4BO9oKfw7gTy8O/YaLr7JVFUki09ca77Xdt0JAbozFeXURlkDJTfDUw==
|
||||
webpack@^5.0.0-beta.12:
|
||||
version "5.0.0-beta.12"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.0.0-beta.12.tgz#3651a0fa6b9ad973b9608305601c08b84c24b402"
|
||||
integrity sha512-a6YqL0l1xQ/B2GcIF1jS6AMlCK7VFoy0O+/2uBK6LjrNX8d85snl0nmEWkBzy9Zwm+orrOZs6deBfkSe6UkHnw==
|
||||
dependencies:
|
||||
"@webassemblyjs/ast" "1.8.5"
|
||||
"@webassemblyjs/helper-module-context" "1.8.5"
|
||||
@@ -7262,14 +7306,15 @@ webpack@^5.0.0-beta.7:
|
||||
glob-to-regexp "^0.4.1"
|
||||
graceful-fs "^4.1.15"
|
||||
json-parse-better-errors "^1.0.2"
|
||||
loader-runner "3.0.0"
|
||||
loader-runner "^3.1.0"
|
||||
loader-utils "^1.2.3"
|
||||
mime "^2.4.4"
|
||||
neo-async "^2.6.1"
|
||||
pkg-dir "^4.2.0"
|
||||
schema-utils "^2.5.0"
|
||||
tapable "2.0.0-beta.8"
|
||||
terser-webpack-plugin "^2.2.1"
|
||||
watchpack "2.0.0-beta.10"
|
||||
tapable "2.0.0-beta.9"
|
||||
terser-webpack-plugin "^2.3.1"
|
||||
watchpack "2.0.0-beta.12"
|
||||
webpack-sources "2.0.0-beta.8"
|
||||
|
||||
which-module@^1.0.0:
|
||||
|
Reference in New Issue
Block a user