electron 11 cleanup

This commit is contained in:
Eugene Pankov 2020-12-24 14:03:14 +01:00
parent e87f6e7af0
commit 0ca971a289
No known key found for this signature in database
GPG key ID: 5896FCBBDD1CF4F4
87 changed files with 9169 additions and 8285 deletions

View file

@ -37,6 +37,7 @@ rules:
'@typescript-eslint/strict-boolean-expressions': off
'@typescript-eslint/no-misused-promises': off
'@typescript-eslint/typedef': off
'@typescript-eslint/consistent-type-imports': off
'@typescript-eslint/no-use-before-define':
- error
- classes: false
@ -53,7 +54,8 @@ rules:
computed-property-spacing:
- error
- never
comma-dangle:
comma-dangle: off
'@typescript-eslint/comma-dangle':
- error
- always-multiline
curly: error
@ -104,3 +106,17 @@ rules:
'@typescript-eslint/no-unsafe-call': off
'@typescript-eslint/no-unsafe-return': off
'@typescript-eslint/no-base-to-string': off # broken in typescript-eslint
'@typescript-eslint/no-unsafe-assignment': off
'@typescript-eslint/naming-convention': off
'@typescript-eslint/lines-between-class-members':
- error
- exceptAfterSingleLine: true
'@typescript-eslint/non-nullable-type-assertion-style': off
'@typescript-eslint/dot-notation': off
'@typescript-eslint/no-confusing-void-expression': off
'@typescript-eslint/prefer-enum-initializers': off
'@typescript-eslint/no-implicit-any-catch': off
'@typescript-eslint/member-ordering': off
'@typescript-eslint/consistent-indexed-object-style': off
'@typescript-eslint/no-var-requires': off
'@typescript-eslint/no-shadow': off

View file

@ -3,6 +3,11 @@ on: [push, pull_request]
jobs:
build:
runs-on: macOS-latest
strategy:
matrix:
include:
- arch: x86_64
- arch: arm64
steps:
- name: Checkout
@ -24,12 +29,16 @@ jobs:
- name: Build native deps
run: scripts/build-native.js
env:
ARCH: ${{arch}}
- name: Webpack
run: yarn run build
- name: Prepackage plugins
run: scripts/prepackage-plugins.js
env:
ARCH: ${{arch}}
- run: sed -i '' 's/updateInfo = await/\/\/updateInfo = await/g' node_modules/app-builder-lib/out/targets/ArchiveTarget.js
@ -37,18 +46,20 @@ jobs:
run: scripts/build-macos.js
if: github.repository == 'Eugeny/terminus' && github.event_name == 'push'
env:
#DEBUG: electron-builder,electron-builder:*
ARCH: ${{arch}}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
# DEBUG: electron-builder,electron-builder:*
- name: Build packages without signing
run: scripts/build-macos.js
if: github.repository != 'Eugeny/terminus' || github.event_name != 'push'
env:
DEBUG: electron-builder,electron-builder:*
ARCH: ${{arch}}
# DEBUG: electron-builder,electron-builder:*
- name: Package artifacts
run: |
@ -60,11 +71,11 @@ jobs:
- uses: actions/upload-artifact@master
name: Upload PKG
with:
name: macOS .pkg
name: macOS .pkg (${{arch}})
path: artifact-pkg
- uses: actions/upload-artifact@master
name: Upload ZIP
with:
name: macOS .zip
name: macOS .zip (${{arch}})
path: artifact-zip

View file

