mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-22 09:11:50 +00:00
Compare commits
1 Commits
commands
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fc6b822297 |
@@ -635,10 +635,10 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"login": "0x973",
|
"login": "X-0x01",
|
||||||
"name": "0x973",
|
"name": "X-0x01",
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/19320096?v=4",
|
"avatar_url": "https://avatars.githubusercontent.com/u/19320096?v=4",
|
||||||
"profile": "https://github.com/0x973",
|
"profile": "http://pingbase.cn",
|
||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
@@ -1220,69 +1220,6 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "siebsie23",
|
|
||||||
"name": "Sibren",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/25083973?v=4",
|
|
||||||
"profile": "https://siebsie23.nl/",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "nwalser",
|
|
||||||
"name": "Nathaniel Walser",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/33339996?v=4",
|
|
||||||
"profile": "https://www.nathaniel-walser.com",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "aaronhuggins",
|
|
||||||
"name": "Aaron Huggins",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/16567111?v=4",
|
|
||||||
"profile": "https://github.com/aaronhuggins",
|
|
||||||
"contributions": [
|
|
||||||
"design"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "zKXDEX",
|
|
||||||
"name": "KDex",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/66271780?v=4",
|
|
||||||
"profile": "https://zkxdex.github.io/",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "kimbob13",
|
|
||||||
"name": "ChangHwan Kim",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/26755098?v=4",
|
|
||||||
"profile": "https://github.com/kimbob13",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "ashneilson",
|
|
||||||
"name": "Ash Neilson",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/35913512?v=4",
|
|
||||||
"profile": "https://github.com/ashneilson",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "cfs4819",
|
|
||||||
"name": "Chen Fansong",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/53071761?v=4",
|
|
||||||
"profile": "https://github.com/cfs4819",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
@@ -1,13 +1,7 @@
|
|||||||
settings:
|
settings:
|
||||||
import/parsers:
|
|
||||||
'@typescript-eslint/parser': ['.ts']
|
|
||||||
import/resolver:
|
import/resolver:
|
||||||
typescript:
|
typescript: true
|
||||||
project:
|
|
||||||
- tsconfig.json
|
|
||||||
- tabby-*/tsconfig.json
|
|
||||||
node: true
|
node: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
browser: true
|
browser: true
|
||||||
es6: true
|
es6: true
|
||||||
@@ -34,7 +28,7 @@ overrides:
|
|||||||
- plugin:import/typescript
|
- plugin:import/typescript
|
||||||
plugins:
|
plugins:
|
||||||
- '@typescript-eslint'
|
- '@typescript-eslint'
|
||||||
- import
|
- 'import'
|
||||||
rules:
|
rules:
|
||||||
'@typescript-eslint/semi':
|
'@typescript-eslint/semi':
|
||||||
- error
|
- error
|
||||||
@@ -136,7 +130,6 @@ overrides:
|
|||||||
'@typescript-eslint/naming-convention': off
|
'@typescript-eslint/naming-convention': off
|
||||||
'@typescript-eslint/lines-between-class-members':
|
'@typescript-eslint/lines-between-class-members':
|
||||||
- error
|
- error
|
||||||
- always
|
|
||||||
- exceptAfterSingleLine: true
|
- exceptAfterSingleLine: true
|
||||||
'@typescript-eslint/dot-notation': off
|
'@typescript-eslint/dot-notation': off
|
||||||
'@typescript-eslint/no-implicit-any-catch': off
|
'@typescript-eslint/no-implicit-any-catch': off
|
||||||
@@ -159,6 +152,3 @@ overrides:
|
|||||||
'@typescript-eslint/consistent-generic-constructors': off
|
'@typescript-eslint/consistent-generic-constructors': off
|
||||||
'keyword-spacing': off
|
'keyword-spacing': off
|
||||||
'@typescript-eslint/keyword-spacing': off
|
'@typescript-eslint/keyword-spacing': off
|
||||||
'@typescript-eslint/class-methods-use-this': off
|
|
||||||
'@typescript-eslint/lines-around-comment': off
|
|
||||||
'@typescript-eslint/no-redundant-type-constituents': off # broken
|
|
||||||
|
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
@@ -2,7 +2,7 @@ name: Package-Build
|
|||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
Lint:
|
Lint:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: macos-11
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v3.7.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
run: yarn run lint
|
run: yarn run lint
|
||||||
|
|
||||||
macOS-Build:
|
macOS-Build:
|
||||||
runs-on: macos-12
|
runs-on: macos-11
|
||||||
needs: Lint
|
needs: Lint
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -47,14 +47,12 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v3.7.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
sudo -H pip3 install setuptools
|
|
||||||
npm config set python python3
|
|
||||||
sudo npm i -g yarn@1.22.1
|
sudo npm i -g yarn@1.22.1
|
||||||
yarn --network-timeout 1000000
|
yarn --network-timeout 1000000
|
||||||
env:
|
env:
|
||||||
@@ -112,16 +110,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Package artifacts
|
- name: Package artifacts
|
||||||
run: |
|
run: |
|
||||||
mkdir artifact-dmg
|
mkdir artifact-pkg
|
||||||
mv dist/*.dmg artifact-dmg/
|
mv dist/*.pkg artifact-pkg/
|
||||||
mkdir artifact-zip
|
mkdir artifact-zip
|
||||||
mv dist/*.zip artifact-zip/
|
mv dist/*.zip artifact-zip/
|
||||||
|
|
||||||
- uses: actions/upload-artifact@master
|
- uses: actions/upload-artifact@master
|
||||||
name: Upload DMG
|
name: Upload PKG
|
||||||
with:
|
with:
|
||||||
name: macOS .dmg (${{matrix.arch}})
|
name: macOS .pkg (${{matrix.arch}})
|
||||||
path: artifact-dmg
|
path: artifact-pkg
|
||||||
|
|
||||||
- uses: actions/upload-artifact@master
|
- uses: actions/upload-artifact@master
|
||||||
name: Upload ZIP
|
name: Upload ZIP
|
||||||
@@ -157,14 +155,14 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v3.7.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
- name: Install deps (amd64)
|
- name: Install deps (amd64)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libarchive-tools zsh python3-distutils
|
sudo apt-get install libarchive-tools zsh
|
||||||
|
|
||||||
- name: Install npm_modules (amd64)
|
- name: Install npm_modules (amd64)
|
||||||
run: |
|
run: |
|
||||||
@@ -347,7 +345,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v3.7.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Installing Node
|
- name: Installing Node
|
||||||
uses: actions/setup-node@v3.7.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
|
15
.github/workflows/issue-translator.yml
vendored
Normal file
15
.github/workflows/issue-translator.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: 'issue-translator'
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: tomsun28/issues-translate-action@v2.7
|
||||||
|
with:
|
||||||
|
IS_MODIFY_TITLE: true
|
||||||
|
CUSTOM_BOT_NOTE: The translator bot has detected that this issue body's language is not English, and has translated it automatically.
|
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -119,7 +119,6 @@ Plugins und Themen können direkt aus der Ansicht "Einstellungen" in Tabby insta
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - ein Beispiel-Plugin, das einen die ganze Zeit nervt
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - ein Beispiel-Plugin, das einen die ganze Zeit nervt
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - ermöglicht das Erstellen eigener Workspace-Profile auf Basis der angegebenen Konfiguration
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - ermöglicht das Erstellen eigener Workspace-Profile auf Basis der angegebenen Konfiguration
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - öffnet den Standard-Systembrowser mit einem Text, der aus dem Tabby Tab ausgewählt wurde
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - öffnet den Standard-Systembrowser mit einem Text, der aus dem Tabby Tab ausgewählt wurde
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
@@ -243,7 +242,7 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -327,15 +326,6 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -120,7 +120,6 @@ Los plugins y los temas se pueden instalar directamente desde la vista de Config
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - un ejemplo de plugin que te molesta todo el tiempo
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - un ejemplo de plugin que te molesta todo el tiempo
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite crear perfiles de espacio de trabajo personalizados basados en la configuración dada
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite crear perfiles de espacio de trabajo personalizados basados en la configuración dada
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre el navegador del sistema por defecto con un texto seleccionado en la pestaña de Tabby's
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre el navegador del sistema por defecto con un texto seleccionado en la pestaña de Tabby's
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
# Temas
|
# Temas
|
||||||
@@ -245,7 +244,7 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -329,15 +328,6 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -120,7 +120,6 @@ Tema dan Plugin bisa langsung di install dari Pengaturan di dalam Tabby.
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - suatu contoh plugin yang akan mengganggu anda setiap saat
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - suatu contoh plugin yang akan mengganggu anda setiap saat
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - memperbolehkan membuat kustom profil workspace dari konfigurasi yang diberikan
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - memperbolehkan membuat kustom profil workspace dari konfigurasi yang diberikan
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - membuka browser default dengan text yang dipilih dari Tab Tabby
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - membuka browser default dengan text yang dipilih dari Tab Tabby
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
@@ -242,7 +241,7 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -326,15 +325,6 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -117,7 +117,6 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
# Temi
|
# Temi
|
||||||
@@ -238,7 +237,7 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -322,15 +321,6 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -127,7 +127,6 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - プラグインの作例として、いつも厄介なあいつが出てくるプラグイン
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - プラグインの作例として、いつも厄介なあいつが出てくるプラグイン
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 指定された設定からカスタマイズされたワークスペースを作成することができます
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 指定された設定からカスタマイズされたワークスペースを作成することができます
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby内の端末で選択したテキストを既定ブラウザで開くことができます。
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby内の端末で選択したテキストを既定ブラウザで開くことができます。
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
@@ -253,7 +252,7 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -337,15 +336,6 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -19,11 +19,6 @@
|
|||||||
* [Repositories](https://packagecloud.io/eugeny/tabby): [Debian/Ubuntu-based](https://packagecloud.io/eugeny/tabby/install#bash-deb), [RPM-based](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
* [Repositories](https://packagecloud.io/eugeny/tabby): [Debian/Ubuntu-based](https://packagecloud.io/eugeny/tabby/install#bash-deb), [RPM-based](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||||
* [Latest nightly build](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
* [Latest nightly build](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||||
|
|
||||||
<br/>
|
|
||||||
<p align="center">
|
|
||||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
**Tabby** (구 **Terminus**)는 Windows, macOS 및 Linux용으로 뛰어난 구성의 터미널 에뮬레이터, SSH 및 시리얼 클라이언트입니다.
|
**Tabby** (구 **Terminus**)는 Windows, macOS 및 Linux용으로 뛰어난 구성의 터미널 에뮬레이터, SSH 및 시리얼 클라이언트입니다.
|
||||||
@@ -116,7 +111,6 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 항상 당신을 귀찮게 하는 예제 플러그인
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - 항상 당신을 귀찮게 하는 예제 플러그인
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 주어진 구성을 기반으로 사용자 정의 작업 공간 프로필을 생성할 수 있습니다
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 주어진 구성을 기반으로 사용자 정의 작업 공간 프로필을 생성할 수 있습니다
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby의 탭에서 선택한 텍스트로 기본 시스템 브라우저를 엽니다
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby의 탭에서 선택한 텍스트로 기본 시스템 브라우저를 엽니다
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
# 테마
|
# 테마
|
||||||
@@ -237,7 +231,7 @@ Pull requests and plugins are welcome!
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -321,15 +315,6 @@ Pull requests and plugins are welcome!
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
19
README.md
19
README.md
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -128,10 +128,6 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
* [background](https://github.com/moemoechu/tabby-background) - change Tabby background image and more...
|
|
||||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
|
||||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-app web authentication popups (Built primarily for warpgate in-browser auth)
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
@@ -142,8 +138,6 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
|||||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox)
|
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox)
|
||||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10)
|
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10)
|
||||||
* [altair](https://github.com/yxuko/terminus-altair)
|
* [altair](https://github.com/yxuko/terminus-altair)
|
||||||
* [catppuccin](https://github.com/catppuccin/tabby) - Soothing pastel theme for Tabby
|
|
||||||
* [noctis](https://github.com/aaronhuggins/tabby-colors-noctis) - color themes inspired by Noctis VS Code theme
|
|
||||||
|
|
||||||
# Sponsors <!-- omit in toc -->
|
# Sponsors <!-- omit in toc -->
|
||||||
|
|
||||||
@@ -259,7 +253,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -343,15 +337,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
363
README.pl-PL.md
363
README.pl-PL.md
@@ -1,363 +0,0 @@
|
|||||||
[](https://tabby.sh)
|
|
||||||
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="Wszystkie wydania na GitHubie" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=POBRANIA&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a>   <a href="https://translate.tabby.sh/"><img alt="Przetłumacz" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://ko-fi.com/J3J8KWTF">
|
|
||||||
<img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=2" width="150">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
> 👋 Zarządzasz zdalnymi środowiskami? Rzuć okiem na [WarpGate, inteligentny serwer typu bastion SSH/HTTP/MySQL](https://github.com/warp-tech/warpgate), świetnie współdziała z Tabby, pokochasz go!
|
|
||||||
|
|
||||||
> 👋 [Tabby-Web](https://github.com/Eugeny/tabby-web) poszukuje sponsorów. Nie jestem w stanie pokryć kosztów hostowania całej infrastruktury, jeśli jesteś zainteresowany wsparciem, proszę [skontakuj się ze mną!](https://twitter.com/eugeeeeny)
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
### Pobieranie:
|
|
||||||
|
|
||||||
* [Ostatnie wydania](https://github.com/Eugeny/tabby/releases/latest)
|
|
||||||
* [Repozytoria](https://packagecloud.io/eugeny/tabby): [Systemy Debian/Ubuntu](https://packagecloud.io/eugeny/tabby/install#bash-deb), [Środowiska RPM](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
|
||||||
* [Ostatnie wydania developerskie](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<p align="center">
|
|
||||||
Ten plik README jest również dostępny w językach: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
[**Tabby**](https://tabby.sh) (formalnie **Terminus**) to wysoce konfigurowalny emulator konsoli, SSH oraz klienta konsoli szeregowej na systemy Windows 10, macOS oraz Linux
|
|
||||||
|
|
||||||
* Zintegrowany klient SSH i Telnet oraz menedżer sesji
|
|
||||||
* Zintegrowany klient terminala szeregowego
|
|
||||||
* Motywy and palety kolorów
|
|
||||||
* W pełni konfigurowalne skróty klawiszowe
|
|
||||||
* Dzielenie ekranu
|
|
||||||
* Zapamiętywanie okien z poprzednich sesji
|
|
||||||
* PowerShell (oraz PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder i wsparcie dla CMD
|
|
||||||
* Bezpośredni transfer plików sesji SSH przez Zmodem
|
|
||||||
* Pełne wsparcie dla znaków Unicode wraz z podwójnymi znakami
|
|
||||||
* Nie zawieszanie się przy szybko wyświetlanych wynikach
|
|
||||||
* Pełne doświadczenie powłoki na systemie Windows zawierającej podpowiedzi (przez Clink)
|
|
||||||
* Zintegrowany zaszyfrowany kontener na klucze SSH i jego konfigurację
|
|
||||||
* Klient SSH, SFTP oraz Telnet dostępny jako [aplikacja webowa](https://tabby.sh/app) (również jako [własna instacja](https://github.com/Eugeny/tabby-web)).
|
|
||||||
|
|
||||||
# Spis treści <!-- omit in toc -->
|
|
||||||
|
|
||||||
- [Czym jest, a czym nie jest Tabby](#what-tabby-is-and-isnt)
|
|
||||||
- [Funkcje konsoli](#terminal-features)
|
|
||||||
- [Klient SSH](#ssh-client)
|
|
||||||
- [Konsola szeregowa](#serial-terminal)
|
|
||||||
- [Wersja przenośna](#portable)
|
|
||||||
- [Wtyczki](#plugins)
|
|
||||||
- [Motywy i palety kolorów](#themes)
|
|
||||||
- [Współtworzenie](#contributing)
|
|
||||||
|
|
||||||
<a name="about"></a>
|
|
||||||
|
|
||||||
# Czym jest, a czym nie jest Tabby
|
|
||||||
|
|
||||||
* **Tabby jest** alternatywą dla standardowej konsoli Windows (conhost), PowerShell ISE, PuTTY, Terminal.app oraz iTerm z macOS
|
|
||||||
|
|
||||||
* **Tabby nie jest** nową powłoką lub zamiennikiem dla MinGW czy Cygwin. Nie jest również zatrważająco szybki - jeśli ważne jest dla Ciebie użycie pamięci RAM, rozważ użycie [Conemu](https://conemu.github.io) lub [Alacritty](https://github.com/jwilm/alacritty)
|
|
||||||
|
|
||||||
<a name="terminal"></a>
|
|
||||||
|
|
||||||
# Funkcje konsoli
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* Konsola V220 + wiele rozszerzeń
|
|
||||||
* Wiele nakładających się podzielonych okien
|
|
||||||
* Okna na każdej stronie ekranu
|
|
||||||
* Opcjonalne dokowanie okna za pomocą skrótu ("Quake console")
|
|
||||||
* Wykrywanie postępu (Pasek)
|
|
||||||
* Powiadomienia przy ukończeniu procesu podczas postępu
|
|
||||||
* Wklejanie z nawiasami, ostrzeżenie przy wielu liniach
|
|
||||||
* Wsparcie różnych czcionek
|
|
||||||
* Niestandardowe profile powłoki
|
|
||||||
* Opcjonalne wklejanie PPM oraz kopiowanie na zaznaczeniu (Styl PuTTY)
|
|
||||||
|
|
||||||
<a name="ssh"></a>
|
|
||||||
|
|
||||||
# Klient SSH
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* Klient SSH2 z zarządzaniem połączeń
|
|
||||||
* X11 oraz przekierowywanie portów
|
|
||||||
* Automatyczne przejście między hostami
|
|
||||||
* Przekierowanie agenta (Pageant oraz Windowsowy natywny "OpenSSH Agent")
|
|
||||||
* Skrypty logowania
|
|
||||||
|
|
||||||
<a name="serial"></a>
|
|
||||||
|
|
||||||
# Konsola Szeregowa
|
|
||||||
|
|
||||||
* Zapisane połączenia
|
|
||||||
* Wczytywanie danych wejścia linii
|
|
||||||
* Opcjonalna konwersja danych wejścia i wyjścia na szesnastkowe "byte-by-byte"
|
|
||||||
* Konwersja na nową linię
|
|
||||||
* Automatyczne połączenie po rozłączeniu
|
|
||||||
|
|
||||||
<a name="portable"></a>
|
|
||||||
|
|
||||||
# Wersja przenośna
|
|
||||||
|
|
||||||
Tabby będzie uruchamiał się jako aplikacja przenośna, tylko wtedy, kiedy utworzysz folder `data` w tej samej lokacji, w której znajduje się `Tabby.exe`.
|
|
||||||
|
|
||||||
<a name="plugins"></a>
|
|
||||||
|
|
||||||
# Wtyczki
|
|
||||||
|
|
||||||
Wtyczki (jak i motywy) mogą być instalowane bezpośrednio z widoku ustawień w środku aplikacji Tabby.
|
|
||||||
|
|
||||||
* [docker](https://github.com/Eugeny/tabby-docker) - połączenie z kontenerami Docker
|
|
||||||
* [title-control](https://github.com/kbjr/terminus-title-control) - pozwala na zmienianie tytułu konsoli jako prefiks, sufiks lub/albo tekst do usunięcia
|
|
||||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - szybko wysyłaj komendy z jednej konsoli do wielu
|
|
||||||
* [save-output](https://github.com/Eugeny/tabby-save-output) - zapisuj dane wyjściowe do pliku
|
|
||||||
* [sync-config](https://github.com/starxg/terminus-sync-config) - synchronizuj konfigurację przez Gista lub Gitee
|
|
||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - przykładowa wtyczka, która zwyczajnie denerwuje
|
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - pozwala na utworzenie niestandardowego profilu pracy w aplikacji odpowiednio do konfiguracji
|
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - otwiera domyślną przeglądarkę z zaznaczonym tekstem w oknie Tabby
|
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - otwiera okno z połączeniem SFTP dla połączeń SSH jak SecureCRT
|
|
||||||
* [background](https://github.com/moemoechu/tabby-background) - zmień tło Tabby oraz wiele więcej
|
|
||||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
|
||||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - okienka autoryzacji wewnątrz konsoli (Zbudowany głównie pod autoryzację projektu Warpgate w przeglądarce)
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
|
||||||
|
|
||||||
# Motywy i palety kolorów
|
|
||||||
|
|
||||||
* [hype](https://github.com/Eugeny/tabby-theme-hype) - Motyw zainspirowany konsolą "Hyper"
|
|
||||||
* [relaxed](https://github.com/Relaxed-Theme/relaxed-terminal-themes#terminus) - Motyw "pełnej relaksacji"
|
|
||||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox) - Motyw zainspirowany konsolą "Hyper" (kolejny)
|
|
||||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10) - Motyw zainspirowany Microsoftem
|
|
||||||
* [altair](https://github.com/yxuko/terminus-altair) - Motwy autorstwa Yacine Kanzari
|
|
||||||
* [catppuccin](https://github.com/catppuccin/tabby) - Paleta pastelowa dla Tabby
|
|
||||||
* [noctis](https://github.com/aaronhuggins/tabby-colors-noctis) - Paleta kolorów zainspirowana motywem Noctis z VS Code
|
|
||||||
|
|
||||||
# Sponsorzy <!-- omit in toc -->
|
|
||||||
|
|
||||||
[](https://packagecloud.io)
|
|
||||||
|
|
||||||
[**packagecloud**](https://packagecloud.io) zapewnia darmowe utrzymanie repozytorium Debian/RPM
|
|
||||||
|
|
||||||
[](https://keygen.sh/?via=eugene)
|
|
||||||
|
|
||||||
[**keygen**](https://keygen.sh/?via=eugene) zapewnia darmowe wydawanie oraz automatycznie utrzymywanie strony
|
|
||||||
|
|
||||||
<a name="contributing"></a>
|
|
||||||
# Współtworzenie
|
|
||||||
|
|
||||||
Pull requesty and dodawanie nowych wtyczek jest mile widziane!
|
|
||||||
|
|
||||||
Zobacz plik [HAKOWANIE.md](https://github.com/Eugeny/tabby/blob/master/HACKING.md) oraz [Dokumentację API](https://docs.tabby.sh/), aby poznać, jak projekt jest prowadzony wraz ze wstępnym poradnikiem jak tworzyć wtyczki.
|
|
||||||
|
|
||||||
---
|
|
||||||
<a name="contributors"></a>
|
|
||||||
|
|
||||||
Dziękujemy wszystkim osobom współtworzącym ten projekt ([emotki są specjalizacją](https://allcontributors.org/docs/en/emoji-key)):
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
||||||
<!-- prettier-ignore-start -->
|
|
||||||
<!-- markdownlint-disable -->
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt="Russell Myers"/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mezner" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt="Austin Warren"/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ehwarren" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt="Felicia Hummel"/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt="Mike MacCana"/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt="Yacine Kanzari"/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yxuko" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt="BBJip"/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BBJip" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt="Futagirl"/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt="Levin Rickert"/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=levrik" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt="OJ Kwon"/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kwonoj" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" 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/tabby/commits?author=Domain" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" 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" valign="top" width="14.28%"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt="Daniel Imms"/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt="Florian Bachmann"/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=baflo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt="Michael Kühnel"/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt="Tilmann Meyer"/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NieLeben" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt="PM Extra"/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt="Jonathan"/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=IgnusG" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt="Hans Koch"/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hammster" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt="Dak Smyth"/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt="Wang Zhi"/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yfwz100" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt="jack1142"/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=jack1142" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt="Howie Douglas"/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hdougie" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt="Chris Kaczor"/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ckaczor" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt="Johannes Kadak"/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boxmein" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt="LeSeulArtichaut"/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt="Cyril Taylor"/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt="nstefanou"/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt="orin220444"/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=orin220444" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt="Gobius Dolhain"/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Goobles" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt="Gwilherm Folliot"/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=3l0w" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt="Dmitry Pronin"/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dimitory" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt="Jonathan Beverley"/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt="Zenghai Liang"/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zend" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt="Mateusz Tracz"/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=matishadow" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt="pinpin"/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=pinpins" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt="Takuro Onoda"/><br /><sub><b>Takuro Onoda</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TakuroOnoda" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt="frauhottelmann"/><br /><sub><b>frauhottelmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=frauhottelmann" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://patalong.pl"><img src="https://avatars.githubusercontent.com/u/29167842?v=4?s=100" width="100px;" alt="Piotr Patalong"/><br /><sub><b>Piotr Patalong</b></sub></a><br /><a href="#design-VectorKappa" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/clarkwang"><img src="https://avatars.githubusercontent.com/u/157076?v=4?s=100" width="100px;" alt="Clark Wang"/><br /><sub><b>Clark Wang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=clarkwang" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/iamchating"><img src="https://avatars.githubusercontent.com/u/7088153?v=4?s=100" width="100px;" alt="iamchating"/><br /><sub><b>iamchating</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=iamchating" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starxg"><img src="https://avatars.githubusercontent.com/u/34997494?v=4?s=100" width="100px;" alt="starxg"/><br /><sub><b>starxg</b></sub></a><br /><a href="#plugin-starxg" title="Plugin/utility libraries">🔌</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://hashnote.net/"><img src="https://avatars.githubusercontent.com/u/546312?v=4?s=100" width="100px;" alt="Alisue"/><br /><sub><b>Alisue</b></sub></a><br /><a href="#design-lambdalisue" title="Design">🎨</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ydcool"><img src="https://avatars.githubusercontent.com/u/5668295?v=4?s=100" width="100px;" alt="Dominic Yin"/><br /><sub><b>Dominic Yin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ydcool" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bdr99"><img src="https://avatars.githubusercontent.com/u/2292715?v=4?s=100" width="100px;" alt="Brandon Rothweiler"/><br /><sub><b>Brandon Rothweiler</b></sub></a><br /><a href="#design-bdr99" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://git.io/JnP49"><img src="https://avatars.githubusercontent.com/u/63876444?v=4?s=100" width="100px;" alt="Logic Machine"/><br /><sub><b>Logic Machine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=logicmachine123" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cypherbits"><img src="https://avatars.githubusercontent.com/u/10424900?v=4?s=100" width="100px;" alt="cypherbits"/><br /><sub><b>cypherbits</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cypherbits" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://modulolotus.net"><img src="https://avatars.githubusercontent.com/u/946421?v=4?s=100" width="100px;" alt="Matthew Davidson"/><br /><sub><b>Matthew Davidson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=KingMob" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/al-wi"><img src="https://avatars.githubusercontent.com/u/11092199?v=4?s=100" width="100px;" alt="Alexander Wiedemann"/><br /><sub><b>Alexander Wiedemann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=al-wi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.notion.so/3d45c6bd2cbd4f938873a4bd12e23375"><img src="https://avatars.githubusercontent.com/u/59506394?v=4?s=100" width="100px;" alt="장보연"/><br /><sub><b>장보연</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BoYeonJang" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=100" width="100px;" alt="zZ"/><br /><sub><b>zZ</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Me1onRind" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tainoNZ"><img src="https://avatars.githubusercontent.com/u/49261322?v=4?s=100" width="100px;" alt="Aaron Davison"/><br /><sub><b>Aaron Davison</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=tainoNZ" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/composer404"><img src="https://avatars.githubusercontent.com/u/58251560?v=4?s=100" width="100px;" alt="Przemyslaw Kozik"/><br /><sub><b>Przemyslaw Kozik</b></sub></a><br /><a href="#design-composer404" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt="Alfredo Arellano de la Fuente"/><br /><sub><b>Alfredo Arellano de la Fuente</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=highfredo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt="MH Kim"/><br /><sub><b>MH Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NessunKim" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt="Marmota"/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt="Ares Andrew"/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt="George Korsnick"/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt="Artem Smirnov"/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt="Tim Kopplow"/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt="mrthock"/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt="Lukas Rottach"/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt="boonkerz"/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt="Milo Ivir"/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt="JasonCubic"/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt="MaxWaldorf"/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://microhobby.com.br/blog"><img src="https://avatars.githubusercontent.com/u/2633321?v=4?s=100" width="100px;" alt="Matheus Castello"/><br /><sub><b>Matheus Castello</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=microhobby" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jai-JAP"><img src="https://avatars.githubusercontent.com/u/78354625?v=4?s=100" width="100px;" alt="Jai A P"/><br /><sub><b>Jai A P</b></sub></a><br /><a href="#platform-Jai-JAP" title="Packaging/porting to new platform">📦</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.ysc3839.com"><img src="https://avatars.githubusercontent.com/u/12028138?v=4?s=100" width="100px;" alt="Richard Yu"/><br /><sub><b>Richard Yu</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ysc3839" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/artu-ole"><img src="https://avatars.githubusercontent.com/u/15938416?v=4?s=100" width="100px;" alt="artu-ole"/><br /><sub><b>artu-ole</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=artu-ole" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://timagribanov.github.io/"><img src="https://avatars.githubusercontent.com/u/48593815?v=4?s=100" width="100px;" alt="Timofey Gribanov"/><br /><sub><b>Timofey Gribanov</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TimaGribanov" title="Documentation">📖</a> <a href="#translation-TimaGribanov" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://git.christianbingman.com"><img src="https://avatars.githubusercontent.com/u/42191425?v=4?s=100" width="100px;" alt="Christian Bingman"/><br /><sub><b>Christian Bingman</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ChristianBingman" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://zhangzhipeng2023.cn/"><img src="https://avatars.githubusercontent.com/u/5310853?v=4?s=100" width="100px;" alt="zhipeng"/><br /><sub><b>zhipeng</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Ox0400" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woodmeal"><img src="https://avatars.githubusercontent.com/u/104011197?v=4?s=100" width="100px;" alt="woodmeal"/><br /><sub><b>woodmeal</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=woodmeal" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://magiclike.codeberg.page/"><img src="https://avatars.githubusercontent.com/u/82117109?v=4?s=100" width="100px;" alt="MagicLike"/><br /><sub><b>MagicLike</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=MagicLike" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hisamafahri"><img src="https://avatars.githubusercontent.com/u/65691613?v=4?s=100" width="100px;" alt="Hisam Fahri"/><br /><sub><b>Hisam Fahri</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hisamafahri" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://liangchengj.com"><img src="https://avatars.githubusercontent.com/u/48881023?v=4?s=100" width="100px;" alt="Liangcheng Juves"/><br /><sub><b>Liangcheng Juves</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LiangchengJ" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/attet"><img src="https://avatars.githubusercontent.com/u/1911416?v=4?s=100" width="100px;" alt="Atte Timonen"/><br /><sub><b>Atte Timonen</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=attet" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/joaolmpinto/"><img src="https://avatars.githubusercontent.com/u/1143125?v=4?s=100" width="100px;" alt="João Pinto"/><br /><sub><b>João Pinto</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=joaompinto" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Qiming-Liu"><img src="https://avatars.githubusercontent.com/u/68600416?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Qiming-Liu" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://74th.tech/"><img src="https://avatars.githubusercontent.com/u/1060011?v=4?s=100" width="100px;" alt="Atsushi Morimoto"/><br /><sub><b>Atsushi Morimoto</b></sub></a><br /><a href="#financial-74th" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://arles.red/"><img src="https://avatars.githubusercontent.com/u/5369096?v=4?s=100" width="100px;" alt="Arles"/><br /><sub><b>Arles</b></sub></a><br /><a href="#financial-aarles" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://pentestbook.six2dez.com/"><img src="https://avatars.githubusercontent.com/u/24670991?v=4?s=100" width="100px;" alt="six2dez"/><br /><sub><b>six2dez</b></sub></a><br /><a href="#financial-six2dez" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CandiceJoy"><img src="https://avatars.githubusercontent.com/u/8854890?v=4?s=100" width="100px;" alt="Candice"/><br /><sub><b>Candice</b></sub></a><br /><a href="#financial-CandiceJoy" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kingrowen"><img src="https://avatars.githubusercontent.com/u/13178700?v=4?s=100" width="100px;" alt="Rowen Willabus"/><br /><sub><b>Rowen Willabus</b></sub></a><br /><a href="#financial-kingrowen" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Sky" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FrancisHG"><img src="https://avatars.githubusercontent.com/u/1611626?v=4?s=100" width="100px;" alt="Francis Gelderloos"/><br /><sub><b>Francis Gelderloos</b></sub></a><br /><a href="#financial-FrancisHG" title="Financial">💵</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/astromasoud"><img src="https://avatars.githubusercontent.com/u/18737721?v=4?s=100" width="100px;" alt="astromasoud"/><br /><sub><b>astromasoud</b></sub></a><br /><a href="#financial-astromasoud" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://spirit55555.dk/"><img src="https://avatars.githubusercontent.com/u/2357565?v=4?s=100" width="100px;" alt="Anders G. Jørgensen"/><br /><sub><b>Anders G. Jørgensen</b></sub></a><br /><a href="#financial-Spirit55555" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/djradon"><img src="https://avatars.githubusercontent.com/u/5224156?v=4?s=100" width="100px;" alt="Dave Richardson"/><br /><sub><b>Dave Richardson</b></sub></a><br /><a href="#financial-djradon" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/tpberntsen"><img src="https://avatars.githubusercontent.com/u/922318?v=4?s=100" width="100px;" alt="Thomas Peter Berntsen"/><br /><sub><b>Thomas Peter Berntsen</b></sub></a><br /><a href="#financial-tpberntsen" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=eltociear" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/giejqf"><img src="https://avatars.githubusercontent.com/u/9211230?v=4?s=100" width="100px;" alt="giejqf"/><br /><sub><b>giejqf</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=giejqf" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LacazeThomas"><img src="https://avatars.githubusercontent.com/u/19855907?v=4?s=100" width="100px;" alt="Thomas LACAZE"/><br /><sub><b>Thomas LACAZE</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LacazeThomas" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://pochen.me/"><img src="https://avatars.githubusercontent.com/u/1329716?v=4?s=100" width="100px;" alt="Po Chen"/><br /><sub><b>Po Chen</b></sub></a><br /><a href="#financial-princemaple" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://victorchandra.carrd.co/"><img src="https://avatars.githubusercontent.com/u/41635105?v=4?s=100" width="100px;" alt="Victor Chandra"/><br /><sub><b>Victor Chandra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mzmznasipadang" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel347x"><img src="https://avatars.githubusercontent.com/u/309746?v=4?s=100" width="100px;" alt="Dan Nissenbaum"/><br /><sub><b>Dan Nissenbaum</b></sub></a><br /><a href="#financial-daniel347x" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DunklerPhoenix"><img src="https://avatars.githubusercontent.com/u/1261305?v=4?s=100" width="100px;" alt="RogueThorn"/><br /><sub><b>RogueThorn</b></sub></a><br /><a href="#financial-DunklerPhoenix" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://spenserblack.github.io"><img src="https://avatars.githubusercontent.com/u/8546709?v=4?s=100" width="100px;" alt="Spenser Black"/><br /><sub><b>Spenser Black</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=spenserblack" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuedev"><img src="https://avatars.githubusercontent.com/u/24614929?v=4?s=100" width="100px;" alt="Alex"/><br /><sub><b>Alex</b></sub></a><br /><a href="#financial-zuedev" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Cola" title="Financial">💵</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.stackscale.com/"><img src="https://avatars.githubusercontent.com/u/195768?v=4?s=100" width="100px;" alt="David Carrero"/><br /><sub><b>David Carrero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dcarrero" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zhoro"><img src="https://avatars.githubusercontent.com/u/1105687?v=4?s=100" width="100px;" alt="Andrii Zhovtiak"/><br /><sub><b>Andrii Zhovtiak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zhoro" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JohnMasoner"><img src="https://avatars.githubusercontent.com/u/42313377?v=4?s=100" width="100px;" alt="Mason Ma"/><br /><sub><b>Mason Ma</b></sub></a><br /><a href="#financial-JohnMasoner" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ntimo"><img src="https://avatars.githubusercontent.com/u/6145026?v=4?s=100" width="100px;" alt="Timo"/><br /><sub><b>Timo</b></sub></a><br /><a href="#financial-ntimo" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/evinwatson/"><img src="https://avatars.githubusercontent.com/u/24227251?v=4?s=100" width="100px;" alt="Evin Watson"/><br /><sub><b>Evin Watson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=EvinRWatson" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://t.me/hendrjl"><img src="https://avatars.githubusercontent.com/u/15981200?v=4?s=100" width="100px;" alt="Hendra Juli"/><br /><sub><b>Hendra Juli</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=deulizealand" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wkricowski"><img src="https://avatars.githubusercontent.com/u/36803521?v=4?s=100" width="100px;" alt="Wellinton Kricowski"/><br /><sub><b>Wellinton Kricowski</b></sub></a><br /><a href="#financial-wkricowski" title="Financial">💵</a> <a href="https://github.com/Eugeny/tabby/commits?author=wkricowski" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/almzau"><img src="https://avatars.githubusercontent.com/u/29115846?v=4?s=100" width="100px;" alt="Allan"/><br /><sub><b>Allan</b></sub></a><br /><a href="#design-almzau" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://oidamo.de"><img src="https://avatars.githubusercontent.com/u/17959794?v=4?s=100" width="100px;" alt="Benjamin Brandmeier"/><br /><sub><b>Benjamin Brandmeier</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BenjaminBrandmeier" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/patric1025"><img src="https://avatars.githubusercontent.com/u/65654040?v=4?s=100" width="100px;" alt="patric1025"/><br /><sub><b>patric1025</b></sub></a><br /><a href="#translation-patric1025" title="Translation">🌍</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hermitpopcorn"><img src="https://avatars.githubusercontent.com/u/16042129?v=4?s=100" width="100px;" alt="hermitpopcorn"/><br /><sub><b>hermitpopcorn</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hermitpopcorn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://joshuatz.com/"><img src="https://avatars.githubusercontent.com/u/17817563?v=4?s=100" width="100px;" alt="Joshua Tzucker"/><br /><sub><b>Joshua Tzucker</b></sub></a><br /><a href="#financial-joshuatz" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luxifr"><img src="https://avatars.githubusercontent.com/u/665715?v=4?s=100" width="100px;" alt="luxifr"/><br /><sub><b>luxifr</b></sub></a><br /><a href="#financial-luxifr" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ukulanne"><img src="https://avatars.githubusercontent.com/u/28586666?v=4?s=100" width="100px;" alt="Anne Summers"/><br /><sub><b>Anne Summers</b></sub></a><br /><a href="#financial-ukulanne" title="Financial">💵</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clem-Fern"><img src="https://avatars.githubusercontent.com/u/20025949?v=4?s=100" width="100px;" alt="Clem"/><br /><sub><b>Clem</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Clem-Fern" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elizabeth-dev"><img src="https://avatars.githubusercontent.com/u/13015727?v=4?s=100" width="100px;" alt="Elizabeth Martín Campos"/><br /><sub><b>Elizabeth Martín Campos</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=elizabeth-dev" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/siccous"><img src="https://avatars.githubusercontent.com/u/7812885?v=4?s=100" width="100px;" alt="Tomáš Hruška"/><br /><sub><b>Tomáš Hruška</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siccous" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/karaketir16"><img src="https://avatars.githubusercontent.com/u/27349806?v=4?s=100" width="100px;" alt="Osman Karaketir"/><br /><sub><b>Osman Karaketir</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=karaketir16" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.gnomegarden.io/"><img src="https://avatars.githubusercontent.com/u/33667144?v=4?s=100" width="100px;" alt="Crypto Gnome"/><br /><sub><b>Crypto Gnome</b></sub></a><br /><a href="#financial-CryptoGnome" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rbukovansky"><img src="https://avatars.githubusercontent.com/u/1004491?v=4?s=100" width="100px;" alt="Richard Bukovansky"/><br /><sub><b>Richard Bukovansky</b></sub></a><br /><a href="#financial-rbukovansky" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pseudocc"><img src="https://avatars.githubusercontent.com/u/85104110?v=4?s=100" width="100px;" alt="catlas"/><br /><sub><b>catlas</b></sub></a><br /><a href="#financial-pseudocc" title="Financial">💵</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
||||||
|
|
||||||
Ten projekt podlega specyfikacji [dla współautorów](https://github.com/all-contributors/all-contributors). Wszelkiego rodzaju przyczynianie się do rozwoju jest tu mile widziane!
|
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -120,7 +120,6 @@ Plugins e temas podem ser instalados durante a execução na pagina de configura
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - um plugin de exemplo que te incomoda o tempo todo
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - um plugin de exemplo que te incomoda o tempo todo
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite criar perfis de espaço de trabalho personalizados com base na configuração fornecida
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite criar perfis de espaço de trabalho personalizados com base na configuração fornecida
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre o navegador padrão do sistema com um texto selecionado na guia do Tabby
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre o navegador padrão do sistema com um texto selecionado na guia do Tabby
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
|
|
||||||
@@ -246,7 +245,7 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -330,15 +329,6 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -117,7 +117,6 @@
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) — плагин-пример, который постоянно будет вас бесить;
|
* [clippy](https://github.com/Eugeny/tabby-clippy) — плагин-пример, который постоянно будет вас бесить;
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) — позволяет создавать пользовательские провили рабочего окружеиня на основе конфига;
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) — позволяет создавать пользовательские провили рабочего окружеиня на основе конфига;
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) — открывает браузер по умолчанию с текстом, выделенном во вкладке Tabby.
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) — открывает браузер по умолчанию с текстом, выделенном во вкладке Tabby.
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
# Темы
|
# Темы
|
||||||
@@ -238,7 +237,7 @@ Pull-запросы и плагины приветствуются!
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -322,15 +321,6 @@ Pull-запросы и плагины приветствуются!
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
----
|
----
|
||||||
@@ -116,7 +116,6 @@
|
|||||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 一个可以一直烦你的示例插件
|
* [clippy](https://github.com/Eugeny/tabby-clippy) - 一个可以一直烦你的示例插件
|
||||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 允许根据给定的配置创建自定义工作区配置文件
|
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 允许根据给定的配置创建自定义工作区配置文件
|
||||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 从 Tabby 标签页带有选中的文本来打开系统默认浏览器
|
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 从 Tabby 标签页带有选中的文本来打开系统默认浏览器
|
||||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - 为ssh连接打开类似SecureCRT的sftp标签页
|
|
||||||
|
|
||||||
<a name="themes"></a>
|
<a name="themes"></a>
|
||||||
# 主题
|
# 主题
|
||||||
@@ -237,7 +236,7 @@
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -321,15 +320,6 @@
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -183,7 +183,7 @@ export class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enableTray (): void {
|
enableTray (): void {
|
||||||
if (!!this.tray || process.platform === 'linux') {
|
if (this.tray || process.platform === 'linux') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
|
@@ -28,16 +28,6 @@ export function parseArgs (argv: string[], cwd: string): any {
|
|||||||
.command('recent [index]', 'open a tab with a recent profile', {
|
.command('recent [index]', 'open a tab with a recent profile', {
|
||||||
profileNumber: { type: 'number' },
|
profileNumber: { type: 'number' },
|
||||||
})
|
})
|
||||||
.command('quickConnect <providerId> <query>', 'open a tab for specified quick connect provider', yargs => {
|
|
||||||
return yargs.positional('providerId', {
|
|
||||||
describe: 'The name of a quick connect profile provider',
|
|
||||||
type: 'string',
|
|
||||||
choices: ['ssh', 'telnet'],
|
|
||||||
}).positional('query', {
|
|
||||||
describe: 'The quick connect query string',
|
|
||||||
type: 'string',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.version(app.getVersion())
|
.version(app.getVersion())
|
||||||
.option('debug', {
|
.option('debug', {
|
||||||
alias: 'd',
|
alias: 'd',
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
|
import { app } from 'electron'
|
||||||
import { writeFile } from 'atomically'
|
import { writeFile } from 'atomically'
|
||||||
|
|
||||||
|
|
||||||
export const configPath = path.join(process.env.TABBY_CONFIG_DIRECTORY!, 'config.yaml')
|
|
||||||
const legacyConfigPath = path.join(process.env.TABBY_CONFIG_DIRECTORY!, '../terminus', 'config.yaml')
|
|
||||||
|
|
||||||
|
|
||||||
export function migrateConfig (): void {
|
export function migrateConfig (): void {
|
||||||
|
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||||
|
const legacyConfigPath = path.join(app.getPath('userData'), '../terminus', 'config.yaml')
|
||||||
if (fs.existsSync(legacyConfigPath) && (
|
if (fs.existsSync(legacyConfigPath) && (
|
||||||
!fs.existsSync(configPath) ||
|
!fs.existsSync(configPath) ||
|
||||||
fs.statSync(configPath).mtime < fs.statSync(legacyConfigPath).mtime
|
fs.statSync(configPath).mtime < fs.statSync(legacyConfigPath).mtime
|
||||||
@@ -20,6 +19,7 @@ export function migrateConfig (): void {
|
|||||||
export function loadConfig (): any {
|
export function loadConfig (): any {
|
||||||
migrateConfig()
|
migrateConfig()
|
||||||
|
|
||||||
|
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||||
if (fs.existsSync(configPath)) {
|
if (fs.existsSync(configPath)) {
|
||||||
return yaml.load(fs.readFileSync(configPath, 'utf8'))
|
return yaml.load(fs.readFileSync(configPath, 'utf8'))
|
||||||
} else {
|
} else {
|
||||||
@@ -27,6 +27,8 @@ export function loadConfig (): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||||
|
|
||||||
export async function saveConfig (content: string): Promise<void> {
|
export async function saveConfig (content: string): Promise<void> {
|
||||||
await writeFile(configPath, content, { encoding: 'utf8' })
|
await writeFile(configPath, content, { encoding: 'utf8' })
|
||||||
await writeFile(configPath + '.backup', content, { encoding: 'utf8' })
|
await writeFile(configPath + '.backup', content, { encoding: 'utf8' })
|
||||||
|
@@ -1,23 +1,17 @@
|
|||||||
import { app, ipcMain, Menu, dialog } from 'electron'
|
|
||||||
|
|
||||||
// set userData Path on portable version
|
|
||||||
import './portable'
|
|
||||||
|
|
||||||
// set defaults of environment variables
|
|
||||||
import 'dotenv/config'
|
|
||||||
process.env.TABBY_PLUGINS ??= ''
|
|
||||||
process.env.TABBY_CONFIG_DIRECTORY ??= app.getPath('userData')
|
|
||||||
|
|
||||||
|
|
||||||
import 'v8-compile-cache'
|
import 'v8-compile-cache'
|
||||||
|
import './portable'
|
||||||
import 'source-map-support/register'
|
import 'source-map-support/register'
|
||||||
import './sentry'
|
import './sentry'
|
||||||
import './lru'
|
import './lru'
|
||||||
|
import { app, ipcMain, Menu, dialog } from 'electron'
|
||||||
import { parseArgs } from './cli'
|
import { parseArgs } from './cli'
|
||||||
import { Application } from './app'
|
import { Application } from './app'
|
||||||
import electronDebug = require('electron-debug')
|
import electronDebug = require('electron-debug')
|
||||||
import { loadConfig } from './config'
|
import { loadConfig } from './config'
|
||||||
|
|
||||||
|
if (!process.env.TABBY_PLUGINS) {
|
||||||
|
process.env.TABBY_PLUGINS = ''
|
||||||
|
}
|
||||||
|
|
||||||
const argv = parseArgs(process.argv, process.cwd())
|
const argv = parseArgs(process.argv, process.cwd())
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@ abstract class GlasstronWindow extends BrowserWindow {
|
|||||||
abstract setBlur (_: boolean)
|
abstract setBlur (_: boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
const macOSVibrancyType: any = process.platform === 'darwin' ? compareVersions(macOSRelease().version || '0.0', '10.14', '>=') ? 'under-window' : 'dark' : null
|
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions(macOSRelease().version || '0.0', '10.14', '>=') ? 'under-window' : 'dark' : null
|
||||||
|
|
||||||
const activityIcon = nativeImage.createFromPath(`${app.getAppPath()}/assets/activity.png`)
|
const activityIcon = nativeImage.createFromPath(`${app.getAppPath()}/assets/activity.png`)
|
||||||
|
|
||||||
@@ -392,15 +392,14 @@ export class Window {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
const symbolColor: string = theme.foreground
|
const symbolColor: string = theme.foreground
|
||||||
|
|
||||||
this.window.setTitleBarOverlay(
|
this.window.setTitleBarOverlay(
|
||||||
{
|
{
|
||||||
symbolColor: symbolColor,
|
symbolColor: symbolColor,
|
||||||
height: 32,
|
height: 32,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('window-set-title', (event, title) => {
|
ipcMain.on('window-set-title', (event, title) => {
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
"@tabby-gang/windows-blurbehind": "^3.0.0",
|
"@tabby-gang/windows-blurbehind": "^3.0.0",
|
||||||
"macos-native-processlist": "^2.1.0",
|
"macos-native-processlist": "^2.1.0",
|
||||||
"patch-package": "^6.5.0",
|
"patch-package": "^6.5.0",
|
||||||
"serialport": "11.0.1",
|
"serialport": "11.0.0",
|
||||||
"serialport-binding-webserialapi": "^1.0.3",
|
"serialport-binding-webserialapi": "^1.0.3",
|
||||||
"windows-native-registry": "^3.2.1",
|
"windows-native-registry": "^3.2.1",
|
||||||
"windows-process-tree": "^0.4.0"
|
"windows-process-tree": "^0.4.0"
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"@ngx-translate/core": "^14.0.0",
|
"@ngx-translate/core": "^14.0.0",
|
||||||
"@types/mz": "2.7.4",
|
"@types/mz": "2.7.4",
|
||||||
"@types/node": "20.3.1",
|
"@types/node": "20.3.1",
|
||||||
"atomically": "^2.0.2",
|
"atomically": "^1.7.0",
|
||||||
"filesize": "^9",
|
"filesize": "^9",
|
||||||
"ngx-filesize": "^3.0.2"
|
"ngx-filesize": "^3.0.2"
|
||||||
},
|
},
|
||||||
@@ -64,7 +64,6 @@
|
|||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"*/node-abi": "^2.20.0",
|
"*/node-abi": "^2.20.0",
|
||||||
"node-gyp": "^10.0.0",
|
|
||||||
"nan": "github:jkleinsc/nan#remove_accessor_signature"
|
"nan": "github:jkleinsc/nan#remove_accessor_signature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
705
app/yarn.lock
705
app/yarn.lock
File diff suppressed because it is too large
Load Diff
570
locale/af-ZA.po
570
locale/af-ZA.po
File diff suppressed because it is too large
Load Diff
568
locale/app.pot
568
locale/app.pot
File diff suppressed because it is too large
Load Diff
570
locale/bg-BG.po
570
locale/bg-BG.po
File diff suppressed because it is too large
Load Diff
570
locale/cs-CZ.po
570
locale/cs-CZ.po
File diff suppressed because it is too large
Load Diff
570
locale/da-DK.po
570
locale/da-DK.po
File diff suppressed because it is too large
Load Diff
570
locale/de-DE.po
570
locale/de-DE.po
File diff suppressed because it is too large
Load Diff
570
locale/en-GB.po
570
locale/en-GB.po
File diff suppressed because it is too large
Load Diff
570
locale/es-ES.po
570
locale/es-ES.po
File diff suppressed because it is too large
Load Diff
570
locale/fr-FR.po
570
locale/fr-FR.po
File diff suppressed because it is too large
Load Diff
570
locale/hr-HR.po
570
locale/hr-HR.po
File diff suppressed because it is too large
Load Diff
590
locale/id-ID.po
590
locale/id-ID.po
File diff suppressed because it is too large
Load Diff
572
locale/it-IT.po
572
locale/it-IT.po
File diff suppressed because it is too large
Load Diff
604
locale/ja-JP.po
604
locale/ja-JP.po
File diff suppressed because it is too large
Load Diff
588
locale/ko-KR.po
588
locale/ko-KR.po
File diff suppressed because it is too large
Load Diff
612
locale/pl-PL.po
612
locale/pl-PL.po
File diff suppressed because it is too large
Load Diff
570
locale/pt-BR.po
570
locale/pt-BR.po
File diff suppressed because it is too large
Load Diff
570
locale/pt-PT.po
570
locale/pt-PT.po
File diff suppressed because it is too large
Load Diff
570
locale/ru-RU.po
570
locale/ru-RU.po
File diff suppressed because it is too large
Load Diff
572
locale/sv-SE.po
572
locale/sv-SE.po
File diff suppressed because it is too large
Load Diff
570
locale/uk-UA.po
570
locale/uk-UA.po
File diff suppressed because it is too large
Load Diff
570
locale/zh-CN.po
570
locale/zh-CN.po
File diff suppressed because it is too large
Load Diff
578
locale/zh-TW.po
578
locale/zh-TW.po
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -26,8 +26,8 @@
|
|||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@types/node": "20.3.1",
|
"@types/node": "20.3.1",
|
||||||
"@types/webpack-env": "^1.18.0",
|
"@types/webpack-env": "^1.18.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.4.1",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^6.4.1",
|
"@typescript-eslint/parser": "^5.54.1",
|
||||||
"apply-loader": "2.0.0",
|
"apply-loader": "2.0.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
@@ -39,23 +39,23 @@
|
|||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"css-loader": "^6.7.3",
|
"css-loader": "^6.7.3",
|
||||||
"deep-equal": "2.0.5",
|
"deep-equal": "2.0.5",
|
||||||
"electron": "^27.0.4",
|
"electron": "^25.3.0",
|
||||||
"electron-builder": "^24.6.4",
|
"electron-builder": "^24.0.0-alpha.1",
|
||||||
"electron-download": "^4.1.1",
|
"electron-download": "^4.1.1",
|
||||||
"electron-installer-snap": "^5.1.0",
|
"electron-installer-snap": "^5.1.0",
|
||||||
"electron-rebuild": "^3.2.9",
|
"electron-rebuild": "^3.2.9",
|
||||||
"eslint": "^8.48.0",
|
"eslint": "^8.38.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.0",
|
"eslint-import-resolver-typescript": "^3.5.2",
|
||||||
"eslint-plugin-import": "^2.28.1",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"gettext-extractor": "^3.8.0",
|
"gettext-extractor": "^3.5.4",
|
||||||
"graceful-fs": "^4.2.10",
|
"graceful-fs": "^4.2.10",
|
||||||
"html-loader": "4.2.0",
|
"html-loader": "4.2.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"lru-cache": "^6.0.0",
|
"lru-cache": "^6.0.0",
|
||||||
"macos-release": "^3.1.0",
|
"macos-release": "^3.1.0",
|
||||||
"ngx-toastr": "^16.0.2",
|
"ngx-toastr": "^16.0.2",
|
||||||
"node-abi": "^3.51.0",
|
"node-abi": "^3.45.0",
|
||||||
"npmlog": "6.0.2",
|
"npmlog": "6.0.2",
|
||||||
"npx": "^10.2.2",
|
"npx": "^10.2.2",
|
||||||
"patch-package": "^6.4.7",
|
"patch-package": "^6.4.7",
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
"source-code-pro": "^2.38.0",
|
"source-code-pro": "^2.38.0",
|
||||||
"source-map-loader": "^4.0.1",
|
"source-map-loader": "^4.0.1",
|
||||||
"source-sans-pro": "3.6.0",
|
"source-sans-pro": "3.6.0",
|
||||||
"ssh2": "^1.14.0",
|
"ssh2": "Eugeny/ssh2#9de907d62907d6d45debdcc0ed8dda5b7b19dc7c",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"svg-inline-loader": "^0.8.2",
|
"svg-inline-loader": "^0.8.2",
|
||||||
"thenby": "^1.3.4",
|
"thenby": "^1.3.4",
|
||||||
@@ -95,7 +95,8 @@
|
|||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"*/pug": "^3",
|
"*/pug": "^3",
|
||||||
"lzma-native": "^8.0.6",
|
"lzma-native": "^8.0.0",
|
||||||
|
"*/node-abi": "^3.33.0",
|
||||||
"**/graceful-fs": "^4.2.4",
|
"**/graceful-fs": "^4.2.4",
|
||||||
"nan": "2.17.0"
|
"nan": "2.17.0"
|
||||||
},
|
},
|
||||||
@@ -114,8 +115,5 @@
|
|||||||
"i18n:push": "crowdin push"
|
"i18n:push": "crowdin push"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true
|
||||||
"dependencies": {
|
|
||||||
"dotenv": "^16.3.1"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@ builder({
|
|||||||
armv7l: process.env.ARCH === 'armv7l',
|
armv7l: process.env.ARCH === 'armv7l',
|
||||||
arm64: process.env.ARCH === 'arm64',
|
arm64: process.env.ARCH === 'arm64',
|
||||||
config: {
|
config: {
|
||||||
npmRebuild: false,
|
|
||||||
extraMetadata: {
|
extraMetadata: {
|
||||||
version: vars.version,
|
version: vars.version,
|
||||||
},
|
},
|
||||||
|
@@ -18,7 +18,7 @@ process.env.APPLE_APP_SPECIFIC_PASSWORD ??= process.env.APPSTORE_PASSWORD
|
|||||||
|
|
||||||
builder({
|
builder({
|
||||||
dir: true,
|
dir: true,
|
||||||
mac: ['dmg', 'zip'],
|
mac: ['pkg', 'zip'],
|
||||||
x64: process.env.ARCH === 'x86_64',
|
x64: process.env.ARCH === 'x86_64',
|
||||||
arm64: process.env.ARCH === 'arm64',
|
arm64: process.env.ARCH === 'arm64',
|
||||||
config: {
|
config: {
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import slugify from 'slugify'
|
|
||||||
import { BaseTabComponent } from '../components/baseTab.component'
|
import { BaseTabComponent } from '../components/baseTab.component'
|
||||||
import { MenuItemOptions } from './menu'
|
import { MenuItemOptions } from './menu'
|
||||||
import { ToolbarButton } from './toolbarButtonProvider'
|
import { ToolbarButton } from './toolbarButtonProvider'
|
||||||
@@ -7,33 +6,34 @@ export enum CommandLocation {
|
|||||||
LeftToolbar = 'left-toolbar',
|
LeftToolbar = 'left-toolbar',
|
||||||
RightToolbar = 'right-toolbar',
|
RightToolbar = 'right-toolbar',
|
||||||
StartPage = 'start-page',
|
StartPage = 'start-page',
|
||||||
TabHeaderMenu = 'tab-header-menu',
|
|
||||||
TabBodyMenu = 'tab-body-menu',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Command {
|
export class Command {
|
||||||
id: string
|
id?: string
|
||||||
label: string
|
label: string
|
||||||
fullLabel?: string
|
sublabel?: string
|
||||||
locations: CommandLocation[]
|
locations?: CommandLocation[]
|
||||||
run?: () => Promise<any>
|
run: () => Promise<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw SVG icon code
|
* Raw SVG icon code
|
||||||
*/
|
*/
|
||||||
icon?: string
|
icon?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional Touch Bar icon ID
|
||||||
|
*/
|
||||||
|
touchBarNSImage?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional Touch Bar button label
|
||||||
|
*/
|
||||||
|
touchBarTitle?: string
|
||||||
|
|
||||||
weight?: number
|
weight?: number
|
||||||
|
|
||||||
parent?: string
|
|
||||||
|
|
||||||
group?: string
|
|
||||||
|
|
||||||
checked?: boolean
|
|
||||||
|
|
||||||
static fromToolbarButton (button: ToolbarButton): Command {
|
static fromToolbarButton (button: ToolbarButton): Command {
|
||||||
const command = new Command()
|
const command = new Command()
|
||||||
command.id = `legacy:${slugify(button.title)}`
|
|
||||||
command.label = button.title
|
command.label = button.title
|
||||||
command.run = async () => button.click?.()
|
command.run = async () => button.click?.()
|
||||||
command.icon = button.icon
|
command.icon = button.icon
|
||||||
@@ -44,29 +44,18 @@ export class Command {
|
|||||||
if ((button.weight ?? 0) > 0) {
|
if ((button.weight ?? 0) > 0) {
|
||||||
command.locations.push(CommandLocation.RightToolbar)
|
command.locations.push(CommandLocation.RightToolbar)
|
||||||
}
|
}
|
||||||
|
command.touchBarNSImage = button.touchBarNSImage
|
||||||
|
command.touchBarTitle = button.touchBarTitle
|
||||||
command.weight = button.weight
|
command.weight = button.weight
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromMenuItem (item: MenuItemOptions): Command[] {
|
static fromMenuItem (item: MenuItemOptions): Command {
|
||||||
if (item.type === 'separator') {
|
const command = new Command()
|
||||||
return []
|
command.label = item.commandLabel ?? item.label ?? ''
|
||||||
}
|
command.sublabel = item.sublabel
|
||||||
const commands: Command[] = [{
|
command.run = async () => item.click?.()
|
||||||
id: `legacy:${slugify(item.commandLabel ?? item.label).toLowerCase()}`,
|
return command
|
||||||
label: item.commandLabel ?? item.label,
|
|
||||||
run: async () => item.click?.(),
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
checked: item.checked,
|
|
||||||
}]
|
|
||||||
for (const submenu of item.submenu ?? []) {
|
|
||||||
commands.push(...Command.fromMenuItem(submenu).map(x => ({
|
|
||||||
...x,
|
|
||||||
id: `${commands[0].id}:${slugify(x.label).toLowerCase()}`,
|
|
||||||
parent: commands[0].id,
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
return commands
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess'
|
|||||||
export { HostWindowService } from './hostWindow'
|
export { HostWindowService } from './hostWindow'
|
||||||
export { HostAppService, Platform } from './hostApp'
|
export { HostAppService, Platform } from './hostApp'
|
||||||
export { FileProvider } from './fileProvider'
|
export { FileProvider } from './fileProvider'
|
||||||
export { ProfileProvider, ConnectableProfileProvider, QuickConnectProfileProvider, Profile, ConnectableProfile, PartialProfile, ProfileSettingsComponent, ProfileGroup, PartialProfileGroup } from './profileProvider'
|
export { ProfileProvider, Profile, PartialProfile, ProfileSettingsComponent } from './profileProvider'
|
||||||
export { PromptModalComponent } from '../components/promptModal.component'
|
export { PromptModalComponent } from '../components/promptModal.component'
|
||||||
export * from './commands'
|
export * from './commands'
|
||||||
|
|
||||||
@@ -37,7 +37,6 @@ export { UpdaterService } from '../services/updater.service'
|
|||||||
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
||||||
export { FileProvidersService } from '../services/fileProviders.service'
|
export { FileProvidersService } from '../services/fileProviders.service'
|
||||||
export { LocaleService } from '../services/locale.service'
|
export { LocaleService } from '../services/locale.service'
|
||||||
export { CommandService } from '../services/commands.service'
|
|
||||||
export { TranslateService } from '@ngx-translate/core'
|
export { TranslateService } from '@ngx-translate/core'
|
||||||
export * from '../utils'
|
export * from '../utils'
|
||||||
export { UTF8Splitter } from '../utfSplitter'
|
export { UTF8Splitter } from '../utfSplitter'
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
export type MenuItemOptions = {
|
export interface MenuItemOptions {
|
||||||
|
type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio')
|
||||||
|
label?: string
|
||||||
sublabel?: string
|
sublabel?: string
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
checked?: boolean
|
checked?: boolean
|
||||||
@@ -7,10 +9,4 @@ export type MenuItemOptions = {
|
|||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
commandLabel?: string
|
commandLabel?: string
|
||||||
} & ({
|
}
|
||||||
type: 'separator',
|
|
||||||
label?: string,
|
|
||||||
} | {
|
|
||||||
type?: 'normal' | 'submenu' | 'checkbox' | 'radio',
|
|
||||||
label: string,
|
|
||||||
})
|
|
||||||
|
@@ -21,10 +21,6 @@ export interface Profile {
|
|||||||
isTemplate: boolean
|
isTemplate: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnectableProfile extends Profile {
|
|
||||||
clearServiceMessagesOnConnect: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
|
export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
|
||||||
[K in keyof T]?: T[K]
|
[K in keyof T]?: T[K]
|
||||||
}, 'options'>, 'type'>, 'name'> & {
|
}, 'options'>, 'type'>, 'name'> & {
|
||||||
@@ -35,21 +31,6 @@ export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProfileGroup {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
profiles: PartialProfile<Profile>[]
|
|
||||||
defaults: any
|
|
||||||
editable: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PartialProfileGroup<T extends ProfileGroup> = Omit<Omit<{
|
|
||||||
[K in keyof T]?: T[K]
|
|
||||||
}, 'id'>, 'name'> & {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfileSettingsComponent<P extends Profile> {
|
export interface ProfileSettingsComponent<P extends Profile> {
|
||||||
profile: P
|
profile: P
|
||||||
save?: () => void
|
save?: () => void
|
||||||
@@ -58,6 +39,7 @@ export interface ProfileSettingsComponent<P extends Profile> {
|
|||||||
export abstract class ProfileProvider<P extends Profile> {
|
export abstract class ProfileProvider<P extends Profile> {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
|
supportsQuickConnect = false
|
||||||
settingsComponent?: new (...args: any[]) => ProfileSettingsComponent<P>
|
settingsComponent?: new (...args: any[]) => ProfileSettingsComponent<P>
|
||||||
configDefaults = {}
|
configDefaults = {}
|
||||||
|
|
||||||
@@ -71,15 +53,13 @@ export abstract class ProfileProvider<P extends Profile> {
|
|||||||
|
|
||||||
abstract getDescription (profile: PartialProfile<P>): string
|
abstract getDescription (profile: PartialProfile<P>): string
|
||||||
|
|
||||||
|
quickConnect (query: string): PartialProfile<P>|null {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
intoQuickConnectString (profile: P): string|null {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
deleteProfile (profile: P): void { }
|
deleteProfile (profile: P): void { }
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ConnectableProfileProvider<P extends ConnectableProfile> extends ProfileProvider<P> {}
|
|
||||||
|
|
||||||
export abstract class QuickConnectProfileProvider<P extends ConnectableProfile> extends ConnectableProfileProvider<P> {
|
|
||||||
|
|
||||||
abstract quickConnect (query: string): PartialProfile<P>|null
|
|
||||||
|
|
||||||
abstract intoQuickConnectString (profile: P): string|null
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -9,6 +9,16 @@ export interface ToolbarButton {
|
|||||||
|
|
||||||
title: string
|
title: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional Touch Bar icon ID
|
||||||
|
*/
|
||||||
|
touchBarNSImage?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional Touch Bar button label
|
||||||
|
*/
|
||||||
|
touchBarTitle?: string
|
||||||
|
|
||||||
weight?: number
|
weight?: number
|
||||||
|
|
||||||
click?: () => void
|
click?: () => void
|
||||||
|
@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'
|
|||||||
import { HostAppService } from './api/hostApp'
|
import { HostAppService } from './api/hostApp'
|
||||||
import { CLIHandler, CLIEvent } from './api/cli'
|
import { CLIHandler, CLIEvent } from './api/cli'
|
||||||
import { HostWindowService } from './api/hostWindow'
|
import { HostWindowService } from './api/hostWindow'
|
||||||
import { QuickConnectProfileProvider } from './api/profileProvider'
|
|
||||||
import { ProfilesService } from './services/profiles.service'
|
import { ProfilesService } from './services/profiles.service'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -28,10 +27,6 @@ export class ProfileCLIHandler extends CLIHandler {
|
|||||||
this.handleOpenRecentProfile(event.argv.profileNumber)
|
this.handleOpenRecentProfile(event.argv.profileNumber)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (op === 'quickConnect') {
|
|
||||||
this.handleOpenQuickConnect(event.argv.providerId, event.argv.query)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,21 +48,6 @@ export class ProfileCLIHandler extends CLIHandler {
|
|||||||
this.profiles.openNewTabForProfile(profiles[profileNumber])
|
this.profiles.openNewTabForProfile(profiles[profileNumber])
|
||||||
this.hostWindow.bringToFront()
|
this.hostWindow.bringToFront()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleOpenQuickConnect (providerId: string, query: string) {
|
|
||||||
const provider = this.profiles.getProviders().find(x => x.id === providerId)
|
|
||||||
if(!provider || !(provider instanceof QuickConnectProfileProvider)) {
|
|
||||||
console.error(`Requested provider "${providerId}" not found`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const profile = provider.quickConnect(query)
|
|
||||||
if(!profile) {
|
|
||||||
console.error(`Could not parse quick connect query "${query}"`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.profiles.openNewTabForProfile(profile)
|
|
||||||
this.hostWindow.bringToFront()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@@ -1,20 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { TranslateService } from '@ngx-translate/core'
|
import { TranslateService } from '@ngx-translate/core'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
|
||||||
|
|
||||||
import { HostAppService, Platform } from './api/hostApp'
|
import { HostAppService, Platform } from './api/hostApp'
|
||||||
import { ProfilesService } from './services/profiles.service'
|
import { ProfilesService } from './services/profiles.service'
|
||||||
import { AppService } from './services/app.service'
|
import { CommandProvider, Command, CommandLocation } from './api/commands'
|
||||||
import { CommandProvider, Command, CommandLocation, CommandContext } from './api/commands'
|
|
||||||
import { SplitDirection, SplitTabComponent } from './components/splitTab.component'
|
|
||||||
import { BaseTabComponent } from './components/baseTab.component'
|
|
||||||
import { PromptModalComponent } from './components/promptModal.component'
|
|
||||||
import { HotkeysService } from './services/hotkeys.service'
|
|
||||||
import { TabsService } from './services/tabs.service'
|
|
||||||
import { SplitLayoutProfilesService } from './profiles'
|
|
||||||
import { TAB_COLORS } from './utils'
|
|
||||||
import { Subscription } from 'rxjs'
|
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
@@ -23,327 +13,38 @@ export class CoreCommandProvider extends CommandProvider {
|
|||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
private profilesService: ProfilesService,
|
private profilesService: ProfilesService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private app: AppService,
|
|
||||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
|
||||||
private ngbModal: NgbModal,
|
|
||||||
private tabsService: TabsService,
|
|
||||||
hotkeys: HotkeysService,
|
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
hotkeys.hotkey$.subscribe(hotkey => {
|
|
||||||
if (hotkey === 'switch-profile') {
|
|
||||||
let tab = this.app.activeTab
|
|
||||||
if (tab instanceof SplitTabComponent) {
|
|
||||||
tab = tab.getFocusedTab()
|
|
||||||
if (tab) {
|
|
||||||
this.switchTabProfile(tab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchTabProfile (tab: BaseTabComponent) {
|
async activate () {
|
||||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
const profile = await this.profilesService.showProfileSelector()
|
||||||
if (!profile) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = await this.profilesService.newTabParametersForProfile(profile)
|
|
||||||
if (!params) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await tab.canClose()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTab = this.tabsService.create(params)
|
|
||||||
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
|
||||||
|
|
||||||
tab.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
async showProfileSelector () {
|
|
||||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
|
||||||
if (profile) {
|
if (profile) {
|
||||||
this.profilesService.launchProfile(profile)
|
this.profilesService.launchProfile(profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async provide (context: CommandContext): Promise<Command[]> {
|
async provide (): Promise<Command[]> {
|
||||||
const commands: Command[] = [
|
return [
|
||||||
{
|
{
|
||||||
id: 'core:profile-selector',
|
id: 'core:profile-selector',
|
||||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage],
|
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage],
|
||||||
label: this.translate.instant('Profiles & connections'),
|
label: this.translate.instant('Profiles & connections'),
|
||||||
weight: 12,
|
|
||||||
icon: this.hostApp.platform === Platform.Web
|
icon: this.hostApp.platform === Platform.Web
|
||||||
? require('./icons/plus.svg')
|
? require('./icons/plus.svg')
|
||||||
: require('./icons/profiles.svg'),
|
: require('./icons/profiles.svg'),
|
||||||
run: async () => this.showProfileSelector(),
|
run: async () => this.activate(),
|
||||||
},
|
},
|
||||||
...this.profilesService.getRecentProfiles().map((profile, index) => ({
|
...this.profilesService.getRecentProfiles().map((profile, index) => ({
|
||||||
id: `core:recent-profile-${index}`,
|
id: `core:recent-profile-${index}`,
|
||||||
label: profile.name,
|
label: profile.name,
|
||||||
locations: [CommandLocation.StartPage],
|
locations: [CommandLocation.StartPage],
|
||||||
icon: require('./icons/history.svg'),
|
icon: require('./icons/history.svg'),
|
||||||
weight: 20,
|
|
||||||
run: async () => {
|
run: async () => {
|
||||||
const p = (await this.profilesService.getProfiles()).find(x => x.id === profile.id) ?? profile
|
const p = (await this.profilesService.getProfiles()).find(x => x.id === profile.id) ?? profile
|
||||||
this.profilesService.launchProfile(p)
|
this.profilesService.launchProfile(p)
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
]
|
]
|
||||||
|
|
||||||
if (context.tab) {
|
|
||||||
const tab = context.tab
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
id: `core:close-tab`,
|
|
||||||
label: this.translate.instant('Close tab'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: -35,
|
|
||||||
group: 'core:close',
|
|
||||||
run: async () => {
|
|
||||||
if (this.app.tabs.includes(tab)) {
|
|
||||||
this.app.closeTab(tab, true)
|
|
||||||
} else {
|
|
||||||
tab.destroy()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
id: `core:close`,
|
|
||||||
label: this.translate.instant('Close'),
|
|
||||||
locations: [CommandLocation.TabBodyMenu],
|
|
||||||
weight: 99,
|
|
||||||
group: 'core:close',
|
|
||||||
run: async () => {
|
|
||||||
tab.destroy()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!context.tab.parent) {
|
|
||||||
commands.push(...[{
|
|
||||||
id: 'core:close-other-tabs',
|
|
||||||
label: this.translate.instant('Close other tabs'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: -34,
|
|
||||||
group: 'core:close',
|
|
||||||
run: async () => {
|
|
||||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
|
||||||
this.app.closeTab(t, true)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'core:close-tabs-to-the-right',
|
|
||||||
label: this.translate.instant('Close tabs to the right'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: -33,
|
|
||||||
group: 'core:close',
|
|
||||||
run: async () => {
|
|
||||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
|
||||||
this.app.closeTab(t, true)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'core:close-tabs-to-the-left',
|
|
||||||
label: this.translate.instant('Close tabs to the left'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: -32,
|
|
||||||
group: 'core:close',
|
|
||||||
run: async () => {
|
|
||||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
|
||||||
this.app.closeTab(t, true)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}])
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
id: 'core:rename-tab',
|
|
||||||
label: this.translate.instant('Rename tab'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
group: 'core:common',
|
|
||||||
weight: -13,
|
|
||||||
run: async () => this.app.renameTab(tab),
|
|
||||||
})
|
|
||||||
commands.push({
|
|
||||||
id: 'core:duplicate-tab',
|
|
||||||
label: this.translate.instant('Duplicate tab'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
group: 'core:common',
|
|
||||||
weight: -12,
|
|
||||||
run: async () => this.app.duplicateTab(tab),
|
|
||||||
})
|
|
||||||
commands.push({
|
|
||||||
id: 'core:tab-color',
|
|
||||||
label: this.translate.instant('Color'),
|
|
||||||
group: 'core:common',
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: -11,
|
|
||||||
})
|
|
||||||
for (const color of TAB_COLORS) {
|
|
||||||
commands.push({
|
|
||||||
id: `core:tab-color-${color.name.toLowerCase()}`,
|
|
||||||
parent: 'core:tab-color',
|
|
||||||
label: this.translate.instant(color.name) ?? color.name,
|
|
||||||
fullLabel: this.translate.instant('Set tab color to {color}', { color: this.translate.instant(color.name) }),
|
|
||||||
checked: tab.color === color.value,
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
run: async () => {
|
|
||||||
tab.color = color.value
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab.parent instanceof SplitTabComponent) {
|
|
||||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
|
||||||
commands.push({
|
|
||||||
id: 'core:split',
|
|
||||||
label: this.translate.instant('Split'),
|
|
||||||
group: 'core:panes',
|
|
||||||
locations: [CommandLocation.TabBodyMenu],
|
|
||||||
})
|
|
||||||
for (const dir of directions) {
|
|
||||||
commands.push({
|
|
||||||
id: `core:split-${dir}`,
|
|
||||||
label: {
|
|
||||||
r: this.translate.instant('Right'),
|
|
||||||
b: this.translate.instant('Down'),
|
|
||||||
l: this.translate.instant('Left'),
|
|
||||||
t: this.translate.instant('Up'),
|
|
||||||
}[dir],
|
|
||||||
fullLabel: {
|
|
||||||
r: this.translate.instant('Split to the right'),
|
|
||||||
b: this.translate.instant('Split to the down'),
|
|
||||||
l: this.translate.instant('Split to the left'),
|
|
||||||
t: this.translate.instant('Split to the up'),
|
|
||||||
}[dir],
|
|
||||||
locations: [CommandLocation.TabBodyMenu],
|
|
||||||
parent: 'core:split',
|
|
||||||
run: async () => {
|
|
||||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
id: 'core:switch-profile',
|
|
||||||
label: this.translate.instant('Switch profile'),
|
|
||||||
group: 'core:common',
|
|
||||||
locations: [CommandLocation.TabBodyMenu],
|
|
||||||
run: async () => this.switchTabProfile(tab),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
|
||||||
commands.push({
|
|
||||||
id: 'core:save-split-tab-as-profile',
|
|
||||||
label: this.translate.instant('Save layout as profile'),
|
|
||||||
group: 'core:common',
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
run: async () => {
|
|
||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
|
||||||
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
|
||||||
const name = (await modal.result.catch(() => null))?.value
|
|
||||||
if (!name) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.splitLayoutProfilesService.createProfile(tab, name)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @hidden */
|
|
||||||
@Injectable({ providedIn: 'root' })
|
|
||||||
export class TaskCompletionCommandProvider extends CommandProvider {
|
|
||||||
constructor (
|
|
||||||
private app: AppService,
|
|
||||||
private translate: TranslateService,
|
|
||||||
) {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
|
|
||||||
async provide (context: CommandContext): Promise<Command[]> {
|
|
||||||
if (!context.tab) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const process = await context.tab.getCurrentProcess()
|
|
||||||
const items: Command[] = []
|
|
||||||
|
|
||||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = context.tab
|
|
||||||
|
|
||||||
if (process) {
|
|
||||||
items.push({
|
|
||||||
id: 'core:process-name',
|
|
||||||
label: this.translate.instant('Current process: {name}', process),
|
|
||||||
group: 'core:process',
|
|
||||||
weight: -1,
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
})
|
|
||||||
items.push({
|
|
||||||
id: 'core:notify-when-done',
|
|
||||||
label: this.translate.instant('Notify when done'),
|
|
||||||
group: 'core:process',
|
|
||||||
weight: 0,
|
|
||||||
checked: extTab.__completionNotificationEnabled,
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
run: async () => {
|
|
||||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
|
||||||
|
|
||||||
if (extTab.__completionNotificationEnabled) {
|
|
||||||
this.app.observeTabCompletion(extTab).subscribe(() => {
|
|
||||||
new Notification(this.translate.instant('Process completed'), {
|
|
||||||
body: process.name,
|
|
||||||
}).addEventListener('click', () => {
|
|
||||||
this.app.selectTab(extTab)
|
|
||||||
})
|
|
||||||
extTab.__completionNotificationEnabled = false
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.app.stopObservingTabCompletion(extTab)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
items.push({
|
|
||||||
id: 'core:notify-on-activity',
|
|
||||||
label: this.translate.instant('Notify on activity'),
|
|
||||||
group: 'core:process',
|
|
||||||
checked: !!extTab.__outputNotificationSubscription,
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
run: async () => {
|
|
||||||
extTab.clearActivity()
|
|
||||||
|
|
||||||
if (extTab.__outputNotificationSubscription) {
|
|
||||||
extTab.__outputNotificationSubscription.unsubscribe()
|
|
||||||
extTab.__outputNotificationSubscription = null
|
|
||||||
} else {
|
|
||||||
extTab.__outputNotificationSubscription = extTab.activity$.subscribe(active => {
|
|
||||||
if (extTab.__outputNotificationSubscription && active) {
|
|
||||||
extTab.__outputNotificationSubscription.unsubscribe()
|
|
||||||
extTab.__outputNotificationSubscription = null
|
|
||||||
new Notification(this.translate.instant('Tab activity'), {
|
|
||||||
body: extTab.title,
|
|
||||||
}).addEventListener('click', () => {
|
|
||||||
this.app.selectTab(extTab)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return items
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
title-bar(
|
title-bar(
|
||||||
*ngIf='ready && !hostWindow.isFullscreen && config.store.appearance.dock == "off" && isTitleBarNeeded()',
|
*ngIf='ready && !hostWindow.isFullscreen && config.store.appearance.frame == "full" && config.store.appearance.dock == "off"',
|
||||||
(dblclick)='toggleMaximize()',
|
(dblclick)='hostWindow.toggleMaximize()',
|
||||||
[hideControls]='hostApp.platform !== Platform.Linux && !hostWindow.isFullscreen',
|
[hideControls]='hostApp.platform !== Platform.Linux && !hostWindow.isFullscreen',
|
||||||
[class.inset]='hostApp.platform == Platform.macOS && !hostWindow.isFullscreen'
|
[class.inset]='hostApp.platform == Platform.macOS && !hostWindow.isFullscreen'
|
||||||
)
|
)
|
||||||
|
|
||||||
.content(
|
.content(
|
||||||
*ngIf='ready',
|
*ngIf='ready',
|
||||||
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left" || config.store.appearance.tabsLocation == "right"',
|
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left"',
|
||||||
[class.tabs-on-left]='hasVerticalTabs() && config.store.appearance.tabsLocation == "left"',
|
[class.tabs-on-left]='hasVerticalTabs() && config.store.appearance.tabsLocation == "left"',
|
||||||
[class.tabs-titlebar-enabled]='isTitleBarNeeded()',
|
[class.tabs-titlebar-enabled]='config.store.appearance.frame == "full"',
|
||||||
[class.tabs-on-right]='hasVerticalTabs() && config.store.appearance.tabsLocation == "right"',
|
[class.tabs-on-right]='hasVerticalTabs() && config.store.appearance.tabsLocation == "right"',
|
||||||
)
|
)
|
||||||
.tab-bar(
|
.tab-bar(
|
||||||
*ngIf='!hostWindow.isFullscreen || config.store.appearance.tabsInFullscreen',
|
*ngIf='!hostWindow.isFullscreen || config.store.appearance.tabsInFullscreen',
|
||||||
[class.tab-bar-no-controls-overlay]='hostApp.platform == Platform.macOS',
|
[class.tab-bar-no-controls-overlay]='hostApp.platform == Platform.macOS',
|
||||||
(dblclick)='!isTitleBarNeeded() && toggleMaximize()'
|
(dblclick)='hostWindow.toggleMaximize()'
|
||||||
)
|
)
|
||||||
.inset.background(*ngIf='hostApp.platform == Platform.macOS \
|
.inset.background(*ngIf='hostApp.platform == Platform.macOS \
|
||||||
&& !hostWindow.isFullscreen \
|
&& !hostWindow.isFullscreen \
|
||||||
@@ -35,7 +35,8 @@ title-bar(
|
|||||||
[@animateTab]='{value: "in", params: {size: targetTabSize}}',
|
[@animateTab]='{value: "in", params: {size: targetTabSize}}',
|
||||||
[@.disabled]='hasVerticalTabs() || !config.store.accessibility.animations',
|
[@.disabled]='hasVerticalTabs() || !config.store.accessibility.animations',
|
||||||
(click)='app.selectTab(tab)',
|
(click)='app.selectTab(tab)',
|
||||||
[class.fully-draggable]='hostApp.platform !== Platform.macOS'
|
[class.fully-draggable]='hostApp.platform != Platform.macOS',
|
||||||
|
[class.drag-region]='hostApp.platform == Platform.macOS && !(app.tabDragActive$|async)',
|
||||||
)
|
)
|
||||||
|
|
||||||
.btn-group.background
|
.btn-group.background
|
||||||
@@ -64,11 +65,7 @@ title-bar(
|
|||||||
(transfersChange)='onTransfersChange()'
|
(transfersChange)='onTransfersChange()'
|
||||||
)
|
)
|
||||||
|
|
||||||
.btn-space.background(
|
.drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
|
||||||
[class.persistent]='config.store.appearance.frame == "thin"',
|
|
||||||
[class.drag]='config.store.appearance.frame == "thin" \
|
|
||||||
&& ((config.store.appearance.tabsLocation !== "left" && config.store.appearance.tabsLocation !== "right") || hostApp.platform !== Platform.macOS)'
|
|
||||||
)
|
|
||||||
|
|
||||||
.btn-group.background
|
.btn-group.background
|
||||||
.d-flex(
|
.d-flex(
|
||||||
@@ -88,9 +85,7 @@ title-bar(
|
|||||||
|
|
||||||
window-controls.background(
|
window-controls.background(
|
||||||
*ngIf='config.store.appearance.frame == "thin" \
|
*ngIf='config.store.appearance.frame == "thin" \
|
||||||
&& config.store.appearance.tabsLocation !== "left" \
|
&& (hostApp.platform == Platform.Linux)',
|
||||||
&& config.store.appearance.tabsLocation !== "right" \
|
|
||||||
&& hostApp.platform == Platform.Linux',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
div.window-controls-spacer(
|
div.window-controls-spacer(
|
||||||
|
@@ -62,7 +62,7 @@ $tab-border-radius: 4px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-space {
|
.drag-space {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,18 +126,15 @@ $tab-border-radius: 4px;
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&>.btn-space {
|
&>.drag-space {
|
||||||
min-width: 1px;
|
min-width: 1px;
|
||||||
flex: 1 0 1%;
|
flex: 1 0 1%;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
.tabs-on-top & {
|
.tabs-on-top & {
|
||||||
margin-top: 2px; // for window resizing
|
margin-top: 2px; // for window resizing
|
||||||
}
|
}
|
||||||
|
|
||||||
&.drag {
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.persistent {
|
&.persistent {
|
||||||
// min-width: 72px; // 2 x 36 px height, ie 2 squares
|
// min-width: 72px; // 2 x 36 px height, ie 2 squares
|
||||||
// Given WCO on Windows, the min-width of the window buttons is about 138px.
|
// Given WCO on Windows, the min-width of the window buttons is about 138px.
|
||||||
|
@@ -238,21 +238,6 @@ export class AppRootComponent {
|
|||||||
|
|
||||||
private async getToolbarButtons (aboveZero: boolean): Promise<Command[]> {
|
private async getToolbarButtons (aboveZero: boolean): Promise<Command[]> {
|
||||||
return (await this.commands.getCommands({ tab: this.app.activeTab ?? undefined }))
|
return (await this.commands.getCommands({ tab: this.app.activeTab ?? undefined }))
|
||||||
.filter(x => x.locations.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
.filter(x => x.locations?.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||||
}
|
|
||||||
|
|
||||||
toggleMaximize (): void {
|
|
||||||
this.hostWindow.toggleMaximize()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected isTitleBarNeeded (): boolean {
|
|
||||||
return (
|
|
||||||
this.config.store.appearance.frame === 'full'
|
|
||||||
||
|
|
||||||
this.hostApp.platform !== Platform.macOS
|
|
||||||
&& this.config.store.appearance.frame === 'thin'
|
|
||||||
&& this.config.store.appearance.tabsLocation !== 'top'
|
|
||||||
&& this.config.store.appearance.tabsLocation !== 'bottom'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -75,7 +75,6 @@ export abstract class BaseTabComponent extends BaseComponent {
|
|||||||
private titleChange = new Subject<string>()
|
private titleChange = new Subject<string>()
|
||||||
private focused = new Subject<void>()
|
private focused = new Subject<void>()
|
||||||
private blurred = new Subject<void>()
|
private blurred = new Subject<void>()
|
||||||
private visibility = new Subject<boolean>()
|
|
||||||
private progress = new Subject<number|null>()
|
private progress = new Subject<number|null>()
|
||||||
private activity = new Subject<boolean>()
|
private activity = new Subject<boolean>()
|
||||||
private destroyed = new Subject<void>()
|
private destroyed = new Subject<void>()
|
||||||
@@ -84,8 +83,6 @@ export abstract class BaseTabComponent extends BaseComponent {
|
|||||||
|
|
||||||
get focused$ (): Observable<void> { return this.focused }
|
get focused$ (): Observable<void> { return this.focused }
|
||||||
get blurred$ (): Observable<void> { return this.blurred }
|
get blurred$ (): Observable<void> { return this.blurred }
|
||||||
/* @hidden */
|
|
||||||
get visibility$ (): Observable<boolean> { return this.visibility }
|
|
||||||
get titleChange$ (): Observable<string> { return this.titleChange.pipe(distinctUntilChanged()) }
|
get titleChange$ (): Observable<string> { return this.titleChange.pipe(distinctUntilChanged()) }
|
||||||
get progress$ (): Observable<number|null> { return this.progress.pipe(distinctUntilChanged()) }
|
get progress$ (): Observable<number|null> { return this.progress.pipe(distinctUntilChanged()) }
|
||||||
get activity$ (): Observable<boolean> { return this.activity }
|
get activity$ (): Observable<boolean> { return this.activity }
|
||||||
@@ -128,7 +125,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the activity marker on the tab header
|
* Shows the acticity marker on the tab header
|
||||||
*/
|
*/
|
||||||
displayActivity (): void {
|
displayActivity (): void {
|
||||||
if (!this.hasActivity) {
|
if (!this.hasActivity) {
|
||||||
@@ -138,7 +135,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the activity marker from the tab header
|
* Removes the acticity marker from the tab header
|
||||||
*/
|
*/
|
||||||
clearActivity (): void {
|
clearActivity (): void {
|
||||||
if (this.hasActivity) {
|
if (this.hasActivity) {
|
||||||
@@ -180,11 +177,6 @@ export abstract class BaseTabComponent extends BaseComponent {
|
|||||||
this.blurred.next()
|
this.blurred.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @hidden */
|
|
||||||
emitVisibility (visibility: boolean): void {
|
|
||||||
this.visibility.next(visibility)
|
|
||||||
}
|
|
||||||
|
|
||||||
insertIntoContainer (container: ViewContainerRef): EmbeddedViewRef<any> {
|
insertIntoContainer (container: ViewContainerRef): EmbeddedViewRef<any> {
|
||||||
this.viewContainerEmbeddedRef = container.insert(this.hostView) as EmbeddedViewRef<any>
|
this.viewContainerEmbeddedRef = container.insert(this.hostView) as EmbeddedViewRef<any>
|
||||||
this.viewContainer = container
|
this.viewContainer = container
|
||||||
|
@@ -18,26 +18,22 @@ export class SelectorModalComponent<T> {
|
|||||||
@Input() selectedIndex = 0
|
@Input() selectedIndex = 0
|
||||||
hasGroups = false
|
hasGroups = false
|
||||||
@ViewChildren('item') itemChildren: QueryList<ElementRef>
|
@ViewChildren('item') itemChildren: QueryList<ElementRef>
|
||||||
private preventEdit: boolean
|
|
||||||
|
|
||||||
constructor (public modalInstance: NgbActiveModal) {
|
constructor (
|
||||||
this.preventEdit = false
|
public modalInstance: NgbActiveModal,
|
||||||
}
|
) { }
|
||||||
|
|
||||||
ngOnInit (): void {
|
ngOnInit (): void {
|
||||||
this.onFilterChange()
|
this.onFilterChange()
|
||||||
this.hasGroups = this.options.some(x => x.group)
|
this.hasGroups = this.options.some(x => x.group)
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('keydown', ['$event']) onKeyDown (event: KeyboardEvent): void {
|
@HostListener('keydown', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
||||||
if (event.key === 'Escape') {
|
|
||||||
this.close()
|
|
||||||
} else if (this.filteredOptions.length > 0) {
|
|
||||||
if (event.key === 'PageUp' || event.key === 'ArrowUp' && event.metaKey) {
|
if (event.key === 'PageUp' || event.key === 'ArrowUp' && event.metaKey) {
|
||||||
this.selectedIndex -= Math.min(10, Math.max(1, this.selectedIndex))
|
this.selectedIndex -= 10
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
} else if (event.key === 'PageDown' || event.key === 'ArrowDown' && event.metaKey) {
|
} else if (event.key === 'PageDown' || event.key === 'ArrowDown' && event.metaKey) {
|
||||||
this.selectedIndex += Math.min(10, Math.max(1, this.filteredOptions.length - this.selectedIndex - 1))
|
this.selectedIndex += 10
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
} else if (event.key === 'ArrowUp') {
|
} else if (event.key === 'ArrowUp') {
|
||||||
this.selectedIndex--
|
this.selectedIndex--
|
||||||
@@ -47,30 +43,21 @@ export class SelectorModalComponent<T> {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
} else if (event.key === 'Enter') {
|
} else if (event.key === 'Enter') {
|
||||||
this.selectOption(this.filteredOptions[this.selectedIndex])
|
this.selectOption(this.filteredOptions[this.selectedIndex])
|
||||||
} else if (event.key === 'Backspace' && !this.preventEdit) {
|
} else if (event.key === 'Escape') {
|
||||||
if (this.canEditSelected()) {
|
this.close()
|
||||||
|
}
|
||||||
|
if (event.key === 'Backspace' && this.canEditSelected()) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.filter = this.filteredOptions[this.selectedIndex].freeInputEquivalent!
|
this.filter = this.filteredOptions[this.selectedIndex].freeInputEquivalent!
|
||||||
this.onFilterChange()
|
this.onFilterChange()
|
||||||
} else {
|
|
||||||
this.preventEdit = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
||||||
|
|
||||||
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
|
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
block: 'nearest',
|
block: 'nearest',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
|
||||||
if (event.key === 'Backspace' && this.preventEdit) {
|
|
||||||
this.preventEdit = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onFilterChange (): void {
|
onFilterChange (): void {
|
||||||
const f = this.filter.trim().toLowerCase()
|
const f = this.filter.trim().toLowerCase()
|
||||||
@@ -89,7 +76,7 @@ export class SelectorModalComponent<T> {
|
|||||||
{ sort: true },
|
{ sort: true },
|
||||||
).search(f)
|
).search(f)
|
||||||
|
|
||||||
this.options.filter(x => x.freeInputPattern).sort(firstBy<SelectorOption<T>, number>(x => x.weight ?? 0)).forEach(freeOption => {
|
this.options.filter(x => x.freeInputPattern).forEach(freeOption => {
|
||||||
if (!this.filteredOptions.includes(freeOption)) {
|
if (!this.filteredOptions.includes(freeOption)) {
|
||||||
this.filteredOptions.push(freeOption)
|
this.filteredOptions.push(freeOption)
|
||||||
}
|
}
|
||||||
|
@@ -275,7 +275,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||||
this.visibility$.subscribe(visibility => this.getAllTabs().forEach(x => x.emitVisibility(visibility)))
|
|
||||||
|
|
||||||
this.tabAdded$.subscribe(() => this.updateTitle())
|
this.tabAdded$.subscribe(() => this.updateTitle())
|
||||||
this.tabRemoved$.subscribe(() => this.updateTitle())
|
this.tabRemoved$.subscribe(() => this.updateTitle())
|
||||||
@@ -350,7 +349,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'close-pane':
|
case 'close-pane':
|
||||||
this.focusedTab.destroy()
|
this.removeTab(this.focusedTab)
|
||||||
break
|
break
|
||||||
case 'pane-increase-vertical':
|
case 'pane-increase-vertical':
|
||||||
this.resizePane('v')
|
this.resizePane('v')
|
||||||
@@ -475,7 +474,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
|||||||
|
|
||||||
let target = relative ? this.getParentOf(relative) : null
|
let target = relative ? this.getParentOf(relative) : null
|
||||||
if (!target) {
|
if (!target) {
|
||||||
// Rewrap the root container just in case the orientation isn't compatible
|
// Rewrap the root container just in case the orientation isn't compatibile
|
||||||
target = new SplitContainer()
|
target = new SplitContainer()
|
||||||
target.orientation = ['l', 'r'].includes(side) ? 'h' : 'v'
|
target.orientation = ['l', 'r'].includes(side) ? 'h' : 'v'
|
||||||
target.children = [this.root]
|
target.children = [this.root]
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
import { DomSanitizer } from '@angular/platform-browser'
|
||||||
import { firstBy } from 'thenby'
|
|
||||||
import { HomeBaseService } from '../services/homeBase.service'
|
import { HomeBaseService } from '../services/homeBase.service'
|
||||||
import { CommandService } from '../services/commands.service'
|
import { CommandService } from '../services/commands.service'
|
||||||
import { Command, CommandLocation } from '../api/commands'
|
import { Command, CommandLocation } from '../api/commands'
|
||||||
@@ -21,8 +20,7 @@ export class StartPageComponent {
|
|||||||
commands: CommandService,
|
commands: CommandService,
|
||||||
) {
|
) {
|
||||||
commands.getCommands({}).then(c => {
|
commands.getCommands({}).then(c => {
|
||||||
this.commands = c.filter(x => x.locations.includes(CommandLocation.StartPage))
|
this.commands = c.filter(x => x.locations?.includes(CommandLocation.StartPage))
|
||||||
this.commands.sort(firstBy(x => x.weight ?? 0))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,19 +1,16 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { Component, Input, HostBinding, HostListener, NgZone } from '@angular/core'
|
import { Component, Input, Optional, Inject, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||||
import { auditTime } from 'rxjs'
|
import { auditTime } from 'rxjs'
|
||||||
|
import { TabContextMenuItemProvider } from '../api/tabContextMenuProvider'
|
||||||
import { BaseTabComponent } from './baseTab.component'
|
import { BaseTabComponent } from './baseTab.component'
|
||||||
|
import { SplitTabComponent } from './splitTab.component'
|
||||||
import { HotkeysService } from '../services/hotkeys.service'
|
import { HotkeysService } from '../services/hotkeys.service'
|
||||||
import { AppService } from '../services/app.service'
|
import { AppService } from '../services/app.service'
|
||||||
import { HostAppService, Platform } from '../api/hostApp'
|
import { HostAppService, Platform } from '../api/hostApp'
|
||||||
import { ConfigService } from '../services/config.service'
|
import { ConfigService } from '../services/config.service'
|
||||||
import { CommandService } from '../services/commands.service'
|
import { BaseComponent } from './base.component'
|
||||||
import { MenuItemOptions } from '../api/menu'
|
import { MenuItemOptions } from '../api/menu'
|
||||||
import { PlatformService } from '../api/platform'
|
import { PlatformService } from '../api/platform'
|
||||||
import { CommandContext, CommandLocation } from '../api/commands'
|
|
||||||
|
|
||||||
import { BaseComponent } from './base.component'
|
|
||||||
import { SplitTabComponent } from './splitTab.component'
|
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Component({
|
@Component({
|
||||||
@@ -34,8 +31,8 @@ export class TabHeaderComponent extends BaseComponent {
|
|||||||
public hostApp: HostAppService,
|
public hostApp: HostAppService,
|
||||||
private hotkeys: HotkeysService,
|
private hotkeys: HotkeysService,
|
||||||
private platform: PlatformService,
|
private platform: PlatformService,
|
||||||
private commands: CommandService,
|
|
||||||
private zone: NgZone,
|
private zone: NgZone,
|
||||||
|
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, (hotkey) => {
|
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, (hotkey) => {
|
||||||
@@ -45,6 +42,7 @@ export class TabHeaderComponent extends BaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
@@ -58,17 +56,26 @@ export class TabHeaderComponent extends BaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async buildContextMenu (): Promise<MenuItemOptions[]> {
|
async buildContextMenu (): Promise<MenuItemOptions[]> {
|
||||||
const contexts: CommandContext[] = [{ tab: this.tab }]
|
let items: MenuItemOptions[] = []
|
||||||
|
|
||||||
// Top-level tab menu
|
// Top-level tab menu
|
||||||
|
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this.tab, true)))) {
|
||||||
|
items.push({ type: 'separator' })
|
||||||
|
items = items.concat(section)
|
||||||
|
}
|
||||||
if (this.tab instanceof SplitTabComponent) {
|
if (this.tab instanceof SplitTabComponent) {
|
||||||
const tab = this.tab.getFocusedTab()
|
const tab = this.tab.getFocusedTab()
|
||||||
if (tab) {
|
if (tab) {
|
||||||
contexts.push({ tab })
|
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, true)))) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||||
|
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||||
|
if (section.length) {
|
||||||
|
items.push({ type: 'separator' })
|
||||||
|
items = items.concat(section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return this.commands.buildContextMenu(contexts, CommandLocation.TabHeaderMenu)
|
}
|
||||||
|
return items.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
onTabDragStart (tab: BaseTabComponent) {
|
onTabDragStart (tab: BaseTabComponent) {
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
.container.mt-3.mb-3
|
.container.mt-5.mb-5
|
||||||
.mb-3
|
.mb-4
|
||||||
.tabby-logo
|
.tabby-logo
|
||||||
h1.tabby-title Tabby
|
h1.tabby-title Tabby
|
||||||
sup α
|
sup α
|
||||||
|
|
||||||
.text-center.mb-3(translate) Thank you for downloading Tabby!
|
.text-center.mb-5(translate) Thank you for downloading Tabby!
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
.header
|
.header
|
||||||
@@ -16,54 +16,13 @@
|
|||||||
*ngFor='let lang of allLanguages'
|
*ngFor='let lang of allLanguages'
|
||||||
) {{lang.name}}
|
) {{lang.name}}
|
||||||
|
|
||||||
.form-line
|
|
||||||
.header
|
|
||||||
.title(translate) Switch color scheme
|
|
||||||
|
|
||||||
.btn-group(role='group')
|
|
||||||
input.btn-check(
|
|
||||||
type='radio',
|
|
||||||
name='colorSchemeMode',
|
|
||||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
|
||||||
(ngModelChange)='config.save()',
|
|
||||||
id='colorSchemeModeAuto',
|
|
||||||
[value]='"auto"'
|
|
||||||
)
|
|
||||||
label.btn.btn-secondary(
|
|
||||||
for='colorSchemeModeAuto'
|
|
||||||
)
|
|
||||||
span(translate) From system
|
|
||||||
input.btn-check(
|
|
||||||
type='radio',
|
|
||||||
name='colorSchemeMode',
|
|
||||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
|
||||||
(ngModelChange)='config.save()',
|
|
||||||
id='colorSchemeModeDark',
|
|
||||||
[value]='"dark"'
|
|
||||||
)
|
|
||||||
label.btn.btn-secondary(
|
|
||||||
for='colorSchemeModeDark'
|
|
||||||
)
|
|
||||||
span(translate) Always dark
|
|
||||||
input.btn-check(
|
|
||||||
type='radio',
|
|
||||||
name='colorSchemeMode',
|
|
||||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
|
||||||
(ngModelChange)='config.save()',
|
|
||||||
id='colorSchemeModeLight',
|
|
||||||
[value]='"light"'
|
|
||||||
)
|
|
||||||
label.btn.btn-secondary(
|
|
||||||
for='colorSchemeModeLight'
|
|
||||||
)
|
|
||||||
span(translate) Always light
|
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title(translate) Enable analytics
|
.title(translate) Enable analytics
|
||||||
.description(translate) Help track the number of Tabby installs across the world!
|
.description(translate) Help track the number of Tabby installs across the world!
|
||||||
toggle([(ngModel)]='config.store.enableAnalytics')
|
toggle([(ngModel)]='config.store.enableAnalytics')
|
||||||
|
|
||||||
|
|
||||||
.form-line
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title(translate) Enable global hotkey (Ctrl-Space)
|
.title(translate) Enable global hotkey (Ctrl-Space)
|
||||||
|
@@ -6,8 +6,3 @@
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabby-logo {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
|
@@ -9,6 +9,5 @@ export class CoreConfigProvider extends ConfigProvider {
|
|||||||
[Platform.Linux]: require('./configDefaults.linux.yaml').default,
|
[Platform.Linux]: require('./configDefaults.linux.yaml').default,
|
||||||
[Platform.Web]: require('./configDefaults.web.yaml').default,
|
[Platform.Web]: require('./configDefaults.web.yaml').default,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaults = require('./configDefaults.yaml').default
|
defaults = require('./configDefaults.yaml').default
|
||||||
}
|
}
|
||||||
|
@@ -96,3 +96,5 @@ hotkeys:
|
|||||||
- '⌘-Shift-E'
|
- '⌘-Shift-E'
|
||||||
command-selector:
|
command-selector:
|
||||||
- '⌘-Shift-P'
|
- '⌘-Shift-P'
|
||||||
|
appearance:
|
||||||
|
vibrancy: true
|
||||||
|
@@ -19,7 +19,6 @@ appearance:
|
|||||||
vibrancyType: 'blur'
|
vibrancyType: 'blur'
|
||||||
lastTabClosesWindow: false
|
lastTabClosesWindow: false
|
||||||
spaciness: 1
|
spaciness: 1
|
||||||
colorSchemeMode: 'dark'
|
|
||||||
terminal:
|
terminal:
|
||||||
showBuiltinProfiles: true
|
showBuiltinProfiles: true
|
||||||
showRecentProfiles: 3
|
showRecentProfiles: 3
|
||||||
@@ -32,7 +31,6 @@ hotkeys:
|
|||||||
profile-selectors:
|
profile-selectors:
|
||||||
__nonStructural: true
|
__nonStructural: true
|
||||||
profiles: []
|
profiles: []
|
||||||
groups: []
|
|
||||||
profileDefaults:
|
profileDefaults:
|
||||||
__nonStructural: true
|
__nonStructural: true
|
||||||
ssh:
|
ssh:
|
||||||
|
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'
|
|||||||
import { TranslateService } from '@ngx-translate/core'
|
import { TranslateService } from '@ngx-translate/core'
|
||||||
import { ProfilesService } from './services/profiles.service'
|
import { ProfilesService } from './services/profiles.service'
|
||||||
import { HotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
|
import { HotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
|
||||||
|
import { PartialProfile, Profile } from './api'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -267,7 +268,7 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
|||||||
return [
|
return [
|
||||||
...this.hotkeys,
|
...this.hotkeys,
|
||||||
...profiles.map(profile => ({
|
...profiles.map(profile => ({
|
||||||
id: `profile.${ProfilesService.getProfileHotkeyName(profile)}`,
|
id: `profile.${AppHotkeyProvider.getProfileHotkeyName(profile)}`,
|
||||||
name: this.translate.instant('New tab: {profile}', { profile: profile.name }),
|
name: this.translate.instant('New tab: {profile}', { profile: profile.name }),
|
||||||
})),
|
})),
|
||||||
...this.profilesService.getProviders().map(provider => ({
|
...this.profilesService.getProviders().map(provider => ({
|
||||||
@@ -277,4 +278,7 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getProfileHotkeyName (profile: PartialProfile<Profile>): string {
|
||||||
|
return (profile.id ?? profile.name).replace(/\./g, '-')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
|||||||
import { DropZoneDirective } from './directives/dropZone.directive'
|
import { DropZoneDirective } from './directives/dropZone.directive'
|
||||||
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
|
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
|
||||||
|
|
||||||
import { Theme, CLIHandler, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||||
|
|
||||||
import { AppService } from './services/app.service'
|
import { AppService } from './services/app.service'
|
||||||
import { ConfigService } from './services/config.service'
|
import { ConfigService } from './services/config.service'
|
||||||
@@ -49,9 +49,10 @@ import { CommandService } from './services/commands.service'
|
|||||||
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme'
|
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme'
|
||||||
import { CoreConfigProvider } from './config'
|
import { CoreConfigProvider } from './config'
|
||||||
import { AppHotkeyProvider } from './hotkeys'
|
import { AppHotkeyProvider } from './hotkeys'
|
||||||
|
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
|
||||||
import { LastCLIHandler, ProfileCLIHandler } from './cli'
|
import { LastCLIHandler, ProfileCLIHandler } from './cli'
|
||||||
import { SplitLayoutProfilesService } from './profiles'
|
import { SplitLayoutProfilesService } from './profiles'
|
||||||
import { CoreCommandProvider, TaskCompletionCommandProvider } from './commands'
|
import { CoreCommandProvider } from './commands'
|
||||||
|
|
||||||
export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler {
|
export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler {
|
||||||
return new TranslateMessageFormatCompiler()
|
return new TranslateMessageFormatCompiler()
|
||||||
@@ -64,13 +65,16 @@ const PROVIDERS = [
|
|||||||
{ provide: Theme, useClass: PaperTheme, multi: true },
|
{ provide: Theme, useClass: PaperTheme, multi: true },
|
||||||
{ provide: Theme, useClass: NewTheme, multi: true },
|
{ provide: Theme, useClass: NewTheme, multi: true },
|
||||||
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: TabManagementContextMenu, multi: true },
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: ProfilesContextMenu, multi: true },
|
||||||
{ provide: TabRecoveryProvider, useExisting: SplitTabRecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useExisting: SplitTabRecoveryProvider, multi: true },
|
||||||
{ provide: CLIHandler, useClass: ProfileCLIHandler, multi: true },
|
{ provide: CLIHandler, useClass: ProfileCLIHandler, multi: true },
|
||||||
{ provide: CLIHandler, useClass: LastCLIHandler, multi: true },
|
{ provide: CLIHandler, useClass: LastCLIHandler, multi: true },
|
||||||
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
||||||
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true },
|
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true },
|
||||||
{ provide: CommandProvider, useExisting: CoreCommandProvider, multi: true },
|
{ provide: CommandProvider, useExisting: CoreCommandProvider, multi: true },
|
||||||
{ provide: CommandProvider, useExisting: TaskCompletionCommandProvider, multi: true },
|
|
||||||
{
|
{
|
||||||
provide: LOCALE_ID,
|
provide: LOCALE_ID,
|
||||||
deps: [LocaleService],
|
deps: [LocaleService],
|
||||||
@@ -173,7 +177,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
|||||||
if (hotkey.startsWith('profile.')) {
|
if (hotkey.startsWith('profile.')) {
|
||||||
const id = hotkey.substring(hotkey.indexOf('.') + 1)
|
const id = hotkey.substring(hotkey.indexOf('.') + 1)
|
||||||
const profiles = await profilesService.getProfiles()
|
const profiles = await profilesService.getProfiles()
|
||||||
const profile = profiles.find(x => ProfilesService.getProfileHotkeyName(x) === id)
|
const profile = profiles.find(x => AppHotkeyProvider.getProfileHotkeyName(x) === id)
|
||||||
if (profile) {
|
if (profile) {
|
||||||
profilesService.openNewTabForProfile(profile)
|
profilesService.openNewTabForProfile(profile)
|
||||||
}
|
}
|
||||||
@@ -184,10 +188,10 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
|||||||
if (!provider) {
|
if (!provider) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.showSelector(provider).catch(() => null)
|
this.showSelector(provider)
|
||||||
}
|
}
|
||||||
if (hotkey === 'command-selector') {
|
if (hotkey === 'command-selector') {
|
||||||
commands.showSelector().catch(() => null)
|
commands.showSelector()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hotkey === 'profile-selector') {
|
if (hotkey === 'profile-selector') {
|
||||||
@@ -210,7 +214,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
|||||||
callback: () => this.profilesService.openNewTabForProfile(p),
|
callback: () => this.profilesService.openNewTabForProfile(p),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (provider instanceof QuickConnectProfileProvider) {
|
if (provider.supportsQuickConnect) {
|
||||||
options.push({
|
options.push({
|
||||||
name: this.translate.instant('Quick connect'),
|
name: this.translate.instant('Quick connect'),
|
||||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||||
|
@@ -230,13 +230,11 @@ export class AppService {
|
|||||||
if (this._activeTab) {
|
if (this._activeTab) {
|
||||||
this._activeTab.clearActivity()
|
this._activeTab.clearActivity()
|
||||||
this._activeTab.emitBlurred()
|
this._activeTab.emitBlurred()
|
||||||
this._activeTab.emitVisibility(false)
|
|
||||||
}
|
}
|
||||||
this._activeTab = tab
|
this._activeTab = tab
|
||||||
this.activeTabChange.next(tab)
|
this.activeTabChange.next(tab)
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this._activeTab?.emitFocused()
|
this._activeTab?.emitFocused()
|
||||||
this._activeTab?.emitVisibility(true)
|
|
||||||
})
|
})
|
||||||
this.hostWindow.setTitle(this._activeTab?.title)
|
this.hostWindow.setTitle(this._activeTab?.title)
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,6 @@
|
|||||||
import { Inject, Injectable, Optional } from '@angular/core'
|
import { Inject, Injectable, Optional } from '@angular/core'
|
||||||
import { TranslateService } from '@ngx-translate/core'
|
import { AppService, Command, CommandContext, CommandProvider, ConfigService, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider, TranslateService } from '../api'
|
||||||
import { Command, CommandContext, CommandLocation, CommandProvider, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider } from '../api'
|
|
||||||
import { AppService } from './app.service'
|
|
||||||
import { ConfigService } from './config.service'
|
|
||||||
import { SelectorService } from './selector.service'
|
import { SelectorService } from './selector.service'
|
||||||
import { firstBy } from 'thenby'
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CommandService {
|
export class CommandService {
|
||||||
@@ -15,11 +11,11 @@ export class CommandService {
|
|||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[]|null,
|
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||||
@Optional() @Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
@Optional() @Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||||
@Inject(CommandProvider) private commandProviders: CommandProvider[],
|
@Inject(CommandProvider) private commandProviders: CommandProvider[],
|
||||||
) {
|
) {
|
||||||
this.contextMenuProviders?.sort((a, b) => a.weight - b.weight)
|
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCommands (context: CommandContext): Promise<Command[]> {
|
async getCommands (context: CommandContext): Promise<Command[]> {
|
||||||
@@ -34,7 +30,7 @@ export class CommandService {
|
|||||||
if (context.tab) {
|
if (context.tab) {
|
||||||
for (const tabHeader of [false, true]) {
|
for (const tabHeader of [false, true]) {
|
||||||
// Top-level tab menu
|
// Top-level tab menu
|
||||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(context.tab!, tabHeader)) ?? [])) {
|
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(context.tab!, tabHeader)))) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||||
items = items.concat(section)
|
items = items.concat(section)
|
||||||
@@ -42,7 +38,7 @@ export class CommandService {
|
|||||||
if (context.tab instanceof SplitTabComponent) {
|
if (context.tab instanceof SplitTabComponent) {
|
||||||
const tab = context.tab.getFocusedTab()
|
const tab = context.tab.getFocusedTab()
|
||||||
if (tab) {
|
if (tab) {
|
||||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(tab, tabHeader)) ?? [])) {
|
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, tabHeader)))) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||||
items = items.concat(section)
|
items = items.concat(section)
|
||||||
@@ -54,10 +50,21 @@ export class CommandService {
|
|||||||
|
|
||||||
items = items.filter(x => (x.enabled ?? true) && x.type !== 'separator')
|
items = items.filter(x => (x.enabled ?? true) && x.type !== 'separator')
|
||||||
|
|
||||||
const commands = [
|
const flatItems: MenuItemOptions[] = []
|
||||||
...buttons.map(x => Command.fromToolbarButton(x)),
|
function flattenItem (item: MenuItemOptions, prefix?: string): void {
|
||||||
...items.map(x => Command.fromMenuItem(x)).flat(),
|
if (item.submenu) {
|
||||||
]
|
item.submenu.forEach(x => flattenItem(x, (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label)))
|
||||||
|
} else {
|
||||||
|
flatItems.push({
|
||||||
|
...item,
|
||||||
|
label: (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.forEach(x => flattenItem(x))
|
||||||
|
|
||||||
|
const commands = buttons.map(x => Command.fromToolbarButton(x))
|
||||||
|
commands.push(...flatItems.map(x => Command.fromMenuItem(x)))
|
||||||
|
|
||||||
for (const provider of this.config.enabledServices(this.commandProviders)) {
|
for (const provider of this.config.enabledServices(this.commandProviders)) {
|
||||||
commands.push(...await provider.provide(context))
|
commands.push(...await provider.provide(context))
|
||||||
@@ -67,36 +74,20 @@ export class CommandService {
|
|||||||
.filter(c => !this.config.store.commandBlacklist.includes(c.id))
|
.filter(c => !this.config.store.commandBlacklist.includes(c.id))
|
||||||
.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||||
.map(command => {
|
.map(command => {
|
||||||
if (command.run) {
|
|
||||||
const run = command.run
|
const run = command.run
|
||||||
command.run = async () => {
|
command.run = async () => {
|
||||||
// Serialize execution
|
// Serialize execution
|
||||||
this.lastCommand = this.lastCommand.finally(run)
|
this.lastCommand = this.lastCommand.finally(run)
|
||||||
await this.lastCommand
|
await this.lastCommand
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return command
|
return command
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCommandsWithContexts (context: CommandContext[]): Promise<Command[]> {
|
|
||||||
let commands: Command[] = []
|
|
||||||
|
|
||||||
for (const commandSet of await Promise.all(context.map(x => this.getCommands(x)))) {
|
|
||||||
for (const command of commandSet) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
||||||
commands = commands.filter(x => x.id !== command.id)
|
|
||||||
commands.push(command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands
|
|
||||||
}
|
|
||||||
|
|
||||||
async run (id: string, context: CommandContext): Promise<void> {
|
async run (id: string, context: CommandContext): Promise<void> {
|
||||||
const commands = await this.getCommands(context)
|
const commands = await this.getCommands(context)
|
||||||
const command = commands.find(x => x.id === id)
|
const command = commands.find(x => x.id === id)
|
||||||
await command?.run?.()
|
await command?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
async showSelector (): Promise<void> {
|
async showSelector (): Promise<void> {
|
||||||
@@ -104,80 +95,20 @@ export class CommandService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const contexts: CommandContext[] = [{}]
|
const context: CommandContext = {}
|
||||||
if (this.app.activeTab) {
|
const tab = this.app.activeTab
|
||||||
contexts.push({ tab: this.app.activeTab })
|
if (tab instanceof SplitTabComponent) {
|
||||||
|
context.tab = tab.getFocusedTab() ?? undefined
|
||||||
}
|
}
|
||||||
if (this.app.activeTab instanceof SplitTabComponent) {
|
const commands = await this.getCommands(context)
|
||||||
const tab = this.app.activeTab.getFocusedTab()
|
await this.selector.show(
|
||||||
if (tab) {
|
|
||||||
contexts.push({ tab })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const commands = (await this.getCommandsWithContexts(contexts))
|
|
||||||
.filter(x => x.run)
|
|
||||||
.sort(firstBy(x => x.weight ?? 0))
|
|
||||||
|
|
||||||
return this.selector.show(
|
|
||||||
this.translate.instant('Commands'),
|
this.translate.instant('Commands'),
|
||||||
commands.map(c => ({
|
commands.map(c => ({
|
||||||
name: c.fullLabel ?? c.label,
|
name: c.label,
|
||||||
callback: c.run,
|
callback: c.run,
|
||||||
|
description: c.sublabel,
|
||||||
icon: c.icon,
|
icon: c.icon,
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hidden */
|
|
||||||
async buildContextMenu (contexts: CommandContext[], location: CommandLocation): Promise<MenuItemOptions[]> {
|
|
||||||
let commands = await this.getCommandsWithContexts(contexts)
|
|
||||||
|
|
||||||
commands = commands.filter(x => x.locations.includes(location))
|
|
||||||
commands.sort(firstBy(x => x.weight ?? 0))
|
|
||||||
|
|
||||||
interface Group {
|
|
||||||
id?: string
|
|
||||||
weight: number
|
|
||||||
commands: Command[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const groups: Group[] = []
|
|
||||||
|
|
||||||
for (const command of commands.filter(x => !x.parent)) {
|
|
||||||
let group = groups.find(x => x.id === command.group)
|
|
||||||
if (!group) {
|
|
||||||
group = {
|
|
||||||
id: command.group,
|
|
||||||
weight: 0,
|
|
||||||
commands: [],
|
|
||||||
}
|
|
||||||
groups.push(group)
|
|
||||||
}
|
|
||||||
group.weight += command.weight ?? 0
|
|
||||||
group.commands.push(command)
|
|
||||||
}
|
|
||||||
|
|
||||||
groups.sort(firstBy(x => x.weight / x.commands.length))
|
|
||||||
|
|
||||||
function mapCommand (command: Command): MenuItemOptions {
|
|
||||||
const submenu = command.id ? commands.filter(x => x.parent === command.id).map(mapCommand) : []
|
|
||||||
return {
|
|
||||||
label: command.label,
|
|
||||||
submenu: submenu.length ? submenu : undefined,
|
|
||||||
checked: command.checked,
|
|
||||||
enabled: !!command.run || !!submenu.length,
|
|
||||||
type: command.checked ? 'checkbox' : undefined,
|
|
||||||
click: () => command.run?.(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const items: MenuItemOptions[] = []
|
|
||||||
for (const group of groups) {
|
|
||||||
items.push({ type: 'separator' })
|
|
||||||
items.push(...group.commands.map(mapCommand))
|
|
||||||
}
|
|
||||||
|
|
||||||
return items.slice(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@ import { PlatformService } from '../api/platform'
|
|||||||
import { HostAppService } from '../api/hostApp'
|
import { HostAppService } from '../api/hostApp'
|
||||||
import { Vault, VaultService } from './vault.service'
|
import { Vault, VaultService } from './vault.service'
|
||||||
import { serializeFunction } from '../utils'
|
import { serializeFunction } from '../utils'
|
||||||
import { PartialProfileGroup, ProfileGroup } from '../api/profileProvider'
|
|
||||||
const deepmerge = require('deepmerge')
|
const deepmerge = require('deepmerge')
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
@@ -365,55 +364,6 @@ export class ConfigService {
|
|||||||
}
|
}
|
||||||
config.version = 4
|
config.version = 4
|
||||||
}
|
}
|
||||||
if (config.version < 5) {
|
|
||||||
const groups: PartialProfileGroup<ProfileGroup>[] = []
|
|
||||||
for (const p of config.profiles ?? []) {
|
|
||||||
if (!(p.group ?? '').trim()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let group = groups.find(x => x.name === p.group)
|
|
||||||
if (!group) {
|
|
||||||
group = {
|
|
||||||
id: `${uuidv4()}`,
|
|
||||||
name: `${p.group}`,
|
|
||||||
}
|
|
||||||
groups.push(group)
|
|
||||||
}
|
|
||||||
p.group = group.id
|
|
||||||
}
|
|
||||||
|
|
||||||
const profileGroupCollapsed = JSON.parse(window.localStorage.profileGroupCollapsed ?? '{}')
|
|
||||||
for (const g of groups) {
|
|
||||||
if (profileGroupCollapsed[g.name]) {
|
|
||||||
const collapsed = profileGroupCollapsed[g.name]
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
||||||
delete profileGroupCollapsed[g.name]
|
|
||||||
profileGroupCollapsed[g.id] = collapsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.localStorage.profileGroupCollapsed = JSON.stringify(profileGroupCollapsed)
|
|
||||||
|
|
||||||
config.groups = groups
|
|
||||||
config.version = 5
|
|
||||||
}
|
|
||||||
if (config.version < 6) {
|
|
||||||
if (config.ssh?.clearServiceMessagesOnConnect === false) {
|
|
||||||
config.profileDefaults ??= {}
|
|
||||||
config.profileDefaults.ssh ??= {}
|
|
||||||
config.profileDefaults.ssh.clearServiceMessagesOnConnect = false
|
|
||||||
delete config.ssh?.clearServiceMessagesOnConnect
|
|
||||||
}
|
|
||||||
config.version = 6
|
|
||||||
}
|
|
||||||
if (config.version < 7) {
|
|
||||||
if (!config.configSync?.host || config.configSync?.host === 'https://api.tabby.sh') {
|
|
||||||
config.configSync ??= {}
|
|
||||||
delete config.configSync.host
|
|
||||||
delete config.configSync.token
|
|
||||||
}
|
|
||||||
config.version = 7
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async maybeDecryptConfig (store) {
|
private async maybeDecryptConfig (store) {
|
||||||
|
@@ -13,9 +13,8 @@ export class FileProvidersService {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
async selectAndStoreFile (description: string): Promise<string> {
|
async selectAndStoreFile (description: string): Promise<string> {
|
||||||
return this.selectProvider().then(p => {
|
const p = await this.selectProvider()
|
||||||
return p.selectAndStoreFile(description)
|
return p.selectAndStoreFile(description)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async retrieveFile (key: string): Promise<Buffer> {
|
async retrieveFile (key: string): Promise<Buffer> {
|
||||||
|
@@ -2,15 +2,12 @@ import { Injectable, Inject } from '@angular/core'
|
|||||||
import { TranslateService } from '@ngx-translate/core'
|
import { TranslateService } from '@ngx-translate/core'
|
||||||
import { NewTabParameters } from './tabs.service'
|
import { NewTabParameters } from './tabs.service'
|
||||||
import { BaseTabComponent } from '../components/baseTab.component'
|
import { BaseTabComponent } from '../components/baseTab.component'
|
||||||
import { QuickConnectProfileProvider, PartialProfile, PartialProfileGroup, Profile, ProfileGroup, ProfileProvider } from '../api/profileProvider'
|
import { PartialProfile, Profile, ProfileProvider } from '../api/profileProvider'
|
||||||
import { SelectorOption } from '../api/selector'
|
import { SelectorOption } from '../api/selector'
|
||||||
import { AppService } from './app.service'
|
import { AppService } from './app.service'
|
||||||
import { configMerge, ConfigProxy, ConfigService } from './config.service'
|
import { configMerge, ConfigProxy, ConfigService } from './config.service'
|
||||||
import { NotificationsService } from './notifications.service'
|
import { NotificationsService } from './notifications.service'
|
||||||
import { SelectorService } from './selector.service'
|
import { SelectorService } from './selector.service'
|
||||||
import deepClone from 'clone-deep'
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import slugify from 'slugify'
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ProfilesService {
|
export class ProfilesService {
|
||||||
@@ -39,127 +36,6 @@ export class ProfilesService {
|
|||||||
@Inject(ProfileProvider) private profileProviders: ProfileProvider<Profile>[],
|
@Inject(ProfileProvider) private profileProviders: ProfileProvider<Profile>[],
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/*
|
|
||||||
* Methods used to interact with ProfileProvider
|
|
||||||
*/
|
|
||||||
|
|
||||||
getProviders (): ProfileProvider<Profile>[] {
|
|
||||||
return [...this.profileProviders]
|
|
||||||
}
|
|
||||||
|
|
||||||
providerForProfile <T extends Profile> (profile: PartialProfile<T>): ProfileProvider<T>|null {
|
|
||||||
const provider = this.profileProviders.find(x => x.id === profile.type) ?? null
|
|
||||||
return provider as unknown as ProfileProvider<T>|null
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription <P extends Profile> (profile: PartialProfile<P>): string|null {
|
|
||||||
profile = this.getConfigProxyForProfile(profile)
|
|
||||||
return this.providerForProfile(profile)?.getDescription(profile) ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Methods used to interact with Profile
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return ConfigProxy for a given Profile
|
|
||||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
|
||||||
* arg: skipGroupDefaults -> do not merge parent group provider defaults in ConfigProxy
|
|
||||||
*/
|
|
||||||
getConfigProxyForProfile <T extends Profile> (profile: PartialProfile<T>, options?: { skipGlobalDefaults?: boolean, skipGroupDefaults?: boolean }): T {
|
|
||||||
const defaults = this.getProfileDefaults(profile, options).reduce(configMerge, {})
|
|
||||||
return new ConfigProxy(profile, defaults) as unknown as T
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an Array of Profiles
|
|
||||||
* arg: includeBuiltin (default: true) -> include BuiltinProfiles
|
|
||||||
* arg: clone (default: false) -> return deepclone Array
|
|
||||||
*/
|
|
||||||
async getProfiles (options?: { includeBuiltin?: boolean, clone?: boolean }): Promise<PartialProfile<Profile>[]> {
|
|
||||||
let list = this.config.store.profiles ?? []
|
|
||||||
if (options?.includeBuiltin ?? true) {
|
|
||||||
const lists = await Promise.all(this.config.enabledServices(this.profileProviders).map(x => x.getBuiltinProfiles()))
|
|
||||||
list = [
|
|
||||||
...this.config.store.profiles ?? [],
|
|
||||||
...lists.reduce((a, b) => a.concat(b), []),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const sortKey = p => `${this.resolveProfileGroupName(p.group ?? '')} / ${p.name}`
|
|
||||||
list.sort((a, b) => sortKey(a).localeCompare(sortKey(b)))
|
|
||||||
list.sort((a, b) => (a.isBuiltin ? 1 : 0) - (b.isBuiltin ? 1 : 0))
|
|
||||||
return options?.clone ? deepClone(list) : list
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a new Profile in config
|
|
||||||
* arg: genId (default: true) -> generate uuid in before pushing Profile into config
|
|
||||||
*/
|
|
||||||
async newProfile (profile: PartialProfile<Profile>, options?: { genId?: boolean }): Promise<void> {
|
|
||||||
if (options?.genId ?? true) {
|
|
||||||
profile.id = `${profile.type}:custom:${slugify(profile.name)}:${uuidv4()}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const cProfile = this.config.store.profiles.find(p => p.id === profile.id)
|
|
||||||
if (cProfile) {
|
|
||||||
throw new Error(`Cannot insert new Profile, duplicated Id: ${profile.id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.config.store.profiles.push(profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a Profile in config
|
|
||||||
*/
|
|
||||||
async writeProfile (profile: PartialProfile<Profile>): Promise<void> {
|
|
||||||
const cProfile = this.config.store.profiles.find(p => p.id === profile.id)
|
|
||||||
if (cProfile) {
|
|
||||||
// Fully replace the config
|
|
||||||
for (const k in cProfile) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
||||||
delete cProfile[k]
|
|
||||||
}
|
|
||||||
Object.assign(cProfile, profile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a Profile from config
|
|
||||||
*/
|
|
||||||
async deleteProfile (profile: PartialProfile<Profile>): Promise<void> {
|
|
||||||
this.providerForProfile(profile)?.deleteProfile(this.getConfigProxyForProfile(profile))
|
|
||||||
this.config.store.profiles = this.config.store.profiles.filter(p => p.id !== profile.id)
|
|
||||||
|
|
||||||
const profileHotkeyName = ProfilesService.getProfileHotkeyName(profile)
|
|
||||||
if (this.config.store.hotkeys.profile.hasOwnProperty(profileHotkeyName)) {
|
|
||||||
const profileHotkeys = deepClone(this.config.store.hotkeys.profile)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
||||||
delete profileHotkeys[profileHotkeyName]
|
|
||||||
this.config.store.hotkeys.profile = profileHotkeys
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all Profiles from config using option filter
|
|
||||||
* arg: filter (p: PartialProfile<Profile>) => boolean -> predicate used to decide which profiles have to be deleted
|
|
||||||
*/
|
|
||||||
async bulkDeleteProfiles (filter: (p: PartialProfile<Profile>) => boolean): Promise<void> {
|
|
||||||
for (const profile of this.config.store.profiles.filter(filter)) {
|
|
||||||
this.providerForProfile(profile)?.deleteProfile(this.getConfigProxyForProfile(profile))
|
|
||||||
|
|
||||||
const profileHotkeyName = ProfilesService.getProfileHotkeyName(profile)
|
|
||||||
if (this.config.store.hotkeys.profile.hasOwnProperty(profileHotkeyName)) {
|
|
||||||
const profileHotkeys = deepClone(this.config.store.hotkeys.profile)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
||||||
delete profileHotkeys[profileHotkeyName]
|
|
||||||
this.config.store.hotkeys.profile = profileHotkeys
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.config.store.profiles = this.config.store.profiles.filter(x => !filter(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
async openNewTabForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<BaseTabComponent|null> {
|
async openNewTabForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<BaseTabComponent|null> {
|
||||||
const params = await this.newTabParametersForProfile(profile)
|
const params = await this.newTabParametersForProfile(profile)
|
||||||
if (params) {
|
if (params) {
|
||||||
@@ -187,40 +63,52 @@ export class ProfilesService {
|
|||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchProfile (profile: PartialProfile<Profile>): Promise<void> {
|
getProviders (): ProfileProvider<Profile>[] {
|
||||||
await this.openNewTabForProfile(profile)
|
return [...this.profileProviders]
|
||||||
|
|
||||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
|
||||||
if (this.config.store.terminal.showRecentProfiles > 0) {
|
|
||||||
recentProfiles = recentProfiles.filter(x => x.group !== profile.group || x.name !== profile.name)
|
|
||||||
recentProfiles.unshift(profile)
|
|
||||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
|
||||||
} else {
|
|
||||||
recentProfiles = []
|
|
||||||
}
|
|
||||||
window.localStorage['recentProfiles'] = JSON.stringify(recentProfiles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getProfileHotkeyName (profile: PartialProfile<Profile>): string {
|
async getProfiles (): Promise<PartialProfile<Profile>[]> {
|
||||||
return (profile.id ?? profile.name).replace(/\./g, '-')
|
const lists = await Promise.all(this.config.enabledServices(this.profileProviders).map(x => x.getBuiltinProfiles()))
|
||||||
|
let list = lists.reduce((a, b) => a.concat(b), [])
|
||||||
|
list = [
|
||||||
|
...this.config.store.profiles ?? [],
|
||||||
|
...list,
|
||||||
|
]
|
||||||
|
const sortKey = p => `${p.group ?? ''} / ${p.name}`
|
||||||
|
list.sort((a, b) => sortKey(a).localeCompare(sortKey(b)))
|
||||||
|
list.sort((a, b) => (a.isBuiltin ? 1 : 0) - (b.isBuiltin ? 1 : 0))
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
providerForProfile <T extends Profile> (profile: PartialProfile<T>): ProfileProvider<T>|null {
|
||||||
* Methods used to interact with Profile Selector
|
const provider = this.profileProviders.find(x => x.id === profile.type) ?? null
|
||||||
*/
|
return provider as unknown as ProfileProvider<T>|null
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription <P extends Profile> (profile: PartialProfile<P>): string|null {
|
||||||
|
profile = this.getConfigProxyForProfile(profile)
|
||||||
|
return this.providerForProfile(profile)?.getDescription(profile) ?? null
|
||||||
|
}
|
||||||
|
|
||||||
selectorOptionForProfile <P extends Profile, T> (profile: PartialProfile<P>): SelectorOption<T> {
|
selectorOptionForProfile <P extends Profile, T> (profile: PartialProfile<P>): SelectorOption<T> {
|
||||||
const fullProfile = this.getConfigProxyForProfile(profile)
|
const fullProfile = this.getConfigProxyForProfile(profile)
|
||||||
const provider = this.providerForProfile(fullProfile)
|
const provider = this.providerForProfile(fullProfile)
|
||||||
const freeInputEquivalent = provider instanceof QuickConnectProfileProvider ? provider.intoQuickConnectString(fullProfile) ?? undefined : undefined
|
const freeInputEquivalent = provider?.intoQuickConnectString(fullProfile) ?? undefined
|
||||||
return {
|
return {
|
||||||
...profile,
|
...profile,
|
||||||
group: this.resolveProfileGroupName(profile.group ?? ''),
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||||
|
group: profile.group || '',
|
||||||
freeInputEquivalent,
|
freeInputEquivalent,
|
||||||
description: provider?.getDescription(fullProfile),
|
description: provider?.getDescription(fullProfile),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRecentProfiles (): PartialProfile<Profile>[] {
|
||||||
|
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||||
|
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||||
|
return recentProfiles
|
||||||
|
}
|
||||||
|
|
||||||
showProfileSelector (): Promise<PartialProfile<Profile>|null> {
|
showProfileSelector (): Promise<PartialProfile<Profile>|null> {
|
||||||
if (this.selector.active) {
|
if (this.selector.active) {
|
||||||
return Promise.resolve(null)
|
return Promise.resolve(null)
|
||||||
@@ -230,12 +118,12 @@ export class ProfilesService {
|
|||||||
try {
|
try {
|
||||||
const recentProfiles = this.getRecentProfiles()
|
const recentProfiles = this.getRecentProfiles()
|
||||||
|
|
||||||
let options: SelectorOption<void>[] = recentProfiles.map((p, i) => ({
|
let options: SelectorOption<void>[] = recentProfiles.map(p => ({
|
||||||
...this.selectorOptionForProfile(p),
|
...this.selectorOptionForProfile(p),
|
||||||
group: this.translate.instant('Recent'),
|
group: this.translate.instant('Recent'),
|
||||||
icon: 'fas fa-history',
|
icon: 'fas fa-history',
|
||||||
color: p.color,
|
color: p.color,
|
||||||
weight: i - (recentProfiles.length + 1),
|
weight: -2,
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
if (p.id) {
|
if (p.id) {
|
||||||
p = (await this.getProfiles()).find(x => x.id === p.id) ?? p
|
p = (await this.getProfiles()).find(x => x.id === p.id) ?? p
|
||||||
@@ -289,8 +177,7 @@ export class ProfilesService {
|
|||||||
})
|
})
|
||||||
} catch { }
|
} catch { }
|
||||||
|
|
||||||
this.getProviders().forEach(provider => {
|
this.getProviders().filter(x => x.supportsQuickConnect).forEach(provider => {
|
||||||
if (provider instanceof QuickConnectProfileProvider) {
|
|
||||||
options.push({
|
options.push({
|
||||||
name: this.translate.instant('Quick connect'),
|
name: this.translate.instant('Quick connect'),
|
||||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||||
@@ -302,25 +189,18 @@ export class ProfilesService {
|
|||||||
resolve(profile)
|
resolve(profile)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.selector.show(this.translate.instant('Select profile or enter an address'), options).catch(() => reject())
|
await this.selector.show(this.translate.instant('Select profile or enter an address'), options)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecentProfiles (): PartialProfile<Profile>[] {
|
|
||||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
|
||||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
|
||||||
return recentProfiles
|
|
||||||
}
|
|
||||||
|
|
||||||
async quickConnect (query: string): Promise<PartialProfile<Profile>|null> {
|
async quickConnect (query: string): Promise<PartialProfile<Profile>|null> {
|
||||||
for (const provider of this.getProviders()) {
|
for (const provider of this.getProviders()) {
|
||||||
if (provider instanceof QuickConnectProfileProvider) {
|
if (provider.supportsQuickConnect) {
|
||||||
const profile = provider.quickConnect(query)
|
const profile = provider.quickConnect(query)
|
||||||
if (profile) {
|
if (profile) {
|
||||||
return profile
|
return profile
|
||||||
@@ -331,178 +211,27 @@ export class ProfilesService {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
getConfigProxyForProfile <T extends Profile> (profile: PartialProfile<T>, skipUserDefaults = false): T {
|
||||||
* Methods used to interact with Profile/ProfileGroup/Global defaults
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return global defaults for a given profile provider
|
|
||||||
* Always return something, empty object if no defaults found
|
|
||||||
*/
|
|
||||||
getProviderDefaults (provider: ProfileProvider<Profile>): any {
|
|
||||||
const defaults = this.config.store.profileDefaults
|
|
||||||
return defaults[provider.id] ?? {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set global defaults for a given profile provider
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
||||||
setProviderDefaults (provider: ProfileProvider<Profile>, pdefaults: any): void {
|
|
||||||
this.config.store.profileDefaults[provider.id] = pdefaults
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return defaults for a given profile
|
|
||||||
* Always return something, empty object if no defaults found
|
|
||||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
|
||||||
* arg: skipGroupDefaults -> do not merge parent group provider defaults in ConfigProxy
|
|
||||||
*/
|
|
||||||
getProfileDefaults (profile: PartialProfile<Profile>, options?: { skipGlobalDefaults?: boolean, skipGroupDefaults?: boolean }): any[] {
|
|
||||||
const provider = this.providerForProfile(profile)
|
const provider = this.providerForProfile(profile)
|
||||||
|
const defaults = [
|
||||||
return [
|
|
||||||
this.profileDefaults,
|
this.profileDefaults,
|
||||||
provider?.configDefaults ?? {},
|
provider?.configDefaults ?? {},
|
||||||
provider && !options?.skipGlobalDefaults ? this.getProviderDefaults(provider) : {},
|
!provider || skipUserDefaults ? {} : this.config.store.profileDefaults[provider.id] ?? {},
|
||||||
provider && !options?.skipGlobalDefaults && !options?.skipGroupDefaults ? this.getProviderProfileGroupDefaults(profile.group ?? '', provider) : {},
|
].reduce(configMerge, {})
|
||||||
]
|
return new ConfigProxy(profile, defaults) as unknown as T
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
async launchProfile (profile: PartialProfile<Profile>): Promise<void> {
|
||||||
* Methods used to interact with ProfileGroup
|
await this.openNewTabForProfile(profile)
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||||
* Synchronously return an Array of the existing ProfileGroups
|
if (this.config.store.terminal.showRecentProfiles > 0) {
|
||||||
* Does not return builtin groups
|
recentProfiles = recentProfiles.filter(x => x.group !== profile.group || x.name !== profile.name)
|
||||||
*/
|
recentProfiles.unshift(profile)
|
||||||
getSyncProfileGroups (): PartialProfileGroup<ProfileGroup>[] {
|
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||||
return deepClone(this.config.store.groups ?? [])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an Array of the existing ProfileGroups
|
|
||||||
* arg: includeProfiles (default: false) -> if false, does not fill up the profiles field of ProfileGroup
|
|
||||||
* arg: includeNonUserGroup (default: false) -> if false, does not add built-in and ungrouped groups
|
|
||||||
*/
|
|
||||||
async getProfileGroups (options?: { includeProfiles?: boolean, includeNonUserGroup?: boolean }): Promise<PartialProfileGroup<ProfileGroup>[]> {
|
|
||||||
let profiles: PartialProfile<Profile>[] = []
|
|
||||||
if (options?.includeProfiles) {
|
|
||||||
profiles = await this.getProfiles({ includeBuiltin: options.includeNonUserGroup, clone: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
let groups: PartialProfileGroup<ProfileGroup>[] = this.getSyncProfileGroups()
|
|
||||||
groups = groups.map(x => {
|
|
||||||
x.editable = true
|
|
||||||
|
|
||||||
if (options?.includeProfiles) {
|
|
||||||
x.profiles = profiles.filter(p => p.group === x.id)
|
|
||||||
profiles = profiles.filter(p => p.group !== x.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
|
||||||
})
|
|
||||||
|
|
||||||
if (options?.includeNonUserGroup) {
|
|
||||||
const builtInGroups: PartialProfileGroup<ProfileGroup>[] = []
|
|
||||||
builtInGroups.push({
|
|
||||||
id: 'built-in',
|
|
||||||
name: this.translate.instant('Built-in'),
|
|
||||||
editable: false,
|
|
||||||
profiles: [],
|
|
||||||
})
|
|
||||||
|
|
||||||
const ungrouped: PartialProfileGroup<ProfileGroup> = {
|
|
||||||
id: 'ungrouped',
|
|
||||||
name: this.translate.instant('Ungrouped'),
|
|
||||||
editable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.includeProfiles) {
|
|
||||||
for (const profile of profiles.filter(p => p.isBuiltin)) {
|
|
||||||
let group: PartialProfileGroup<ProfileGroup> | undefined = builtInGroups.find(g => g.id === slugify(profile.group ?? 'built-in'))
|
|
||||||
if (!group) {
|
|
||||||
group = {
|
|
||||||
id: `${slugify(profile.group!)}`,
|
|
||||||
name: `${profile.group!}`,
|
|
||||||
editable: false,
|
|
||||||
profiles: [],
|
|
||||||
}
|
|
||||||
builtInGroups.push(group)
|
|
||||||
}
|
|
||||||
|
|
||||||
group.profiles!.push(profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
ungrouped.profiles = profiles.filter(p => !p.isBuiltin)
|
|
||||||
}
|
|
||||||
|
|
||||||
groups = groups.concat(builtInGroups)
|
|
||||||
groups.push(ungrouped)
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a new ProfileGroup in config
|
|
||||||
* arg: genId (default: true) -> generate uuid in before pushing Profile into config
|
|
||||||
*/
|
|
||||||
async newProfileGroup (group: PartialProfileGroup<ProfileGroup>, options?: { genId?: boolean }): Promise<void> {
|
|
||||||
if (options?.genId ?? true) {
|
|
||||||
group.id = `${uuidv4()}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const cProfileGroup = this.config.store.groups.find(p => p.id === group.id)
|
|
||||||
if (cProfileGroup) {
|
|
||||||
throw new Error(`Cannot insert new ProfileGroup, duplicated Id: ${group.id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.config.store.groups.push(group)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a ProfileGroup in config
|
|
||||||
*/
|
|
||||||
async writeProfileGroup (group: PartialProfileGroup<ProfileGroup>): Promise<void> {
|
|
||||||
delete group.profiles
|
|
||||||
delete group.editable
|
|
||||||
|
|
||||||
const cGroup = this.config.store.groups.find(g => g.id === group.id)
|
|
||||||
if (cGroup) {
|
|
||||||
Object.assign(cGroup, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a ProfileGroup from config
|
|
||||||
*/
|
|
||||||
async deleteProfileGroup (group: PartialProfileGroup<ProfileGroup>, options?: { deleteProfiles?: boolean }): Promise<void> {
|
|
||||||
this.config.store.groups = this.config.store.groups.filter(g => g.id !== group.id)
|
|
||||||
if (options?.deleteProfiles) {
|
|
||||||
await this.bulkDeleteProfiles((p) => p.group === group.id)
|
|
||||||
} else {
|
} else {
|
||||||
for (const profile of this.config.store.profiles.filter(x => x.group === group.id)) {
|
recentProfiles = []
|
||||||
delete profile.group
|
}
|
||||||
|
window.localStorage['recentProfiles'] = JSON.stringify(recentProfiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve and return ProfileGroup Name from ProfileGroup ID
|
|
||||||
*/
|
|
||||||
resolveProfileGroupName (groupId: string): string {
|
|
||||||
return this.config.store.groups.find(g => g.id === groupId)?.name ?? groupId
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return defaults for a given group ID and provider
|
|
||||||
* Always return something, empty object if no defaults found
|
|
||||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
|
||||||
*/
|
|
||||||
getProviderProfileGroupDefaults (groupId: string, provider: ProfileProvider<Profile>): any {
|
|
||||||
return this.getSyncProfileGroups().find(g => g.id === groupId)?.defaults?.[provider.id] ?? {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -3,7 +3,7 @@ import { Subject, Observable } from 'rxjs'
|
|||||||
import * as Color from 'color'
|
import * as Color from 'color'
|
||||||
import { ConfigService } from '../services/config.service'
|
import { ConfigService } from '../services/config.service'
|
||||||
import { Theme } from '../api/theme'
|
import { Theme } from '../api/theme'
|
||||||
import { PlatformService, PlatformTheme } from '../api/platform'
|
import { PlatformService } from '../api/platform'
|
||||||
import { NewTheme } from '../theme'
|
import { NewTheme } from '../theme'
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
@@ -194,14 +194,7 @@ export class ThemesService {
|
|||||||
|
|
||||||
/// @hidden
|
/// @hidden
|
||||||
_getActiveColorScheme (): any {
|
_getActiveColorScheme (): any {
|
||||||
let theme: PlatformTheme = 'dark'
|
if (this.platform.getTheme() === 'light') {
|
||||||
if (this.config.store.appearance.colorSchemeMode === 'light') {
|
|
||||||
theme = 'light'
|
|
||||||
} else if (this.config.store.appearance.colorSchemeMode === 'auto') {
|
|
||||||
theme = this.platform.getTheme()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theme === 'light') {
|
|
||||||
return this.config.store.terminal.lightColorScheme
|
return this.config.store.terminal.lightColorScheme
|
||||||
} else {
|
} else {
|
||||||
return this.config.store.terminal.colorScheme
|
return this.config.store.terminal.colorScheme
|
||||||
|
@@ -285,7 +285,7 @@ export class VaultFileProvider extends FileProvider {
|
|||||||
icon: 'fas fa-file',
|
icon: 'fas fa-file',
|
||||||
result: f,
|
result: f,
|
||||||
})),
|
})),
|
||||||
]).catch(() => null)
|
])
|
||||||
if (result) {
|
if (result) {
|
||||||
return `${this.prefix}${result.key.id}`
|
return `${this.prefix}${result.key.id}`
|
||||||
}
|
}
|
||||||
|
298
tabby-core/src/tabContextMenu.ts
Normal file
298
tabby-core/src/tabContextMenu.ts
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { TranslateService } from '@ngx-translate/core'
|
||||||
|
import { Subscription } from 'rxjs'
|
||||||
|
import { AppService } from './services/app.service'
|
||||||
|
import { BaseTabComponent } from './components/baseTab.component'
|
||||||
|
import { SplitTabComponent, SplitDirection } from './components/splitTab.component'
|
||||||
|
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
||||||
|
import { MenuItemOptions } from './api/menu'
|
||||||
|
import { ProfilesService } from './services/profiles.service'
|
||||||
|
import { TabsService } from './services/tabs.service'
|
||||||
|
import { HotkeysService } from './services/hotkeys.service'
|
||||||
|
import { PromptModalComponent } from './components/promptModal.component'
|
||||||
|
import { SplitLayoutProfilesService } from './profiles'
|
||||||
|
import { TAB_COLORS } from './utils'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||||
|
weight = 99
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private app: AppService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||||
|
let items: MenuItemOptions[] = [
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Close'),
|
||||||
|
commandLabel: this.translate.instant('Close tab'),
|
||||||
|
click: () => {
|
||||||
|
if (this.app.tabs.includes(tab)) {
|
||||||
|
this.app.closeTab(tab, true)
|
||||||
|
} else {
|
||||||
|
tab.destroy()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
if (!tab.parent) {
|
||||||
|
items = [
|
||||||
|
...items,
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Close other tabs'),
|
||||||
|
click: () => {
|
||||||
|
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||||
|
this.app.closeTab(t, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Close tabs to the right'),
|
||||||
|
click: () => {
|
||||||
|
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||||
|
this.app.closeTab(t, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Close tabs to the left'),
|
||||||
|
click: () => {
|
||||||
|
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||||
|
this.app.closeTab(t, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else if (tab.parent instanceof SplitTabComponent) {
|
||||||
|
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('Split'),
|
||||||
|
submenu: directions.map(dir => ({
|
||||||
|
label: {
|
||||||
|
r: this.translate.instant('Right'),
|
||||||
|
b: this.translate.instant('Down'),
|
||||||
|
l: this.translate.instant('Left'),
|
||||||
|
t: this.translate.instant('Up'),
|
||||||
|
}[dir],
|
||||||
|
commandLabel: {
|
||||||
|
r: this.translate.instant('Split to the right'),
|
||||||
|
b: this.translate.instant('Split to the down'),
|
||||||
|
l: this.translate.instant('Split to the left'),
|
||||||
|
t: this.translate.instant('Split to the up'),
|
||||||
|
}[dir],
|
||||||
|
click: () => {
|
||||||
|
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||||
|
},
|
||||||
|
})) as MenuItemOptions[],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||||
|
weight = -1
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private app: AppService,
|
||||||
|
private ngbModal: NgbModal,
|
||||||
|
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||||
|
let items: MenuItemOptions[] = []
|
||||||
|
if (tabHeader) {
|
||||||
|
const currentColor = TAB_COLORS.find(x => x.value === tab.color)?.name
|
||||||
|
items = [
|
||||||
|
...items,
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Rename'),
|
||||||
|
commandLabel: this.translate.instant('Rename tab'),
|
||||||
|
click: () => {
|
||||||
|
this.app.renameTab(tab)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Duplicate'),
|
||||||
|
commandLabel: this.translate.instant('Duplicate tab'),
|
||||||
|
click: () => this.app.duplicateTab(tab),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Color'),
|
||||||
|
commandLabel: this.translate.instant('Change tab color'),
|
||||||
|
sublabel: currentColor ? this.translate.instant(currentColor) : undefined,
|
||||||
|
submenu: TAB_COLORS.map(color => ({
|
||||||
|
label: this.translate.instant(color.name) ?? color.name,
|
||||||
|
type: 'radio',
|
||||||
|
checked: tab.color === color.value,
|
||||||
|
click: () => {
|
||||||
|
tab.color = color.value
|
||||||
|
},
|
||||||
|
})) as MenuItemOptions[],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('Save layout as profile'),
|
||||||
|
click: async () => {
|
||||||
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
|
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
||||||
|
const name = (await modal.result)?.value
|
||||||
|
if (!name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.splitLayoutProfilesService.createProfile(tab, name)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||||
|
constructor (
|
||||||
|
private app: AppService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||||
|
const process = await tab.getCurrentProcess()
|
||||||
|
const items: MenuItemOptions[] = []
|
||||||
|
|
||||||
|
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
|
||||||
|
|
||||||
|
if (process) {
|
||||||
|
items.push({
|
||||||
|
enabled: false,
|
||||||
|
label: this.translate.instant('Current process: {name}', process),
|
||||||
|
})
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('Notify when done'),
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: extTab.__completionNotificationEnabled,
|
||||||
|
click: () => {
|
||||||
|
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||||
|
|
||||||
|
if (extTab.__completionNotificationEnabled) {
|
||||||
|
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||||
|
new Notification(this.translate.instant('Process completed'), {
|
||||||
|
body: process.name,
|
||||||
|
}).addEventListener('click', () => {
|
||||||
|
this.app.selectTab(tab)
|
||||||
|
})
|
||||||
|
extTab.__completionNotificationEnabled = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.app.stopObservingTabCompletion(tab)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('Notify on activity'),
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: !!extTab.__outputNotificationSubscription,
|
||||||
|
click: () => {
|
||||||
|
tab.clearActivity()
|
||||||
|
|
||||||
|
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(this.translate.instant('Tab activity'), {
|
||||||
|
body: tab.title,
|
||||||
|
}).addEventListener('click', () => {
|
||||||
|
this.app.selectTab(tab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class ProfilesContextMenu extends TabContextMenuItemProvider {
|
||||||
|
weight = 10
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private profilesService: ProfilesService,
|
||||||
|
private tabsService: TabsService,
|
||||||
|
private app: AppService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
hotkeys: HotkeysService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
hotkeys.hotkey$.subscribe(hotkey => {
|
||||||
|
if (hotkey === 'switch-profile') {
|
||||||
|
let tab = this.app.activeTab
|
||||||
|
if (tab instanceof SplitTabComponent) {
|
||||||
|
tab = tab.getFocusedTab()
|
||||||
|
if (tab) {
|
||||||
|
this.switchTabProfile(tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async switchTabProfile (tab: BaseTabComponent) {
|
||||||
|
const profile = await this.profilesService.showProfileSelector()
|
||||||
|
if (!profile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = await this.profilesService.newTabParametersForProfile(profile)
|
||||||
|
if (!params) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await tab.canClose()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTab = this.tabsService.create(params)
|
||||||
|
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
||||||
|
|
||||||
|
tab.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||||
|
|
||||||
|
if (tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.translate.instant('Switch profile'),
|
||||||
|
click: () => this.switchTabProfile(tab),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
@@ -22,6 +22,5 @@ export class ElectronConfigProvider extends ConfigProvider {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
defaults = {}
|
defaults = {}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@ import { ElectronHostWindow } from './hostWindow.service'
|
|||||||
import { ShellIntegrationService } from './shellIntegration.service'
|
import { ShellIntegrationService } from './shellIntegration.service'
|
||||||
import { ElectronHostAppService } from './hostApp.service'
|
import { ElectronHostAppService } from './hostApp.service'
|
||||||
import { PlatformTheme } from '../../../tabby-core/src/api/platform'
|
import { PlatformTheme } from '../../../tabby-core/src/api/platform'
|
||||||
import { configPath } from '../../../app/lib/config'
|
|
||||||
const fontManager = require('fontmanager-redux') // eslint-disable-line
|
const fontManager = require('fontmanager-redux') // eslint-disable-line
|
||||||
|
|
||||||
/* eslint-disable block-scoped-var */
|
/* eslint-disable block-scoped-var */
|
||||||
@@ -37,7 +36,7 @@ export class ElectronPlatformService extends PlatformService {
|
|||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.configPath = configPath
|
this.configPath = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||||
|
|
||||||
electron.ipcRenderer.on('host:display-metrics-changed', () => {
|
electron.ipcRenderer.on('host:display-metrics-changed', () => {
|
||||||
this.zone.run(() => this.displayMetricsChanged.next())
|
this.zone.run(() => this.displayMetricsChanged.next())
|
||||||
|
@@ -33,7 +33,6 @@ export class ShellIntegrationService {
|
|||||||
command: 'paste "%V"',
|
command: 'paste "%V"',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
private constructor (
|
private constructor (
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private hostApp: HostAppService,
|
private hostApp: HostAppService,
|
||||||
|
@@ -25,7 +25,7 @@ export class ElectronUpdaterService extends UpdaterService {
|
|||||||
super()
|
super()
|
||||||
this.logger = log.create('updater')
|
this.logger = log.create('updater')
|
||||||
|
|
||||||
if (process.platform === 'linux' || process.env.PORTABLE_EXECUTABLE_FILE) {
|
if (process.platform === 'linux') {
|
||||||
this.electronUpdaterAvailable = false
|
this.electronUpdaterAvailable = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
28
tabby-local/src/buttonProvider.ts
Normal file
28
tabby-local/src/buttonProvider.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { ToolbarButtonProvider, ToolbarButton, TranslateService } from 'tabby-core'
|
||||||
|
import { TerminalService } from './services/terminal.service'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class ButtonProvider extends ToolbarButtonProvider {
|
||||||
|
constructor (
|
||||||
|
private terminal: TerminalService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
provide (): ToolbarButton[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
icon: require('./icons/plus.svg'),
|
||||||
|
title: this.translate.instant('New terminal'),
|
||||||
|
touchBarNSImage: 'NSTouchBarAddDetailTemplate',
|
||||||
|
click: () => {
|
||||||
|
this.terminal.openTab()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@@ -1,123 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { Inject, Injectable, Optional } from '@angular/core'
|
|
||||||
|
|
||||||
import { CommandProvider, Command, CommandLocation, TranslateService, CommandContext, ProfilesService } from 'tabby-core'
|
|
||||||
|
|
||||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
|
||||||
import { TerminalService } from './services/terminal.service'
|
|
||||||
import { LocalProfile, UACService } from './api'
|
|
||||||
|
|
||||||
/** @hidden */
|
|
||||||
@Injectable({ providedIn: 'root' })
|
|
||||||
export class LocalCommandProvider extends CommandProvider {
|
|
||||||
constructor (
|
|
||||||
private terminal: TerminalService,
|
|
||||||
private profilesService: ProfilesService,
|
|
||||||
private translate: TranslateService,
|
|
||||||
@Optional() @Inject(UACService) private uac: UACService|undefined,
|
|
||||||
) {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
|
|
||||||
async provide (context: CommandContext): Promise<Command[]> {
|
|
||||||
const profiles = (await this.profilesService.getProfiles()).filter(x => x.type === 'local') as LocalProfile[]
|
|
||||||
|
|
||||||
const commands: Command[] = [
|
|
||||||
{
|
|
||||||
id: 'local:new-tab',
|
|
||||||
group: 'local:new-tab',
|
|
||||||
label: this.translate.instant('New terminal'),
|
|
||||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage, CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
weight: 11,
|
|
||||||
icon: require('./icons/plus.svg'),
|
|
||||||
run: async () => this.runOpenTab(context),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
commands.push({
|
|
||||||
id: 'local:new-tab-with-profile',
|
|
||||||
group: 'local:new-tab',
|
|
||||||
label: this.translate.instant('New with profile'),
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
weight: 12,
|
|
||||||
})
|
|
||||||
|
|
||||||
for (const profile of profiles) {
|
|
||||||
commands.push({
|
|
||||||
id: `local:new-tab-with-profile:${profile.id}`,
|
|
||||||
group: 'local:new-tab',
|
|
||||||
parent: 'local:new-tab-with-profile',
|
|
||||||
label: profile.name,
|
|
||||||
fullLabel: this.translate.instant('New terminal with profile: {profile}', { profile: profile.name }),
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
||||||
run: async () => {
|
|
||||||
let workingDirectory = profile.options.cwd
|
|
||||||
if (!workingDirectory && context.tab instanceof TerminalTabComponent) {
|
|
||||||
workingDirectory = await context.tab.session?.getWorkingDirectory() ?? undefined
|
|
||||||
}
|
|
||||||
await this.terminal.openTab(profile, workingDirectory)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.uac?.isAvailable) {
|
|
||||||
commands.push({
|
|
||||||
id: 'local:new-tab-as-administrator-with-profile',
|
|
||||||
group: 'local:new-tab',
|
|
||||||
label: this.translate.instant('New admin tab'),
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
weight: 13,
|
|
||||||
})
|
|
||||||
|
|
||||||
for (const profile of profiles) {
|
|
||||||
commands.push({
|
|
||||||
id: `local:new-tab-as-administrator-with-profile:${profile.id}`,
|
|
||||||
group: 'local:new-tab',
|
|
||||||
label: profile.name,
|
|
||||||
fullLabel: this.translate.instant('New admin tab with profile: {profile}', { profile: profile.name }),
|
|
||||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
|
||||||
run: async () => {
|
|
||||||
this.profilesService.openNewTabForProfile({
|
|
||||||
...profile,
|
|
||||||
options: {
|
|
||||||
...profile.options,
|
|
||||||
runAsAdministrator: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.tab && context.tab instanceof TerminalTabComponent) {
|
|
||||||
const terminalTab = context.tab
|
|
||||||
commands.push({
|
|
||||||
id: 'local:duplicate-tab-as-administrator',
|
|
||||||
group: 'local:new-tab',
|
|
||||||
label: this.translate.instant('Duplicate as administrator'),
|
|
||||||
locations: [CommandLocation.TabHeaderMenu],
|
|
||||||
weight: 14,
|
|
||||||
run: async () => {
|
|
||||||
this.profilesService.openNewTabForProfile({
|
|
||||||
...terminalTab.profile,
|
|
||||||
options: {
|
|
||||||
...terminalTab.profile.options,
|
|
||||||
runAsAdministrator: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands
|
|
||||||
}
|
|
||||||
|
|
||||||
runOpenTab (context: CommandContext) {
|
|
||||||
if (context.tab && context.tab instanceof TerminalTabComponent) {
|
|
||||||
this.profilesService.openNewTabForProfile(context.tab.profile)
|
|
||||||
} else {
|
|
||||||
this.terminal.openTab()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms'
|
|||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { ToastrModule } from 'ngx-toastr'
|
import { ToastrModule } from 'ngx-toastr'
|
||||||
|
|
||||||
import TabbyCorePlugin, { HostAppService, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, CLIHandler, ProfileProvider, CommandProvider } from 'tabby-core'
|
import TabbyCorePlugin, { HostAppService, ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, TabContextMenuItemProvider, CLIHandler, ProfileProvider } from 'tabby-core'
|
||||||
import TabbyTerminalModule from 'tabby-terminal'
|
import TabbyTerminalModule from 'tabby-terminal'
|
||||||
import { SettingsTabProvider } from 'tabby-settings'
|
import { SettingsTabProvider } from 'tabby-settings'
|
||||||
|
|
||||||
@@ -16,14 +16,15 @@ import { CommandLineEditorComponent } from './components/commandLineEditor.compo
|
|||||||
|
|
||||||
import { TerminalService } from './services/terminal.service'
|
import { TerminalService } from './services/terminal.service'
|
||||||
|
|
||||||
|
import { ButtonProvider } from './buttonProvider'
|
||||||
import { RecoveryProvider } from './recoveryProvider'
|
import { RecoveryProvider } from './recoveryProvider'
|
||||||
import { ShellSettingsTabProvider } from './settings'
|
import { ShellSettingsTabProvider } from './settings'
|
||||||
import { TerminalConfigProvider } from './config'
|
import { TerminalConfigProvider } from './config'
|
||||||
import { LocalTerminalHotkeyProvider } from './hotkeys'
|
import { LocalTerminalHotkeyProvider } from './hotkeys'
|
||||||
|
import { NewTabContextMenu } from './tabContextMenu'
|
||||||
|
|
||||||
import { AutoOpenTabCLIHandler, OpenPathCLIHandler, TerminalCLIHandler } from './cli'
|
import { AutoOpenTabCLIHandler, OpenPathCLIHandler, TerminalCLIHandler } from './cli'
|
||||||
import { LocalProfilesService } from './profiles'
|
import { LocalProfilesService } from './profiles'
|
||||||
import { LocalCommandProvider } from './commands'
|
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -38,13 +39,15 @@ import { LocalCommandProvider } from './commands'
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: SettingsTabProvider, useClass: ShellSettingsTabProvider, multi: true },
|
{ provide: SettingsTabProvider, useClass: ShellSettingsTabProvider, multi: true },
|
||||||
|
|
||||||
{ provide: CommandProvider, useExisting: LocalCommandProvider, multi: true },
|
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||||
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
||||||
{ provide: HotkeyProvider, useClass: LocalTerminalHotkeyProvider, multi: true },
|
{ provide: HotkeyProvider, useClass: LocalTerminalHotkeyProvider, multi: true },
|
||||||
|
|
||||||
{ provide: ProfileProvider, useClass: LocalProfilesService, multi: true },
|
{ provide: ProfileProvider, useClass: LocalProfilesService, multi: true },
|
||||||
|
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
|
||||||
|
|
||||||
{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
|
{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
|
||||||
{ provide: CLIHandler, useClass: OpenPathCLIHandler, multi: true },
|
{ provide: CLIHandler, useClass: OpenPathCLIHandler, multi: true },
|
||||||
{ provide: CLIHandler, useClass: AutoOpenTabCLIHandler, multi: true },
|
{ provide: CLIHandler, useClass: AutoOpenTabCLIHandler, multi: true },
|
||||||
|
87
tabby-local/src/tabContextMenu.ts
Normal file
87
tabby-local/src/tabContextMenu.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { Inject, Injectable, Optional } from '@angular/core'
|
||||||
|
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, MenuItemOptions, ProfilesService, TranslateService } from 'tabby-core'
|
||||||
|
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||||
|
import { TerminalService } from './services/terminal.service'
|
||||||
|
import { LocalProfile, UACService } from './api'
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class NewTabContextMenu extends TabContextMenuItemProvider {
|
||||||
|
weight = 10
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
public config: ConfigService,
|
||||||
|
private profilesService: ProfilesService,
|
||||||
|
private terminalService: TerminalService,
|
||||||
|
@Optional() @Inject(UACService) private uac: UACService|undefined,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||||
|
const profiles = (await this.profilesService.getProfiles()).filter(x => x.type === 'local') as LocalProfile[]
|
||||||
|
|
||||||
|
const items: MenuItemOptions[] = [
|
||||||
|
{
|
||||||
|
label: this.translate.instant('New terminal'),
|
||||||
|
click: () => {
|
||||||
|
if (tab instanceof TerminalTabComponent) {
|
||||||
|
this.profilesService.openNewTabForProfile(tab.profile)
|
||||||
|
} else {
|
||||||
|
this.terminalService.openTab()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.translate.instant('New with profile'),
|
||||||
|
submenu: profiles.map(profile => ({
|
||||||
|
label: profile.name,
|
||||||
|
click: async () => {
|
||||||
|
let workingDirectory = profile.options.cwd
|
||||||
|
if (!workingDirectory && tab instanceof TerminalTabComponent) {
|
||||||
|
workingDirectory = await tab.session?.getWorkingDirectory() ?? undefined
|
||||||
|
}
|
||||||
|
await this.terminalService.openTab(profile, workingDirectory)
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (this.uac?.isAvailable) {
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('New admin tab'),
|
||||||
|
submenu: profiles.map(profile => ({
|
||||||
|
label: profile.name,
|
||||||
|
click: () => {
|
||||||
|
this.profilesService.openNewTabForProfile({
|
||||||
|
...profile,
|
||||||
|
options: {
|
||||||
|
...profile.options,
|
||||||
|
runAsAdministrator: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tab instanceof TerminalTabComponent && tabHeader && this.uac?.isAvailable) {
|
||||||
|
const terminalTab = tab
|
||||||
|
items.push({
|
||||||
|
label: this.translate.instant('Duplicate as administrator'),
|
||||||
|
click: () => {
|
||||||
|
this.profilesService.openNewTabForProfile({
|
||||||
|
...terminalTab.profile,
|
||||||
|
options: {
|
||||||
|
...terminalTab.profile.options,
|
||||||
|
runAsAdministrator: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
@@ -70,7 +70,6 @@ export class PluginManagerService {
|
|||||||
map(plugins => {
|
map(plugins => {
|
||||||
const mapping: Record<string, PluginInfo[]> = {}
|
const mapping: Record<string, PluginInfo[]> = {}
|
||||||
for (const p of plugins) {
|
for (const p of plugins) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
mapping[p.name] ??= []
|
mapping[p.name] ??= []
|
||||||
mapping[p.name].push(p)
|
mapping[p.name].push(p)
|
||||||
}
|
}
|
||||||
|
@@ -3,10 +3,10 @@ import { SerialPortStream } from '@serialport/stream'
|
|||||||
import { LogService, NotificationsService } from 'tabby-core'
|
import { LogService, NotificationsService } from 'tabby-core'
|
||||||
import { Subject, Observable } from 'rxjs'
|
import { Subject, Observable } from 'rxjs'
|
||||||
import { Injector, NgZone } from '@angular/core'
|
import { Injector, NgZone } from '@angular/core'
|
||||||
import { BaseSession, ConnectableTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal'
|
import { BaseSession, BaseTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal'
|
||||||
import { SerialService } from './services/serial.service'
|
import { SerialService } from './services/serial.service'
|
||||||
|
|
||||||
export interface SerialProfile extends ConnectableTerminalProfile {
|
export interface SerialProfile extends BaseTerminalProfile {
|
||||||
options: SerialProfileOptions
|
options: SerialProfileOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -87,11 +87,6 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
.description(translate) Sends data one byte at a time
|
.description(translate) Sends data one byte at a time
|
||||||
toggle([(ngModel)]='profile.options.slowSend')
|
toggle([(ngModel)]='profile.options.slowSend')
|
||||||
|
|
||||||
li(ngbNavItem)
|
|
||||||
a(ngbNavLink, translate) Colors
|
|
||||||
ng-template(ngbNavContent)
|
|
||||||
color-scheme-selector([(model)]='profile.terminalColorScheme')
|
|
||||||
|
|
||||||
li(ngbNavItem)
|
li(ngbNavItem)
|
||||||
a(ngbNavLink, translate) Login scripts
|
a(ngbNavLink, translate) Login scripts
|
||||||
ng-template(ngbNavContent)
|
ng-template(ngbNavContent)
|
||||||
|
@@ -2,14 +2,14 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
|||||||
import slugify from 'slugify'
|
import slugify from 'slugify'
|
||||||
import deepClone from 'clone-deep'
|
import deepClone from 'clone-deep'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { NewTabParameters, SelectorService, HostAppService, Platform, TranslateService, ConnectableProfileProvider } from 'tabby-core'
|
import { ProfileProvider, NewTabParameters, SelectorService, HostAppService, Platform, TranslateService } from 'tabby-core'
|
||||||
import { SerialProfileSettingsComponent } from './components/serialProfileSettings.component'
|
import { SerialProfileSettingsComponent } from './components/serialProfileSettings.component'
|
||||||
import { SerialTabComponent } from './components/serialTab.component'
|
import { SerialTabComponent } from './components/serialTab.component'
|
||||||
import { SerialService } from './services/serial.service'
|
import { SerialService } from './services/serial.service'
|
||||||
import { BAUD_RATES, SerialProfile } from './api'
|
import { BAUD_RATES, SerialProfile } from './api'
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class SerialProfilesService extends ConnectableProfileProvider<SerialProfile> {
|
export class SerialProfilesService extends ProfileProvider<SerialProfile> {
|
||||||
id = 'serial'
|
id = 'serial'
|
||||||
name = _('Serial')
|
name = _('Serial')
|
||||||
settingsComponent = SerialProfileSettingsComponent
|
settingsComponent = SerialProfileSettingsComponent
|
||||||
@@ -32,7 +32,6 @@ export class SerialProfilesService extends ConnectableProfileProvider<SerialProf
|
|||||||
slowSend: false,
|
slowSend: false,
|
||||||
input: { backspace: 'backspace' },
|
input: { backspace: 'backspace' },
|
||||||
},
|
},
|
||||||
clearServiceMessagesOnConnect: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@@ -18,8 +18,8 @@
|
|||||||
"author": "Eugene Pankov",
|
"author": "Eugene Pankov",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/marked": "^5.0.1",
|
"@types/marked": "^4.0.8",
|
||||||
"marked": "^5.1.2",
|
"marked": "^4.2.12",
|
||||||
"ngx-infinite-scroll": "^16"
|
"ngx-infinite-scroll": "^16"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { CommandProvider, AppService, HostAppService, HotkeysService, TranslateService, Command, CommandLocation } from 'tabby-core'
|
import { ToolbarButtonProvider, ToolbarButton, AppService, HostAppService, HotkeysService, TranslateService } from 'tabby-core'
|
||||||
|
|
||||||
import { SettingsTabComponent } from './components/settingsTab.component'
|
import { SettingsTabComponent } from './components/settingsTab.component'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable()
|
||||||
export class SettingsCommandProvider extends CommandProvider {
|
export class ButtonProvider extends ToolbarButtonProvider {
|
||||||
constructor (
|
constructor (
|
||||||
hostApp: HostAppService,
|
hostApp: HostAppService,
|
||||||
hotkeys: HotkeysService,
|
hotkeys: HotkeysService,
|
||||||
@@ -22,14 +22,13 @@ export class SettingsCommandProvider extends CommandProvider {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async provide (): Promise<Command[]> {
|
provide (): ToolbarButton[] {
|
||||||
return [{
|
return [{
|
||||||
id: 'settings:open',
|
|
||||||
icon: require('./icons/cog.svg'),
|
icon: require('./icons/cog.svg'),
|
||||||
label: this.translate.instant('Settings'),
|
title: this.translate.instant('Settings'),
|
||||||
weight: 99,
|
touchBarNSImage: 'NSTouchBarComposeTemplate',
|
||||||
locations: [CommandLocation.RightToolbar, CommandLocation.StartPage],
|
weight: 10,
|
||||||
run: async () => this.open(),
|
click: (): void => this.open(),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
@@ -20,7 +20,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
)
|
)
|
||||||
i.fas.fa-external-link-alt
|
i.fas.fa-external-link-alt
|
||||||
|
|
||||||
.form-line(*ngIf='config.store.configSync.host')
|
.form-line
|
||||||
.header
|
.header
|
||||||
.title(translate) Secret sync token
|
.title(translate) Secret sync token
|
||||||
.description(translate) Get it from the Tabby Web settings window
|
.description(translate) Get it from the Tabby Web settings window
|
||||||
@@ -36,11 +36,6 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
i.fas.fa-fw.fa-check.text-success(*ngIf='connectionSuccessful')
|
i.fas.fa-fw.fa-check.text-success(*ngIf='connectionSuccessful')
|
||||||
i.fas.fa-fw.fa-exclamation-triangle.text-danger(*ngIf='connectionSuccessful === false')
|
i.fas.fa-fw.fa-exclamation-triangle.text-danger(*ngIf='connectionSuccessful === false')
|
||||||
|
|
||||||
.alert.alert-info.d-flex.align-items-center
|
|
||||||
.me-auto
|
|
||||||
span(translate) Config sync requires an instance of the Tabby Web service.
|
|
||||||
a.ml-1((click)='openTabbyWebInfo()', href='#', translate) Learn more
|
|
||||||
|
|
||||||
ng-container(*ngIf='config.store.configSync.token')
|
ng-container(*ngIf='config.store.configSync.token')
|
||||||
.alert.alert-danger(*ngIf='connectionSuccessful === false')
|
.alert.alert-danger(*ngIf='connectionSuccessful === false')
|
||||||
i.fas.fa-exclamation-triangle
|
i.fas.fa-exclamation-triangle
|
||||||
|
@@ -59,7 +59,7 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent {
|
|||||||
const modal = this.ngbModal.open(PromptModalComponent)
|
const modal = this.ngbModal.open(PromptModalComponent)
|
||||||
modal.componentInstance.prompt = this.translate.instant('Name for the new config')
|
modal.componentInstance.prompt = this.translate.instant('Name for the new config')
|
||||||
modal.componentInstance.value = name
|
modal.componentInstance.value = name
|
||||||
name = (await modal.result.catch(() => null))?.value
|
name = (await modal.result)?.value
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -141,8 +141,4 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent {
|
|||||||
this.platform.openExternal(this.config.store.configSync.host)
|
this.platform.openExternal(this.config.store.configSync.host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openTabbyWebInfo () {
|
|
||||||
this.platform.openExternal('https://github.com/Eugeny/tabby-web')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
.modal-header
|
|
||||||
h3.m-0 {{group.name}}
|
|
||||||
|
|
||||||
.modal-body
|
|
||||||
.row
|
|
||||||
.col-12.col-lg-4
|
|
||||||
.mb-3
|
|
||||||
label(translate) Name
|
|
||||||
input.form-control(
|
|
||||||
type='text',
|
|
||||||
autofocus,
|
|
||||||
[(ngModel)]='group.name',
|
|
||||||
)
|
|
||||||
|
|
||||||
.col-12.col-lg-8
|
|
||||||
.form-line.content-box
|
|
||||||
.header
|
|
||||||
.title(translate) Default profile group settings
|
|
||||||
.description(translate) These apply to all profiles of a given type in this group
|
|
||||||
|
|
||||||
.list-group.mt-3.mb-3.content-box
|
|
||||||
a.list-group-item.list-group-item-action.d-flex.align-items-center(
|
|
||||||
(click)='editDefaults(provider)',
|
|
||||||
*ngFor='let provider of providers'
|
|
||||||
) {{provider.name|translate}}
|
|
||||||
.me-auto
|
|
||||||
button.btn.btn-link.hover-reveal.ms-1((click)='$event.stopPropagation(); deleteDefaults(provider)')
|
|
||||||
i.fas.fa-trash-arrow-up
|
|
||||||
|
|
||||||
.modal-footer
|
|
||||||
button.btn.btn-primary((click)='save()', translate) Save
|
|
||||||
button.btn.btn-danger((click)='cancel()', translate) Cancel
|
|
@@ -1,54 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { Component, Input } from '@angular/core'
|
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
|
||||||
import { ConfigProxy, ProfileGroup, Profile, ProfileProvider, PlatformService, TranslateService } from 'tabby-core'
|
|
||||||
|
|
||||||
/** @hidden */
|
|
||||||
@Component({
|
|
||||||
templateUrl: './editProfileGroupModal.component.pug',
|
|
||||||
})
|
|
||||||
export class EditProfileGroupModalComponent<G extends ProfileGroup> {
|
|
||||||
@Input() group: G & ConfigProxy
|
|
||||||
@Input() providers: ProfileProvider<Profile>[]
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private modalInstance: NgbActiveModal,
|
|
||||||
private platform: PlatformService,
|
|
||||||
private translate: TranslateService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
save () {
|
|
||||||
this.modalInstance.close({ group: this.group })
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel () {
|
|
||||||
this.modalInstance.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
editDefaults (provider: ProfileProvider<Profile>) {
|
|
||||||
this.modalInstance.close({ group: this.group, provider })
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteDefaults (provider: ProfileProvider<Profile>): Promise<void> {
|
|
||||||
if ((await this.platform.showMessageBox(
|
|
||||||
{
|
|
||||||
type: 'warning',
|
|
||||||
message: this.translate.instant('Restore settings to inherited defaults ?'),
|
|
||||||
buttons: [
|
|
||||||
this.translate.instant('Delete'),
|
|
||||||
this.translate.instant('Keep'),
|
|
||||||
],
|
|
||||||
defaultId: 1,
|
|
||||||
cancelId: 1,
|
|
||||||
},
|
|
||||||
)).response === 0) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
||||||
delete this.group.defaults?.[provider.id]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EditProfileGroupModalComponentResult<G extends ProfileGroup> {
|
|
||||||
group: G
|
|
||||||
provider?: ProfileProvider<Profile>
|
|
||||||
}
|
|
@@ -1,7 +1,7 @@
|
|||||||
.modal-header(*ngIf='defaultsMode === "disabled"')
|
.modal-header(*ngIf='!defaultsMode')
|
||||||
h3.m-0 {{profile.name}}
|
h3.m-0 {{profile.name}}
|
||||||
|
|
||||||
.modal-header(*ngIf='defaultsMode !== "disabled"')
|
.modal-header(*ngIf='defaultsMode')
|
||||||
h3.m-0(
|
h3.m-0(
|
||||||
translate='Defaults for {type}',
|
translate='Defaults for {type}',
|
||||||
[translateParams]='{type: profileProvider.name}'
|
[translateParams]='{type: profileProvider.name}'
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
.modal-body
|
.modal-body
|
||||||
.row
|
.row
|
||||||
.col-12.col-lg-4
|
.col-12.col-lg-4
|
||||||
.mb-3(*ngIf='defaultsMode === "disabled"')
|
.mb-3(*ngIf='!defaultsMode')
|
||||||
label(translate) Name
|
label(translate) Name
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
@@ -18,20 +18,17 @@
|
|||||||
[(ngModel)]='profile.name',
|
[(ngModel)]='profile.name',
|
||||||
)
|
)
|
||||||
|
|
||||||
.mb-3(*ngIf='defaultsMode === "disabled"')
|
.mb-3(*ngIf='!defaultsMode')
|
||||||
label(translate) Group
|
label(translate) Group
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
alwaysVisibleTypeahead,
|
alwaysVisibleTypeahead,
|
||||||
placeholder='Ungrouped',
|
placeholder='Ungrouped',
|
||||||
[(ngModel)]='profileGroup',
|
[(ngModel)]='profile.group',
|
||||||
[ngbTypeahead]='groupTypeahead',
|
[ngbTypeahead]='groupTypeahead',
|
||||||
[inputFormatter]="groupFormatter",
|
|
||||||
[resultFormatter]="groupFormatter",
|
|
||||||
[editable]="false"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
.mb-3(*ngIf='defaultsMode === "disabled"')
|
.mb-3(*ngIf='!defaultsMode')
|
||||||
label(translate) Icon
|
label(translate) Icon
|
||||||
.input-group
|
.input-group
|
||||||
input.form-control(
|
input.form-control(
|
||||||
@@ -77,15 +74,9 @@
|
|||||||
)
|
)
|
||||||
option(ngValue='auto', translate) Auto
|
option(ngValue='auto', translate) Auto
|
||||||
option(ngValue='keep', translate) Keep
|
option(ngValue='keep', translate) Keep
|
||||||
option(*ngIf='isConnectable()', ngValue='reconnect', translate) Reconnect
|
option(*ngIf='profile.type == "serial" || profile.type == "telnet" || profile.type == "ssh"', ngValue='reconnect', translate) Reconnect
|
||||||
option(ngValue='close', translate) Close
|
option(ngValue='close', translate) Close
|
||||||
|
|
||||||
.form-line(*ngIf='isConnectable()')
|
|
||||||
.header
|
|
||||||
.title(translate) Clear terminal after connection
|
|
||||||
toggle(
|
|
||||||
[(ngModel)]='profile.clearServiceMessagesOnConnect',
|
|
||||||
)
|
|
||||||
.mb-4
|
.mb-4
|
||||||
|
|
||||||
.col-12.col-lg-8(*ngIf='this.profileProvider.settingsComponent')
|
.col-12.col-lg-8(*ngIf='this.profileProvider.settingsComponent')
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
import { Observable, OperatorFunction, debounceTime, map, distinctUntilChanged } from 'rxjs'
|
import { Observable, OperatorFunction, debounceTime, map, distinctUntilChanged } from 'rxjs'
|
||||||
import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, Injector } from '@angular/core'
|
import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, Injector } from '@angular/core'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { ConfigProxy, PartialProfileGroup, Profile, ProfileProvider, ProfileSettingsComponent, ProfilesService, TAB_COLORS, ProfileGroup, ConnectableProfileProvider } from 'tabby-core'
|
import { ConfigProxy, ConfigService, Profile, ProfileProvider, ProfileSettingsComponent, ProfilesService, TAB_COLORS } from 'tabby-core'
|
||||||
|
|
||||||
const iconsData = require('../../../tabby-core/src/icons.json')
|
const iconsData = require('../../../tabby-core/src/icons.json')
|
||||||
const iconsClassList = Object.keys(iconsData).map(
|
const iconsClassList = Object.keys(iconsData).map(
|
||||||
@@ -19,9 +19,8 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
@Input() profile: P & ConfigProxy
|
@Input() profile: P & ConfigProxy
|
||||||
@Input() profileProvider: ProfileProvider<P>
|
@Input() profileProvider: ProfileProvider<P>
|
||||||
@Input() settingsComponent: new () => ProfileSettingsComponent<P>
|
@Input() settingsComponent: new () => ProfileSettingsComponent<P>
|
||||||
@Input() defaultsMode: 'enabled'|'group'|'disabled' = 'disabled'
|
@Input() defaultsMode = false
|
||||||
@Input() profileGroup: PartialProfileGroup<ProfileGroup> | undefined
|
groupNames: string[]
|
||||||
groups: PartialProfileGroup<ProfileGroup>[]
|
|
||||||
@ViewChild('placeholder', { read: ViewContainerRef }) placeholder: ViewContainerRef
|
@ViewChild('placeholder', { read: ViewContainerRef }) placeholder: ViewContainerRef
|
||||||
|
|
||||||
private _profile: Profile
|
private _profile: Profile
|
||||||
@@ -31,14 +30,14 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
private injector: Injector,
|
private injector: Injector,
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private profilesService: ProfilesService,
|
private profilesService: ProfilesService,
|
||||||
|
config: ConfigService,
|
||||||
private modalInstance: NgbActiveModal,
|
private modalInstance: NgbActiveModal,
|
||||||
) {
|
) {
|
||||||
if (this.defaultsMode === 'disabled') {
|
this.groupNames = [...new Set(
|
||||||
this.profilesService.getProfileGroups().then(groups => {
|
(config.store.profiles as Profile[])
|
||||||
this.groups = groups
|
.map(x => x.group)
|
||||||
this.profileGroup = groups.find(g => g.id === this.profile.group)
|
.filter(x => !!x),
|
||||||
})
|
)].sort() as string[]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
colorsAutocomplete = text$ => text$.pipe(
|
colorsAutocomplete = text$ => text$.pipe(
|
||||||
@@ -57,7 +56,7 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this._profile = this.profile
|
this._profile = this.profile
|
||||||
this.profile = this.profilesService.getConfigProxyForProfile(this.profile, { skipGlobalDefaults: this.defaultsMode === 'enabled', skipGroupDefaults: this.defaultsMode === 'group' })
|
this.profile = this.profilesService.getConfigProxyForProfile(this.profile, this.defaultsMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit () {
|
ngAfterViewInit () {
|
||||||
@@ -73,15 +72,13 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groupTypeahead: OperatorFunction<string, readonly PartialProfileGroup<ProfileGroup>[]> = (text$: Observable<string>) =>
|
groupTypeahead = (text$: Observable<string>) =>
|
||||||
text$.pipe(
|
text$.pipe(
|
||||||
debounceTime(200),
|
debounceTime(200),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
map(q => this.groups.filter(g => !q || g.name.toLowerCase().includes(q.toLowerCase()))),
|
map(q => this.groupNames.filter(x => !q || x.toLowerCase().includes(q.toLowerCase()))),
|
||||||
)
|
)
|
||||||
|
|
||||||
groupFormatter = (g: PartialProfileGroup<ProfileGroup>) => g.name
|
|
||||||
|
|
||||||
iconSearch: OperatorFunction<string, string[]> = (text$: Observable<string>) =>
|
iconSearch: OperatorFunction<string, string[]> = (text$: Observable<string>) =>
|
||||||
text$.pipe(
|
text$.pipe(
|
||||||
debounceTime(200),
|
debounceTime(200),
|
||||||
@@ -89,12 +86,7 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
)
|
)
|
||||||
|
|
||||||
save () {
|
save () {
|
||||||
if (!this.profileGroup) {
|
this.profile.group ||= undefined
|
||||||
this.profile.group = undefined
|
|
||||||
} else {
|
|
||||||
this.profile.group = this.profileGroup.id
|
|
||||||
}
|
|
||||||
|
|
||||||
this.settingsComponentInstance?.save?.()
|
this.settingsComponentInstance?.save?.()
|
||||||
this.profile.__cleanup()
|
this.profile.__cleanup()
|
||||||
this.modalInstance.close(this._profile)
|
this.modalInstance.close(this._profile)
|
||||||
@@ -103,9 +95,4 @@ export class EditProfileModalComponent<P extends Profile> {
|
|||||||
cancel () {
|
cancel () {
|
||||||
this.modalInstance.dismiss()
|
this.modalInstance.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnectable (): boolean {
|
|
||||||
return this.profileProvider instanceof ConnectableProfileProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -12,12 +12,10 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
[(ngModel)]='config.store.terminal.profile',
|
[(ngModel)]='config.store.terminal.profile',
|
||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save()',
|
||||||
)
|
)
|
||||||
optgroup([label]='"Custom Profiles"|translate', *ngIf='customProfiles?.length > 0')
|
|
||||||
option(
|
option(
|
||||||
*ngFor='let profile of customProfiles',
|
*ngFor='let profile of profiles',
|
||||||
[ngValue]='profile.id'
|
[ngValue]='profile.id'
|
||||||
) {{profile.name}}
|
) {{profile.name}}
|
||||||
optgroup([label]='"Built-in Profiles"|translate')
|
|
||||||
option(
|
option(
|
||||||
*ngFor='let profile of builtinProfiles',
|
*ngFor='let profile of builtinProfiles',
|
||||||
[ngValue]='profile.id'
|
[ngValue]='profile.id'
|
||||||
@@ -29,17 +27,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
i.fas.fa-fw.fa-search
|
i.fas.fa-fw.fa-search
|
||||||
input.form-control(type='search', [placeholder]='"Filter"|translate', [(ngModel)]='filter')
|
input.form-control(type='search', [placeholder]='"Filter"|translate', [(ngModel)]='filter')
|
||||||
|
|
||||||
div(ngbDropdown).d-inline-block.flex-shrink-0.ms-3
|
button.btn.btn-primary.flex-shrink-0.ms-3((click)='newProfile()')
|
||||||
button.btn.btn-primary(ngbDropdownToggle)
|
|
||||||
i.fas.fa-fw.fa-plus
|
|
||||||
span(translate) New
|
|
||||||
div(ngbDropdownMenu)
|
|
||||||
button(ngbDropdownItem, (click)='newProfile()')
|
|
||||||
i.fas.fa-fw.fa-plus
|
i.fas.fa-fw.fa-plus
|
||||||
span(translate) New profile
|
span(translate) New profile
|
||||||
button(ngbDropdownItem, (click)='newProfileGroup()')
|
|
||||||
i.fas.fa-fw.fa-plus
|
|
||||||
span(translate) New profile Group
|
|
||||||
|
|
||||||
.list-group.mt-3.mb-3
|
.list-group.mt-3.mb-3
|
||||||
ng-container(*ngFor='let group of profileGroups')
|
ng-container(*ngFor='let group of profileGroups')
|
||||||
@@ -47,17 +37,17 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||||
(click)='toggleGroupCollapse(group)'
|
(click)='toggleGroupCollapse(group)'
|
||||||
)
|
)
|
||||||
.fa.fa-fw.fa-chevron-right(*ngIf='group.collapsed && group.profiles?.length > 0')
|
.fa.fa-fw.fa-chevron-right(*ngIf='group.collapsed')
|
||||||
.fa.fa-fw.fa-chevron-down(*ngIf='!group.collapsed && group.profiles?.length > 0')
|
.fa.fa-fw.fa-chevron-down(*ngIf='!group.collapsed')
|
||||||
span.ms-3.me-auto {{group.name || ("Ungrouped"|translate)}}
|
span.ms-3.me-auto {{group.name || ("Ungrouped"|translate)}}
|
||||||
button.btn.btn-sm.btn-link.hover-reveal.ms-2(
|
button.btn.btn-sm.btn-link.hover-reveal.ms-2(
|
||||||
*ngIf='group.editable && group.name',
|
*ngIf='group.editable && group.name',
|
||||||
(click)='$event.stopPropagation(); editProfileGroup(group)'
|
(click)='$event.stopPropagation(); editGroup(group)'
|
||||||
)
|
)
|
||||||
i.fas.fa-pencil-alt
|
i.fas.fa-pencil-alt
|
||||||
button.btn.btn-sm.btn-link.hover-reveal.ms-2(
|
button.btn.btn-sm.btn-link.hover-reveal.ms-2(
|
||||||
*ngIf='group.editable && group.name',
|
*ngIf='group.editable && group.name',
|
||||||
(click)='$event.stopPropagation(); deleteProfileGroup(group)'
|
(click)='$event.stopPropagation(); deleteGroup(group)'
|
||||||
)
|
)
|
||||||
i.fas.fa-trash-alt
|
i.fas.fa-trash-alt
|
||||||
ng-container(*ngIf='!group.collapsed')
|
ng-container(*ngIf='!group.collapsed')
|
||||||
@@ -77,7 +67,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
|
|
||||||
.me-auto
|
.me-auto
|
||||||
|
|
||||||
button.btn.btn-link.hover-reveal.ms-1(*ngIf='!profile.isTemplate', (click)='$event.stopPropagation(); launchProfile(profile)')
|
button.btn.btn-link.hover-reveal.ms-1((click)='$event.stopPropagation(); launchProfile(profile)')
|
||||||
i.fas.fa-play
|
i.fas.fa-play
|
||||||
|
|
||||||
.ms-1.hover-reveal(ngbDropdown, placement='bottom-right top-right auto')
|
.ms-1.hover-reveal(ngbDropdown, placement='bottom-right top-right auto')
|
||||||
@@ -179,12 +169,9 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
|
|||||||
.description(translate) These apply to all profiles of a given type
|
.description(translate) These apply to all profiles of a given type
|
||||||
|
|
||||||
.list-group.mt-3.mb-3.content-box
|
.list-group.mt-3.mb-3.content-box
|
||||||
a.list-group-item.list-group-item-action.d-flex.align-items-center(
|
a.list-group-item.list-group-item-action(
|
||||||
(click)='editDefaults(provider)',
|
(click)='editDefaults(provider)',
|
||||||
*ngFor='let provider of profileProviders'
|
*ngFor='let provider of profileProviders'
|
||||||
) {{provider.name|translate}}
|
) {{provider.name|translate}}
|
||||||
.me-auto
|
|
||||||
button.btn.btn-link.hover-reveal.ms-1((click)='$event.stopPropagation(); deleteDefaults(provider)')
|
|
||||||
i.fas.fa-trash-arrow-up
|
|
||||||
|
|
||||||
div([ngbNavOutlet]='nav')
|
div([ngbNavOutlet]='nav')
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user