Compare commits

...

49 Commits
v1.0.94 ... ivy

Author SHA1 Message Date
Eugene Pankov
39732908a3 ivy test 2019-12-19 01:45:12 +01:00
Eugene Pankov
b6c97ffa49 ui tweaks 2019-12-15 16:57:38 +01:00
Eugene Pankov
786daaac32 lint 2019-12-11 18:07:01 +01:00
Eugene Pankov
0360ad2dd0 lint 2019-12-11 16:34:01 +01:00
Eugene Pankov
0a451c5876 automatically reconnect without x11 forwarding if rejected (fixes #1880) 2019-12-11 16:31:05 +01:00
Eugene Pankov
5a9625424c added 'duplicate as admin' tab menu item 2019-12-09 18:06:16 +01:00
Eugene Pankov
62c1f6463b added x11 forwarding (fixes #630) 2019-12-08 13:40:15 +01:00
Eugene Pankov
9fe82f2c0a xterm binary input support 2019-12-06 12:26:19 +01:00
Eugene
09838197a2 Bump electron from 7.1.2 to 7.1.3 (#1858)
Bump electron from 7.1.2 to 7.1.3
2019-12-06 12:06:38 +01:00
Eugene
27114797a2 Bump typescript from 3.7.2 to 3.7.3 (#1859)
Bump typescript from 3.7.2 to 3.7.3
2019-12-06 12:06:17 +01:00
Eugene
4dc77d11cf Bump xterm-addon-search from 0.4.0-beta5 to 0.4.0 in /terminus-… (#1863)
Bump xterm-addon-search from 0.4.0-beta5 to 0.4.0 in /terminus-terminal
2019-12-06 12:06:00 +01:00
Eugene
245698b67d Bump xterm-addon-webgl from 0.4.0-beta.15 to 0.4.0 in /terminus… (#1862)
Bump xterm-addon-webgl from 0.4.0-beta.15 to 0.4.0 in /terminus-terminal
2019-12-06 12:05:49 +01:00
Eugene
017fabaf6f Bump xterm from 4.3.0-beta.30 to 4.3.0 in /terminus-terminal (#1864)
Bump xterm from 4.3.0-beta.30 to 4.3.0 in /terminus-terminal
2019-12-06 12:05:11 +01:00
dependabot-preview[bot]
6c11189b3e Bump xterm from 4.3.0-beta.30 to 4.3.0 in /terminus-terminal
Bumps [xterm](https://github.com/xtermjs/xterm.js) from 4.3.0-beta.30 to 4.3.0.
- [Release notes](https://github.com/xtermjs/xterm.js/releases)
- [Commits](https://github.com/xtermjs/xterm.js/commits/4.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-06 04:26:55 +00:00
dependabot-preview[bot]
dd70f5f5d8 Bump xterm-addon-search from 0.4.0-beta5 to 0.4.0 in /terminus-terminal
Bumps [xterm-addon-search](https://github.com/xtermjs/xterm.js) from 0.4.0-beta5 to 0.4.0.
- [Release notes](https://github.com/xtermjs/xterm.js/releases)
- [Commits](https://github.com/xtermjs/xterm.js/commits/0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-06 04:26:30 +00:00
dependabot-preview[bot]
47277ac5aa Bump xterm-addon-webgl from 0.4.0-beta.15 to 0.4.0 in /terminus-terminal
Bumps [xterm-addon-webgl](https://github.com/xtermjs/xterm.js) from 0.4.0-beta.15 to 0.4.0.
- [Release notes](https://github.com/xtermjs/xterm.js/releases)
- [Commits](https://github.com/xtermjs/xterm.js/commits/0.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-06 04:26:30 +00:00
Eugene
b69cbbcdd1 [Security] Bump serialize-javascript from 2.1.0 to 2.1.1 (#1861)
[Security] Bump serialize-javascript from 2.1.0 to 2.1.1
2019-12-05 20:31:44 +01:00
dependabot-preview[bot]
efba980a1d [Security] Bump serialize-javascript from 2.1.0 to 2.1.1
Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 2.1.0 to 2.1.1. **This update includes a security fix.**
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v2.1.0...v2.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-05 18:51:22 +00:00
dependabot-preview[bot]
f31da67508 Bump typescript from 3.7.2 to 3.7.3
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 3.7.2 to 3.7.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v3.7.2...v3.7.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-05 04:27:04 +00:00
dependabot-preview[bot]
2ba76cc0b9 Bump electron from 7.1.2 to 7.1.3
Bumps [electron](https://github.com/electron/electron) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v7.1.2...v7.1.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-05 04:26:44 +00:00
Eugene
c1b4ffd248 Bump raw-loader from 3.1.0 to 4.0.0 (#1813)
Bump raw-loader from 3.1.0 to 4.0.0
2019-12-04 11:11:01 +01:00
Eugene
87cacdb568 Bump url-loader from 2.3.0 to 3.0.0 (#1827)
Bump url-loader from 2.3.0 to 3.0.0
2019-12-04 11:09:33 +01:00
Eugene
2a11bc4fcc Bump node-abi from 2.12.0 to 2.13.0 in /app (#1835)
Bump node-abi from 2.12.0 to 2.13.0 in /app
2019-12-04 11:04:02 +01:00
Eugene
f716baa7d4 Bump file-loader from 4.3.0 to 5.0.2 (#1815)
Bump file-loader from 4.3.0 to 5.0.2
2019-12-04 11:03:31 +01:00
Eugene
5b60daf366 Bump css-loader from 3.2.0 to 3.2.1 (#1848)
Bump css-loader from 3.2.0 to 3.2.1
2019-12-04 11:03:08 +01:00
Eugene
11f9f4e824 Bump @typescript-eslint/parser from 2.9.0 to 2.10.0 (#1845)
Bump @typescript-eslint/parser from 2.9.0 to 2.10.0
2019-12-04 11:02:38 +01:00
Eugene
0daf48f699 Bump style-loader from 1.0.0 to 1.0.1 (#1840)
Bump style-loader from 1.0.0 to 1.0.1
2019-12-04 11:01:57 +01:00
Eugene
8fb0ea4d75 Bump ssh2 from 0.8.6 to 0.8.7 in /terminus-ssh (#1852)
Bump ssh2 from 0.8.6 to 0.8.7 in /terminus-ssh
2019-12-04 11:01:38 +01:00
dependabot-preview[bot]
d9948cf6e2 Bump ssh2 from 0.8.6 to 0.8.7 in /terminus-ssh
Bumps [ssh2](https://github.com/mscdex/ssh2) from 0.8.6 to 0.8.7.
- [Release notes](https://github.com/mscdex/ssh2/releases)
- [Commits](https://github.com/mscdex/ssh2/compare/v0.8.6...v0.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 07:54:14 +00:00
Eugene
54b618cffc Merge pull request #1853 from Eugeny/dependabot/npm_and_yarn/terminus-ssh/ssh2-streams-0.4.8
Bump ssh2-streams from 0.4.7 to 0.4.8 in /terminus-ssh
2019-12-04 08:52:56 +01:00
dependabot-preview[bot]
690dde628e Bump ssh2-streams from 0.4.7 to 0.4.8 in /terminus-ssh
Bumps [ssh2-streams](https://github.com/mscdex/ssh2-streams) from 0.4.7 to 0.4.8.
- [Release notes](https://github.com/mscdex/ssh2-streams/releases)
- [Commits](https://github.com/mscdex/ssh2-streams/compare/v0.4.7...v0.4.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 04:22:42 +00:00
dependabot-preview[bot]
3dfbcf9d41 Bump css-loader from 3.2.0 to 3.2.1
Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-03 04:26:53 +00:00
dependabot-preview[bot]
d91ba71ec0 Bump @typescript-eslint/parser from 2.9.0 to 2.10.0
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.10.0/packages/parser)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-03 04:25:19 +00:00
Eugene Pankov
99698913a8 lint 2019-12-03 00:55:22 +01:00
Eugene Pankov
0dbb16d859 implemented port forwarding (fixes #821) 2019-12-03 00:45:35 +01:00
Eugene Pankov
0f8cff2d5b fixes 2019-12-01 19:11:05 +01:00
Eugene Pankov
471f9effcf better search UI 2019-12-01 18:52:22 +01:00
dependabot-preview[bot]
04faf1a04a Bump file-loader from 4.3.0 to 5.0.2
Bumps [file-loader](https://github.com/webpack-contrib/file-loader) from 4.3.0 to 5.0.2.
- [Release notes](https://github.com/webpack-contrib/file-loader/releases)
- [Changelog](https://github.com/webpack-contrib/file-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/file-loader/compare/v4.3.0...v5.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-30 20:11:55 +00:00
Eugene Pankov
656f5c2561 eslint 2019-11-30 21:09:42 +01:00
Eugene
99bc2c1c65 Bump @typescript-eslint/parser from 2.8.0 to 2.9.0 (#1814)
Bump @typescript-eslint/parser from 2.8.0 to 2.9.0
2019-11-30 21:01:11 +01:00
dependabot-preview[bot]
c8735243f3 Bump style-loader from 1.0.0 to 1.0.1
Bumps [style-loader](https://github.com/webpack-contrib/style-loader) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/webpack-contrib/style-loader/releases)
- [Changelog](https://github.com/webpack-contrib/style-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/style-loader/compare/v1.0.0...v1.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-29 04:30:36 +00:00
dependabot-preview[bot]
b197a16e5c Bump node-abi from 2.12.0 to 2.13.0 in /app
Bumps [node-abi](https://github.com/lgeiger/node-abi) from 2.12.0 to 2.13.0.
- [Release notes](https://github.com/lgeiger/node-abi/releases)
- [Commits](https://github.com/lgeiger/node-abi/compare/v2.12.0...v2.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-28 04:22:41 +00:00
dependabot-preview[bot]
1a361e67b3 Bump url-loader from 2.3.0 to 3.0.0
Bumps [url-loader](https://github.com/webpack-contrib/url-loader) from 2.3.0 to 3.0.0.
- [Release notes](https://github.com/webpack-contrib/url-loader/releases)
- [Changelog](https://github.com/webpack-contrib/url-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/url-loader/compare/v2.3.0...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-27 04:28:12 +00:00
Eugene Pankov
fc471b2c16 prevent infinite timers caused by sentry 2019-11-26 16:55:33 +01:00
dependabot-preview[bot]
ae17faa7e5 Bump raw-loader from 3.1.0 to 4.0.0
Bumps [raw-loader](https://github.com/webpack-contrib/raw-loader) from 3.1.0 to 4.0.0.
- [Release notes](https://github.com/webpack-contrib/raw-loader/releases)
- [Changelog](https://github.com/webpack-contrib/raw-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/raw-loader/compare/v3.1.0...v4.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-26 14:53:43 +00:00
Eugene Pankov
5fb70f1812 sentry electron sdk 2019-11-26 15:51:31 +01:00
Eugene Pankov
03fc68bb6d fixed #1785 2019-11-26 15:11:26 +01:00
Eugene Pankov
bb9c80623d fixed wnr version 2019-11-26 10:49:22 +01:00
dependabot-preview[bot]
4dd0a5951f Bump @typescript-eslint/parser from 2.8.0 to 2.9.0
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 2.8.0 to 2.9.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.9.0/packages/parser)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-26 04:26:18 +00:00
81 changed files with 2854 additions and 1023 deletions

View File

@@ -97,3 +97,4 @@ rules:
'@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors '@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors
'@typescript-eslint/restrict-template-expressions': off '@typescript-eslint/restrict-template-expressions': off
'@typescript-eslint/no-dynamic-delete': off '@typescript-eslint/no-dynamic-delete': off
'@typescript-eslint/prefer-nullish-coalescing': off

4
.gitignore vendored
View File

@@ -24,3 +24,7 @@ yarn-error.log
docs/api docs/api
.travis.ssh.key .travis.ssh.key
*.code-workspace *.code-workspace
.electron-symbols
sentry.properties
sentry-symbols.js

View File

@@ -22,7 +22,6 @@ export class Application {
app.commandLine.appendSwitch('lang', 'EN') app.commandLine.appendSwitch('lang', 'EN')
for (const flag of configData.flags || [['force_discrete_gpu', '0']]) { for (const flag of configData.flags || [['force_discrete_gpu', '0']]) {
console.log('Setting Electron flag:', flag.join('='))
app.commandLine.appendSwitch(flag[0], flag[1]) app.commandLine.appendSwitch(flag[0], flag[1])
} }
} }

View File

@@ -1,8 +1,9 @@
import './sentry'
import './lru' import './lru'
import { app, ipcMain, Menu } from 'electron' import { app, ipcMain, Menu } from 'electron'
import { parseArgs } from './cli' import { parseArgs } from './cli'
import { Application } from './app' import { Application } from './app'
import electronDebug = require('electron-debug') import * as electronDebug from 'electron-debug'
if (!process.env.TERMINUS_PLUGINS) { if (!process.env.TERMINUS_PLUGINS) {
process.env.TERMINUS_PLUGINS = '' process.env.TERMINUS_PLUGINS = ''
@@ -46,7 +47,7 @@ if (argv.d) {
electronDebug({ electronDebug({
isEnabled: true, isEnabled: true,
showDevTools: true, showDevTools: true,
devToolsMode: 'undocked' devToolsMode: 'undocked',
}) })
} }

18
app/lib/sentry.ts Normal file
View File

@@ -0,0 +1,18 @@
const { init } = process.type === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
let release
try {
release = require('electron').app.getVersion()
} catch {
release = require('electron').remote.app.getVersion()
}
init({
dsn: SENTRY_DSN,
release,
integrations (integrations) {
return integrations.filter(integration => integration.name !== 'Breadcrumbs')
},
})

View File

@@ -1,8 +1,9 @@
import { Subject, Observable } from 'rxjs' import { Subject, Observable } from 'rxjs'
import { debounceTime } from 'rxjs/operators' import { debounceTime } from 'rxjs/operators'
import { BrowserWindow, app, ipcMain, Rectangle, screen } from 'electron' import { BrowserWindow, app, ipcMain, Rectangle, screen } from 'electron'
import ElectronConfig = require('electron-config') import * as ElectronConfig from 'electron-config'
import * as os from 'os' import * as os from 'os'
import * as path from 'path'
import { loadConfig } from './config' import { loadConfig } from './config'
@@ -46,6 +47,7 @@ export class Window {
minHeight: 300, minHeight: 300,
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
preload: path.join(__dirname, 'sentry.js'),
}, },
frame: false, frame: false,
show: false, show: false,
@@ -147,14 +149,14 @@ export class Window {
this.window.webContents.send(event, ...args) this.window.webContents.send(event, ...args)
} }
isDestroyed() { isDestroyed () {
return !this.window || this.window.isDestroyed(); return !this.window || this.window.isDestroyed();
} }
private setupWindowManagement () { private setupWindowManagement () {
this.window.on('show', () => { this.window.on('show', () => {
this.visible.next(true) this.visible.next(true)
this.window.webContents.send('host:window-shown') this.send('host:window-shown')
}) })
this.window.on('hide', () => { this.window.on('hide', () => {
@@ -164,20 +166,20 @@ export class Window {
let moveSubscription = new Observable<void>(observer => { let moveSubscription = new Observable<void>(observer => {
this.window.on('move', () => observer.next()) this.window.on('move', () => observer.next())
}).pipe(debounceTime(250)).subscribe(() => { }).pipe(debounceTime(250)).subscribe(() => {
this.window.webContents.send('host:window-moved') this.send('host:window-moved')
}) })
this.window.on('closed', () => { this.window.on('closed', () => {
moveSubscription.unsubscribe() moveSubscription.unsubscribe()
}) })
this.window.on('enter-full-screen', () => this.window.webContents.send('host:window-enter-full-screen')) this.window.on('enter-full-screen', () => this.send('host:window-enter-full-screen'))
this.window.on('leave-full-screen', () => this.window.webContents.send('host:window-leave-full-screen')) this.window.on('leave-full-screen', () => this.send('host:window-leave-full-screen'))
this.window.on('close', event => { this.window.on('close', event => {
if (!this.closing) { if (!this.closing) {
event.preventDefault() event.preventDefault()
this.window.webContents.send('host:window-close-request') this.send('host:window-close-request')
return return
} }
this.windowConfig.set('windowBoundaries', this.windowBounds) this.windowConfig.set('windowBoundaries', this.windowBounds)

View File

@@ -13,14 +13,14 @@
"watch": "webpack --progress --color --watch" "watch": "webpack --progress --color --watch"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "7.2.8", "@angular/animations": "9.0.0-rc.5",
"@angular/common": "7.2.8", "@angular/common": "9.0.0-rc.5",
"@angular/compiler": "7.2.8", "@angular/compiler": "9.0.0-rc.5",
"@angular/core": "7.2.8", "@angular/core": "9.0.0-rc.5",
"@angular/forms": "7.2.8", "@angular/forms": "9.0.0-rc.5",
"@angular/platform-browser": "7.2.8", "@angular/platform-browser": "9.0.0-rc.5",
"@angular/platform-browser-dynamic": "7.2.8", "@angular/platform-browser-dynamic": "9.0.0-rc.5",
"@ng-bootstrap/ng-bootstrap": "^4.2.2", "@ng-bootstrap/ng-bootstrap": "^5.1.4",
"devtron": "1.4.0", "devtron": "1.4.0",
"electron-config": "2.0.0", "electron-config": "2.0.0",
"electron-debug": "^3.0.1", "electron-debug": "^3.0.1",
@@ -30,25 +30,26 @@
"js-yaml": "3.13.1", "js-yaml": "3.13.1",
"keytar": "^5.0.0", "keytar": "^5.0.0",
"mz": "^2.7.0", "mz": "^2.7.0",
"ngx-toastr": "^10.2.0", "ngx-toastr": "^11.2.1",
"node-pty": "^0.10.0-beta2", "node-pty": "^0.10.0-beta2",
"npm": "6.9.0", "npm": "6.9.0",
"path": "0.12.7", "path": "0.12.7",
"rxjs": "^6.5.3", "rxjs": "^6.5.3",
"rxjs-compat": "^6.5.3", "rxjs-compat": "^6.5.3",
"yargs": "^15.0.2", "yargs": "^15.0.2",
"zone.js": "^0.8.29" "zone.js": "^0.10.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"macos-native-processlist": "^1.0.2", "macos-native-processlist": "^1.0.2",
"windows-blurbehind": "^1.0.1", "windows-blurbehind": "^1.0.1",
"windows-native-registry": "^1.0.15", "windows-native-registry": "^1.0.16",
"windows-process-tree": "^0.2.4", "windows-process-tree": "^0.2.4",
"windows-swca": "^2.0.2" "windows-swca": "^2.0.2"
}, },
"devDependencies": { "devDependencies": {
"@angular/localize": "^9.0.0-rc.7",
"@types/mz": "0.0.32", "@types/mz": "0.0.32",
"@types/node": "12.7.12", "@types/node": "12.7.12",
"node-abi": "^2.12.0" "node-abi": "^2.13.0"
} }
} }

View File

@@ -1,20 +1,48 @@
import { NgModule } from '@angular/core' import { NgModule, Compiler, Inject, Injector, ɵcreateInjector as createInjector } from '@angular/core'
import '@angular/localize/init'
import { CommonModule } from '@angular/common'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr' import { ToastrModule } from 'ngx-toastr'
export function getRootModule (plugins: any[]) { @NgModule({
const imports = [ imports: [
BrowserModule, BrowserModule,
...plugins, CommonModule,
NgbModule.forRoot(), NgbModule,
ToastrModule.forRoot({ ToastrModule.forRoot({
positionClass: 'toast-bottom-center', positionClass: 'toast-bottom-center',
toastClass: 'toast', toastClass: 'toast',
preventDuplicates: true, preventDuplicates: true,
extendedTimeOut: 5000, extendedTimeOut: 5000,
}), }),
] ],
})
export class RootModule {
constructor (
private compiler: Compiler,
private injector: Injector,
@Inject('plugins') private plugins: any[],
) { }
async ngDoBootstrap (app) {
console.log('bootstrap', app)
for (let plugin of this.plugins) {
console.log(plugin)
// try {
const injector = createInjector(plugin, this.injector)
console.log(injector)
const module = await this.compiler.compileModuleAsync(plugin)
console.log(module)
// } catch (e) {
// console.error('Failed loading', plugin, e)
// }
}
}
}
export function setupRootModule (plugins: any[]) {
const bootstrap = [ const bootstrap = [
...plugins.filter(x => x.bootstrap).map(x => x.bootstrap), ...plugins.filter(x => x.bootstrap).map(x => x.bootstrap),
] ]
@@ -22,11 +50,4 @@ export function getRootModule (plugins: any[]) {
if (bootstrap.length === 0) { if (bootstrap.length === 0) {
throw new Error('Did not find any bootstrap components. Are there any plugins installed?') throw new Error('Did not find any bootstrap components. Are there any plugins installed?')
} }
@NgModule({
imports,
bootstrap,
}) class RootModule { } // eslint-disable-line @typescript-eslint/no-extraneous-class
return RootModule
} }

View File

@@ -1,4 +1,5 @@
import '../lib/lru' import '../lib/lru'
import 'core-js/proposals/reflect-metadata'
import 'source-sans-pro/source-sans-pro.css' import 'source-sans-pro/source-sans-pro.css'
import 'source-code-pro/source-code-pro.css' import 'source-code-pro/source-code-pro.css'
import '@fortawesome/fontawesome-free/css/solid.css' import '@fortawesome/fontawesome-free/css/solid.css'
@@ -6,33 +7,71 @@ import '@fortawesome/fontawesome-free/css/brands.css'
import '@fortawesome/fontawesome-free/css/fontawesome.css' import '@fortawesome/fontawesome-free/css/fontawesome.css'
import 'ngx-toastr/toastr.css' import 'ngx-toastr/toastr.css'
import './preload.scss' import './preload.scss'
import * as path from 'path'
import * as Raven from 'raven-js' const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
const nodeRequire = (global as any).require
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
Raven.config( const builtinModules = [
SENTRY_DSN, '@angular/animations',
{ '@angular/common',
release: require('electron').remote.app.getVersion(), '@angular/compiler',
dataCallback: (data: any) => { '@angular/core',
const normalize = (filename: string) => { '@angular/forms',
const splitArray = filename.split('/') '@angular/localize',
return splitArray[splitArray.length - 1] '@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@ng-bootstrap/ng-bootstrap',
'ngx-toastr',
'rxjs',
'rxjs/operators',
'rxjs/internal/observable/fromEvent',
'rxjs/internal/observable/merge',
'rxjs-compat/Subject',
'zone.js/dist/zone.js',
'terminus-core',
// 'terminus-settings',
// 'terminus-terminal',
]
const cachedBuiltinModules = {}
if (process.env.TERMINUS_DEV) {
console.info(path.dirname(require('electron').remote.app.getAppPath()))
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
nodeModule.globalPaths.unshift(path.join(require('electron').remote.app.getAppPath(), 'node_modules'))
}
const originalRequire = (global as any).require
;(global as any).require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
} }
return originalRequire.apply(this, arguments)
}
data.exception.values[0].stacktrace.frames.forEach((frame: any) => { const originalModuleRequire = nodeModule.prototype.require
frame.filename = normalize(frame.filename) nodeModule.prototype.require = function (query: string) {
}) if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalModuleRequire.call(this, query)
}
data.culprit = data.exception.values[0].stacktrace.frames[0].filename global['require'].resolve = originalRequire.resolve
nodeModule.prototype.require.resolve = originalModuleRequire.resolve
return data builtinModules.forEach(m => {
}, const label = 'Caching ' + m
}, console.time(label)
) try {
console.log(m + '/__ivy_ngcc__/fesm5/' + m.split('/')[1] + '.js')
process.on('uncaughtException' as any, (err) => { cachedBuiltinModules[m] = nodeRequire(m + '/__ivy_ngcc__/fesm5/' + m.split('/')[1] + '.js')
Raven.captureException(err as any) console.log('loaded ivy')
console.error(err) } catch (e) {
console.error(e)
cachedBuiltinModules[m] = nodeRequire(m)
}
console.timeEnd(label)
}) })

View File

@@ -1,7 +1,3 @@
import 'zone.js'
import 'core-js/proposals/reflect-metadata'
import 'rxjs'
import * as isDev from 'electron-is-dev' import * as isDev from 'electron-is-dev'
import './global.scss' import './global.scss'
@@ -10,7 +6,7 @@ import './toastr.scss'
import { enableProdMode, NgModuleRef } from '@angular/core' import { enableProdMode, NgModuleRef } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { getRootModule } from './app.module' import { setupRootModule, RootModule } from './app.module'
import { findPlugins, loadPlugins, PluginInfo } from './plugins' import { findPlugins, loadPlugins, PluginInfo } from './plugins'
// Always land on the start view // Always land on the start view
@@ -32,12 +28,14 @@ async function bootstrap (plugins: PluginInfo[], safeMode = false): Promise<NgMo
if (safeMode) { if (safeMode) {
plugins = plugins.filter(x => x.isBuiltin) plugins = plugins.filter(x => x.isBuiltin)
} }
const pluginsModules = await loadPlugins(plugins, (current, total) => { const pluginModules = await loadPlugins(plugins, (current, total) => {
(document.querySelector('.progress .bar') as HTMLElement).style.width = `${100 * current / total}%` // eslint-disable-line (document.querySelector('.progress .bar') as HTMLElement).style.width = `${100 * current / total}%` // eslint-disable-line
}) })
const module = getRootModule(pluginsModules) setupRootModule(pluginModules)
window['rootModule'] = module window['rootModule'] = RootModule
return platformBrowserDynamic().bootstrapModule(module) return platformBrowserDynamic([
{ provide: 'plugins', useValue: pluginModules },
]).bootstrapModule(RootModule)
} }
findPlugins().then(async plugins => { findPlugins().then(async plugins => {

View File

@@ -14,9 +14,6 @@ function normalizePath (path: string): string {
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x))) global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
if (process.env.TERMINUS_DEV) {
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
}
const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(require('electron').remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins') const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(require('electron').remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
@@ -52,49 +49,6 @@ export interface PluginInfo {
info?: any info?: any
} }
const builtinModules = [
'@angular/animations',
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/forms',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@ng-bootstrap/ng-bootstrap',
'ngx-toastr',
'rxjs',
'rxjs/operators',
'rxjs-compat/Subject',
'terminus-core',
'terminus-settings',
'terminus-terminal',
'zone.js/dist/zone.js',
]
const cachedBuiltinModules = {}
builtinModules.forEach(m => {
const label = 'Caching ' + m
console.time(label)
cachedBuiltinModules[m] = nodeRequire(m)
console.timeEnd(label)
})
const originalRequire = (global as any).require
;(global as any).require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalRequire.apply(this, arguments)
}
const originalModuleRequire = nodeModule.prototype.require
nodeModule.prototype.require = function (query: string) {
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalModuleRequire.call(this, query)
}
export async function findPlugins (): Promise<PluginInfo[]> { export async function findPlugins (): Promise<PluginInfo[]> {
const paths = nodeModule.globalPaths const paths = nodeModule.globalPaths
let foundPlugins: PluginInfo[] = [] let foundPlugins: PluginInfo[] = []
@@ -167,6 +121,7 @@ export async function loadPlugins (foundPlugins: PluginInfo[], progress: Progres
progress(0, 1) progress(0, 1)
let index = 0 let index = 0
for (const foundPlugin of foundPlugins) { for (const foundPlugin of foundPlugins) {
if (foundPlugin.name !== 'core') continue
console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`) console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`)
progress(index, foundPlugins.length) progress(index, foundPlugins.length)
try { try {

View File

@@ -1,6 +0,0 @@
import { Component } from '@angular/core'
@Component({
template: '<app-root></app-root>',
})
export class RootComponent { } // eslint-disable-line @typescript-eslint/no-extraneous-class

View File

@@ -10,6 +10,10 @@
background-image: none; background-image: none;
width: auto; width: auto;
&.toast-error {
background-color: #BD362F;
}
&.toast-info { &.toast-info {
background-color: #555; background-color: #555;
} }

View File

@@ -1,7 +1,8 @@
{ {
"compilerOptions": { "compilerOptions": {
"baseUrl": "./src", "baseUrl": "./src",
"module": "commonjs", "module": "es2015",
"moduleResolution": "node",
"target": "es2015", "target": "es2015",
"declaration": false, "declaration": false,
"noImplicitAny": false, "noImplicitAny": false,
@@ -19,7 +20,10 @@
"es2015.iterable", "es2015.iterable",
"es2017", "es2017",
"es7" "es7"
] ],
"paths": {
"*": ["../../app/node_modules/*"]
}
}, },
"compileOnSave": false, "compileOnSave": false,
"exclude": [ "exclude": [
@@ -28,5 +32,9 @@
"*/node_modules", "*/node_modules",
"terminus*", "terminus*",
"platforms" "platforms"
] ],
"angularCompilerOptions": {
"enableIvy": true,
"disableTypeScriptVersionCheck": true
}
} }

View File

@@ -1,11 +1,13 @@
const path = require('path') const path = require('path')
const webpack = require('webpack') const webpack = require('webpack')
const { AngularCompilerPlugin } = require('@ngtools/webpack')
module.exports = { module.exports = {
name: 'terminus', name: 'terminus',
target: 'node', target: 'node',
entry: { entry: {
'index.ignore': 'file-loader?name=index.html!pug-html-loader!' + path.resolve(__dirname, './index.pug'), 'index.ignore': 'file-loader?name=index.html!pug-html-loader!' + path.resolve(__dirname, './index.pug'),
sentry: path.resolve(__dirname, 'lib/sentry.ts'),
preload: path.resolve(__dirname, 'src/entry.preload.ts'), preload: path.resolve(__dirname, 'src/entry.preload.ts'),
bundle: path.resolve(__dirname, 'src/entry.ts'), bundle: path.resolve(__dirname, 'src/entry.ts'),
}, },
@@ -27,13 +29,8 @@ module.exports = {
module: { module: {
rules: [ rules: [
{ {
test: /\.ts$/, test: /(?:\.ngfactory\.js|\.ngfactory|\.ngstyle\.js|\.ts)$/,
use: { loader: '@ngtools/webpack',
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.json'),
},
},
}, },
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, { test: /\.css$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
@@ -78,5 +75,13 @@ module.exports = {
}, },
plugins: [ plugins: [
new webpack.optimize.ModuleConcatenationPlugin(), new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.DefinePlugin({
'process.type': '"renderer"'
}),
new AngularCompilerPlugin({
tsConfigPath: path.resolve(__dirname, 'tsconfig.json'),
entryModule: 'src/index#default',
sourceMap: true,
}),
], ],
} }

View File

@@ -45,5 +45,8 @@ module.exports = {
}, },
plugins: [ plugins: [
new webpack.optimize.ModuleConcatenationPlugin(), new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.DefinePlugin({
'process.type': '"main"',
}),
], ],
} }

View File

@@ -2,59 +2,170 @@
# yarn lockfile v1 # yarn lockfile v1
"@angular/animations@7.2.8": "@angular/animations@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.8.tgz#0285364c839c660a934ab0f753ec21424bfb292e" resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.0.0-rc.5.tgz#8ed3fa2f5d16c16d1ea013ec71e46365c8336622"
integrity sha512-dJn9koYukyz15TouBc+z5z9fdThDk+bKgdlij25eYSu5Mpmtk04gB4eIMQA97K0UDh1d4YukgSJ5w3ZIk0m8DQ== integrity sha512-pb1QJjBaBOenSIdKB9h1Ts8yQwdAjjTuH9ckVycjYH3yKDc1cQuaGy4NxEx7TJF8ADo4iKkCvKTyh0dW42TOvg==
dependencies:
tslib "^1.9.0"
"@angular/common@7.2.8": "@angular/common@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.8.tgz#660c816b6f08cd2919a6efb7465397e4ff14d265" resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.0.0-rc.5.tgz#05c6cfeef03d55757bf131c8171fb3bf35daa59f"
integrity sha512-LgOhf68+LPndGZhtnUlGFd2goReXYmHzaFZW8gCEi9aC+H+Io8bjYh0gkH3xDreevEOe3f0z6coXNFLIxSmTuA== integrity sha512-Gg24S8dMUwVrmIvVHIz2rWCU+q+4Su41s4oipJWJIW1bCBMWqb2oGtaWMhy7RbUkFq2TeL7tC3dS2FOqvgj9sg==
dependencies:
tslib "^1.9.0"
"@angular/compiler@7.2.8": "@angular/compiler@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.8.tgz#9d9c1515e99914399e6915c1c90484b1d255560b" resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.0-rc.5.tgz#4771e04d8a4c25cfe195232b194dd8ac61bdce42"
integrity sha512-PrU97cTsOdofpaDkxK0rWUA/CGd0u6ESOI6XvFVm5xH9zJInsdY8ShSHklnr1JJnss70e1dGKZbZq32OChxWMw== integrity sha512-0CWPDbpHoWm/ZN40/Y+iPikRQbhd50keoE4xSAYM2SS1pnomJaF2ytIL9xfc3BMGGKgiX3aIk57B0m4yDYTiBw==
dependencies:
tslib "^1.9.0"
"@angular/core@7.2.8": "@angular/core@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.8.tgz#6586d9b6c6321c80119b3f3e2bd0edbb32d0b649" resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.0-rc.5.tgz#4d6140e3bf14b7be86e2045bf6a657ec7b4ef211"
integrity sha512-QKwug2kWJC00zm2rvmD9mCJzsOkMVhSu8vqPWf83poWTh8+F9aIVWcy29W0VoGpBkSchOnK8hf9DnKVv28j9nw== integrity sha512-g9IhWc5znQGNj056Qtk1OnNYDQAIT8ti++xgcAYJ2Z1Yp0Bkb8gL7WexiuwKxmilHmZxnZiRHsPfSlKl0Hxp5g==
dependencies:
tslib "^1.9.0"
"@angular/forms@7.2.8": "@angular/forms@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.8.tgz#adf194088495822d55dcf3e5bf69196dcf19465d" resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.0.0-rc.5.tgz#ab8886d865d968ab23b7680e80061c16fef0a5d8"
integrity sha512-lbSX4IHFHz/c4e2RHiPpL8MJlzDkCuQEHnqsujDaV2X9o9fApS6+C1X4x7Z2XDKqonmeX+aHQwv9+SLejX6OyQ== integrity sha512-+K4MHD7EmSbxljKd/+vugyGWUROSy8PAcqV160gCQQbxW9MuYsHJM/BBPaq2H07gE5YHJ/HOSQoepNdXJ3PUSw==
dependencies:
tslib "^1.9.0"
"@angular/platform-browser-dynamic@7.2.8": "@angular/localize@^9.0.0-rc.7":
version "7.2.8" version "9.0.0-rc.7"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.8.tgz#e82768900cedfa75bf453263f931a9f90f7aaab2" resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.0.0-rc.7.tgz#8819a32309d44a631c102d3c8d064302cfc23f3c"
integrity sha512-nOJt28A5pRn4mdL8y98V7bA6OOdMRjsQAcWCr/isGYF0l1yDC0ijUGWkHuRtj3z1/9tmERN0BLXx+xs1h4JhCQ== integrity sha512-y03uNKoZSsedY5W2X7NUNcmxm6rsL6dMs2g1NRw0jOmveXjk8N0g7uUgcBQhXJ7LiHtaRcIK+bOq+2JvvTtZlQ==
dependencies: dependencies:
tslib "^1.9.0" "@babel/core" "^7.5.5"
glob "7.1.2"
yargs "13.1.0"
"@angular/platform-browser@7.2.8": "@angular/platform-browser-dynamic@9.0.0-rc.5":
version "7.2.8" version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.8.tgz#11096727b99bf3d7fd82a00a3a468b933c9713bd" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.0-rc.5.tgz#6beb6e5f625df5939b757b80f7f39134e95769f0"
integrity sha512-SizCRMc7Or27g2CugcqWnaAikRPfgLgRvb9GFFGpcgoq8CRfOVwkyR5dFZuqN39H+uwtwuTMP5OUYhZcrFNKug== integrity sha512-MCDIuwcFlXo4f/ro9NiYcV1t8SBdt22dXjQWWSij+ABlVqrW7Xwl8oNq0q2+HJQIlg+a37Y2svJouUN1kLvZ3A==
"@angular/platform-browser@9.0.0-rc.5":
version "9.0.0-rc.5"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.0.0-rc.5.tgz#b10dcd5df71c33e7bff48154ae3876de5236eb5e"
integrity sha512-omnc9GnVU8THx2YSnJUzrR2Lk2alzao9AhR+I05GOlYgL3HsuttTtTBEzVfvecGLwSBKrdtbPUwWG4NTuuxGTA==
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==
dependencies: dependencies:
tslib "^1.9.0" "@babel/highlight" "^7.0.0"
"@ng-bootstrap/ng-bootstrap@^4.2.2": "@babel/core@^7.5.5":
version "4.2.2" version "7.7.5"
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.2.2.tgz#a1c3a9576656cb4f793bbc3df56dfbdeb098f2fb" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.5.tgz#ae1323cd035b5160293307f50647e83f8ba62f7e"
integrity sha512-v8QmC17bv9he5Ep6zutaI9aQ2w/2NqySP0fejOKe7cacKpGUqsLIakpyd2FD7mfZu7pSCCtHYpRWR+h6yq+Ngg== integrity sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.4"
"@babel/helpers" "^7.7.4"
"@babel/parser" "^7.7.5"
"@babel/template" "^7.7.4"
"@babel/traverse" "^7.7.4"
"@babel/types" "^7.7.4"
convert-source-map "^1.7.0"
debug "^4.1.0"
json5 "^2.1.0"
lodash "^4.17.13"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369"
integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==
dependencies:
"@babel/types" "^7.7.4"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
"@babel/helper-function-name@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e"
integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==
dependencies:
"@babel/helper-get-function-arity" "^7.7.4"
"@babel/template" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/helper-get-function-arity@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0"
integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==
dependencies:
"@babel/types" "^7.7.4"
"@babel/helper-split-export-declaration@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8"
integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==
dependencies:
"@babel/types" "^7.7.4"
"@babel/helpers@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302"
integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==
dependencies:
"@babel/template" "^7.7.4"
"@babel/traverse" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/highlight@^7.0.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
dependencies:
chalk "^2.0.0"
esutils "^2.0.2"
js-tokens "^4.0.0"
"@babel/parser@^7.7.4", "@babel/parser@^7.7.5":
version "7.7.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71"
integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==
"@babel/template@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b"
integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/parser" "^7.7.4"
"@babel/types" "^7.7.4"
"@babel/traverse@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558"
integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.4"
"@babel/helper-function-name" "^7.7.4"
"@babel/helper-split-export-declaration" "^7.7.4"
"@babel/parser" "^7.7.4"
"@babel/types" "^7.7.4"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
"@babel/types@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193"
integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==
dependencies:
esutils "^2.0.2"
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@ng-bootstrap/ng-bootstrap@^5.1.4":
version "5.1.4"
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-5.1.4.tgz#1ace4d4a7b80017fb1c55547a5569993b4742b5d"
integrity sha512-UtL9GBkAMy0O/0Rkc4DG1WoFDWhAnAdvsQuJ1IFLmlN2v6HAX+E84tgUK0n15WLBhYBXXuhRx0dIW2jafjg1xQ==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
@@ -151,6 +262,11 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.0: ansi-regex@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
@@ -384,7 +500,7 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^2.0.1: chalk@^2.0.0, chalk@^2.0.1:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -569,6 +685,13 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
dependencies:
safe-buffer "~5.1.1"
copy-concurrently@^1.0.0: copy-concurrently@^1.0.0:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@@ -602,6 +725,17 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0" shebang-command "^1.2.0"
which "^1.2.9" which "^1.2.9"
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
crypto-random-string@^1.0.0: crypto-random-string@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
@@ -640,7 +774,7 @@ debug@^3.1.0:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debug@^4.1.1: debug@^4.1.0, debug@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@@ -812,6 +946,11 @@ electron-updater@^4.2.0:
pako "^1.0.10" pako "^1.0.10"
semver "^6.3.0" semver "^6.3.0"
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -877,6 +1016,11 @@ esprima@^4.0.0:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
execa@^0.7.0: execa@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@@ -890,6 +1034,19 @@ execa@^0.7.0:
signal-exit "^3.0.0" signal-exit "^3.0.0"
strip-eof "^1.0.0" strip-eof "^1.0.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
expand-template@^2.0.3: expand-template@^2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
@@ -1117,6 +1274,18 @@ github-from-package@0.0.0:
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.3, glob@^7.1.1, glob@^7.1.3: glob@^7.0.3, glob@^7.1.1, glob@^7.1.3:
version "7.1.4" version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
@@ -1136,6 +1305,11 @@ global-dirs@^0.1.0:
dependencies: dependencies:
ini "^1.3.4" ini "^1.3.4"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
got@^6.7.1: got@^6.7.1:
version "6.7.1" version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -1314,6 +1488,11 @@ invert-kv@^1.0.0:
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
ip-regex@^2.1.0: ip-regex@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -1420,6 +1599,11 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@3.13.1, js-yaml@^3.13.1: js-yaml@3.13.1, js-yaml@^3.13.1:
version "3.13.1" version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
@@ -1433,6 +1617,11 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -1453,6 +1642,13 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json5@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
dependencies:
minimist "^1.2.0"
jsonfile@^4.0.0: jsonfile@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
@@ -1517,6 +1713,13 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" invert-kv "^1.0.0"
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
dependencies:
invert-kv "^2.0.0"
libcipm@^3.0.3: libcipm@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-3.0.3.tgz#2e764effe0b90d458790dab3165794c804075ed3" resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-3.0.3.tgz#2e764effe0b90d458790dab3165794c804075ed3"
@@ -1732,6 +1935,11 @@ lodash.without@~4.4.0:
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
lodash@^4.17.13:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
lowercase-keys@^1.0.0: lowercase-keys@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
@@ -1783,6 +1991,13 @@ make-fetch-happen@^4.0.1:
socks-proxy-agent "^4.0.0" socks-proxy-agent "^4.0.0"
ssri "^6.0.0" ssri "^6.0.0"
map-age-cleaner@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
dependencies:
p-defer "^1.0.0"
meant@~1.0.1: meant@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d" resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
@@ -1795,6 +2010,15 @@ mem@^1.1.0:
dependencies: dependencies:
mimic-fn "^1.0.0" mimic-fn "^1.0.0"
mem@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
dependencies:
map-age-cleaner "^0.1.1"
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
mime-db@1.40.0: mime-db@1.40.0:
version "1.40.0" version "1.40.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
@@ -1812,6 +2036,11 @@ mimic-fn@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^2.0.0: mimic-response@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
@@ -1918,17 +2147,22 @@ napi-build-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
ngx-toastr@^10.2.0: ngx-toastr@^11.2.1:
version "10.2.0" version "11.2.1"
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-10.2.0.tgz#8a79008de0b1c013f90120a53e0355af5762e969" resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-11.2.1.tgz#130dcb416499f4419b18c39ad9cfea2e7790c7c4"
integrity sha512-6ASr5bcvQmtNKb4D2VEsQjCXyROq6GwberBWO0bVt+xcBYPUea4aRTgX8in9apX9buaTafzG+h3HlnIraspoPg== integrity sha512-qLZA+h1lIGLQ1HAJpx5JJ8i87PAZPAN6MnexmrWipSONqrK4fRh+nUKIxqmcckIiD16dgu2O5SNloSJymTKUAw==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
node-abi@^2.12.0, node-abi@^2.7.0: nice-try@^1.0.4:
version "2.12.0" version "1.0.5"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.12.0.tgz#40e9cfabdda1837863fa825e7dfa0b15686adf6f" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw== integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-abi@^2.13.0, node-abi@^2.7.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.13.0.tgz#e2f2ec444d0aca3ea1b3874b6de41d1665828f63"
integrity sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==
dependencies: dependencies:
semver "^5.4.1" semver "^5.4.1"
@@ -2282,6 +2516,15 @@ os-locale@^2.0.0:
lcid "^1.0.0" lcid "^1.0.0"
mem "^1.1.0" mem "^1.1.0"
os-locale@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
dependencies:
execa "^1.0.0"
lcid "^2.0.0"
mem "^4.0.0"
os-tmpdir@^1.0.0: os-tmpdir@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -2295,11 +2538,21 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5:
os-homedir "^1.0.0" os-homedir "^1.0.0"
os-tmpdir "^1.0.0" os-tmpdir "^1.0.0"
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
p-finally@^1.0.0: p-finally@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-is-promise@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
p-limit@^1.1.0: p-limit@^1.1.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@@ -2429,7 +2682,7 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2:
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
path-key@^2.0.0: path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
@@ -2777,6 +3030,13 @@ resolve@^1.10.0:
dependencies: dependencies:
path-parse "^1.0.6" path-parse "^1.0.6"
resolve@^1.3.2:
version "1.14.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.0.tgz#6d14c6f9db9f8002071332b600039abf82053f64"
integrity sha512-uviWSi5N67j3t3UKFxej1loCH0VZn5XuqdNxoLShPcYPw6cUZn74K1VRj+9myynRX03bxIBEkwlkob/ujLsJVw==
dependencies:
path-parse "^1.0.6"
retry@^0.10.0: retry@^0.10.0:
version "0.10.1" version "0.10.1"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
@@ -2938,6 +3198,11 @@ sorted-union-stream@~2.1.3:
from2 "^1.3.0" from2 "^1.3.0"
stream-iterate "^1.1.0" stream-iterate "^1.1.0"
source-map@^0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
spdx-correct@^3.0.0: spdx-correct@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@@ -3039,6 +3304,15 @@ string-width@^1.0.1:
is-fullwidth-code-point "^2.0.0" is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0" strip-ansi "^4.0.0"
string-width@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string-width@^4.1.0, string-width@^4.2.0: string-width@^4.1.0, string-width@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
@@ -3086,6 +3360,13 @@ strip-ansi@^4.0.0:
dependencies: dependencies:
ansi-regex "^3.0.0" ansi-regex "^3.0.0"
strip-ansi@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0: strip-ansi@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
@@ -3202,6 +3483,11 @@ tiny-relative-date@^1.3.0:
resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
tough-cookie@~2.4.3: tough-cookie@~2.4.3:
version "2.4.3" version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
@@ -3397,10 +3683,10 @@ windows-blurbehind@^1.0.1:
resolved "https://registry.yarnpkg.com/windows-blurbehind/-/windows-blurbehind-1.0.1.tgz#ff098713873304e38330b2c54cc41bb369b587b9" resolved "https://registry.yarnpkg.com/windows-blurbehind/-/windows-blurbehind-1.0.1.tgz#ff098713873304e38330b2c54cc41bb369b587b9"
integrity sha512-1HzHfCiM1ayrbACJu5qE9zELV24uX/tINT6kxaZwLY3rtQAoeav6x9z7LFHWoLaGDN/sYbnK+9Vk0cz7fsk5HQ== integrity sha512-1HzHfCiM1ayrbACJu5qE9zELV24uX/tINT6kxaZwLY3rtQAoeav6x9z7LFHWoLaGDN/sYbnK+9Vk0cz7fsk5HQ==
windows-native-registry@^1.0.15: windows-native-registry@^1.0.16:
version "1.0.15" version "1.0.16"
resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.15.tgz#02593331fb7dcab99ef3ac9dd71f2c71ae57b189" resolved "https://registry.yarnpkg.com/windows-native-registry/-/windows-native-registry-1.0.16.tgz#761f21b7dfa6cdb28479cf9bc66b705592e3ae6a"
integrity sha512-uIsz1y3LrKPkphcZsezThz07FW7Vm00Zfa6ZU88rIo2zilOLE6Ui75jh6UkBAMso8xJeyvYbbcxF9kr4Zt8Iuw== integrity sha512-RROB5VPEafEJLK93vdttfq4BGWaMWI/OHjAE2cqA31eMjmPShD2KaerlhEfUgqa5THsaAbYUK0LQKc4UQTjIMg==
dependencies: dependencies:
nan "^2.14.0" nan "^2.14.0"
@@ -3486,6 +3772,14 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yargs-parser@^13.0.0:
version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^16.1.0: yargs-parser@^16.1.0:
version "16.1.0" version "16.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1"
@@ -3501,6 +3795,23 @@ yargs-parser@^9.0.2:
dependencies: dependencies:
camelcase "^4.1.0" camelcase "^4.1.0"
yargs@13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301"
integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==
dependencies:
cliui "^4.0.0"
find-up "^3.0.0"
get-caller-file "^2.0.1"
os-locale "^3.1.0"
require-directory "^2.1.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^3.0.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^13.0.0"
yargs@^11.0.0: yargs@^11.0.0:
version "11.1.0" version "11.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"
@@ -3536,7 +3847,7 @@ yargs@^15.0.2:
y18n "^4.0.0" y18n "^4.0.0"
yargs-parser "^16.1.0" yargs-parser "^16.1.0"
zone.js@^0.8.29: zone.js@^0.10.2:
version "0.8.29" version "0.10.2"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.2.tgz#67ca084b3116fc33fc40435e0d5ea40a207e392e"
integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ== integrity sha512-UAYfiuvxLN4oyuqhJwd21Uxb4CNawrq6fPS/05Su5L4G+1TN+HVDJMUHNMobVQDFJRir2cLAODXwluaOKB7HFg==

View File

@@ -1,25 +1,33 @@
{ {
"devDependencies": { "devDependencies": {
"@angular/compiler": "9.0.0-rc.5",
"@angular/compiler-cli": "9.0.0-rc.5",
"@angular/core": "9.0.0-rc.5",
"@fortawesome/fontawesome-free": "^5.11.2", "@fortawesome/fontawesome-free": "^5.11.2",
"@ngtools/webpack": "9.0.0-rc.5",
"@sentry/cli": "^1.49.0",
"@sentry/electron": "^1.0.0",
"@types/electron-config": "^3.2.2", "@types/electron-config": "^3.2.2",
"@types/electron-debug": "^2.1.0", "@types/electron-debug": "^2.1.0",
"@types/js-yaml": "^3.12.1", "@types/js-yaml": "^3.12.1",
"@types/node": "12.7.12", "@types/node": "12.7.12",
"@types/webpack-env": "1.14.1", "@types/webpack-env": "1.14.1",
"@typescript-eslint/eslint-plugin": "^2.8.0", "@typescript-eslint/eslint-plugin": "^2.9.0",
"@typescript-eslint/parser": "^2.8.0", "@typescript-eslint/parser": "^2.10.0",
"apply-loader": "2.0.0", "apply-loader": "2.0.0",
"awesome-typescript-loader": "^5.0.0", "awesome-typescript-loader": "^5.0.0",
"core-js": "^3.4.2", "core-js": "^3.4.2",
"cross-env": "6.0.3", "cross-env": "6.0.3",
"css-loader": "3.2.0", "css-loader": "3.4.0",
"electron": "^7.1.2", "electron": "^7.1.3",
"electron-builder": "22.1.0", "electron-builder": "22.1.0",
"electron-download": "^4.1.1",
"electron-installer-snap": "^4.1.0", "electron-installer-snap": "^4.1.0",
"electron-notarize": "^0.1.1", "electron-notarize": "^0.1.1",
"electron-rebuild": "^1.8.5", "electron-rebuild": "^1.8.5",
"eslint": "^6.7.1", "eslint": "^6.7.1",
"file-loader": "^4.3.0", "eslint-plugin-import": "^2.18.2",
"file-loader": "^5.0.2",
"graceful-fs": "^4.2.2", "graceful-fs": "^4.2.2",
"html-loader": "0.5.5", "html-loader": "0.5.5",
"json-loader": "0.5.7", "json-loader": "0.5.7",
@@ -33,21 +41,20 @@
"pug-lint": "^2.6.0", "pug-lint": "^2.6.0",
"pug-loader": "^2.4.0", "pug-loader": "^2.4.0",
"pug-static-loader": "2.0.0", "pug-static-loader": "2.0.0",
"raven-js": "3.27.2", "raw-loader": "4.0.0",
"raw-loader": "3.1.0",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"shelljs": "0.8.3", "shelljs": "0.8.3",
"source-code-pro": "^2.30.2", "source-code-pro": "^2.30.2",
"source-sans-pro": "3.6.0", "source-sans-pro": "3.6.0",
"style-loader": "^1.0.0", "style-loader": "^1.0.1",
"svg-inline-loader": "^0.8.0", "svg-inline-loader": "^0.8.0",
"to-string-loader": "1.1.6", "to-string-loader": "1.1.6",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"typedoc": "^0.15.3", "typedoc": "^0.15.3",
"typescript": "^3.6.4", "typescript": "^3.7.3",
"url-loader": "^2.3.0", "url-loader": "^3.0.0",
"val-loader": "2.0.1", "val-loader": "2.1.0",
"webpack": "^5.0.0-beta.7", "webpack": "4",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.10",
"yaml-loader": "0.5.0" "yaml-loader": "0.5.0"
}, },
@@ -133,8 +140,5 @@
"lint": "eslint --ext ts */src", "lint": "eslint --ext ts */src",
"postinstall": "node ./scripts/install-deps.js" "postinstall": "node ./scripts/install-deps.js"
}, },
"repository": "eugeny/terminus", "repository": "eugeny/terminus"
"dependencies": {
"eslint-plugin-import": "^2.18.2"
}
} }

View File

@@ -25,8 +25,5 @@ if (['darwin', 'linux'].includes(process.platform)) {
for (let x of vars.builtinPlugins) { for (let x of vars.builtinPlugins) {
sh.ln('-fs', '../' + x, x) sh.ln('-fs', '../' + x, x)
} }
for (let x of vars.bundledModules) {
sh.ln('-fs', '../app/node_modules/' + x, x)
}
sh.cd('..') sh.cd('..')
} }

View File

@@ -22,8 +22,4 @@ exports.builtinPlugins = [
'terminus-plugin-manager', 'terminus-plugin-manager',
'terminus-ssh', 'terminus-ssh',
] ]
exports.bundledModules = [
'@angular',
'@ng-bootstrap',
]
exports.electronVersion = electronInfo.version exports.electronVersion = electronInfo.version

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-community-color-schemes", "name": "terminus-community-color-schemes",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "Community color schemes for Terminus", "description": "Community color schemes for Terminus",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-core", "name": "terminus-core",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "Terminus core", "description": "Terminus core",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"

View File

@@ -10,8 +10,8 @@ title-bar(
.inset.background(*ngIf='hostApp.platform == Platform.macOS && config.store.appearance.frame == "thin" && config.store.appearance.tabsLocation == "top"') .inset.background(*ngIf='hostApp.platform == Platform.macOS && config.store.appearance.frame == "thin" && config.store.appearance.tabsLocation == "top"')
.tabs( .tabs(
dnd-sortable-container, dnd-sortable-container,
[sortableData]='app.tabs',
) )
//- [sortableData]='app.tabs',
tab-header( tab-header(
*ngFor='let tab of app.tabs; let idx = index', *ngFor='let tab of app.tabs; let idx = index',
dnd-sortable, dnd-sortable,
@@ -47,8 +47,11 @@ title-bar(
(click)='item.click()', (click)='item.click()',
ngbDropdownItem, ngbDropdownItem,
) )
.icon-wrapper([innerHTML]='sanitizeIcon(item.icon)') .icon-wrapper(
.ml-3 {{item.title}} *ngIf='hasIcons(button.submenuItems)',
[innerHTML]='sanitizeIcon(item.icon)'
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
.drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS') .drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
@@ -70,8 +73,11 @@ title-bar(
(click)='item.click()', (click)='item.click()',
ngbDropdownItem, ngbDropdownItem,
) )
.icon-wrapper([innerHTML]='sanitizeIcon(item.icon)') .icon-wrapper(
.ml-3 {{item.title}} *ngIf='hasIcons(button.submenuItems)',
[innerHTML]='sanitizeIcon(item.icon)'
)
div([class.ml-3]='hasIcons(button.submenuItems)') {{item.title}}
button.btn.btn-secondary.btn-tab-bar.btn-update( button.btn.btn-secondary.btn-tab-bar.btn-update(
*ngIf='updatesAvailable', *ngIf='updatesAvailable',

View File

@@ -20,8 +20,8 @@ import { AppService, ToolbarButton, ToolbarButtonProvider } from '../api'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
template: require('./appRoot.component.pug'), templateUrl: './appRoot.component.pug',
styles: [require('./appRoot.component.scss')], styleUrls: ['./appRoot.component.scss'],
animations: [ animations: [
trigger('animateTab', [ trigger('animateTab', [
state('in', style({ state('in', style({
@@ -250,6 +250,10 @@ export class AppRootComponent {
} }
} }
hasIcons (submenuItems: ToolbarButton[]): boolean {
return submenuItems.some(x => !!x.icon)
}
sanitizeIcon (icon: string): any { sanitizeIcon (icon: string): any {
return this.domSanitizer.bypassSecurityTrustHtml(icon || '') return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
} }

View File

@@ -1,4 +0,0 @@
.icon(tabindex='0', [class.active]='model', (keyup.space)='click()')
i.fas.fa-square.off
i.fas.fa-check-square.on
.text {{text}}

View File

@@ -1,55 +0,0 @@
:host {
cursor: pointer;
margin: 5px 0;
&:focus {
background: rgba(255,255,255,.05);
border-radius: 5px;
}
&:active {
background: rgba(255,255,255,.1);
border-radius: 3px;
}
&[disabled] {
opacity: 0.5;
}
display: flex;
flex-direction: row;
align-items: center;
.off {
color: rgba(0, 0, 0, .5);
}
.icon {
position: relative;
flex: none;
width: 14px;
height: 14px;
i {
position: absolute;
left: 0;
top: -2px;
transition: 0.25s opacity;
display: block;
font-size: 18px;
}
i.on, &.active i.off {
opacity: 0;
}
i.off, &.active i.on {
opacity: 1;
}
}
.text {
flex: auto;
margin-left: 8px;
}
}

View File

@@ -4,8 +4,12 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'checkbox', selector: 'checkbox',
template: require('./checkbox.component.pug'), template: `
styles: [require('./checkbox.component.scss')], <div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" [(ngModel)]='model'>
<label class="custom-control-label">{{text}}</label>
</div>
`,
providers: [ providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true }, { provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true },
], ],

View File

@@ -4,7 +4,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'rename-tab-modal', selector: 'rename-tab-modal',
template: require('./renameTabModal.component.pug'), templateUrl: './renameTabModal.component.pug',
}) })
export class RenameTabModalComponent { export class RenameTabModalComponent {
@Input() value: string @Input() value: string

View File

@@ -3,7 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
/** @hidden */ /** @hidden */
@Component({ @Component({
template: require('./safeModeModal.component.pug'), templateUrl: './safeModeModal.component.pug',
}) })
export class SafeModeModalComponent { export class SafeModeModalComponent {
@Input() error: Error @Input() error: Error

View File

@@ -138,7 +138,7 @@ export interface SplitSpannerInfo {
(change)='onSpannerAdjusted(spanner)' (change)='onSpannerAdjusted(spanner)'
></split-tab-spanner> ></split-tab-spanner>
`, `,
styles: [require('./splitTab.component.scss')], styleUrls: ['./splitTab.component.scss'],
}) })
export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy { export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
/** @hidden */ /** @hidden */

View File

@@ -5,7 +5,7 @@ import { SplitContainer } from './splitTab.component'
@Component({ @Component({
selector: 'split-tab-spanner', selector: 'split-tab-spanner',
template: '', template: '',
styles: [require('./splitTabSpanner.component.scss')], styleUrls: ['./splitTabSpanner.component.scss'],
}) })
export class SplitTabSpannerComponent { export class SplitTabSpannerComponent {
@Input() container: SplitContainer @Input() container: SplitContainer

View File

@@ -7,8 +7,8 @@ import { ToolbarButton, ToolbarButtonProvider } from '../api'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'start-page', selector: 'start-page',
template: require('./startPage.component.pug'), templateUrl: './startPage.component.pug',
styles: [require('./startPage.component.scss')], styleUrls: ['./startPage.component.scss'],
}) })
export class StartPageComponent { export class StartPageComponent {
version: string version: string

View File

@@ -10,9 +10,9 @@ import { BaseTabComponent } from '../components/baseTab.component'
</perfect-scrollbar--> </perfect-scrollbar-->
<ng-template #placeholder></ng-template> <ng-template #placeholder></ng-template>
`, `,
styles: [ styleUrls: [
require('./tabBody.component.scss'), './tabBody.component.scss',
require('./tabBody.deep.component.css'), './tabBody.deep.component.css',
], ],
}) })
export class TabBodyComponent implements OnChanges { export class TabBodyComponent implements OnChanges {

View File

@@ -48,7 +48,7 @@ $tabs-height: 38px;
width: $button-size; width: $button-size;
height: $button-size; height: $button-size;
border-radius: $button-size / 2; border-radius: $button-size / 2;
line-height: $button-size * 0.9; line-height: $button-size;
align-self: center; align-self: center;
margin-right: 10px; margin-right: 10px;

View File

@@ -17,8 +17,8 @@ export interface SortableComponentProxy {
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'tab-header', selector: 'tab-header',
template: require('./tabHeader.component.pug'), templateUrl: './tabHeader.component.pug',
styles: [require('./tabHeader.component.scss')], styleUrls: ['./tabHeader.component.scss'],
}) })
export class TabHeaderComponent { export class TabHeaderComponent {
@Input() index: number @Input() index: number

View File

@@ -1,9 +1,12 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { HostAppService } from '../services/hostApp.service'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'title-bar', selector: 'title-bar',
template: require('./titleBar.component.pug'), templateUrl: './titleBar.component.pug',
styles: [require('./titleBar.component.scss')], styleUrls: ['./titleBar.component.scss'],
}) })
export class TitleBarComponent { } // eslint-disable-line @typescript-eslint/no-extraneous-class export class TitleBarComponent {
constructor (public hostApp: HostAppService) { }
}

View File

@@ -16,55 +16,8 @@
padding-left: 10px; padding-left: 10px;
margin-left: -10px; margin-left: -10px;
&:focus {
background: rgba(255,255,255,.05);
border-radius: 5px;
}
&[disabled] { &[disabled] {
opacity: 0.5; opacity: 0.5;
} }
.body {
$border-width: 2px;
border-radius: 5px;
border: $border-width solid rgba(255, 255, 255, .2);
padding: $padding;
height: $toggle-size + $border-width * 2 + $padding * 2;
width: $toggle-size * 2 + $border-width * 2 + $padding * 2;
position: relative;
.toggle {
position: absolute;
border-radius: 2px;
width: $toggle-size;
height: $toggle-size;
background: #475158;
top: $padding;
left: $padding;
transition: 0.25s left;
line-height: 19px;
text-align: center;
font-size: 10px;
i {
opacity: 0;
transition: 0.25s opacity;
}
}
}
&.active .body .toggle {
left: $toggle-size + $padding;
i {
color: white;
opacity: 1;
}
}
&:active {
background: rgba(255,255,255,.1);
}
} }

View File

@@ -6,15 +6,12 @@ import { CheckboxComponent } from './checkbox.component'
@Component({ @Component({
selector: 'toggle', selector: 'toggle',
template: ` template: `
<div class="switch"> <div class="custom-control custom-switch">
<div class="body"> <input type="checkbox" class="custom-control-input" [(ngModel)]='model'>
<div class="toggle" [class.bg-primary]='model'> <label class="custom-control-label"></label>
<i class="fa fa-check"></i>
</div>
</div>
</div> </div>
`, `,
styles: [require('./toggle.component.scss')], styleUrls: ['./toggle.component.scss'],
providers: [ providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: ToggleComponent, multi: true }, { provide: NG_VALUE_ACCESSOR, useExisting: ToggleComponent, multi: true },
], ],

View File

@@ -6,8 +6,8 @@ import { AppService } from '../services/app.service'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'welcome-page', selector: 'welcome-page',
template: require('./welcomeTab.component.pug'), templateUrl: './welcomeTab.component.pug',
styles: [require('./welcomeTab.component.scss')], styleUrls: ['./welcomeTab.component.scss'],
}) })
export class WelcomeTabComponent extends BaseTabComponent { export class WelcomeTabComponent extends BaseTabComponent {
constructor ( constructor (

View File

@@ -5,8 +5,8 @@ import { AppService } from '../services/app.service'
/** @hidden */ /** @hidden */
@Component({ @Component({
selector: 'window-controls', selector: 'window-controls',
template: require('./windowControls.component.pug'), templateUrl: './windowControls.component.pug',
styles: [require('./windowControls.component.scss')], styleUrls: ['./windowControls.component.scss'],
}) })
export class WindowControlsComponent { export class WindowControlsComponent {
constructor (public hostApp: HostAppService, public app: AppService) { } constructor (public hostApp: HostAppService, public app: AppService) { }

View File

@@ -1,10 +1,11 @@
import { NgModule, ModuleWithProviders } from '@angular/core' import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar' import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar'
import { DndModule } from 'ng2-dnd' // import { DndModule } from 'ng2-dnd'
import { AppRootComponent } from './components/appRoot.component' import { AppRootComponent } from './components/appRoot.component'
import { CheckboxComponent } from './components/checkbox.component' import { CheckboxComponent } from './components/checkbox.component'
@@ -25,7 +26,7 @@ import { AutofocusDirective } from './directives/autofocus.directive'
import { HotkeyProvider } from './api/hotkeyProvider' import { HotkeyProvider } from './api/hotkeyProvider'
import { ConfigProvider } from './api/configProvider' import { ConfigProvider } from './api/configProvider'
import { Theme } from './api/theme' import { Theme } from './api/theme'
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider' // import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
import { TabRecoveryProvider } from './api/tabRecovery' import { TabRecoveryProvider } from './api/tabRecovery'
import { AppService } from './services/app.service' import { AppService } from './services/app.service'
@@ -34,7 +35,7 @@ import { ConfigService } from './services/config.service'
import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme' import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
import { CoreConfigProvider } from './config' import { CoreConfigProvider } from './config'
import { AppHotkeyProvider } from './hotkeys' import { AppHotkeyProvider } from './hotkeys'
import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu' // import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu'
import 'perfect-scrollbar/css/perfect-scrollbar.css' import 'perfect-scrollbar/css/perfect-scrollbar.css'
import 'ng2-dnd/bundles/style.css' import 'ng2-dnd/bundles/style.css'
@@ -51,9 +52,9 @@ const PROVIDERS = [
{ provide: Theme, useClass: StandardCompactTheme, multi: true }, { provide: Theme, useClass: StandardCompactTheme, multi: true },
{ provide: Theme, useClass: PaperTheme, multi: true }, { provide: Theme, useClass: PaperTheme, multi: true },
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true }, { provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true }, // { provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: CloseContextMenu, multi: true }, // { provide: TabContextMenuItemProvider, useClass: CloseContextMenu, multi: true },
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true }, // { provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
{ provide: TabRecoveryProvider, useClass: SplitTabRecoveryProvider, multi: true }, { provide: TabRecoveryProvider, useClass: SplitTabRecoveryProvider, multi: true },
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } }, { provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } },
] ]
@@ -64,10 +65,11 @@ const PROVIDERS = [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
FormsModule, FormsModule,
NgbModule.forRoot(), NgbModule,
PerfectScrollbarModule, PerfectScrollbarModule,
DndModule.forRoot(), // DndModule,
], ],
providers: PROVIDERS,
declarations: [ declarations: [
AppRootComponent as any, AppRootComponent as any,
CheckboxComponent, CheckboxComponent,
@@ -96,7 +98,7 @@ const PROVIDERS = [
AutofocusDirective, AutofocusDirective,
], ],
}) })
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class export class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
constructor (app: AppService, config: ConfigService) { constructor (app: AppService, config: ConfigService) {
app.ready$.subscribe(() => { app.ready$.subscribe(() => {
if (config.store.enableWelcomeTab) { if (config.store.enableWelcomeTab) {
@@ -104,18 +106,17 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
} }
}) })
} }
static forRoot (): ModuleWithProviders {
return {
ngModule: AppModule,
providers: PROVIDERS,
}
}
} }
export default AppModule
export { AppRootComponent as bootstrap } export { AppRootComponent as bootstrap }
export * from './api' export * from './api'
// Deprecations // Deprecations
export { ToolbarButton as IToolbarButton } from './api' export { ToolbarButton as IToolbarButton } from './api'
export { HotkeyDescription as IHotkeyDescription } from './api' export { HotkeyDescription as IHotkeyDescription } from './api'
export function fakeBootstrap () {
return platformBrowserDynamic().bootstrapModule(AppModule)
}

View File

@@ -5,7 +5,7 @@ import { TabHeaderComponent } from './components/tabHeader.component'
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider' import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
/** @hidden */ /** @hidden */
@Injectable() @Injectable({ providedIn: 'root' })
export class CloseContextMenu extends TabContextMenuItemProvider { export class CloseContextMenu extends TabContextMenuItemProvider {
weight = -5 weight = -5
@@ -63,7 +63,7 @@ const COLORS = [
] ]
/** @hidden */ /** @hidden */
@Injectable() @Injectable({ providedIn: 'root' })
export class CommonOptionsContextMenu extends TabContextMenuItemProvider { export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
weight = -1 weight = -1
@@ -78,7 +78,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
return [ return [
{ {
label: 'Rename', label: 'Rename',
click: () => this.zone.run(() => tabHeader && tabHeader.showRenameTabModal()), click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
}, },
{ {
label: 'Duplicate', label: 'Duplicate',
@@ -101,7 +101,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
} }
/** @hidden */ /** @hidden */
@Injectable() @Injectable({ providedIn: 'root' })
export class TaskCompletionContextMenu extends TabContextMenuItemProvider { export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
constructor ( constructor (
private app: AppService, private app: AppService,

View File

@@ -1,103 +1,11 @@
$tab-border-radius: 5px; @import "./theme.vars";
// ---------
$button-hover-bg: rgba(0, 0, 0, .25); $button-hover-bg: rgba(0, 0, 0, .25);
$button-active-bg: rgba(0, 0, 0, .5); $button-active-bg: rgba(0, 0, 0, .5);
$white: #fff !default;
$black: #000 !default;
$red: #d9534f !default;
$orange: #f0ad4e !default;
$yellow: #ffd500 !default;
$green: #5cb85c !default;
$blue: #0275d8 !default;
$teal: #5bc0de !default;
$pink: #ff5b77 !default;
$purple: #613d7c !default;
$theme-colors: (
"primary": $blue,
"secondary": #394b5d
);
$content-bg: rgba(39, 49, 60, 0.65); //#1D272D;
$content-bg-solid: #1D272D;
$body-bg: #131d27;
$body-bg2: #20333e;
$body-color: #ccc;
$font-family-sans-serif: "Source Sans Pro";
$font-family-monospace: "Source Code Pro";
$font-size-base: 14rem / 16;
$btn-border-radius: 0;
$btn-secondary-color: #ccc;
$btn-secondary-bg: #222;
$btn-secondary-border: #444;
//$btn-warning-bg: rgba($orange, .5);
$nav-tabs-border-width: 0;
$nav-tabs-border-radius: 0;
$nav-tabs-link-hover-border-color: $body-bg;
$nav-tabs-active-link-hover-color: $white;
$nav-tabs-active-link-hover-bg: $blue;
$nav-tabs-active-link-hover-border-color: darken($blue, 30%);
$nav-pills-border-radius: 0;
$input-bg: #111;
$input-disabled-bg: #333;
$input-color: $body-color;
$input-color-placeholder: #333;
$input-border-color: #344;
$input-border-width: 1px;
//$input-box-shadow: inset 0 1px 1px rgba($black,.075);
$input-border-radius: 0;
$custom-select-border-radius: 0;
$input-bg-focus: $input-bg;
$input-border-focus: lighten($blue, 25%);
$input-focus-box-shadow: none;
$input-color-focus: $input-color;
$input-group-addon-bg: $body-bg;
$input-group-addon-border-color: $input-border-color;
$modal-content-bg: $content-bg-solid;
$modal-content-border-color: $body-bg;
$modal-header-border-color: transparent;
$modal-footer-border-color: transparent;
$popover-bg: $body-bg;
$dropdown-bg: $body-bg;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: white;
$dropdown-link-hover-bg: $body-bg2;
//$dropdown-link-active-color: $component-active-color;
//$dropdown-link-active-bg: $component-active-bg;
$dropdown-link-disabled-color: #333;
$dropdown-header-color: #333;
$list-group-color: $body-color;
$list-group-bg: rgba(255,255,255,.05);
$list-group-border-color: rgba(255,255,255,.1);
$list-group-hover-bg: rgba(255,255,255,.1);
$list-group-link-active-bg: rgba(255,255,255,.2);
$list-group-action-color: $body-color;
$list-group-action-bg: rgba(255,255,255,.05);
$list-group-action-active-bg: $list-group-link-active-bg;
$pre-bg: $dropdown-bg;
$pre-color: $dropdown-link-color;
$alert-danger-bg: $body-bg;
$alert-danger-text: $red;
$alert-danger-border: $red;
$headings-font-weight: lighter;
$headings-color: #eee;
@import '~bootstrap/scss/bootstrap.scss'; @import '~bootstrap/scss/bootstrap.scss';
window-controls { window-controls {
@@ -236,6 +144,7 @@ settings-tab > ngb-tabset {
border: none; border: none;
padding: 10px 50px 10px 20px; padding: 10px 50px 10px 20px;
font-size: 14px; font-size: 14px;
border-radius: 0;
&:not(.active) { &:not(.active) {
color: $body-color; color: $body-color;
@@ -310,14 +219,6 @@ hotkey-input-modal {
margin-bottom: 2px; margin-bottom: 2px;
} }
.nav-tabs {
background: $btn-secondary-bg;
.nav-link {
transition: 0.25s all;
border-bottom-color: $nav-tabs-border-color;
}
}
ngb-tabset .tab-content { ngb-tabset .tab-content {
padding-top: 20px; padding-top: 20px;
} }
@@ -361,22 +262,10 @@ ngb-tabset .tab-content {
} }
} }
select.form-control {
-webkit-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='#444' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
background-position: 100% 50%;
background-repeat: no-repeat;
padding-right: 30px;
}
checkbox i.on { checkbox i.on {
color: $blue; color: $blue;
} }
toggle.active .body .toggle {
background: $blue;
}
.modal .modal-footer { .modal .modal-footer {
background: rgba(0, 0, 0, .25); background: rgba(0, 0, 0, .25);
@@ -405,3 +294,101 @@ toggle.active .body .toggle {
*::-webkit-resizer { *::-webkit-resizer {
opacity: 0; opacity: 0;
} }
search-panel {
background: rgba(39, 49, 60, 0.65) !important;
}
.btn {
cursor: pointer;
justify-content: flex-start;
overflow: hidden;
&.disabled,
&:disabled {
cursor: not-allowed;
}
}
.btn.btn-outline-secondary {
@include button-outline-variant(#9badb9, #fff);
&:hover:not([disabled]), &:active:not([disabled]), &.active:not([disabled]) {
background-color: #3f484e;
border-color: darken(#9badb9, 25%);
}
border-color: darken(#9badb9, 25%);
&.disabled,
&:disabled {
color: #9badb9;
}
}
.btn-warning:not(:disabled):not(.disabled) {
&.active, &:active {
color: $gray-900;
}
}
.btn-secondary:not(:disabled):not(.disabled) {
&.active, &:active {
background: #191e23;
}
}
.btn-link {
&:hover, &[aria-expanded=true], &:active, &.active {
color: $link-hover-color;
border-radius: $btn-border-radius;
}
&[aria-expanded=true], &:active, &.active {
background: rgba(255, 255, 255, 0.1);
}
}
.btn-group .btn.active {
border-color: transparent !important;
}
.nav-tabs {
margin-bottom: 10px;
&.nav-justified .nav-link {
margin-right: 5px;
}
.nav-link {
border: none;
border-bottom: $nav-tabs-border-width solid transparent;
text-transform: uppercase;
font-weight: bold;
padding: 5px 0;
margin-right: 20px;
uib-tab-heading > i {
font-size: 18px;
}
@include hover-focus {
color: $nav-tabs-link-active-color;
}
&.disabled {
color: $nav-link-disabled-color;
border-color: transparent;
}
}
.nav-item:last-child .nav-link {
margin-right: 0;
}
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-tabs-link-active-color;
border-color: $nav-tabs-link-active-border-color;
}
}

View File

@@ -0,0 +1,187 @@
$white: #fff;
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
$gray-400: #ced4da;
$gray-500: #adb5bd;
$gray-600: #6c757d;
$gray-700: #495057;
$gray-800: #343a40;
$gray-900: #212529;
$black: #000;
$red: #d9534f !default;
$orange: #f0ad4e !default;
$yellow: #ffd500 !default;
$green: #5cb85c !default;
$blue: #0275d8 !default;
$teal: #5bc0de !default;
$pink: #ff5b77 !default;
$purple: #613d7c !default;
@import "~bootstrap/scss/functions";
$content-bg: rgba(39, 49, 60, 0.65); //#1D272D;
$content-bg-solid: #1D272D;
$table-bg: rgba(255,255,255,.05);
$table-bg-hover: rgba(255,255,255,.1);
$table-border-color: rgba(255,255,255,.1);
$theme-colors: (
primary: $blue,
secondary: #38434e,
success: $green,
info: $blue,
warning: $orange,
danger: $red,
light: $gray-300,
dark: $gray-800,
rare: $purple
);
$body-color: #ccc;
$body-bg: #131d27;
$body-bg2: #20333e;
$font-family-sans-serif: "Source Sans Pro";
$font-family-monospace: "Source Code Pro";
$font-size-base: 14rem / 16;
$font-size-lg: 1.28rem;
$font-size-sm: .85rem;
$line-height-base: 1.6;
$headings-color: #ced9e2;
$headings-font-weight: lighter;
$input-btn-padding-y: .3rem;
$input-btn-padding-x: .9rem;
$input-btn-line-height: 1.6;
$input-btn-line-height-sm: 1.8;
$input-btn-line-height-lg: 1.8;
$btn-link-disabled-color: $gray-600;
$btn-focus-box-shadow: none;
$h4-font-size: 18px;
$link-color: $gray-400;
$link-hover-color: $white;
$link-hover-decoration: none;
$component-active-color: $white;
$component-active-bg: #2f3a42;
$list-group-bg: $table-bg;
$list-group-border-color: $table-border-color;
$list-group-item-padding-y: 0.8rem;
$list-group-item-padding-x: 1rem;
$list-group-hover-bg: $table-bg-hover;
$list-group-active-bg: rgba(255,255,255,.2);
$list-group-active-color: $component-active-color;
$list-group-active-border-color: translate;
$list-group-action-color: $body-color;
$list-group-action-hover-color: white;
$list-group-action-active-color: $component-active-color;
$list-group-action-active-bg: $list-group-active-bg;
$alert-padding-y: 0.9rem;
$alert-padding-x: 1.25rem;
$input-box-shadow: none;
$transition-base: all .15s ease-in-out;
$transition-fade: opacity .1s linear;
$transition-collapse: height .35s ease;
$btn-transition: all .15s ease-in-out;
$popover-bg: $body-bg;
$popover-body-color: $body-color;
$popover-header-bg: $table-bg-hover;
$popover-header-color: $headings-color;
$popover-arrow-color: $popover-bg;
$popover-max-width: 360px;
$btn-border-width: 2px;
$input-bg: #181e23;
$input-disabled-bg: #2e3235;
$input-color: #ddd;
$input-border-color: $input-bg;
$input-border-width: 2px;
$input-focus-bg: $input-bg;
$input-focus-border-color: rgba(171, 171, 171, 0.61);
$input-focus-color: $input-color;
$input-btn-focus-color: var(--focus-color);
$input-btn-focus-box-shadow: 0 0 0 2px $input-btn-focus-color;
$input-group-addon-color: $input-color;
$input-group-addon-bg: $input-bg;
$input-group-addon-border-color: transparent;
$input-group-btn-border-color: $input-bg;
$nav-tabs-border-radius: 0;
$nav-tabs-border-color: transparent;
$nav-tabs-border-width: 2px;
$nav-tabs-link-hover-border-color: transparent;
$nav-tabs-link-active-color: #eee;
$nav-tabs-link-active-bg: transparent;
$nav-tabs-link-active-border-color: #eee;
$navbar-padding-y: 0;
$navbar-padding-x: 0;
$dropdown-bg: $table-bg;
$dropdown-color: $body-color;
$dropdown-border-width: 1px;
$dropdown-box-shadow: 0 .5rem 1rem rgba($black,.175);
$dropdown-header-color: $gray-500;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: #eee;
$dropdown-link-hover-bg: rgba(255,255,255,.04);
$dropdown-link-active-color: white;
$dropdown-link-active-bg: rgba(0, 0, 0, .2);
$dropdown-item-padding-y: 0.5rem;
$dropdown-item-padding-x: 1.5rem;
$code-color: $orange;
$code-bg: rgba(0, 0, 0, .25);
$code-padding-y: 3px;
$code-padding-x: 5px;
$pre-bg: $dropdown-bg;
$pre-color: $dropdown-link-color;
$badge-font-size: 0.75rem;
$badge-font-weight: bold;
$badge-padding-y: 4px;
$badge-padding-x: 6px;
$custom-control-indicator-size: 1.2rem;
$custom-control-indicator-bg: $body-bg;
$custom-control-indicator-border-color: lighten($body-bg, 25%);
$custom-control-indicator-checked-bg: theme-color("primary");
$custom-control-indicator-checked-color: $body-bg;
$custom-control-indicator-checked-border-color: transparent;
$custom-control-indicator-active-bg: rgba(255, 255, 0, 0.5);
$modal-content-bg: $content-bg-solid;
$modal-content-border-color: $body-bg;
$modal-header-border-width: 0;
$modal-footer-border-color: #222;
$modal-footer-border-width: 1px;
$modal-content-border-width: 0;

View File

@@ -2,6 +2,9 @@
"extends": "../tsconfig.json", "extends": "../tsconfig.json",
"exclude": ["node_modules", "dist"], "exclude": ["node_modules", "dist"],
"compilerOptions": { "compilerOptions": {
"baseUrl": "src" "baseUrl": "src",
"paths": {
"*": ["../../app/node_modules/*"]
}
} }
} }

View File

@@ -1,10 +1,11 @@
const path = require('path') const path = require('path')
const { AngularCompilerPlugin } = require('@ngtools/webpack')
module.exports = { module.exports = {
target: 'node', target: 'node',
entry: 'src/index.ts', entry: 'src/index.ts',
context: __dirname, context: __dirname,
devtool: 'eval-cheap-module-source-map', devtool: 'cheap-module-source-map',
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
filename: 'index.js', filename: 'index.js',
@@ -23,22 +24,26 @@ module.exports = {
module: { module: {
rules: [ rules: [
{ {
test: /\.ts$/, test: /(?:\.ngfactory\.js|\.ngfactory|\.ngstyle\.js|\.ts)$/,
use: { loader: '@ngtools/webpack',
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.json'),
typeRoots: [
path.resolve(__dirname, 'node_modules/@types'),
path.resolve(__dirname, '../node_modules/@types'),
],
paths: {
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
"*": [path.resolve(__dirname, '../app/node_modules/*')],
},
},
},
}, },
// {
// test: /\.ts$/,
// use: {
// loader: 'awesome-typescript-loader',
// options: {
// configFileName: path.resolve(__dirname, 'tsconfig.json'),
// typeRoots: [
// path.resolve(__dirname, 'node_modules/@types'),
// path.resolve(__dirname, '../node_modules/@types'),
// ],
// paths: {
// "terminus-*": [path.resolve(__dirname, '../terminus-*')],
// "*": [path.resolve(__dirname, '../app/node_modules/*')],
// },
// },
// },
// },
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] }, { test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] }, { test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['to-string-loader', 'css-loader'], include: /component\.css/ }, { test: /\.css$/, use: ['to-string-loader', 'css-loader'], include: /component\.css/ },
@@ -57,4 +62,12 @@ module.exports = {
/^@angular/, /^@angular/,
/^@ng-bootstrap/, /^@ng-bootstrap/,
], ],
plugins: [
new AngularCompilerPlugin({
tsConfigPath: path.resolve(__dirname, 'tsconfig.json'),
entryModule: './terminus-core/src/index#AppModule',
sourceMap: true,
directTemplateLoading: true,
}),
],
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-plugin-manager", "name": "terminus-plugin-manager",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "Terminus' plugin manager", "description": "Terminus' plugin manager",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"

View File

@@ -5,7 +5,7 @@
.d-flex .d-flex
h3.mb-1 Installed h3.mb-1 Installed
button.btn.btn-outline-info.btn-sm.ml-auto((click)='openPluginsFolder()') button.btn.btn-outline-secondary.btn-sm.ml-auto((click)='openPluginsFolder()')
i.fas.fa-folder i.fas.fa-folder
span Plugins folder span Plugins folder
@@ -28,19 +28,19 @@
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing') i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
span Upgrade ({{knownUpgrades[plugin.name].version}}) span Upgrade ({{knownUpgrades[plugin.name].version}})
button.btn.btn-primary.ml-2( button.btn.btn-link.text-primary.ml-2(
*ngIf='config.store.pluginBlacklist.includes(plugin.name)', *ngIf='config.store.pluginBlacklist.includes(plugin.name)',
(click)='enablePlugin(plugin)' (click)='enablePlugin(plugin)'
) )
i.fas.fa-fw.fa-play i.fas.fa-fw.fa-play
button.btn.btn-secondary.ml-2( button.btn.btn-link.ml-2(
*ngIf='!config.store.pluginBlacklist.includes(plugin.name)', *ngIf='!config.store.pluginBlacklist.includes(plugin.name)',
(click)='disablePlugin(plugin)' (click)='disablePlugin(plugin)'
) )
i.fas.fa-fw.fa-pause i.fas.fa-fw.fa-pause
button.btn.btn-danger.ml-2( button.btn.btn-link.text-danger.ml-2(
(click)='uninstallPlugin(plugin)', (click)='uninstallPlugin(plugin)',
*ngIf='!plugin.isBuiltin', *ngIf='!plugin.isBuiltin',
[disabled]='busy[plugin.name] != undefined' [disabled]='busy[plugin.name] != undefined'

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-settings", "name": "terminus-settings",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "Terminus terminal settings page", "description": "Terminus terminal settings page",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-ssh", "name": "terminus-ssh",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "SSH connection manager for Terminus", "description": "SSH connection manager for Terminus",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
@@ -20,7 +20,8 @@
"@types/node": "12.7.3", "@types/node": "12.7.3",
"@types/ssh2": "^0.5.35", "@types/ssh2": "^0.5.35",
"ssh2": "^0.8.2", "ssh2": "^0.8.2",
"ssh2-streams": "^0.4.2" "ssh2-streams": "^0.4.2",
"terminus-terminal": "^1.0.98-nightly.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/common": "^7", "@angular/common": "^7",

View File

@@ -1,4 +1,8 @@
import { BaseSession } from 'terminus-terminal' import { BaseSession } from 'terminus-terminal'
import { Server, Socket, createServer, createConnection } from 'net'
import { Client, ClientChannel } from 'ssh2'
import { Logger } from 'terminus-core'
import { Subject, Observable } from 'rxjs'
export interface LoginScript { export interface LoginScript {
expect: string expect: string
@@ -21,7 +25,7 @@ export interface SSHConnection {
user: string user: string
password?: string password?: string
privateKey?: string privateKey?: string
group?: string group: string | null
scripts?: LoginScript[] scripts?: LoginScript[]
keepaliveInterval?: number keepaliveInterval?: number
keepaliveCountMax?: number keepaliveCountMax?: number
@@ -30,18 +34,82 @@ export interface SSHConnection {
algorithms?: {[t: string]: string[]} algorithms?: {[t: string]: string[]}
} }
export enum PortForwardType {
Local, Remote
}
export class ForwardedPort {
type: PortForwardType
host = '127.0.0.1'
port: number
targetAddress: string
targetPort: number
private listener: Server
async startLocalListener (callback: (Socket) => void): Promise<void> {
this.listener = createServer(callback)
return new Promise((resolve, reject) => {
this.listener.listen(this.port, '127.0.0.1')
this.listener.on('error', reject)
this.listener.on('listening', resolve)
})
}
stopLocalListener () {
this.listener.close()
}
toString () {
if (this.type === PortForwardType.Local) {
return `(local) ${this.host}:${this.port} → (remote) ${this.targetAddress}:${this.targetPort}`
} else {
return `(remote) ${this.host}:${this.port} → (local) ${this.targetAddress}:${this.targetPort}`
}
}
}
export class SSHSession extends BaseSession { export class SSHSession extends BaseSession {
scripts?: LoginScript[] scripts?: LoginScript[]
shell: any shell: ClientChannel
ssh: Client
forwardedPorts: ForwardedPort[] = []
logger: Logger
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
private serviceMessage = new Subject<string>()
constructor (public connection: SSHConnection) { constructor (public connection: SSHConnection) {
super() super()
this.scripts = connection.scripts || [] this.scripts = connection.scripts || []
} }
start () { async start () {
this.open = true this.open = true
try {
try {
this.shell = await this.openShellChannel({ x11: true })
} catch (e) {
if (e.toString().includes('Unable to request X11')) {
this.logger.debug('X11 forwarding rejected, trying without')
this.shell = await this.openShellChannel({})
} else {
throw e
}
}
} catch (err) {
this.emitServiceMessage(`Remote rejected opening a shell channel: ${err}`)
}
this.shell.on('greeting', greeting => {
this.emitServiceMessage(`Shell greeting: ${greeting}`)
})
this.shell.on('banner', banner => {
this.emitServiceMessage(`Shell banner: ${banner}`)
})
this.shell.on('data', data => { this.shell.on('data', data => {
const dataString = data.toString() const dataString = data.toString()
this.emitOutput(dataString) this.emitOutput(dataString)
@@ -67,12 +135,12 @@ export class SSHSession extends BaseSession {
} }
if (match) { if (match) {
console.log('Executing script: "' + cmd + '"') this.logger.info('Executing script: "' + cmd + '"')
this.shell.write(cmd + '\n') this.shell.write(cmd + '\n')
this.scripts = this.scripts.filter(x => x !== script) this.scripts = this.scripts.filter(x => x !== script)
} else { } else {
if (script.optional) { if (script.optional) {
console.log('Skip optional script: ' + script.expect) this.logger.debug('Skip optional script: ' + script.expect)
found = true found = true
this.scripts = this.scripts.filter(x => x !== script) this.scripts = this.scripts.filter(x => x !== script)
} else { } else {
@@ -88,17 +156,140 @@ export class SSHSession extends BaseSession {
}) })
this.shell.on('end', () => { this.shell.on('end', () => {
this.logger.info('Shell session ended')
if (this.open) { if (this.open) {
this.destroy() this.destroy()
} }
}) })
this.ssh.on('tcp connection', (details, accept, reject) => {
this.logger.info(`Incoming forwarded connection: (remote) ${details.srcIP}:${details.srcPort} -> (local) ${details.destIP}:${details.destPort}`)
const forward = this.forwardedPorts.find(x => x.port === details.destPort)
if (!forward) {
this.emitServiceMessage(`Rejected incoming forwarded connection for unrecognized port ${details.destPort}`)
return reject()
}
const socket = new Socket()
socket.connect(forward.targetPort, forward.targetAddress)
socket.on('error', e => {
this.emitServiceMessage(`Could not forward the remote connection to ${forward.targetAddress}:${forward.targetPort}: ${e}`)
reject()
})
socket.on('connect', () => {
this.logger.info('Connection forwarded')
const stream = accept()
stream.pipe(socket)
socket.pipe(stream)
stream.on('close', () => {
socket.destroy()
})
socket.on('close', () => {
stream.close()
})
})
})
this.ssh.on('x11', (details, accept, reject) => {
this.logger.info(`Incoming X11 connection from ${details.srcIP}:${details.srcPort}`)
let displaySpec = process.env.DISPLAY || ':0'
this.logger.debug(`Trying display ${displaySpec}`)
let xHost = displaySpec.split(':')[0]
let xDisplay = parseInt(displaySpec.split(':')[1].split('.')[0] || '0')
let xPort = xDisplay < 100 ? xDisplay + 6000 : xDisplay
const socket = displaySpec.startsWith('/') ? createConnection(displaySpec) : new Socket()
if (!displaySpec.startsWith('/')) {
socket.connect(xPort, xHost)
}
socket.on('error', e => {
this.emitServiceMessage(`Could not connect to the X server ${xHost}:${xPort}: ${e}`)
reject()
})
socket.on('connect', () => {
this.logger.info('Connection forwarded')
const stream = accept()
stream.pipe(socket)
socket.pipe(stream)
stream.on('close', () => {
socket.destroy()
})
socket.on('close', () => {
stream.close()
})
})
})
this.executeUnconditionalScripts() this.executeUnconditionalScripts()
} }
emitServiceMessage (msg: string) {
this.serviceMessage.next(msg)
this.logger.info(msg)
}
async addPortForward (fw: ForwardedPort) {
if (fw.type === PortForwardType.Local) {
await fw.startLocalListener((socket: Socket) => {
this.logger.info(`New connection on ${fw}`)
this.ssh.forwardOut(
socket.remoteAddress || '127.0.0.1',
socket.remotePort || 0,
fw.targetAddress,
fw.targetPort,
(err, stream) => {
if (err) {
this.emitServiceMessage(`Remote has rejected the forwaded connection via ${fw}: ${err}`)
socket.destroy()
return
}
stream.pipe(socket)
socket.pipe(stream)
stream.on('close', () => {
socket.destroy()
})
socket.on('close', () => {
stream.close()
})
}
)
}).then(() => {
this.emitServiceMessage(`Forwaded ${fw}`)
this.forwardedPorts.push(fw)
}).catch(e => {
this.emitServiceMessage(`Failed to forward port ${fw}: ${e}`)
throw e
})
}
if (fw.type === PortForwardType.Remote) {
await new Promise((resolve, reject) => {
this.ssh.forwardIn(fw.host, fw.port, err => {
if (err) {
this.emitServiceMessage(`Remote rejected port forwarding for ${fw}: ${err}`)
return reject(err)
}
resolve()
})
})
this.emitServiceMessage(`Forwaded ${fw}`)
this.forwardedPorts.push(fw)
}
}
async removePortForward (fw: ForwardedPort) {
if (fw.type === PortForwardType.Local) {
fw.stopLocalListener()
this.forwardedPorts = this.forwardedPorts.filter(x => x !== fw)
}
if (fw.type === PortForwardType.Remote) {
this.ssh.unforwardIn(fw.host, fw.port)
this.forwardedPorts = this.forwardedPorts.filter(x => x !== fw)
}
this.emitServiceMessage(`Stopped forwarding ${fw}`)
}
resize (columns, rows) { resize (columns, rows) {
if (this.shell) { if (this.shell) {
this.shell.setWindow(rows, columns) this.shell.setWindow(rows, columns, rows, columns)
} }
} }
@@ -114,6 +305,11 @@ export class SSHSession extends BaseSession {
} }
} }
async destroy (): Promise<void> {
this.serviceMessage.complete()
await super.destroy()
}
async getChildProcesses (): Promise<any[]> { async getChildProcesses (): Promise<any[]> {
return [] return []
} }
@@ -126,6 +322,18 @@ export class SSHSession extends BaseSession {
return null return null
} }
private openShellChannel (options): Promise<ClientChannel> {
return new Promise<ClientChannel>((resolve, reject) => {
this.ssh.shell({ term: 'xterm-256color' }, options, (err, shell) => {
if (err) {
reject(err)
} else {
resolve(shell)
}
})
})
}
private executeUnconditionalScripts () { private executeUnconditionalScripts () {
if (this.scripts) { if (this.scripts) {
for (const script of this.scripts) { for (const script of this.scripts) {

View File

@@ -1,5 +1,5 @@
.modal-body .modal-body
ngb-tabset(type='pills', [activeId]='basic') ngb-tabset([activeId]='basic')
ngb-tab(id='basic') ngb-tab(id='basic')
ng-template(ngbTabTitle) General ng-template(ngbTabTitle) General
ng-template(ngbTabContent) ng-template(ngbTabContent)
@@ -63,7 +63,7 @@
placeholder='Key file path', placeholder='Key file path',
[(ngModel)]='connection.privateKey' [(ngModel)]='connection.privateKey'
) )
.input-group-btn .input-group-append
button.btn.btn-secondary((click)='selectPrivateKey()') button.btn.btn-secondary((click)='selectPrivateKey()')
i.fas.fa-folder-open i.fas.fa-folder-open

View File

@@ -66,7 +66,7 @@ export class EditConnectionModalComponent {
modal.componentInstance.password = true modal.componentInstance.password = true
try { try {
const result = await modal.result const result = await modal.result
if (result && result.value) { if (result?.value) {
this.passwordStorage.savePassword(this.connection, result.value) this.passwordStorage.savePassword(this.connection, result.value)
this.hasSavedPassword = true this.hasSavedPassword = true
} }

View File

@@ -6,6 +6,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
template: require('./promptModal.component.pug'), template: require('./promptModal.component.pug'),
}) })
export class PromptModalComponent { export class PromptModalComponent {
@Input() prompt: string
@Input() value: string @Input() value: string
@Input() password: boolean @Input() password: boolean
@Input() remember: boolean @Input() remember: boolean

View File

@@ -49,6 +49,7 @@ export class SSHModalComponent {
const connection: SSHConnection = { const connection: SSHConnection = {
name: this.quickTarget, name: this.quickTarget,
group: null,
host, host,
user, user,
port, port,
@@ -91,7 +92,7 @@ export class SSHModalComponent {
} }
for (const connection of connections) { for (const connection of connections) {
connection.group = connection.group || undefined connection.group = connection.group || null
let group = this.childGroups.find(x => x.name === connection.group) let group = this.childGroups.find(x => x.name === connection.group)
if (!group) { if (!group) {
group = { group = {

View File

@@ -0,0 +1,48 @@
.modal-header
h5.m-0 Port forwarding
.modal-body.pt-0
.list-group-light.mb-3
.list-group-item.d-flex.align-items-center(*ngFor='let fw of session.forwardedPorts')
strong(*ngIf='fw.type === PortForwardType.Local') Local
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
.ml-3 {{fw.host}}:{{fw.port}} &rarr; {{fw.targetAddress}}:{{fw.targetPort}}
button.btn.btn-link.ml-auto((click)='remove(fw)')
i.fas.fa-trash-alt.mr-2
span Remove
.input-group.mb-2
input.form-control(type='text', [(ngModel)]='newForward.host')
.input-group-append
.input-group-text :
input.form-control(type='number', [(ngModel)]='newForward.port')
.input-group-append
.input-group-text &rarr;
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
.input-group-append
.input-group-text :
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
.d-flex
.btn-group.mr-auto(
[(ngModel)]='newForward.type',
ngbRadioGroup
)
label.btn.btn-secondary.m-0(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='PortForwardType.Local'
)
| Local
label.btn.btn-secondary.m-0(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='PortForwardType.Remote'
)
| Remote
button.btn.btn-primary((click)='addForward()')
i.fas.fa-check.mr-2
span Forward port

View File

@@ -0,0 +1,42 @@
import { Component, Input } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { ForwardedPort, PortForwardType, SSHSession } from '../api'
/** @hidden */
@Component({
template: require('./sshPortForwardingModal.component.pug'),
// styles: [require('./sshPortForwardingModal.component.scss')],
})
export class SSHPortForwardingModalComponent {
@Input() session: SSHSession
newForward = new ForwardedPort()
PortForwardType = PortForwardType
constructor (
public modalInstance: NgbActiveModal,
) {
this.reset()
}
reset () {
this.newForward = new ForwardedPort()
this.newForward.type = PortForwardType.Local
this.newForward.host = '127.0.0.1'
this.newForward.port = 8000
this.newForward.targetAddress = '127.0.0.1'
this.newForward.targetPort = 80
}
async addForward () {
try {
await this.session.addPortForward(this.newForward)
this.reset()
} catch (e) {
console.error(e)
}
}
remove (fw: ForwardedPort) {
this.session.removePortForward(fw)
}
}

View File

@@ -27,6 +27,7 @@ export class SSHSettingsTabComponent {
createConnection () { createConnection () {
const connection: SSHConnection = { const connection: SSHConnection = {
name: '', name: '',
group: null,
host: '', host: '',
port: 22, port: 22,
user: 'root', user: 'root',
@@ -97,7 +98,7 @@ export class SSHSettingsTabComponent {
} }
)).response === 1) { )).response === 1) {
for (const connection of this.connections.filter(x => x.group === group.name)) { for (const connection of this.connections.filter(x => x.group === group.name)) {
connection.group = undefined connection.group = null
} }
this.config.save() this.config.save()
this.refresh() this.refresh()
@@ -109,7 +110,7 @@ export class SSHSettingsTabComponent {
this.childGroups = [] this.childGroups = []
for (const connection of this.connections) { for (const connection of this.connections) {
connection.group = connection.group || undefined connection.group = connection.group || null
let group = this.childGroups.find(x => x.name === connection.group) let group = this.childGroups.find(x => x.name === connection.group)
if (!group) { if (!group) {
group = { group = {

View File

@@ -0,0 +1,3 @@
button.btn.btn-outline-secondary((click)='showPortForwarding()')
i.fas.fa-plug
span Ports

View File

@@ -3,6 +3,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
position: relative;
&> .content { &> .content {
flex: auto; flex: auto;
@@ -11,4 +12,11 @@
overflow: hidden; overflow: hidden;
margin: 15px; margin: 15px;
} }
&> button {
position: absolute;
bottom: 20px;
right: 40px;
z-index: 4;
}
} }

View File

@@ -1,12 +1,14 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { first } from 'rxjs/operators' import { first } from 'rxjs/operators'
import { BaseTerminalTabComponent } from 'terminus-terminal' import { BaseTerminalTabComponent } from 'terminus-terminal'
import { SSHService } from '../services/ssh.service' import { SSHService } from '../services/ssh.service'
import { SSHConnection, SSHSession } from '../api' import { SSHConnection, SSHSession } from '../api'
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
/** @hidden */ /** @hidden */
@Component({ @Component({
template: BaseTerminalTabComponent.template, template: BaseTerminalTabComponent.template + require<string>('./sshTab.component.pug'),
styles: [require('./sshTab.component.scss'), ...BaseTerminalTabComponent.styles], styles: [require('./sshTab.component.scss'), ...BaseTerminalTabComponent.styles],
animations: BaseTerminalTabComponent.animations, animations: BaseTerminalTabComponent.animations,
}) })
@@ -14,8 +16,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
connection: SSHConnection connection: SSHConnection
ssh: SSHService ssh: SSHService
session: SSHSession session: SSHSession
private ngbModal: NgbModal
ngOnInit () { ngOnInit () {
this.ngbModal = this.injector.get<NgbModal>(NgbModal)
this.logger = this.log.create('terminalTab') this.logger = this.log.create('terminalTab')
this.ssh = this.injector.get(SSHService) this.ssh = this.injector.get(SSHService)
this.frontendReady$.pipe(first()).subscribe(() => { this.frontendReady$.pipe(first()).subscribe(() => {
@@ -35,7 +40,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
return return
} }
this.session = new SSHSession(this.connection) this.session = this.ssh.createSession(this.connection)
this.session.serviceMessage$.subscribe(msg => {
this.write(`\r\n[SSH] ${msg}\r\n`)
this.session.resize(this.size.columns, this.size.rows)
})
this.attachSessionHandlers() this.attachSessionHandlers()
this.write(`Connecting to ${this.connection.host}`) this.write(`Connecting to ${this.connection.host}`)
const interval = setInterval(() => this.write('.'), 500) const interval = setInterval(() => this.write('.'), 500)
@@ -51,8 +60,8 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
clearInterval(interval) clearInterval(interval)
this.write('\r\n') this.write('\r\n')
} }
await this.session.start()
this.session.resize(this.size.columns, this.size.rows) this.session.resize(this.size.columns, this.size.rows)
this.session.start()
} }
async getRecoveryToken (): Promise<any> { async getRecoveryToken (): Promise<any> {
@@ -61,4 +70,9 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
connection: this.connection, connection: this.connection,
} }
} }
showPortForwarding () {
const modal = this.ngbModal.open(SSHPortForwardingModalComponent).componentInstance as SSHPortForwardingModalComponent
modal.session = this.session
}
} }

View File

@@ -9,6 +9,7 @@ import TerminusTerminalModule from 'terminus-terminal'
import { EditConnectionModalComponent } from './components/editConnectionModal.component' import { EditConnectionModalComponent } from './components/editConnectionModal.component'
import { SSHModalComponent } from './components/sshModal.component' import { SSHModalComponent } from './components/sshModal.component'
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
import { PromptModalComponent } from './components/promptModal.component' import { PromptModalComponent } from './components/promptModal.component'
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component' import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
import { SSHTabComponent } from './components/sshTab.component' import { SSHTabComponent } from './components/sshTab.component'
@@ -40,6 +41,7 @@ import { SSHHotkeyProvider } from './hotkeys'
EditConnectionModalComponent, EditConnectionModalComponent,
PromptModalComponent, PromptModalComponent,
SSHModalComponent, SSHModalComponent,
SSHPortForwardingModalComponent,
SSHSettingsTabComponent, SSHSettingsTabComponent,
SSHTabComponent, SSHTabComponent,
], ],
@@ -47,6 +49,7 @@ import { SSHHotkeyProvider } from './hotkeys'
EditConnectionModalComponent, EditConnectionModalComponent,
PromptModalComponent, PromptModalComponent,
SSHModalComponent, SSHModalComponent,
SSHPortForwardingModalComponent,
SSHSettingsTabComponent, SSHSettingsTabComponent,
SSHTabComponent, SSHTabComponent,
], ],

View File

@@ -20,7 +20,7 @@ export class SSHService {
private logger: Logger private logger: Logger
private constructor ( private constructor (
log: LogService, private log: LogService,
private app: AppService, private app: AppService,
private zone: NgZone, private zone: NgZone,
private ngbModal: NgbModal, private ngbModal: NgbModal,
@@ -38,6 +38,12 @@ export class SSHService {
) as SSHTabComponent) ) as SSHTabComponent)
} }
createSession (connection: SSHConnection): SSHSession {
const session = new SSHSession(connection)
session.logger = this.log.create(`ssh-${connection.host}-${connection.port}`)
return session
}
async connectSession (session: SSHSession, logCallback?: (s: any) => void): Promise<void> { async connectSession (session: SSHSession, logCallback?: (s: any) => void): Promise<void> {
let privateKey: string|null = null let privateKey: string|null = null
let privateKeyPassphrase: string|null = null let privateKeyPassphrase: string|null = null
@@ -91,6 +97,7 @@ export class SSHService {
} }
const ssh = new Client() const ssh = new Client()
session.ssh = ssh
let connected = false let connected = false
let savedPassword: string|null = null let savedPassword: string|null = null
await new Promise(async (resolve, reject) => { await new Promise(async (resolve, reject) => {
@@ -202,7 +209,7 @@ export class SSHService {
if (result.remember) { if (result.remember) {
savedPassword = result.value savedPassword = result.value
} }
return result.value return await result.value
} }
return '' return ''
} catch (_) { } catch (_) {
@@ -210,31 +217,6 @@ export class SSHService {
} }
}) })
}) })
try {
const shell: any = await new Promise<any>((resolve, reject) => {
ssh.shell({ term: 'xterm-256color' }, (err, shell) => {
if (err) {
reject(err)
} else {
resolve(shell)
}
})
})
session.shell = shell
shell.on('greeting', greeting => {
log(`Shell Greeting: ${greeting}`)
})
shell.on('banner', banner => {
log(`Shell Banner: ${banner}`)
})
} catch (error) {
this.toastr.error(error.message)
throw error
}
} }
} }

View File

@@ -46,27 +46,32 @@ safer-buffer@~2.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
ssh2-streams@^0.4.2, ssh2-streams@~0.4.7: ssh2-streams@^0.4.2, ssh2-streams@~0.4.8:
version "0.4.7" version "0.4.8"
resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.7.tgz#093b89069de9cf5f06feff0601a5301471b01611" resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.8.tgz#2ff92df2e0063fef86cf934eaea197967deda715"
integrity sha512-JhF8BNfeguOqVHOLhXjzLlRKlUP8roAEhiT/y+NcBQCqpRUupLNrRf2M+549OPNVGx21KgKktug4P3MY/IvTig== integrity sha512-auxXfgYySz2vYw7TMU7PK7vFI7EPvhvTH8/tZPgGaWocK4p/vwCMiV3icz9AEkb0R40kOKZtFtqYIxDJyJiytw==
dependencies: dependencies:
asn1 "~0.2.0" asn1 "~0.2.0"
bcrypt-pbkdf "^1.0.2" bcrypt-pbkdf "^1.0.2"
streamsearch "~0.1.2" streamsearch "~0.1.2"
ssh2@^0.8.2: ssh2@^0.8.2:
version "0.8.6" version "0.8.7"
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.6.tgz#dcc62e1d3b9e58a21f711f5186f043e4e792e6da" resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.7.tgz#2dc15206f493010b98027201cf399b90bab79c89"
integrity sha512-T0cPmEtmtC8WxSupicFDjx3vVUdNXO8xu2a/D5bjt8ixOUCe387AgvxU3mJgEHpu7+Sq1ZYx4d3P2pl/yxMH+w== integrity sha512-/u1BO12kb0lDVxJXejWB9pxyF3/ncgRqI9vPCZuPzo05pdNDzqUeQRavScwSPsfMGK+5H/VRqp1IierIx0Bcxw==
dependencies: dependencies:
ssh2-streams "~0.4.7" ssh2-streams "~0.4.8"
streamsearch@~0.1.2: streamsearch@~0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
terminus-terminal@^1.0.98-nightly.0:
version "1.0.98-nightly.0"
resolved "https://registry.yarnpkg.com/terminus-terminal/-/terminus-terminal-1.0.98-nightly.0.tgz#10df71b0a81adf76a076fb21a91c859dd2f8bef7"
integrity sha512-JLxkeoQkORcfe6cRW6BJF5ZPSbvKA8IWUAb7fzBONVmNfRKj2Mq/uYPy76UXsdmb9F1n+rYIg+DShNp57asMKA==
tweetnacl@^0.14.3: tweetnacl@^0.14.3:
version "0.14.5" version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-terminal", "name": "terminus-terminal",
"version": "1.0.93-nightly.0", "version": "1.0.98-nightly.0",
"description": "Terminus' terminal emulation core", "description": "Terminus' terminal emulation core",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
@@ -27,11 +27,11 @@
"runes": "^0.4.2", "runes": "^0.4.2",
"slug": "^1.1.0", "slug": "^1.1.0",
"uuid": "^3.3.2", "uuid": "^3.3.2",
"xterm": "4.3.0-beta.30", "xterm": "4.3.0",
"xterm-addon-fit": "^0.4.0-beta2", "xterm-addon-fit": "^0.4.0-beta2",
"xterm-addon-ligatures": "^0.2.1", "xterm-addon-ligatures": "^0.2.1",
"xterm-addon-search": "^0.4.0-beta5", "xterm-addon-search": "^0.4.0",
"xterm-addon-webgl": "^0.4.0-beta.15" "xterm-addon-webgl": "^0.4.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/animations": "^7", "@angular/animations": "^7",

View File

@@ -22,8 +22,8 @@ export interface ToastrServiceProxy {
* A class to base your custom terminal tabs on * A class to base your custom terminal tabs on
*/ */
export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy { export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
static template = require('../components/baseTerminalTab.component.pug') static template = require<string>('../components/baseTerminalTab.component.pug')
static styles = [require('../components/terminalTab.component.scss')] static styles = [require<string>('../components/terminalTab.component.scss')]
static animations: AnimationTriggerMetadata[] = [trigger('slideInOut', [ static animations: AnimationTriggerMetadata[] = [trigger('slideInOut', [
transition(':enter', [ transition(':enter', [
style({ transform: 'translateY(-25%)' }), style({ transform: 'translateY(-25%)' }),
@@ -63,7 +63,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
private bellPlayer: HTMLAudioElement private bellPlayer: HTMLAudioElement
private termContainerSubscriptions: Subscription[] = [] private termContainerSubscriptions: Subscription[] = []
get input$ (): Observable<string> { return this.frontend.input$ } get input$ (): Observable<Buffer> { return this.frontend.input$ }
get output$ (): Observable<string> { return this.output } get output$ (): Observable<string> { return this.output }
get resize$ (): Observable<ResizeEvent> { return this.frontend.resize$ } get resize$ (): Observable<ResizeEvent> { return this.frontend.resize$ }
get alternateScreenActive$ (): Observable<boolean> { return this.frontend.alternateScreenActive$ } get alternateScreenActive$ (): Observable<boolean> { return this.frontend.alternateScreenActive$ }
@@ -229,7 +229,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
/** /**
* Feeds input into the active session * Feeds input into the active session
*/ */
sendInput (data: string) { sendInput (data: string|Buffer) {
if (!(data instanceof Buffer)) {
data = Buffer.from(data, 'utf-8')
}
this.session.write(data) this.session.write(data)
if (this.config.store.terminal.scrollOnInput) { if (this.config.store.terminal.scrollOnInput) {
this.frontend.scrollToBottom() this.frontend.scrollToBottom()

View File

@@ -1,24 +1,11 @@
h3.mb-3 Appearance h3.mb-3 Appearance
.d-flex .d-flex
.mr-5 .mr-5
.form-line
.header
.title Frontend
.description Switches terminal frontend implementation (experimental)
select.form-control(
[(ngModel)]='config.store.terminal.frontend',
(ngModelChange)='config.save()',
)
option(value='hterm') hterm
option(value='xterm') xterm
option(value='xterm-webgl') xterm (WebGL)
.form-line .form-line
.header .header
.title Font .title Font
.d-flex.w-75 .input-group.w-75
input.form-control.w-75( input.form-control.w-75(
type='text', type='text',
[ngbTypeahead]='fontAutocomplete', [ngbTypeahead]='fontAutocomplete',
@@ -52,9 +39,10 @@ h3.mb-3 Appearance
) )
option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}} option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}}
option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}} option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}}
.input-group-btn .input-group-append
button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)')
.input-group-btn i.fas.fa-pen
.input-group-append
button.btn.btn-outline-danger( button.btn.btn-outline-danger(
(click)='deleteScheme(config.store.terminal.colorScheme)', (click)='deleteScheme(config.store.terminal.colorScheme)',
*ngIf='isCustomScheme(config.store.terminal.colorScheme)' *ngIf='isCustomScheme(config.store.terminal.colorScheme)'
@@ -65,10 +53,12 @@ h3.mb-3 Appearance
label Editing label Editing
.input-group .input-group
input.form-control(type='text', [(ngModel)]='editingColorScheme.name') input.form-control(type='text', [(ngModel)]='editingColorScheme.name')
.input-group-btn .input-group-append
button.btn.btn-secondary((click)='saveScheme()') Save button.btn.btn-secondary((click)='saveScheme()')
.input-group-btn i.fas.fa-check
button.btn.btn-secondary((click)='cancelEditing()') Cancel .input-group-append
button.btn.btn-secondary((click)='cancelEditing()')
i.fas.fa-times
.form-group(*ngIf='editingColorScheme') .form-group(*ngIf='editingColorScheme')
color-picker( color-picker(
@@ -180,6 +170,19 @@ h3.mb-3 Appearance
span rm -rf / span rm -rf /
span([style.background-color]='config.store.terminal.colorScheme.cursor') &nbsp; span([style.background-color]='config.store.terminal.colorScheme.cursor') &nbsp;
.form-line
.header
.title Frontend
.description Switches terminal frontend implementation (experimental)
select.form-control(
[(ngModel)]='config.store.terminal.frontend',
(ngModelChange)='config.save()',
)
option(value='hterm') hterm
option(value='xterm') xterm
option(value='xterm-webgl') xterm (WebGL)
.form-line .form-line
.header .header
.title Terminal background .title Terminal background

View File

@@ -23,7 +23,7 @@
type='text', type='text',
[(ngModel)]='profile.sessionOptions.args[i]', [(ngModel)]='profile.sessionOptions.args[i]',
) )
.input-group-btn .input-group-append
button.btn.btn-secondary((click)='profile.sessionOptions.args.splice(i, 1)') button.btn.btn-secondary((click)='profile.sessionOptions.args.splice(i, 1)')
i.fas.fa-trash i.fas.fa-trash

View File

@@ -1,9 +1,10 @@
.mb-2.d-flex.align-items-center(*ngFor='let pair of vars') .mb-2.d-flex.align-items-center(*ngFor='let pair of vars')
.input-group.w-50 .input-group
input.form-control([(ngModel)]='pair.key', (blur)='emitUpdate()', placeholder='Variable name') input.form-control.w-25([(ngModel)]='pair.key', (blur)='emitUpdate()', placeholder='Variable name')
.input-group-append .input-group-append
.input-group-text = .input-group-text =
input.form-control.w-50.mr-1([(ngModel)]='pair.value', (blur)='emitUpdate()', placeholder='Value') input.form-control.w-50([(ngModel)]='pair.value', (blur)='emitUpdate()', placeholder='Value')
.input-group-append
button.btn.btn-secondary((click)='removeEnvironmentVar(pair.key)') button.btn.btn-secondary((click)='removeEnvironmentVar(pair.key)')
i.fas.fa-trash i.fas.fa-trash

View File

@@ -2,7 +2,7 @@
input.search-input.form-control( input.search-input.form-control(
type='search', type='search',
[(ngModel)]='query', [(ngModel)]='query',
(ngModelChange)='notFound = false', (ngModelChange)='onQueryChange()',
[class.text-danger]='notFound', [class.text-danger]='notFound',
(click)='$event.stopPropagation()', (click)='$event.stopPropagation()',
(keyup.enter)='findNext()', (keyup.enter)='findNext()',
@@ -10,31 +10,27 @@
placeholder='Search...' placeholder='Search...'
) )
.input-group-append .input-group-append
.btn-group .input-group-text
button.btn.btn-outline-primary( a(
(click)='options.caseSensitive = !options.caseSensitive', (click)='options.caseSensitive = !options.caseSensitive',
[class.active]='options.caseSensitive', [class.text-info]='options.caseSensitive',
ngbTooltip='Case sensitivity', ngbTooltip='Case sensitivity',
placement='bottom' placement='bottom'
) )
i.fa.fa-fw.fa-font i.fa.fa-fw.fa-font
button.btn.btn-outline-primary( a(
(click)='options.regex = !options.regex', (click)='options.regex = !options.regex',
[class.active]='options.regex', [class.text-info]='options.regex',
ngbTooltip='Regular expression', ngbTooltip='Regular expression',
placement='bottom' placement='bottom'
) )
i.fa.fa-fw.fa-asterisk i.fa.fa-fw.fa-asterisk
button.btn.btn-outline-primary( a(
(click)='options.wholeWord = !options.wholeWord', (click)='options.wholeWord = !options.wholeWord',
[class.active]='options.wholeWord', [class.text-info]='options.wholeWord',
ngbTooltip='Whole word', ngbTooltip='Whole word',
placement='bottom' placement='bottom'
) )
i.fa.fa-fw.fa-text-width i.fa.fa-fw.fa-text-width
button.btn.btn-outline(
(click)='close.emit()', button.close.text-light.pl-3.pr-2((click)='close.emit()') &times;
ngbTooltip='Close',
placement='bottom'
)
i.fa.fa-fw.fa-times

View File

@@ -1,9 +1,20 @@
:host { :host {
position: fixed; position: fixed;
width: 400px; width: 400px;
align-self: center; right: 50px;
z-index: 5; z-index: 5;
padding: 10px; padding: 10px;
border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px;
background: rgba(0, 0, 0, .75); background: rgba(0, 0, 0, .75);
border: 1px solid rgba(0, 0, 0, .5);
border-top: 0;
display: flex;
a {
padding-left: 10px;
&:first-child {
padding-left: 0;
}
}
} }

View File

@@ -11,7 +11,9 @@ export class SearchPanelComponent {
@Input() query: string @Input() query: string
@Input() frontend: Frontend @Input() frontend: Frontend
notFound = false notFound = false
options: SearchOptions = {} options: SearchOptions = {
incremental: true,
}
@Output() close = new EventEmitter() @Output() close = new EventEmitter()
@@ -19,8 +21,13 @@ export class SearchPanelComponent {
private toastr: ToastrService, private toastr: ToastrService,
) { } ) { }
findNext () { onQueryChange () {
if (!this.frontend.findNext(this.query, this.options)) { this.notFound = false
this.findNext(true)
}
findNext (incremental = false) {
if (!this.frontend.findNext(this.query, { ...this.options, incremental: incremental || undefined })) {
this.notFound = true this.notFound = true
this.toastr.error('Not found') this.toastr.error('Not found')
} }

View File

@@ -51,14 +51,16 @@ h3.mb-3 Shell
[(ngModel)]='config.store.terminal.workingDirectory', [(ngModel)]='config.store.terminal.workingDirectory',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
) )
.input-group-btn .input-group-append
button.btn.btn-secondary((click)='pickWorkingDirectory()') button.btn.btn-secondary((click)='pickWorkingDirectory()')
i.fas.fa-folder-open i.fas.fa-folder-open
.form-line .form-line
.header .header
.title Always Use Working Directory .title Always Use Working Directory
.description By default, new terminals will open where the previous terminal was working. Enabling this option will always launch new terminals in the working directory specified above. .description
div By default, new terminals will open where the previous terminal was working.
div Enabling this option will always launch new terminals in the working directory specified above.
toggle( toggle(
[(ngModel)]='config.store.terminal.alwaysUseWorkingDirectory', [(ngModel)]='config.store.terminal.alwaysUseWorkingDirectory',

View File

@@ -6,6 +6,7 @@ export interface SearchOptions {
regex?: boolean regex?: boolean
wholeWord?: boolean wholeWord?: boolean
caseSensitive?: boolean caseSensitive?: boolean
incremental?: true
} }
/** /**
@@ -23,7 +24,7 @@ export abstract class Frontend {
protected mouseEvent = new Subject<MouseEvent>() protected mouseEvent = new Subject<MouseEvent>()
protected bell = new Subject<void>() protected bell = new Subject<void>()
protected contentUpdated = new Subject<void>() protected contentUpdated = new Subject<void>()
protected input = new Subject<string>() protected input = new Subject<Buffer>()
protected resize = new ReplaySubject<ResizeEvent>(1) protected resize = new ReplaySubject<ResizeEvent>(1)
protected dragOver = new Subject<DragEvent>() protected dragOver = new Subject<DragEvent>()
protected drop = new Subject<DragEvent>() protected drop = new Subject<DragEvent>()
@@ -34,7 +35,7 @@ export abstract class Frontend {
get mouseEvent$ (): Observable<MouseEvent> { return this.mouseEvent } get mouseEvent$ (): Observable<MouseEvent> { return this.mouseEvent }
get bell$ (): Observable<void> { return this.bell } get bell$ (): Observable<void> { return this.bell }
get contentUpdated$ (): Observable<void> { return this.contentUpdated } get contentUpdated$ (): Observable<void> { return this.contentUpdated }
get input$ (): Observable<string> { return this.input } get input$ (): Observable<Buffer> { return this.input }
get resize$ (): Observable<ResizeEvent> { return this.resize } get resize$ (): Observable<ResizeEvent> { return this.resize }
get dragOver$ (): Observable<DragEvent> { return this.dragOver } get dragOver$ (): Observable<DragEvent> { return this.dragOver }
get drop$ (): Observable<DragEvent> { return this.drop } get drop$ (): Observable<DragEvent> { return this.drop }

View File

@@ -182,7 +182,7 @@ export class HTermFrontend extends Frontend {
this.term.installKeyboard() this.term.installKeyboard()
this.term.scrollPort_.setCtrlVPaste(true) this.term.scrollPort_.setCtrlVPaste(true)
this.io = this.term.io.push() this.io = this.term.io.push()
this.io.onVTKeystroke = this.io.sendString = data => this.input.next(data) this.io.onVTKeystroke = this.io.sendString = data => this.input.next(Buffer.from(data, 'utf-8'))
this.io.onTerminalResize = (columns, rows) => { this.io.onTerminalResize = (columns, rows) => {
this.resize.next({ columns, rows }) this.resize.next({ columns, rows })
} }

View File

@@ -39,8 +39,11 @@ export class XTermFrontend extends Frontend {
}) })
this.xtermCore = (this.xterm as any)._core this.xtermCore = (this.xterm as any)._core
this.xterm.onBinary(data => {
this.input.next(Buffer.from(data, 'binary'))
})
this.xterm.onData(data => { this.xterm.onData(data => {
this.input.next(data) this.input.next(Buffer.from(data, 'utf-8'))
}) })
this.xterm.onResize(({ cols, rows }) => { this.xterm.onResize(({ cols, rows }) => {
this.resize.next({ rows, columns: cols }) this.resize.next({ rows, columns: cols })
@@ -113,6 +116,8 @@ export class XTermFrontend extends Frontend {
} }
attach (host: HTMLElement): void { attach (host: HTMLElement): void {
this.configure()
this.xterm.open(host) this.xterm.open(host)
this.opened = true this.opened = true
@@ -209,7 +214,7 @@ export class XTermFrontend extends Frontend {
const theme: ITheme = { const theme: ITheme = {
foreground: config.terminal.colorScheme.foreground, foreground: config.terminal.colorScheme.foreground,
background: config.terminal.background === 'colorScheme' ? config.terminal.colorScheme.background : config.appearance.vibrancy ? 'transparent' : this.themesService.findCurrentTheme().terminalBackground, background: config.terminal.background === 'colorScheme' ? config.terminal.colorScheme.background : config.appearance.vibrancy ? '#00000000' : this.themesService.findCurrentTheme().terminalBackground,
cursor: config.terminal.colorScheme.cursor, cursor: config.terminal.colorScheme.cursor,
} }

View File

@@ -77,7 +77,7 @@ export abstract class BaseSession {
abstract start (options: SessionOptions): void abstract start (options: SessionOptions): void
abstract resize (columns: number, rows: number): void abstract resize (columns: number, rows: number): void
abstract write (data: string): void abstract write (data: Buffer): void
abstract kill (signal?: string): void abstract kill (signal?: string): void
abstract async getChildProcesses (): Promise<ChildProcess[]> abstract async getChildProcesses (): Promise<ChildProcess[]>
abstract async gracefullyKillProcess (): Promise<void> abstract async gracefullyKillProcess (): Promise<void>
@@ -201,10 +201,10 @@ export class Session extends BaseSession {
} }
} }
write (data) { write (data: Buffer) {
if (this.open) { if (this.open) {
if (this.pty._writable) { if (this.pty._writable) {
this.pty.write(Buffer.from(data, 'utf-8')) this.pty.write(data)
} else { } else {
this.destroy() this.destroy()
} }

View File

@@ -2,6 +2,8 @@ import { Injectable, NgZone } from '@angular/core'
import { ToastrService } from 'ngx-toastr' import { ToastrService } from 'ngx-toastr'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider } from 'terminus-core' import { ConfigService, BaseTabComponent, TabContextMenuItemProvider } from 'terminus-core'
import { TerminalTabComponent } from './components/terminalTab.component' import { TerminalTabComponent } from './components/terminalTab.component'
import { UACService } from './services/uac.service'
import { TerminalService } from './services/terminal.service'
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
@@ -10,6 +12,8 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
private config: ConfigService, private config: ConfigService,
private zone: NgZone, private zone: NgZone,
private toastr: ToastrService, private toastr: ToastrService,
private uac: UACService,
private terminalService: TerminalService,
) { ) {
super() super()
} }
@@ -18,7 +22,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
if (!(tab instanceof TerminalTabComponent)) { if (!(tab instanceof TerminalTabComponent)) {
return [] return []
} }
return [ const items: Electron.MenuItemConstructorOptions[] = [
{ {
label: 'Save as profile', label: 'Save as profile',
click: () => this.zone.run(async () => { click: () => this.zone.run(async () => {
@@ -38,5 +42,19 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
}), }),
}, },
] ]
if (this.uac.isAvailable) {
items.push({
label: 'Duplicate as administrator',
click: () => this.zone.run(async () => {
this.terminalService.openTabWithOptions({
...tab.sessionOptions,
runAsAdministrator: true,
})
}),
})
}
return items
} }
} }

View File

@@ -226,20 +226,20 @@ xterm-addon-ligatures@^0.2.1:
font-finder "^1.0.4" font-finder "^1.0.4"
font-ligatures "^1.3.2" font-ligatures "^1.3.2"
xterm-addon-search@^0.4.0-beta5: xterm-addon-search@^0.4.0:
version "0.4.0-beta5" version "0.4.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta5.tgz#d7b7d35502cc5155d35175ab63e0465c1447eebd" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1"
integrity sha512-aA+WmoM6U8H9V4ofKLaZaTBFoRLdxVujWA2mQxbzXBF8FLLCDSJOK8kEor4BSb8OtGr0Nlfs1Qy9O0HBmXSQWA== integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg==
xterm-addon-webgl@^0.4.0-beta.15: xterm-addon-webgl@^0.4.0:
version "0.4.0-beta.15" version "0.4.0"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.4.0-beta.15.tgz#a85a6f2374e1d3c9227bb3a9741ae1f126bafa47" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.4.0.tgz#7b7cdbdbf9b0d06189af20d468d8ea2798382e0f"
integrity sha512-zsD6av31hRQh1yeY3XjRZIvPZdrqAPixvKz2Rczi1ZVwGl1IrXdMeAN2gofNej5ao09v/jfnherCmqEpsVIISw== integrity sha512-2ExOKJQcyv4hUo/d41uMDe7fNZCi42kPtbvG/v+dVj1NwqGD7g1bhuoH2j1iA1vTP5O1fClc6pU9nLBpbwrdZQ==
xterm@4.3.0-beta.30: xterm@4.3.0:
version "4.3.0-beta.30" version "4.3.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0-beta.30.tgz#2cdb5e21fece98a5f4fe70d13ccebbb50c639bae" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0.tgz#9a302efefe75172d4f7ea3afc20f9bd983f05027"
integrity sha512-3ojuqTigSwvfq607O5UAcdAt6Clg0Y5+Fq6u5qEWNjd69G84tOqJVVogqTn0QON87OeiQN3ibQiBdi/+4xZ2KA== integrity sha512-6dnrC4nxgnRKQzIWwC5HA0mnT9/rpDPZflUIr24gdcdSMTKM1QQcor4qQ/xz4Zerz6AIL/CuuBPypFfzsB63dQ==
yallist@^2.1.2: yallist@^2.1.2:
version "2.1.2" version "2.1.2"

View File

@@ -1,7 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "es2015", "module": "es2015",
"target": "es2016", "target": "es5",
"moduleResolution": "node", "moduleResolution": "node",
"noImplicitAny": false, "noImplicitAny": false,
"removeComments": false, "removeComments": false,
@@ -25,5 +25,9 @@
"es2015", "es2015",
"es2017" "es2017"
] ]
},
"angularCompilerOptions": {
"enableIvy": true,
"disableTypeScriptVersionCheck": true
} }
} }

1625
yarn.lock

File diff suppressed because it is too large Load Diff