@ -1,6 +1,4 @@
import { app, ipcMain, Menu, Tray, shell, globalShortcut } from 'electron'
// eslint-disable-next-line no-duplicate-imports
import * as electron from 'electron'
import { app, ipcMain, Menu, Tray, shell, screen, globalShortcut, MenuItemConstructorOptions } from 'electron'
import { loadConfig } from './config'
import { Window, WindowOptions } from './window'
@ -15,7 +13,7 @@ export class Application {
ipcMain.on('app:register-global-hotkey', (_event, specs) => {
globalShortcut.unregisterAll()
for (let spec of specs) {
for (const spec of specs) {
globalShortcut.register(spec, () => {
this.onGlobalHotkey()
})
@ -41,11 +39,13 @@ export class Application {
}
init (): void {
electron.screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
screen.on('display-added', () => this.broadcast('host:displays-changed'))
screen.on('display-removed', () => this.broadcast('host:displays-changed'))
}
async newWindow (options?: WindowOptions): Promise<Window> {
let window = new Window(options)
const window = new Window(options)
this.windows.push(window)
window.visible$.subscribe(visible => {
if (visible) {
@ -66,29 +66,29 @@ export class Application {
onGlobalHotkey (): void {
if (this.windows.some(x => x.isFocused())) {
for (let window of this.windows) {
for (const window of this.windows) {
window.hide()
}
} else {
for (let window of this.windows) {
for (const window of this.windows) {
window.present()
}
}
}
presentAllWindows (): void {
for (let window of this.windows) {
for (const window of this.windows) {
window.present()
}
}
broadcast (event: string, ...args): void {
broadcast (event: string, ...args: any[]): void {
for (const window of this.windows) {
window.send(event, ...args)
}
}
async send (event: string, ...args): Promise<void> {
async send (event: string, ...args: any[]): Promise<void> {
if (!this.hasWindows()) {
await this.newWindow()
}
@ -132,7 +132,7 @@ export class Application {
}
focus (): void {
for (let window of this.windows) {
for (const window of this.windows) {
window.show()
}
}
@ -143,7 +143,7 @@ export class Application {
}
private setupMenu () {
let template: Electron.MenuItemConstructorOptions[] = [
const template: MenuItemConstructorOptions[] = [
{
label: 'Application',
submenu: [

View file

@ -4,7 +4,7 @@ import * as yaml from 'js-yaml'
import { app } from 'electron'
export function loadConfig (): any {
let configPath = path.join(app.getPath('userData'), 'config.yaml')
const configPath = path.join(app.getPath('userData'), 'config.yaml')
if (fs.existsSync(configPath)) {
return yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
} else {

View file

@ -1,6 +1,6 @@
import * as createLRU from 'lru-cache'
import * as LRU from 'lru-cache'
import * as fs from 'fs'
const lru = new createLRU({ max: 256, maxAge: 250 })
const lru = new LRU({ max: 256, maxAge: 250 })
const origLstat = fs.realpathSync.bind(fs)
// NB: The biggest offender of thrashing realpathSync is the node module system

View file

@ -9,7 +9,7 @@ try {
}
if (null != appPath) {
if(fs.existsSync(path.join(appPath, 'terminus-data'))) {
if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
}
const portableData = path.join(appPath, 'data')

View file

@ -3,7 +3,7 @@ import * as isDev from 'electron-is-dev'
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
let release
let release = null
try {
release = require('electron').app.getVersion()
} catch {

View file

@ -5,7 +5,7 @@ if (process.platform === 'win32' || process.platform === 'linux') {
import { Subject, Observable } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen } from 'electron'
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowConstructorOptions } from 'electron'
import ElectronConfig = require('electron-config')
import * as os from 'os'
import * as path from 'path'
@ -13,7 +13,7 @@ import * as path from 'path'
import { parseArgs } from './cli'
import { loadConfig } from './config'
let DwmEnableBlurBehindWindow: any
let DwmEnableBlurBehindWindow: any = null
if (process.platform === 'win32') {
DwmEnableBlurBehindWindow = require('windows-blurbehind').DwmEnableBlurBehindWindow
}
@ -45,13 +45,13 @@ export class Window {
this.windowConfig = new ElectronConfig({ name: 'window' })
this.windowBounds = this.windowConfig.get('windowBoundaries')
let maximized = this.windowConfig.get('maximized')
let bwOptions: Electron.BrowserWindowConstructorOptions = {
const maximized = this.windowConfig.get('maximized')
const bwOptions: BrowserWindowConstructorOptions = {
width: 800,
height: 600,
title: 'Terminus',
minWidth: 400,
minHeight: 300,
minHeight: 300,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'sentry.js'),
@ -139,7 +139,7 @@ export class Window {
} else {
DwmEnableBlurBehindWindow(this.window, enabled)
}
} else if (process.platform ==='linux') {
} else if (process.platform === 'linux') {
glasstron.update(this.window, {
linux: { requestBlur: enabled },
})
@ -158,7 +158,7 @@ export class Window {
this.window.focus()
}
send (event: string, ...args): void {
send (event: string, ...args: any[]): void {
if (!this.window) {
return
}
@ -225,7 +225,7 @@ export class Window {
this.visible.next(false)
})
let moveSubscription = new Observable<void>(observer => {
const moveSubscription = new Observable<void>(observer => {
this.window.on('move', () => observer.next())
}).pipe(debounceTime(250)).subscribe(() => {
this.send('host:window-moved')

View file

@ -21,8 +21,7 @@
"@angular/platform-browser": "^9.1.9",
"@angular/platform-browser-dynamic": "^9.1.9",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@terminus-term/node-pty": "0.10.0-beta9",
"devtron": "1.4.0",
"@terminus-term/node-pty": "0.10.0-beta10",
"electron-config": "2.0.0",
"electron-debug": "^3.0.1",
"electron-is-dev": "1.1.0",
@ -30,18 +29,12 @@
"glasstron": "AryToNeX/Glasstron#dependabot/npm_and_yarn/electron-11.1.0",
"js-yaml": "3.14.0",
"keytar": "^7.2.0",
"macos-native-processlist": "^2.0.0",
"mz": "^2.7.0",
"ngx-toastr": "^12.0.1",
"node-gyp": "^7.1.2",
"npm": "7.0.15",
"path": "0.12.7",
"rxjs": "^6.5.5",
"rxjs-compat": "^6.6.0",
"serialport": "^9.0.4",
"windows-blurbehind": "^1.0.1",
"windows-native-registry": "^3.0.0",
"windows-process-tree": "^0.2.4",
"yargs": "^15.4.1",
"zone.js": "^0.11.3"
},
@ -55,15 +48,15 @@
"devDependencies": {
"@types/mz": "0.0.32",
"@types/node": "14.14.14",
"node-abi": "github:lgeiger/node-abi"
"node-abi": "2.19.3"
},
"peerDependencies": {
"terminus-core": "*",
"terminus-settings": "*",
"terminus-serial": "*",
"terminus-plugin-manager": "*",
"terminus-community-color-schemes": "*",
"terminus-core": "*",
"terminus-plugin-manager": "*",
"terminus-serial": "*",
"terminus-settings": "*",
"terminus-ssh": "*",
"terminus-terminal": "*"
}
}
}

View file

@ -83,7 +83,7 @@ const originalRequire = (global as any).require
if (cachedBuiltinModules[query]) {
return cachedBuiltinModules[query]
}
return originalRequire.apply(this, arguments)
return originalRequire.apply(this, [query])
}
const originalModuleRequire = nodeModule.prototype.require

View file

@ -266,12 +266,12 @@
dependencies:
debug "^4.1.1"
"@terminus-term/node-pty@0.10.0-beta9":
version "0.10.0-beta9"
resolved "https://registry.npmjs.org/@terminus-term/node-pty/-/node-pty-0.10.0-beta9.tgz"
integrity sha512-wnttx12b9gxP9CPB9uqBMQx/Vp4EboUDGOY3xRP0Nvhec6pSF2qFZD6bwMbNzFIopbaohluEYcbEul0jTQcdeQ==
"@terminus-term/node-pty@0.10.0-beta10":
version "0.10.0-beta10"
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-beta10.tgz#de9dade3d7549d44b0906ec0d0b9e1bb411f1f21"
integrity sha512-j9RJk7sD/es4vR6+AR5M/p3SicVxY6kZEeE0UQKhHNcaAla90/mcGeBNicAWPaAkjO1uQZVbYh5cJMMu5unQgA==
dependencies:
nan "^2.13.2"
nan "^2.14.0"
"@tootallnate/once@1":
version "1.1.2"
@ -295,11 +295,6 @@ abbrev@1, abbrev@~1.1.1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accessibility-developer-tools@^2.11.0:
version "2.12.0"
resolved "https://registry.npmjs.org/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz"
integrity sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz"
@ -738,15 +733,6 @@ detect-libc@^1.0.3:
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
devtron@1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/devtron/-/devtron-1.4.0.tgz"
integrity sha1-tedIvW6Vu+cL/MaKrm/mlhGUQeE=
dependencies:
accessibility-developer-tools "^2.11.0"
highlight.js "^9.3.0"
humanize-plus "^1.8.1"
dezalgo@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz"
@ -1022,11 +1008,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
highlight.js@^9.3.0:
version "9.18.5"
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz"
integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==
hosted-git-info@^3.0.6:
version "3.0.7"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.7.tgz"
@ -1072,11 +1053,6 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
humanize-plus@^1.8.1:
version "1.8.2"
resolved "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz"
integrity sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=
iconv-lite@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz"
@ -1585,9 +1561,9 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.13.2, nan@^2.14.2:
nan@^2.13.2, nan@^2.14.0, nan@^2.14.2:
version "2.14.2"
resolved "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
napi-build-utils@^1.0.1:
@ -1602,19 +1578,13 @@ ngx-toastr@^12.0.1:
dependencies:
tslib "^1.10.0"
node-abi@^2.7.0:
node-abi@2.19.3, node-abi@^2.7.0:
version "2.19.3"
resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz"
integrity sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==
dependencies:
semver "^5.4.1"
"node-abi@github:lgeiger/node-abi":
version "0.0.0-development"
resolved "https://codeload.github.com/lgeiger/node-abi/tar.gz/d7a3f00c93cb16b5f4fbb3ae8c106e798cc52042"
dependencies:
semver "^5.4.1"
node-addon-api@3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz"

View file

@ -1,78 +0,0 @@
{
'conditions': [
['OS=="win"', {
'targets': [
{
'target_name': 'conpty',
'include_dirs' : [
'<!(node -e "require(\'nan\')")'
],
'sources' : [
'src/win/conpty.cc',
'src/win/path_util.cc'
],
'libraries': [
'shlwapi.lib'
]
},
{
'target_name': 'conpty_console_list',
'include_dirs' : [
'<!(node -e "require(\'nan\')")'
],
'sources' : [
'src/win/conpty_console_list.cc'
]
},
{
'target_name': 'pty',
'include_dirs' : [
'<!(node -e "require(\'nan\')")',
'deps/winpty/src/include',
],
# Disabled due to winpty
'msvs_disabled_warnings': [ 4506, 4530 ],
'dependencies' : [
'deps/winpty/src/winpty.gyp:winpty-agent',
'deps/winpty/src/winpty.gyp:winpty',
],
'sources' : [
'src/win/winpty.cc',
'src/win/path_util.cc'
],
'libraries': [
'shlwapi.lib'
],
}
]
}, { # OS!="win"
'targets': [{
'target_name': 'pty',
'include_dirs' : [
'<!(node -e "require(\'nan\')")'
],
'sources': [
'src/unix/pty.cc'
],
'libraries': [
'-lutil'
],
'conditions': [
# http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html
# One some systems (at least including Cygwin, Interix,
# OSF/1 4 and 5, and Mac OS X) linking with -lutil is not required.
['OS=="mac" or OS=="solaris"', {
'libraries!': [
'-lutil'
]
}],
['OS=="mac"', {
"xcode_settings": {
"MACOSX_DEPLOYMENT_TARGET":"10.7"
}
}]
]
}]
}]
]
}

View file

@ -25,7 +25,7 @@ nsis:
mac:
category: public.app-category.video
icon: "./build/mac/icon.icns"
artifactName: terminus-${version}-macos.${ext}
artifactName: terminus-${version}-macos-${env.ARCH}.${ext}
hardenedRuntime: true
entitlements: "./build/mac/entitlements.plist"
entitlementsInherit: "./build/mac/entitlements.plist"
@ -40,9 +40,6 @@ mac:
NSNetworkVolumesUsageDescription: 'A subprocess requests access to files on a network volume.'
NSRemovableVolumesUsageDescription: 'A subprocess requests access to files on a removable volume.'
pkg:
artifactName: terminus-${version}-macos.pkg
linux:
category: Utilities
icon: "./build/icons"

View file

@ -9,8 +9,8 @@
"@types/js-yaml": "^3.12.5",
"@types/node": "14.14.14",
"@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
"@typescript-eslint/eslint-plugin": "^4.11.0",
"@typescript-eslint/parser": "^4.11.0",
"apply-loader": "2.0.0",
"awesome-typescript-loader": "^5.2.1",
"core-js": "^3.8.1",
@ -22,13 +22,13 @@
"electron-installer-snap": "^5.1.0",
"electron-notarize": "^1.0.0",
"electron-rebuild": "^2.3.4",
"eslint": "^7.16.0",
"eslint-plugin-import": "^2.22.1",
"eslint": "^7.6.0",
"eslint-plugin-import": "^2.21.1",
"file-loader": "^5.1.0",
"graceful-fs": "^4.2.4",
"html-loader": "0.5.5",
"json-loader": "0.5.7",
"node-abi": "lgeiger/node-abi#d7a3f00c93cb16b5f4fbb3ae8c106e798cc52042",
"node-abi": "^2.19.3",
"node-gyp": "^7.1.2",
"node-sass": "^5.0.0",
"npmlog": "4.1.2",
@ -39,7 +39,6 @@
"pug-loader": "^2.4.0",
"pug-static-loader": "2.0.0",
"raw-loader": "4.0.1",
"run-script-os": "^1.1.3",
"sass-loader": "^10.1.0",
"shelljs": "0.8.4",
"source-code-pro": "^2.30.2",
@ -55,8 +54,6 @@
"val-loader": "2.1.1",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",
"winston": "^3.3.3",
"winston-transport": "winstonjs/winston-transport",
"yaml-loader": "0.6.0"
},
"resolutions": {
@ -76,10 +73,5 @@
},
"repository": "eugeny/terminus",
"author": "Eugene Pankov",
"license": "MIT",
"dependencies": {
"ssh2-streams": "^0.4.10",
"winston": "^3.3.3",
"yarn": "^1.22.10"
}
"license": "MIT"
}

View file

@ -1,22 +0,0 @@
#!/usr/bin/env node
const builder = require('electron-builder').build
const vars = require('./vars')
const fs = require('fs')
const signHook = require('../build/mac/afterSignHook')
const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
builder({
dir: true,
mac: ['pkg', 'zip'],
arm64: true,
config: {
extraMetadata: {
version: vars.version,
},
},
publish: isTag ? 'always' : 'onTag',
}).catch(e => {
console.error(e)
process.exit(1)
})

View file

@ -9,6 +9,7 @@ const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
builder({
dir: true,
mac: ['pkg', 'zip'],
arm64: (process.env.ARCH ?? process.arch) === 'arm64',
config: {
extraMetadata: {
version: vars.version,

View file

@ -8,6 +8,7 @@ for (let dir of ['app', 'terminus-core', 'terminus-ssh', 'terminus-terminal']) {
const build = rebuild({
buildPath: path.resolve(__dirname, '../' + dir),
electronVersion: vars.electronVersion,
arch: process.env.ARCH ?? process.arch,
force: true,
})
build.catch(e => {

View file

@ -20,8 +20,6 @@ vars.builtinPlugins.forEach(plugin => {
sh.cd('..')
})
sh.cp('binding.gyp_hack', "app/node_modules/@terminus-term/node-pty/binding.gyp")
if (['darwin', 'linux'].includes(process.platform)) {
sh.cd('node_modules')
for (let x of vars.builtinPlugins) {

View file

@ -1,7 +0,0 @@
#This script creates local release for macos
./scripts/install-deps.js
./scripts/build-native.js
./scripts/prepackage-plugins.js
npm run build
./scripts/build-macos-arm64.js

View file

@ -6,9 +6,6 @@ const fs = require('fs')
const vars = require('./vars')
const log = require('npmlog')
const localBinPath = path.resolve(__dirname, '../node_modules/.bin');
const npx = `${localBinPath}/npx`;
let target = path.resolve(__dirname, '../builtin-plugins')
sh.mkdir('-p', target)
fs.writeFileSync(path.join(target, 'package.json'), '{}')
@ -18,13 +15,17 @@ vars.builtinPlugins.forEach(plugin => {
sh.cp('-r', path.join('..', plugin), '.')
sh.rm('-rf', path.join(plugin, 'node_modules'))
sh.cd(plugin)
//sh.exec(`npm install --only=prod`)
sh.exec(`${npx} yarn install --force`)
sh.exec(`yarn install --force --production`)
log.info('rebuild', 'native')
if (fs.existsSync('node_modules')) {
rebuild(path.resolve('.'), vars.electronVersion, process.arch, [], true)
rebuild({
buildPath: path.resolve('.'),
electronVersion: vars.electronVersion,
arch: process.env.ARCH ?? process.arch,
force: true,
})
}
sh.cd('..')
})

View file

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

View file

@ -1,6 +1,6 @@
{
"name": "terminus-core",
"version": "1.0.104-nightly.0",
"version": "1.0.123-nightly.0",
"description": "Terminus core",
"keywords": [
"terminus-builtin-plugin"
@ -29,11 +29,10 @@
"mixpanel": "^0.10.2",
"ng2-dnd": "^5.0.2",
"ngx-perfect-scrollbar": "^8.0.0",
"readable-stream": "^2.3.7",
"readable-stream": "2.3.7",
"shell-escape": "^0.2.0",
"uuid": "^8.0.0",
"winston": "^3.3.3",
"winston-transport": "winstonjs/winston-transport"
"winston": "^3.3.3"
},
"peerDependencies": {
"@angular/animations": "^9.1.9",

View file

@ -1,3 +1,4 @@
import type { MenuItemConstructorOptions } from 'electron'
import { BaseTabComponent } from '../components/baseTab.component'
import { TabHeaderComponent } from '../components/tabHeader.component'
@ -7,5 +8,5 @@ import { TabHeaderComponent } from '../components/tabHeader.component'
export abstract class TabContextMenuItemProvider {
weight = 0
abstract async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]>
abstract async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]>
}

View file

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import type { MenuItemConstructorOptions } from 'electron'
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
import { SortableComponent } from 'ng2-dnd'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@ -13,7 +14,7 @@ import { ConfigService } from '../services/config.service'
/** @hidden */
export interface SortableComponentProxy {
setDragHandle (_: HTMLElement)
setDragHandle: (_: HTMLElement) => void
}
/** @hidden */
@ -71,8 +72,8 @@ export class TabHeaderComponent {
}).catch(() => null)
}
async buildContextMenu (): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = []
async buildContextMenu (): Promise<MenuItemConstructorOptions[]> {
let items: MenuItemConstructorOptions[] = []
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this.tab, this)))) {
items.push({ type: 'separator' })
items = items.concat(section)

View file

@ -38,7 +38,6 @@ import { CoreConfigProvider } from './config'
import { AppHotkeyProvider } from './hotkeys'
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu } from './tabContextMenu'
//import 'ngx-perfect-scrollbar/dist/lib/perfect-scrollbar.component.css'
import 'perfect-scrollbar/css/perfect-scrollbar.css'
import 'ng2-dnd/bundles/style.css'

View file

@ -97,7 +97,7 @@ export class ConfigService {
private changed = new Subject<void>()
private _store: any
private defaults: any
private servicesCache: { [id: string]: Function[] }|null = null
private servicesCache: Record<string, Function[]>|null = null // eslint-disable-line @typescript-eslint/ban-types
get changed$ (): Observable<void> { return this.changed }
@ -189,7 +189,7 @@ export class ConfigService {
*
* @typeparam T Base provider type
*/
enabledServices<T extends object> (services: T[]): T[] {
enabledServices<T extends object> (services: T[]): T[] { // eslint-disable-line @typescript-eslint/ban-types
if (!this.servicesCache) {
this.servicesCache = {}
const ngModule = window['rootModule'].ɵinj

View file

@ -1,3 +1,4 @@
import type { Display } from 'electron'
import { Injectable } from '@angular/core'
import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
@ -11,8 +12,8 @@ export class DockingService {
private config: ConfigService,
private hostApp: HostAppService,
) {
electron.screen.on('display-removed', () => this.repositionWindow())
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
hostApp.displaysChanged$.subscribe(() => this.repositionWindow())
hostApp.displayMetricsChanged$.subscribe(() => this.repositionWindow())
}
dock (): void {
@ -61,11 +62,11 @@ export class DockingService {
})
}
getCurrentScreen (): Electron.Display {
getCurrentScreen (): Display {
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
}
getScreens (): Electron.Display[] {
getScreens (): Display[] {
const primaryDisplayID = this.electron.screen.getPrimaryDisplay().id
return this.electron.screen.getAllDisplays().sort((a, b) =>
a.bounds.x === b.bounds.x ? a.bounds.y - b.bounds.y : a.bounds.x - b.bounds.x
@ -73,7 +74,7 @@ export class DockingService {
return {
...display,
id: display.id,
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index +1}`,
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index + 1}`,
}
})
}

View file

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'
import { TouchBar, BrowserWindow, Menu, MenuItem, NativeImage } from 'electron'
import { App, IpcRenderer, Shell, Dialog, Clipboard, GlobalShortcut, Screen, Remote, AutoUpdater, TouchBar, BrowserWindow, Menu, MenuItem, NativeImage, MessageBoxOptions } from 'electron'
export interface MessageBoxResponse {
response: number
@ -8,16 +8,16 @@ export interface MessageBoxResponse {
@Injectable({ providedIn: 'root' })
export class ElectronService {
app: Electron.App
ipcRenderer: Electron.IpcRenderer
shell: Electron.Shell
dialog: Electron.Dialog
clipboard: Electron.Clipboard
globalShortcut: Electron.GlobalShortcut
app: App
ipcRenderer: IpcRenderer
shell: Shell
dialog: Dialog
clipboard: Clipboard
globalShortcut: GlobalShortcut
nativeImage: typeof NativeImage
screen: Electron.Screen
remote: Electron.Remote
autoUpdater: Electron.AutoUpdater
screen: Screen
remote: Remote
autoUpdater: AutoUpdater
TouchBar: typeof TouchBar
BrowserWindow: typeof BrowserWindow
Menu: typeof Menu
@ -44,8 +44,8 @@ export class ElectronService {
}
async showMessageBox (
browserWindow: Electron.BrowserWindow,
options: Electron.MessageBoxOptions
browserWindow: BrowserWindow,
options: MessageBoxOptions
): Promise<MessageBoxResponse> {
return this.dialog.showMessageBox(browserWindow, options)
}

View file

@ -58,7 +58,7 @@ export class HomeBaseService {
getAnalyticsProperties (): Record<string, string> {
return {
distinct_id: window.localStorage.analyticsUserID, // eslint-disable-line @typescript-eslint/camelcase
distinct_id: window.localStorage.analyticsUserID,
platform: process.platform,
os: os.release(),
version: this.appVersion,

View file

@ -1,3 +1,4 @@
import type { BrowserWindow, TouchBar, MenuItemConstructorOptions } from 'electron'
import * as path from 'path'
import shellEscape from 'shell-escape'
import { Observable, Subject } from 'rxjs'
@ -42,6 +43,7 @@ export class HostAppService {
private windowMoved = new Subject<void>()
private windowFocused = new Subject<void>()
private displayMetricsChanged = new Subject<void>()
private displaysChanged = new Subject<void>()
private logger: Logger
private windowId: number
@ -91,6 +93,8 @@ export class HostAppService {
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
get displaysChanged$ (): Observable<void> { return this.displaysChanged }
private constructor (
private zone: NgZone,
private electron: ElectronService,
@ -140,6 +144,10 @@ export class HostAppService {
this.zone.run(() => this.displayMetricsChanged.next())
})
electron.ipcRenderer.on('host:displays-changed', () => {
this.zone.run(() => this.displaysChanged.next())
})
electron.ipcRenderer.on('host:second-instance', (_$event, argv: any, cwd: string) => this.zone.run(() => {
this.logger.info('Second instance', argv)
const op = argv._[0]
@ -177,8 +185,8 @@ export class HostAppService {
/**
* Returns the current remote [[BrowserWindow]]
*/
getWindow (): Electron.BrowserWindow {
return this.electron.BrowserWindow.fromId(this.windowId)
getWindow (): BrowserWindow {
return this.electron.BrowserWindow.fromId(this.windowId)!
}
newWindow (): void {
@ -239,11 +247,11 @@ export class HostAppService {
this.electron.ipcRenderer.send('window-set-title', title)
}
setTouchBar (touchBar: Electron.TouchBar): void {
setTouchBar (touchBar: TouchBar): void {
this.getWindow().setTouchBar(touchBar)
}
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]): void {
popupContextMenu (menuDefinition: MenuItemConstructorOptions[]): void {
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
}

View file

@ -28,7 +28,7 @@ const initializeWinston = (electron: ElectronService) => {
export class Logger {
constructor (
private winstonLogger: any,
private winstonLogger: winston.Logger,
private name: string,
) {}
@ -62,7 +62,7 @@ export class Logger {
@Injectable({ providedIn: 'root' })
export class LogService {
private log: any
private log: winston.Logger
/** @hidden */
private constructor (electron: ElectronService) {

View file

@ -73,10 +73,10 @@ export class ShellIntegrationService {
wnr.setRegistryValue(wnr.HK.CU, registryKey.path + '\\command', '', wnr.REG.SZ, exe + ' ' + registryKey.command)
}
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
if (wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')
}
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
if (wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')
}
}

View file

@ -1,5 +1,5 @@
import { NativeImage, SegmentedControlSegment, TouchBarSegmentedControl } from 'electron'
import { Injectable, Inject, NgZone } from '@angular/core'
import { TouchBarSegmentedControl, SegmentedControlSegment } from 'electron'
import { AppService } from './app.service'
import { ConfigService } from './config.service'
import { ElectronService } from './electron.service'
@ -12,7 +12,7 @@ export class TouchbarService {
private tabsSegmentedControl: TouchBarSegmentedControl
private buttonsSegmentedControl: TouchBarSegmentedControl
private tabSegments: SegmentedControlSegment[] = []
private nsImageCache: {[id: string]: Electron.NativeImage} = {}
private nsImageCache: {[id: string]: NativeImage} = {}
private constructor (
private app: AppService,
@ -100,7 +100,7 @@ export class TouchbarService {
this.hostApp.setTouchBar(touchBar)
}
private getButton (button: ToolbarButton): Electron.SegmentedControlSegment {
private getButton (button: ToolbarButton): SegmentedControlSegment {
return {
label: button.touchBarNSImage ? undefined : this.shortenTitle(button.touchBarTitle || button.title),
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : undefined,

View file

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import type { MenuItemConstructorOptions } from 'electron'
import { Injectable, NgZone } from '@angular/core'
import { Subscription } from 'rxjs'
import { AppService } from './services/app.service'
@ -19,8 +20,8 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = [
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
let items: MenuItemConstructorOptions[] = [
{
label: 'Close',
click: () => this.zone.run(() => {
@ -75,7 +76,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
click: () => this.zone.run(() => {
(tab.parent as SplitTabComponent).splitTab(tab, dir)
}),
})) as Electron.MenuItemConstructorOptions[],
})) as MenuItemConstructorOptions[],
})
}
}
@ -105,8 +106,8 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = []
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
let items: MenuItemConstructorOptions[] = []
if (tabHeader) {
items = [
...items,
@ -128,7 +129,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
click: () => this.zone.run(() => {
tab.color = color.value
}),
})) as Electron.MenuItemConstructorOptions[],
})) as MenuItemConstructorOptions[],
},
]
}
@ -146,9 +147,9 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent): Promise<MenuItemConstructorOptions[]> {
const process = await tab.getCurrentProcess()
let items: Electron.MenuItemConstructorOptions[] = []
const items: MenuItemConstructorOptions[] = []
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab

View file

@ -349,7 +349,7 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
readable-stream@^2.3.7:
readable-stream@2.3.7, readable-stream@^2.3.7:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@ -470,14 +470,6 @@ winston-transport@^4.4.0:
readable-stream "^2.3.7"
triple-beam "^1.2.0"
winston-transport@winstonjs/winston-transport:
version "4.4.0"
resolved "https://codeload.github.com/winstonjs/winston-transport/tar.gz/6a3bf79175288328d37c6cf4121d6b39eb68f19f"
dependencies:
logform "^2.2.0"
readable-stream "^3.4.0"
triple-beam "^1.2.0"
winston@*, winston@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"

View file

@ -1,6 +1,6 @@
{
"name": "terminus-plugin-manager",
"version": "1.0.104-nightly.0",
"version": "1.0.123-nightly.0",
"description": "Terminus' plugin manager",
"keywords": [
"terminus-builtin-plugin"
@ -15,17 +15,17 @@
"dist"
],
"author": "Eugene Pankov",
"license": "MIT",
"license": "MIT",
"devDependencies": {
"@types/semver": "^7.1.0",
"axios": "^0.19.0",
"mz": "^2.6.0",
"semver": "^7.1.1"
},
"peerDependencies": {
"peerDependencies": {
"@angular/common": "^9.1.11",
"@angular/core": "^9.1.9",
"@angular/forms": "^9.1.11",
"@angular/forms": "^9.1.11",
"@angular/platform-browser": "^9.1.11",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"rxjs": "^6.5.5",

View file

@ -1,6 +1,6 @@
{
"name": "terminus-serial",
"version": "1.0.104-nightly.0",
"version": "1.0.123-nightly.0",
"description": "Serial connection manager for Terminus",
"keywords": [
"terminus-builtin-plugin"
@ -15,7 +15,7 @@
"dist"
],
"author": "Eugene Pankov",
"license": "MIT",
"license": "MIT",
"devDependencies": {
"@types/node": "14.14.14",
"@types/ssh2": "^0.5.35",

View file

@ -11,7 +11,7 @@ import { Subscription } from 'rxjs'
/** @hidden */
@Component({
selector: 'serial-tab',
template: BaseTerminalTabComponent.template + require<string>('./serialTab.component.pug'),
template: BaseTerminalTabComponent.template + (require('./serialTab.component.pug') as string),
styles: [require('./serialTab.component.scss'), ...BaseTerminalTabComponent.styles],
animations: BaseTerminalTabComponent.animations,
})
@ -64,7 +64,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
this.session = this.injector.get(SerialService).createSession(this.connection)
this.session.serviceMessage$.subscribe(msg => {
this.write('\r\n' + colors.black.bgWhite(' serial ') + ' ' + msg + '\r\n')
this.write(`\r\n${colors.black.bgWhite(' serial ')} ${msg}\r\n`)
this.session.resize(this.size.columns, this.size.rows)
})
this.attachSessionHandlers()

View file

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

View file

@ -71,13 +71,9 @@ export class SettingsTabComponent extends BaseTabComponent {
this.configSubscription = config.changed$.subscribe(onConfigChange)
onConfigChange()
const onScreenChange = () => {
hostApp.displaysChanged$.subscribe(() => {
this.zone.run(() => this.screens = this.docking.getScreens())
}
electron.screen.on('display-added', onScreenChange)
electron.screen.on('display-removed', onScreenChange)
electron.screen.on('display-metrics-changed', onScreenChange)
})
hotkeys.getHotkeyDescriptions().then(descriptions => {
this.hotkeyDescriptions = descriptions

View file

@ -1,6 +1,6 @@
{
"name": "terminus-ssh",
"version": "1.0.104-nightly.0",
"version": "1.0.123-nightly.0",
"description": "SSH connection manager for Terminus",
"keywords": [
"terminus-builtin-plugin"

View file

@ -18,7 +18,7 @@ export enum SSHAlgorithmType {
HMAC = 'hmac',
KEX = 'kex',
CIPHER = 'cipher',
HOSTKEY = 'serverHostKey'
HOSTKEY = 'serverHostKey',
}
export interface SSHConnection {
@ -45,7 +45,7 @@ export interface SSHConnection {
}
export enum PortForwardType {
Local, Remote, Dynamic
Local, Remote, Dynamic,
}
export class ForwardedPort {
@ -230,11 +230,11 @@ export class SSHSession extends BaseSession {
this.ssh.on('x11', (details, accept, reject) => {
this.logger.info(`Incoming X11 connection from ${details.srcIP}:${details.srcPort}`)
let displaySpec = process.env.DISPLAY || ':0'
const 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 xHost = displaySpec.split(':')[0]
const xDisplay = parseInt(displaySpec.split(':')[1].split('.')[0] || '0')
const xPort = xDisplay < 100 ? xDisplay + 6000 : xDisplay
const socket = displaySpec.startsWith('/') ? createConnection(displaySpec) : new Socket()
if (!displaySpec.startsWith('/')) {

View file

@ -14,7 +14,7 @@ import { Subscription } from 'rxjs'
/** @hidden */
@Component({
selector: 'ssh-tab',
template: BaseTerminalTabComponent.template + require<string>('./sshTab.component.pug'),
template: BaseTerminalTabComponent.template + (require('./sshTab.component.pug') as string),
styles: [require('./sshTab.component.scss'), ...BaseTerminalTabComponent.styles],
animations: BaseTerminalTabComponent.animations,
})
@ -91,7 +91,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
session.serviceMessage$.subscribe(msg => {
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ' ' + msg + '\r\n')
this.write(`\r\n${colors.black.bgWhite(' SSH ')} ${msg}\r\n`)
session.resize(this.size.columns, this.size.rows)
})

View file

@ -87,7 +87,7 @@ export class SSHService {
try {
const result = await modal.result
passphrase = result?.value
} catch (e) { }
} catch { }
parsedKey = sshpk.parsePrivateKey(
privateKey,
'auto',
@ -269,7 +269,7 @@ export class SSHService {
sock: session.jumpStream,
authHandler: methodsLeft => {
while (true) {
let method = authMethodsLeft.shift()
const method = authMethodsLeft.shift()
if (!method) {
return false
}
@ -348,8 +348,8 @@ export class SSHService {
})
}
let groups: { name: string, connections: SSHConnection[] }[] = []
let connections = this.config.store.ssh.connections
const groups: { name: string, connections: SSHConnection[] }[] = []
const connections = this.config.store.ssh.connections
for (const connection of connections) {
connection.group = connection.group || null
let group = groups.find(x => x.name === connection.group)

View file

@ -1,3 +1,4 @@
import type { MenuItemConstructorOptions } from 'electron'
import { execFile } from 'child_process'
import { Injectable } from '@angular/core'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform } from 'terminus-core'
@ -36,7 +37,7 @@ export class WinSCPContextMenu extends TabContextMenuItemProvider {
}
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
if (this.hostApp.platform !== Platform.Windows || tabHeader) {
return []
}
@ -75,7 +76,7 @@ export class WinSCPContextMenu extends TabContextMenuItemProvider {
if (!path) {
return
}
let args = [await this.getURI(connection)]
const args = [await this.getURI(connection)]
if ((!connection.auth || connection.auth === 'publicKey') && connection.privateKey) {
args.push('/privatekey')
args.push(connection.privateKey)

View file

@ -1,6 +1,6 @@
{
"name": "terminus-terminal",
"version": "1.0.104-nightly.0",
"version": "1.0.123-nightly.0",
"description": "Terminus' terminal emulation core",
"keywords": [
"terminus-builtin-plugin"

View file

@ -1,3 +1,4 @@
import type { MenuItemConstructorOptions } from 'electron'
import { Observable, Subject, Subscription } from 'rxjs'
import { first } from 'rxjs/operators'
import { ToastrService } from 'ngx-toastr'
@ -16,14 +17,14 @@ import { TerminalDecorator } from './decorator'
/** @hidden */
export interface ToastrServiceProxy {
info (_: string)
info: (_: string) => void
}
/**
* A class to base your custom terminal tabs on
*/
export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
static template = require<string>('../components/baseTerminalTab.component.pug')
static styles = [require<string>('../components/terminalTab.component.scss')]
static template: string = require<string>('../components/baseTerminalTab.component.pug')
static styles: string[] = [require<string>('../components/terminalTab.component.scss')]
static animations: AnimationTriggerMetadata[] = [trigger('slideInOut', [
transition(':enter', [
style({ transform: 'translateY(-25%)' }),
@ -277,8 +278,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
})
}
async buildContextMenu (): Promise<Electron.MenuItemConstructorOptions[]> {
let items: Electron.MenuItemConstructorOptions[] = []
async buildContextMenu (): Promise<MenuItemConstructorOptions[]> {
let items: MenuItemConstructorOptions[] = []
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this)))) {
items = items.concat(section)
items.push({ type: 'separator' })
@ -435,7 +436,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
async destroy (): Promise<void> {
super.destroy()
if (this.session && this.session.open) {
if (this.session?.open) {
await this.session.destroy()
}
}
@ -512,7 +513,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.logger.debug(`Resizing to ${columns}x${rows}`)
this.size = { columns, rows }
this.zone.run(() => {
if (this.session && this.session.open) {
if (this.session?.open) {
this.session.resize(columns, rows)
}
})

View file

@ -1,3 +1,4 @@
import type { MenuItemConstructorOptions } from 'electron'
import { BaseTerminalTabComponent } from './baseTerminalTab.component'
/**
@ -7,5 +8,5 @@ import { BaseTerminalTabComponent } from './baseTerminalTab.component'
export abstract class TerminalContextMenuItemProvider {
weight: number
abstract async getItems (tab: BaseTerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]>
abstract async getItems (tab: BaseTerminalTabComponent): Promise<MenuItemConstructorOptions[]>
}

View file

@ -8,7 +8,7 @@ export interface SessionOptions {
command: string
args: string[]
cwd?: string
env?: {[id: string]: string}
env?: Record<string, string>
width?: number
height?: number
pauseAfterExit?: boolean

View file

@ -20,10 +20,10 @@ export class HyperColorSchemes extends TerminalColorSchemeProvider {
try {
const module = (global as any).require(path.join(pluginsPath, plugin))
if (module.decorateConfig) {
let config: any
let config: any = {}
try {
config = module.decorateConfig({})
} catch (error) {
} catch {
console.warn('Could not load Hyper theme:', plugin)
return
}

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/camelcase */
import colors from 'ansi-colors'
import * as ZModem from 'zmodem.js'
import * as fs from 'fs'

View file

@ -99,16 +99,16 @@ export class XTermFrontend extends Frontend {
this.resizeHandler = () => {
try {
if (this.xterm.element && getComputedStyle(this.xterm.element).getPropertyValue('height') !== 'auto') {
let t = window.getComputedStyle(this.xterm.element.parentElement!)
let r = parseInt(t.getPropertyValue('height'))
let n = Math.max(0, parseInt(t.getPropertyValue('width')))
let o = window.getComputedStyle(this.xterm.element)
let i = r - (parseInt(o.getPropertyValue('padding-top')) + parseInt(o.getPropertyValue('padding-bottom')))
let l = n - (parseInt(o.getPropertyValue('padding-right')) + parseInt(o.getPropertyValue('padding-left'))) - this.xtermCore.viewport.scrollBarWidth
let actualCellWidth = this.xtermCore._renderService.dimensions.actualCellWidth || 9
let actualCellHeight = this.xtermCore._renderService.dimensions.actualCellHeight || 17
let cols = Math.floor(l / actualCellWidth)
let rows = Math.floor(i / actualCellHeight)
const t = window.getComputedStyle(this.xterm.element.parentElement!)
const r = parseInt(t.getPropertyValue('height'))
const n = Math.max(0, parseInt(t.getPropertyValue('width')))
const o = window.getComputedStyle(this.xterm.element)
const i = r - (parseInt(o.getPropertyValue('padding-top')) + parseInt(o.getPropertyValue('padding-bottom')))
const l = n - (parseInt(o.getPropertyValue('padding-right')) + parseInt(o.getPropertyValue('padding-left'))) - this.xtermCore.viewport.scrollBarWidth
const actualCellWidth = this.xtermCore._renderService.dimensions.actualCellWidth || 9
const actualCellHeight = this.xtermCore._renderService.dimensions.actualCellHeight || 17
const cols = Math.floor(l / actualCellWidth)
const rows = Math.floor(i / actualCellHeight)
if (!isNaN(cols) && !isNaN(rows)) {
this.xterm.resize(cols, rows)

View file

@ -171,7 +171,7 @@ export default class TerminalModule { // eslint-disable-line @typescript-eslint/
argv = argv.slice(1)
}
if(require('yargs').parse(argv.slice(1))._[0] !== 'open'){
if (require('yargs').parse(argv.slice(1))._[0] !== 'open'){
app.ready$.subscribe(() => {
terminal.openTab()
})

View file

@ -267,7 +267,7 @@ export class Session extends BaseSession {
return null
}
if (process.platform === 'darwin') {
let lines: string[]
let lines: string[] = []
try {
lines = (await exec(`lsof -p ${this.truePID} -Fn`))[0].toString().split('\n')
} catch (e) {
@ -312,7 +312,7 @@ export class Session extends BaseSession {
private processOSC1337 (data: Buffer) {
if (data.includes(OSC1337Prefix)) {
const preData = data.subarray(0, data.indexOf(OSC1337Prefix))
let params = data.subarray(data.indexOf(OSC1337Prefix) + OSC1337Prefix.length)
const params = data.subarray(data.indexOf(OSC1337Prefix) + OSC1337Prefix.length)
const postData = params.subarray(params.indexOf(OSC1337Suffix) + OSC1337Suffix.length)
const paramString = params.subarray(0, params.indexOf(OSC1337Suffix)).toString()

View file

@ -1,3 +1,4 @@
import { MenuItemConstructorOptions } from 'electron'
import { Injectable, NgZone, Optional, Inject } from '@angular/core'
import { ToastrService } from 'ngx-toastr'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, SplitTabComponent } from 'terminus-core'
@ -18,11 +19,11 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
if (!(tab instanceof TerminalTabComponent)) {
return []
}
const items: Electron.MenuItemConstructorOptions[] = [
const items: MenuItemConstructorOptions[] = [
{
label: 'Save as profile',
click: () => this.zone.run(async () => {
@ -61,10 +62,10 @@ export class NewTabContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
const profiles = await this.terminalService.getProfiles()
const items: Electron.MenuItemConstructorOptions[] = [
const items: MenuItemConstructorOptions[] = [
{
label: 'New terminal',
click: () => this.zone.run(() => {
@ -138,7 +139,7 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
if (tabHeader) {
return []
}
@ -178,12 +179,12 @@ export class LegacyContextMenu extends TabContextMenuItemProvider {
super()
}
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
async getItems (tab: BaseTabComponent, _tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
if (!this.contextMenuProviders) {
return []
}
if (tab instanceof BaseTerminalTabComponent) {
let items: Electron.MenuItemConstructorOptions[] = []
let items: MenuItemConstructorOptions[] = []
for (const p of this.contextMenuProviders) {
items = items.concat(await p.getItems(tab))
}

BIN
tmp/assets/activity.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

55
tmp/assets/logo.svg Normal file
View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{opacity:0.16;fill:url(#SVGID_2_);}
.st2{fill:url(#SVGID_3_);}
.st3{opacity:0.16;fill:url(#SVGID_4_);}
.st4{fill:url(#SVGID_5_);}
.st5{opacity:0.15;fill:url(#SVGID_6_);}
.st6{fill:url(#SVGID_7_);}
</style>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="260.9675" y1="871.1813" x2="919.1845" y2="491.1596">
<stop offset="0" style="stop-color:#669ABD"/>
<stop offset="1" style="stop-color:#77DBDB"/>
</linearGradient>
<polygon class="st0" points="297.54,934.52 882.6,596.72 882.61,427.82 297.54,765.65 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="553.5051" y1="617.8278" x2="626.647" y2="744.5132">
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon class="st1" points="297.54,934.52 882.6,596.72 882.61,427.82 297.54,765.65 "/>
</g>
<g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="114.6631" y1="744.5275" x2="334.0905" y2="871.2141">
<stop offset="0" style="stop-color:#6A8FAD"/>
<stop offset="1" style="stop-color:#669ABD"/>
</linearGradient>
<polygon class="st2" points="151.23,681.18 151.22,850.09 297.54,934.52 297.54,765.65 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="260.9478" y1="744.5281" x2="187.8059" y2="871.2135">
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon class="st3" points="151.23,681.18 151.22,850.09 297.54,934.52 297.54,765.65 "/>
</g>
<g>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="114.663" y1="237.793" x2="553.5026" y2="491.1571">
<stop offset="0" style="stop-color:#6A8FAD"/>
<stop offset="1" style="stop-color:#669ABD"/>
</linearGradient>
<polygon class="st4" points="151.23,174.45 151.21,343.36 443.79,512.27 590.08,427.81 "/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="370.6562" y1="301.1281" x2="297.5094" y2="427.8221">
<stop offset="0.5588" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon class="st5" points="151.23,174.45 151.21,343.36 443.79,512.27 590.08,427.81 "/>
</g>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="78.0912" y1="554.4979" x2="736.3375" y2="174.4593">
<stop offset="0" style="stop-color:#CCECFF"/>
<stop offset="1" style="stop-color:#9FECED"/>
</linearGradient>
<polygon class="st6" points="297.51,765.64 151.23,681.18 590.08,427.81 151.23,174.45 297.5,90 882.61,427.82 "/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

BIN
tmp/assets/tray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

4
tmp/dev-app-update.yml Normal file
View file

@ -0,0 +1,4 @@
owner: eugeny
repo: terminus
provider: github
updaterCacheDirName: terminus-updater

22
tmp/index.pug Normal file
View file

@ -0,0 +1,22 @@
doctype html
html
head
meta(charset='UTF-8')
base(href='index.html')
script.
console.timeStamp('index')
window.nodeRequire = require
script(src='./preload.js')
script(src='./bundle.js', defer)
style.
body { transition: 0.5s background; }
body
style#custom-css
app-root
.preload-logo
div
.terminus-logo
h1.terminus-title Terminus
sup α
.progress
.bar(style='width: 0%')

230
tmp/lib/app.ts Normal file
View file

@ -0,0 +1,230 @@
import { app, ipcMain, Menu, Tray, shell, screen, globalShortcut, MenuItemConstructorOptions } from 'electron'
import { loadConfig } from './config'
import { Window, WindowOptions } from './window'
export class Application {
private tray: Tray
private windows: Window[] = []
constructor () {
ipcMain.on('app:config-change', (_event, config) => {
this.broadcast('host:config-change', config)
})
ipcMain.on('app:register-global-hotkey', (_event, specs) => {
globalShortcut.unregisterAll()
for (const spec of specs) {
globalShortcut.register(spec, () => {
this.onGlobalHotkey()
})
}
})
const configData = loadConfig()
if (process.platform === 'linux') {
app.commandLine.appendSwitch('no-sandbox')
if (((configData.appearance || {}).opacity || 1) !== 1) {
app.commandLine.appendSwitch('enable-transparent-visuals')
app.disableHardwareAcceleration()
}
}
app.commandLine.appendSwitch('disable-http-cache')
app.commandLine.appendSwitch('lang', 'EN')
app.allowRendererProcessReuse = false
for (const flag of configData.flags || [['force_discrete_gpu', '0']]) {
app.commandLine.appendSwitch(flag[0], flag[1])
}
}
init (): void {
screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
screen.on('display-added', () => this.broadcast('host:displays-changed'))
screen.on('display-removed', () => this.broadcast('host:displays-changed'))
}
async newWindow (options?: WindowOptions): Promise<Window> {
const window = new Window(options)
this.windows.push(window)
window.visible$.subscribe(visible => {
if (visible) {
this.disableTray()
} else {
this.enableTray()
}
})
window.closed$.subscribe(() => {
this.windows = this.windows.filter(x => x !== window)
})
if (process.platform === 'darwin') {
this.setupMenu()
}
await window.ready
return window
}
onGlobalHotkey (): void {
if (this.windows.some(x => x.isFocused())) {
for (const window of this.windows) {
window.hide()
}
} else {
for (const window of this.windows) {
window.present()
}
}
}
presentAllWindows (): void {
for (const window of this.windows) {
window.present()
}
}
broadcast (event: string, ...args: any[]): void {
for (const window of this.windows) {
window.send(event, ...args)
}
}
async send (event: string, ...args: any[]): Promise<void> {
if (!this.hasWindows()) {
await this.newWindow()
}
this.windows.filter(w => !w.isDestroyed())[0].send(event, ...args)
}
enableTray (): void {
if (this.tray) {
return
}
if (process.platform === 'darwin') {
this.tray = new Tray(`${app.getAppPath()}/assets/tray-darwinTemplate.png`)
this.tray.setPressedImage(`${app.getAppPath()}/assets/tray-darwinHighlightTemplate.png`)
} else {
this.tray = new Tray(`${app.getAppPath()}/assets/tray.png`)
}
this.tray.on('click', () => setTimeout(() => this.focus()))
const contextMenu = Menu.buildFromTemplate([{
label: 'Show',
click: () => this.focus(),
}])
if (process.platform !== 'darwin') {
this.tray.setContextMenu(contextMenu)
}
this.tray.setToolTip(`Terminus ${app.getVersion()}`)
}
disableTray (): void {
if (this.tray) {
this.tray.destroy()
this.tray = null
}
}
hasWindows (): boolean {
return !!this.windows.length
}
focus (): void {
for (const window of this.windows) {
window.show()
}
}
handleSecondInstance (argv: string[], cwd: string): void {
this.presentAllWindows()
this.windows[this.windows.length - 1].handleSecondInstance(argv, cwd)
}
private setupMenu () {
const template: MenuItemConstructorOptions[] = [
{
label: 'Application',
submenu: [
{ role: 'about', label: 'About Terminus' },
{ type: 'separator' },
{
label: 'Preferences',
accelerator: 'Cmd+,',
click: async () => {
if (!this.hasWindows()) {
await this.newWindow()
}
this.windows[0].send('host:preferences-menu')
},
},
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{
label: 'Quit',
accelerator: 'Cmd+Q',
click () {
app.quit()
},
},
],
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
],
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' },
],
},
{
role: 'window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'front' },
],
},
{
role: 'help',
submenu: [
{
label: 'Website',
click () {
shell.openExternal('https://eugeny.github.io/terminus')
},
},
],
},
]
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
}
}

45
tmp/lib/cli.ts Normal file
View file

@ -0,0 +1,45 @@
import { app } from 'electron'
export function parseArgs (argv: string[], cwd: string): any {
if (argv[0].includes('node')) {
argv = argv.slice(1)
}
return require('yargs')
.usage('terminus [command] [arguments]')
.command('open [directory]', 'open a shell in a directory', {
directory: { type: 'string', 'default': cwd },
})
.command('run [command...]', 'run a command in the terminal', {
command: { type: 'string' },
})
.command('profile [profileName]', 'open a tab with specified profile', {
profileName: { type: 'string' },
})
.command('paste [text]', 'paste stdin into the active tab', yargs => {
return yargs.option('escape', {
alias: 'e',
type: 'boolean',
describe: 'Perform shell escaping',
}).positional('text', {
type: 'string',
})
})
.version('version', '', app.getVersion())
.option('debug', {
alias: 'd',
describe: 'Show DevTools on start',
type: 'boolean',
})
.option('hidden', {
describe: 'Start minimized',
type: 'boolean',
})
.option('version', {
alias: 'v',
describe: 'Show version and exit',
type: 'boolean',
})
.help('help')
.parse(argv.slice(1))
}

13
tmp/lib/config.ts Normal file
View file

@ -0,0 +1,13 @@
import * as fs from 'fs'
import * as path from 'path'
import * as yaml from 'js-yaml'
import { app } from 'electron'
export function loadConfig (): any {
const configPath = path.join(app.getPath('userData'), 'config.yaml')
if (fs.existsSync(configPath)) {
return yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
} else {
return {}
}
}

68
tmp/lib/index.ts Normal file
View file

@ -0,0 +1,68 @@
import './portable'
import './sentry'
import './lru'
import { app, ipcMain, Menu } from 'electron'
import { parseArgs } from './cli'
import { Application } from './app'
import electronDebug = require('electron-debug')
if (!process.env.TERMINUS_PLUGINS) {
process.env.TERMINUS_PLUGINS = ''
}
const application = new Application()
ipcMain.on('app:new-window', () => {
application.newWindow()
})
app.on('activate', () => {
if (!application.hasWindows()) {
application.newWindow()
} else {
application.focus()
}
})
app.on('window-all-closed', () => {
app.quit()
})
process.on('uncaughtException' as any, err => {
console.log(err)
application.broadcast('uncaughtException', err)
})
app.on('second-instance', (_event, argv, cwd) => {
application.handleSecondInstance(argv, cwd)
})
const argv = parseArgs(process.argv, process.cwd())
if (!app.requestSingleInstanceLock()) {
app.quit()
app.exit(0)
}
if (argv.d) {
electronDebug({
isEnabled: true,
showDevTools: true,
devToolsMode: 'undocked',
})
}
app.on('ready', () => {
if (process.platform === 'darwin') {
app.dock.setMenu(Menu.buildFromTemplate([
{
label: 'New window',
click () {
this.app.newWindow()
},
},
]))
}
application.init()
application.newWindow({ hidden: argv.hidden })
})

17
tmp/lib/lru.ts Normal file
View file

@ -0,0 +1,17 @@
import * as LRU from 'lru-cache'
import * as fs from 'fs'
const lru = new LRU({ max: 256, maxAge: 250 })
const origLstat = fs.realpathSync.bind(fs)
// NB: The biggest offender of thrashing realpathSync is the node module system
// itself, which we can't get into via any sane means.
require('fs').realpathSync = function (p) {
let r = lru.get(p)
if (r) {
return r
}
r = origLstat(p)
lru.set(p, r)
return r
}

24
tmp/lib/portable.ts Normal file
View file

@ -0,0 +1,24 @@
import * as path from 'path'
import * as fs from 'fs'
let appPath: string | null = null
try {
appPath = path.dirname(require('electron').app.getPath('exe'))
} catch {
appPath = path.dirname(require('electron').remote.app.getPath('exe'))
}
if (null != appPath) {
if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
}
const portableData = path.join(appPath, 'data')
if (fs.existsSync(portableData)) {
console.log('reset user data to ' + portableData)
try {
require('electron').app.setPath('userData', portableData)
} catch {
require('electron').remote.app.setPath('userData', portableData)
}
}
}

21
tmp/lib/sentry.ts Normal file
View file

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

389
tmp/lib/window.ts Normal file
View file

@ -0,0 +1,389 @@
import * as glasstron from 'glasstron'
if (process.platform === 'win32' || process.platform === 'linux') {
glasstron.init()
}
import { Subject, Observable } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowConstructorOptions } from 'electron'
import ElectronConfig = require('electron-config')
import * as os from 'os'
import * as path from 'path'
import { parseArgs } from './cli'
import { loadConfig } from './config'
let DwmEnableBlurBehindWindow: any = null
if (process.platform === 'win32') {
DwmEnableBlurBehindWindow = require('windows-blurbehind').DwmEnableBlurBehindWindow
}
export interface WindowOptions {
hidden?: boolean
}
export class Window {
ready: Promise<void>
private visible = new Subject<boolean>()
private closed = new Subject<void>()
private window: BrowserWindow
private windowConfig: ElectronConfig
private windowBounds: Rectangle
private closing = false
private lastVibrancy: {enabled: boolean, type?: string} | null = null
private disableVibrancyWhileDragging = false
private configStore: any
get visible$ (): Observable<boolean> { return this.visible }
get closed$ (): Observable<void> { return this.closed }
constructor (options?: WindowOptions) {
this.configStore = loadConfig()
options = options || {}
this.windowConfig = new ElectronConfig({ name: 'window' })
this.windowBounds = this.windowConfig.get('windowBoundaries')
const maximized = this.windowConfig.get('maximized')
const bwOptions: BrowserWindowConstructorOptions = {
width: 800,
height: 600,
title: 'Terminus',
minWidth: 400,
minHeight: 300,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'sentry.js'),
backgroundThrottling: false,
enableRemoteModule: true,
},
frame: false,
show: false,
backgroundColor: '#00000000',
}
if (this.windowBounds) {
Object.assign(bwOptions, this.windowBounds)
const closestDisplay = screen.getDisplayNearestPoint( { x: this.windowBounds.x, y: this.windowBounds.y } )
const [left1, top1, right1, bottom1] = [this.windowBounds.x, this.windowBounds.y, this.windowBounds.x + this.windowBounds.width, this.windowBounds.y + this.windowBounds.height]
const [left2, top2, right2, bottom2] = [closestDisplay.bounds.x, closestDisplay.bounds.y, closestDisplay.bounds.x + closestDisplay.bounds.width, closestDisplay.bounds.y + closestDisplay.bounds.height]
if ((left2 > right1 || right2 < left1 || top2 > bottom1 || bottom2 < top1) && !maximized) {
bwOptions.x = closestDisplay.bounds.width / 2 - bwOptions.width / 2
bwOptions.y = closestDisplay.bounds.height / 2 - bwOptions.height / 2
}
}
if ((this.configStore.appearance || {}).frame === 'native') {
bwOptions.frame = true
} else {
if (process.platform === 'darwin') {
bwOptions.titleBarStyle = 'hiddenInset'
}
}
this.window = new BrowserWindow(bwOptions)
this.window.once('ready-to-show', () => {
if (process.platform === 'darwin') {
this.window.setVibrancy('window')
} else if (process.platform === 'win32' && (this.configStore.appearance || {}).vibrancy) {
this.setVibrancy(true)
}
if (!options.hidden) {
if (maximized) {
this.window.maximize()
} else {
this.window.show()
}
this.window.focus()
this.window.moveTop()
}
})
this.window.on('blur', () => {
if (this.configStore.appearance?.dockHideOnBlur) {
this.hide()
}
})
this.window.loadURL(`file://${app.getAppPath()}/dist/index.html?${this.window.id}`, { extraHeaders: 'pragma: no-cache\n' })
if (process.platform !== 'darwin') {
this.window.setMenu(null)
}
this.setupWindowManagement()
this.ready = new Promise(resolve => {
const listener = event => {
if (event.sender === this.window.webContents) {
ipcMain.removeListener('app:ready', listener as any)
resolve()
}
}
ipcMain.on('app:ready', listener)
})
}
setVibrancy (enabled: boolean, type?: string): void {
this.lastVibrancy = { enabled, type }
if (process.platform === 'win32') {
if (parseFloat(os.release()) >= 10) {
glasstron.update(this.window, {
windows: { blurType: enabled ? type === 'fluent' ? 'acrylic' : 'blurbehind' : null },
})
} else {
DwmEnableBlurBehindWindow(this.window, enabled)
}
} else if (process.platform === 'linux') {
glasstron.update(this.window, {
linux: { requestBlur: enabled },
})
this.window.setBackgroundColor(enabled ? '#00000000' : '#131d27')
} else {
this.window.setVibrancy(enabled ? 'dark' : null as any) // electron issue 20269
}
}
show (): void {
this.window.show()
this.window.moveTop()
}
focus (): void {
this.window.focus()
}
send (event: string, ...args: any[]): void {
if (!this.window) {
return
}
this.window.webContents.send(event, ...args)
if (event === 'host:config-change') {
this.configStore = args[0]
}
}
isDestroyed (): boolean {
return !this.window || this.window.isDestroyed()
}
isFocused (): boolean {
return this.window.isFocused()
}
hide (): void {
if (process.platform === 'darwin') {
// Lose focus
Menu.sendActionToFirstResponder('hide:')
}
this.window.blur()
if (process.platform !== 'darwin') {
this.window.hide()
}
}
present (): void {
if (!this.window.isVisible()) {
// unfocused, invisible
this.window.show()
this.window.focus()
} else {
if (!this.configStore.appearance?.dock || this.configStore.appearance?.dock === 'off') {
// not docked, visible
setTimeout(() => {
this.window.show()
this.window.focus()
})
} else {
if (this.configStore.appearance?.dockAlwaysOnTop) {
// docked, visible, on top
this.window.hide()
} else {
// docked, visible, not on top
this.window.focus()
}
}
}
}
handleSecondInstance (argv: string[], cwd: string): void {
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
}
private setupWindowManagement () {
this.window.on('show', () => {
this.visible.next(true)
this.send('host:window-shown')
})
this.window.on('hide', () => {
this.visible.next(false)
})
const moveSubscription = new Observable<void>(observer => {
this.window.on('move', () => observer.next())
}).pipe(debounceTime(250)).subscribe(() => {
this.send('host:window-moved')
})
this.window.on('closed', () => {
moveSubscription.unsubscribe()
})
this.window.on('enter-full-screen', () => this.send('host:window-enter-full-screen'))
this.window.on('leave-full-screen', () => this.send('host:window-leave-full-screen'))
this.window.on('close', event => {
if (!this.closing) {
event.preventDefault()
this.send('host:window-close-request')
return
}
this.windowConfig.set('windowBoundaries', this.windowBounds)
this.windowConfig.set('maximized', this.window.isMaximized())
})
this.window.on('closed', () => {
this.destroy()
})
this.window.on('resize', () => {
if (!this.window.isMaximized()) {
this.windowBounds = this.window.getBounds()
}
})
this.window.on('move', () => {
if (!this.window.isMaximized()) {
this.windowBounds = this.window.getBounds()
}
})
this.window.on('focus', () => {
this.send('host:window-focused')
})
ipcMain.on('window-focus', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.focus()
})
ipcMain.on('window-maximize', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.maximize()
})
ipcMain.on('window-unmaximize', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.unmaximize()
})
ipcMain.on('window-toggle-maximize', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
if (this.window.isMaximized()) {
this.window.unmaximize()
} else {
this.window.maximize()
}
})
ipcMain.on('window-minimize', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.minimize()
})
ipcMain.on('window-set-bounds', (event, bounds) => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.setBounds(bounds)
})
ipcMain.on('window-set-always-on-top', (event, flag) => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.setAlwaysOnTop(flag)
})
ipcMain.on('window-set-vibrancy', (event, enabled, type) => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.setVibrancy(enabled, type)
})
ipcMain.on('window-set-title', (event, title) => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.window.setTitle(title)
})
ipcMain.on('window-bring-to-front', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
if (this.window.isMinimized()) {
this.window.restore()
}
this.window.show()
this.window.moveTop()
})
ipcMain.on('window-close', event => {
if (!this.window || event.sender !== this.window.webContents) {
return
}
this.closing = true
this.window.close()
})
this.window.webContents.on('new-window', event => event.preventDefault())
ipcMain.on('window-set-disable-vibrancy-while-dragging', (_event, value) => {
this.disableVibrancyWhileDragging = value
})
this.window.on('will-move', () => {
if (!this.lastVibrancy?.enabled || !this.disableVibrancyWhileDragging) {
return
}
let timeout: number|null = null
const oldVibrancy = this.lastVibrancy
this.setVibrancy(false)
const onMove = () => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
this.window.off('move', onMove)
this.setVibrancy(oldVibrancy.enabled, oldVibrancy.type)
}, 500)
}
this.window.on('move', onMove)
})
}
private destroy () {
this.window = null
this.closed.next()
this.visible.complete()
this.closed.complete()
}
}

54
tmp/package.json Normal file
View file

@ -0,0 +1,54 @@
{
"name": "terminus",
"description": "A terminal for a modern age",
"repository": "https://github.com/eugeny/terminus",
"author": {
"name": "Eugene Pankov",
"email": "e@ajenti.org"
},
"main": "dist/main.js",
"version": "1.0.123-nightly.0",
"dependencies": {
"@angular/animations": "^9.1.9",
"@angular/common": "^9.1.11",
"@angular/compiler": "^9.1.9",
"@angular/core": "^9.1.9",
"@angular/forms": "^9.1.11",
"@angular/platform-browser": "^9.1.9",
"@angular/platform-browser-dynamic": "^9.1.9",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@terminus-term/node-pty": "0.10.0-beta10",
"devtron": "1.4.0",
"electron-config": "2.0.0",
"electron-debug": "^3.0.1",
"electron-is-dev": "1.1.0",
"fontmanager-redux": "1.0.0",
"glasstron": "AryToNeX/Glasstron#dependabot/npm_and_yarn/electron-11.1.0",
"js-yaml": "3.14.0",
"keytar": "^7.2.0",
"mz": "^2.7.0",
"ngx-toastr": "^12.0.1",
"npm": "7.0.15",
"path": "0.12.7",
"rxjs": "^6.5.5",
"rxjs-compat": "^6.6.0",
"yargs": "^15.4.1",
"zone.js": "^0.11.3"
},
"optionalDependencies": {
"macos-native-processlist": "^2.0.0",
"serialport": "^9.0.4",
"windows-blurbehind": "^1.0.1",
"windows-native-registry": "^3.0.0",
"windows-process-tree": "^0.2.4"
},
"peerDependencies": {
"terminus-core": "*",
"terminus-settings": "*",
"terminus-serial": "*",
"terminus-plugin-manager": "*",
"terminus-community-color-schemes": "*",
"terminus-ssh": "*",
"terminus-terminal": "*"
}
}

33
tmp/src/app.module.ts Normal file
View file

@ -0,0 +1,33 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr'
export function getRootModule (plugins: any[]) {
const imports = [
BrowserModule,
...plugins,
NgbModule,
ToastrModule.forRoot({
positionClass: 'toast-bottom-center',
toastClass: 'toast',
preventDuplicates: true,
extendedTimeOut: 5000,
}),
]
const bootstrap = [
...plugins.filter(x => x.bootstrap).map(x => x.bootstrap),
]
if (bootstrap.length === 0) {
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
}

9
tmp/src/entry.preload.ts Normal file
View file

@ -0,0 +1,9 @@
import '../lib/lru'
import 'source-sans-pro/source-sans-pro.css'
import 'source-code-pro/source-code-pro.css'
import '@fortawesome/fontawesome-free/css/solid.css'
import '@fortawesome/fontawesome-free/css/brands.css'
import '@fortawesome/fontawesome-free/css/regular.css'
import '@fortawesome/fontawesome-free/css/fontawesome.css'
import 'ngx-toastr/toastr.css'
import './preload.scss'

65
tmp/src/entry.ts Normal file
View file

@ -0,0 +1,65 @@
import 'zone.js'
import 'core-js/proposals/reflect-metadata'
import 'rxjs'
import * as isDev from 'electron-is-dev'
import './global.scss'
import './toastr.scss'
import { enableProdMode, NgModuleRef, ApplicationRef } from '@angular/core'
import { enableDebugTools } from '@angular/platform-browser'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { getRootModule } from './app.module'
import { findPlugins, loadPlugins, PluginInfo } from './plugins'
// Always land on the start view
location.hash = ''
;(process as any).enablePromiseAPI = true
if (process.platform === 'win32' && !('HOME' in process.env)) {
process.env.HOME = `${process.env.HOMEDRIVE}${process.env.HOMEPATH}`
}
if (isDev) {
console.warn('Running in debug mode')
} else {
enableProdMode()
}
async function bootstrap (plugins: PluginInfo[], safeMode = false): Promise<NgModuleRef<any>> {
if (safeMode) {
plugins = plugins.filter(x => x.isBuiltin)
}
const pluginsModules = await loadPlugins(plugins, (current, total) => {
(document.querySelector('.progress .bar') as HTMLElement).style.width = `${100 * current / total}%` // eslint-disable-line
})
const module = getRootModule(pluginsModules)
window['rootModule'] = module
return platformBrowserDynamic().bootstrapModule(module).then(moduleRef => {
if (isDev) {
const applicationRef = moduleRef.injector.get(ApplicationRef)
const componentRef = applicationRef.components[0]
enableDebugTools(componentRef)
}
return moduleRef
})
}
findPlugins().then(async plugins => {
console.log('Starting with plugins:', plugins)
try {
await bootstrap(plugins)
} catch (error) {
console.error('Angular bootstrapping error:', error)
console.warn('Trying safe mode')
window['safeModeReason'] = error
try {
await bootstrap(plugins, true)
} catch (error) {
console.error('Bootstrap failed:', error)
}
}
})

97
tmp/src/global.scss Normal file
View file

@ -0,0 +1,97 @@
body {
min-height: 100vh;
overflow: hidden;
background: #1D272D;
}
.modal-dialog, .modal-backdrop, .no-drag {
-webkit-app-region: no-drag;
}
.selectable {
user-select: text;
}
[ngbradiogroup] input[type="radio"] {
display: none;
}
.btn {
& > svg {
pointer-events: none;
}
}
.form-line {
display: flex;
border-top: 1px solid rgba(0, 0, 0, 0.2);
align-items: center;
padding: 10px 0;
margin: 0;
min-height: 64px;
.header {
margin-right: auto;
.title {
}
.description {
font-size: 13px;
opacity: .5;
}
}
&>.form-control, &>.input-group {
width: 33%;
}
}
input[type=range] {
-webkit-appearance: none;
background: transparent;
outline: none;
padding: 0;
&:focus {
border-color: transparent;
}
@mixin thumb() {
-webkit-appearance: none;
display: block;
height: 12px;
width: 12px;
background: #aaa;
border-radius: 6px;
cursor: pointer;
margin-top: -4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.95);
transition: 0.25s background;
&:hover {
background: #777;
}
&:active {
background: #666;
}
}
&::-webkit-slider-thumb { @include thumb(); }
&::-moz-range-thumb { @include thumb(); }
&::-ms-thumb { @include thumb(); }
&::thumb { @include thumb(); }
@mixin track() {
height: 4px;
background: #111;
margin: 3px 0 0;
box-sizing: border-box;
}
&::-webkit-slider-runnable-track { @include track(); }
&:focus::-webkit-slider-runnable-track { @include track(); }
&::-moz-range-track { @include track(); }
&::-ms-track { @include track(); }
}

188
tmp/src/plugins.ts Normal file
View file

@ -0,0 +1,188 @@
import * as fs from 'mz/fs'
import * as path from 'path'
const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
const nodeRequire = (global as any).require
function normalizePath (path: string): string {
const cygwinPrefix = '/cygdrive/'
if (path.startsWith(cygwinPrefix)) {
path = path.substring(cygwinPrefix.length).replace('/', '\\')
path = path[0] + ':' + path.substring(1)
}
return path
}
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 userPluginsPath = path.join(
require('electron').remote.app.getPath('userData'),
'plugins',
)
if (!fs.existsSync(userPluginsPath)) {
fs.mkdir(userPluginsPath)
}
Object.assign(window, { builtinPluginsPath, userPluginsPath })
nodeModule.globalPaths.unshift(builtinPluginsPath)
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
// nodeModule.globalPaths.unshift(path.join((process as any).resourcesPath, 'app.asar', 'node_modules'))
if (process.env.TERMINUS_PLUGINS) {
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.push(normalizePath(x)))
}
export type ProgressCallback = (current: number, total: number) => void // eslint-disable-line @typescript-eslint/no-type-alias
export interface PluginInfo {
name: string
description: string
packageName: string
isBuiltin: boolean
version: string
author: string
homepage?: string
path?: string
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, [query])
}
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[]> {
const paths = nodeModule.globalPaths
let foundPlugins: PluginInfo[] = []
const candidateLocations: { pluginDir: string, packageName: string }[] = []
const PREFIX = 'terminus-'
for (let pluginDir of paths) {
pluginDir = normalizePath(pluginDir)
if (!await fs.exists(pluginDir)) {
continue
}
const pluginNames = await fs.readdir(pluginDir)
if (await fs.exists(path.join(pluginDir, 'package.json'))) {
candidateLocations.push({
pluginDir: path.dirname(pluginDir),
packageName: path.basename(pluginDir),
})
}
for (const packageName of pluginNames) {
if (packageName.startsWith(PREFIX)) {
candidateLocations.push({ pluginDir, packageName })
}
}
}
for (const { pluginDir, packageName } of candidateLocations) {
const pluginPath = path.join(pluginDir, packageName)
const infoPath = path.join(pluginPath, 'package.json')
if (!await fs.exists(infoPath)) {
continue
}
const name = packageName.substring(PREFIX.length)
if (foundPlugins.some(x => x.name === name)) {
console.info(`Plugin ${packageName} already exists, overriding`)
foundPlugins = foundPlugins.filter(x => x.name !== name)
}
try {
const info = JSON.parse(await fs.readFile(infoPath, { encoding: 'utf-8' }))
if (!info.keywords || !(info.keywords.includes('terminus-plugin') || info.keywords.includes('terminus-builtin-plugin'))) {
continue
}
let author = info.author
author = author.name || author
foundPlugins.push({
name: name,
packageName: packageName,
isBuiltin: pluginDir === builtinPluginsPath,
version: info.version,
description: info.description,
author,
path: pluginPath,
info,
})
} catch (error) {
console.error('Cannot load package info for', packageName)
}
}
foundPlugins.sort((a, b) => a.name > b.name ? 1 : -1)
;(window as any).installedPlugins = foundPlugins
return foundPlugins
}
export async function loadPlugins (foundPlugins: PluginInfo[], progress: ProgressCallback): Promise<any[]> {
const plugins: any[] = []
progress(0, 1)
let index = 0
for (const foundPlugin of foundPlugins) {
console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`)
progress(index, foundPlugins.length)
try {
const label = 'Loading ' + foundPlugin.name
console.time(label)
const packageModule = nodeRequire(foundPlugin.path)
const pluginModule = packageModule.default.forRoot ? packageModule.default.forRoot() : packageModule.default
pluginModule['pluginName'] = foundPlugin.name
pluginModule['bootstrap'] = packageModule.bootstrap
plugins.push(pluginModule)
console.timeEnd(label)
await new Promise(x => setTimeout(x, 50))
} catch (error) {
console.error(`Could not load ${foundPlugin.name}:`, error)
}
index++
}
progress(1, 1)
return plugins
}

60
tmp/src/preload.scss Normal file
View file

@ -0,0 +1,60 @@
.preload-logo {
-webkit-app-region: drag;
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
display: flex;
animation: 0.5s ease-out fadeIn;
&>div {
width: 200px;
height: 200px;
margin: auto;
flex: none;
.progress {
background: rgba(0,0,0,.25);
height: 3px;
margin: 10px 50px;
.bar {
transition: 1s ease-out width;
background: #a1c5e4;
height: 3px;
}
}
}
}
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
.terminus-logo {
width: 160px;
height: 160px;
background: url('../assets/logo.svg');
background-repeat: none;
background-size: contain;
margin: auto;
}
.terminus-title {
color: #a1c5e4;
font-family: 'Source Sans Pro';
text-align: center;
font-weight: normal;
font-size: 42px;
margin: 0;
sup {
color: #842fe0;
}
}

View file

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

21
tmp/src/toastr.scss Normal file
View file

@ -0,0 +1,21 @@
#toast-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
.toast {
box-shadow: 0 1px 0 rgba(0,0,0,.25);
padding: 10px;
background-image: none;
width: auto;
&.toast-error {
background-color: #BD362F;
}
&.toast-info {
background-color: #555;
}
}
}

32
tmp/tsconfig.json Normal file
View file

@ -0,0 +1,32 @@
{
"compilerOptions": {
"baseUrl": "./src",
"module": "commonjs",
"target": "es2015",
"declaration": false,
"noImplicitAny": false,
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"lib": [
"dom",
"es2015",
"es2015.iterable",
"es2017",
"es7"
]
},
"compileOnSave": false,
"exclude": [
"dist",
"node_modules",
"*/node_modules",
"terminus*",
"platforms"
]
}

30
tmp/tsconfig.main.json Normal file
View file

@ -0,0 +1,30 @@
{
"compilerOptions": {
"baseUrl": "./lib",
"module": "commonjs",
"target": "es2017",
"declaration": false,
"noImplicitAny": false,
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"lib": [
"dom",
"es2015",
"es2015.iterable",
"es2017",
"es7"
]
},
"compileOnSave": false,
"exclude": [
"dist",
"node_modules",
"*/node_modules"
]
}

86
tmp/webpack.config.js Normal file
View file

@ -0,0 +1,86 @@
const path = require('path')
const webpack = require('webpack')
module.exports = {
name: 'terminus',
target: 'node',
entry: {
'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'),
bundle: path.resolve(__dirname, 'src/entry.ts'),
},
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
optimization:{
minimize: false,
},
context: __dirname,
devtool: 'source-map',
output: {
path: path.join(__dirname, 'dist'),
pathinfo: true,
filename: '[name].js',
},
resolve: {
modules: ['src/', 'node_modules', '../node_modules', 'assets/'].map(x => path.join(__dirname, x)),
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.json'),
},
},
},
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /\.css$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{
test: /\.(png|svg)$/,
use: {
loader: 'file-loader',
options: {
name: 'images/[name].[ext]',
},
},
},
{
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
},
},
},
],
},
externals: {
'@angular/core': 'commonjs @angular/core',
'@angular/compiler': 'commonjs @angular/compiler',
'@angular/platform-browser': 'commonjs @angular/platform-browser',
'@angular/platform-browser-dynamic': 'commonjs @angular/platform-browser-dynamic',
'@angular/forms': 'commonjs @angular/forms',
'@angular/common': 'commonjs @angular/common',
'@ng-bootstrap/ng-bootstrap': 'commonjs @ng-bootstrap/ng-bootstrap',
child_process: 'commonjs child_process',
electron: 'commonjs electron',
'electron-is-dev': 'commonjs electron-is-dev',
fs: 'commonjs fs',
'ngx-toastr': 'commonjs ngx-toastr',
module: 'commonjs module',
mz: 'commonjs mz',
path: 'commonjs path',
rxjs: 'commonjs rxjs',
'zone.js': 'commonjs zone.js/dist/zone.js',
},
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.DefinePlugin({
'process.type': '"renderer"'
}),
],
}

View file

@ -0,0 +1,53 @@
const path = require('path')
const webpack = require('webpack')
module.exports = {
name: 'terminus-main',
target: 'node',
entry: {
main: path.resolve(__dirname, 'lib/index.ts'),
},
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
context: __dirname,
devtool: 'source-map',
output: {
path: path.join(__dirname, 'dist'),
pathinfo: true,
filename: '[name].js',
},
resolve: {
modules: ['lib/', 'node_modules', '../node_modules'].map(x => path.join(__dirname, x)),
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'awesome-typescript-loader',
options: {
configFileName: path.resolve(__dirname, 'tsconfig.main.json'),
},
},
},
],
},
externals: {
electron: 'commonjs electron',
'electron-config': 'commonjs electron-config',
'electron-vibrancy': 'commonjs electron-vibrancy',
fs: 'commonjs fs',
glasstron: 'commonjs glasstron',
mz: 'commonjs mz',
path: 'commonjs path',
yargs: 'commonjs yargs',
'windows-swca': 'commonjs windows-swca',
'windows-blurbehind': 'commonjs windows-blurbehind',
},
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.DefinePlugin({
'process.type': '"main"',
}),
],
}

View file

@ -16,7 +16,7 @@
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"importHelpers": true,
"strictNullChecks": false,
"strictNullChecks": true,
"lib": [
"dom",
"es5",

15278
yarn.lock

File diff suppressed because it is too large Load diff