mirror of
https://github.com/Eugeny/tabby-web.git
synced 2025-06-10 06:29:55 +00:00
wip
This commit is contained in:
parent
dc69574c07
commit
e1425c6c80
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
node_modules
|
||||
index.d.ts
|
||||
*.ignore.js
|
||||
*.ignore.js.map
|
||||
dist
|
||||
@ -9,3 +8,5 @@ app-dist
|
||||
db.sqlite3
|
||||
__pycache__
|
||||
.vscode
|
||||
build
|
||||
*.d.ts
|
||||
|
@ -1 +0,0 @@
|
||||
<!DOCTYPE html><html><head><base href="dist/"><meta name="viewport" content="initial-scale=1, minimal-ui, shrink-to-fit=no"><link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400" rel="stylesheet"><script src="index.js" defer></script><title>Terminus</title></head><body><div class="terminal"><iframe src="terminal.html"></iframe></div></body></html>
|
35
package.json
35
package.json
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "terminus-web",
|
||||
"name": "terminus-web-container",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@ -8,24 +8,40 @@
|
||||
},
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@angular/animations": "^11.0.0",
|
||||
"@angular/common": "^11.0.0",
|
||||
"@angular/compiler": "^11.0.0",
|
||||
"@angular/compiler-cli": "^11.0.0",
|
||||
"@angular/core": "^11.0.0",
|
||||
"@angular/forms": "^11.0.0",
|
||||
"@angular/platform-browser": "^11.0.0",
|
||||
"@angular/platform-browser-dynamic": "^11.0.0",
|
||||
"@fortawesome/fontawesome-free": "^5.7.2",
|
||||
"@ng-bootstrap/ng-bootstrap": "11.0.0-beta.1",
|
||||
"@ngtools/webpack": "^12.0.4",
|
||||
"@terminus-term/to-string-loader": "^1.1.7-beta.1",
|
||||
"@types/node": "^11.9.5",
|
||||
"apply-loader": "^2.0.0",
|
||||
"assert": "1.5.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap": "^5.0.1",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"core-js": "^3.8.3",
|
||||
"core-js": "^3.14.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^2.1.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"js-yaml": "^4.1.0",
|
||||
"ngx-toastr": "^14.0.0",
|
||||
"node-sass": "^6.0.0",
|
||||
"pug": "^2.0.3",
|
||||
"pug": "^3.0.2",
|
||||
"pug-cli": "^1.0.0-alpha6",
|
||||
"pug-html-loader": "^1.1.5",
|
||||
"raw-loader": "^1.0.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rxjs": "^7.1.0",
|
||||
"sass-loader": "^11.1.1",
|
||||
"script-loader": "^0.7.2",
|
||||
"setimmediate": "^1.0.5",
|
||||
@ -35,10 +51,11 @@
|
||||
"stream-browserify": "^3.0.0",
|
||||
"string_decoder": "^1.3.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"typescript": "3.3.3333",
|
||||
"val-loader": "^1.1.1",
|
||||
"webpack": "^5.37.0",
|
||||
"webpack-cli": "^4.7.0"
|
||||
"typescript": "~4.1",
|
||||
"val-loader": "^4.0.0",
|
||||
"webpack": "^5.38.1",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/util": "^0.12.0"
|
||||
|
4
polyfills.d.ts
vendored
4
polyfills.d.ts
vendored
@ -1,4 +0,0 @@
|
||||
export declare function utf8Write(string: any, offset: any, length: any): any;
|
||||
export declare function base64Slice(start: any, end: any): any;
|
||||
export declare function latin1Slice(start: any, end: any): string;
|
||||
export declare function utf8Slice(this: any, start: any, end: any): any;
|
21
src/app.module.ts
Normal file
21
src/app.module.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http'
|
||||
import { AppComponent } from './components/app.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
HttpClientXsrfModule,
|
||||
NgbDropdownModule,
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
1
src/assets/logo.svg
Normal file
1
src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 1024 1024" xml:space="preserve" style="enable-background:new 0 0 1024 1024"><style type="text/css">.st0{fill:url(#SVGID_1_)}.st1{opacity:.16;fill:url(#SVGID_2_)}.st2{fill:url(#SVGID_3_)}.st3{opacity:.16;fill:url(#SVGID_4_)}.st4{fill:url(#SVGID_5_)}.st5{opacity:.15;fill:url(#SVGID_6_)}.st6{fill:url(#SVGID_7_)}</style><g><linearGradient id="SVGID_1_" x1="260.967" x2="919.184" y1="871.181" y2="491.16" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#669abd"/><stop offset="1" style="stop-color:#77dbdb"/></linearGradient><polygon points="297.54 934.52 882.6 596.72 882.61 427.82 297.54 765.65" class="st0"/><linearGradient id="SVGID_2_" x1="553.505" x2="626.647" y1="617.828" y2="744.513" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="297.54 934.52 882.6 596.72 882.61 427.82 297.54 765.65" class="st1"/></g><g><linearGradient id="SVGID_3_" x1="114.663" x2="334.091" y1="744.528" y2="871.214" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="151.23 681.18 151.22 850.09 297.54 934.52 297.54 765.65" class="st2"/><linearGradient id="SVGID_4_" x1="260.948" x2="187.806" y1="744.528" y2="871.213" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="151.23 681.18 151.22 850.09 297.54 934.52 297.54 765.65" class="st3"/></g><g><linearGradient id="SVGID_5_" x1="114.663" x2="553.503" y1="237.793" y2="491.157" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#6a8fad"/><stop offset="1" style="stop-color:#669abd"/></linearGradient><polygon points="151.23 174.45 151.21 343.36 443.79 512.27 590.08 427.81" class="st4"/><linearGradient id="SVGID_6_" x1="370.656" x2="297.509" y1="301.128" y2="427.822" gradientUnits="userSpaceOnUse"><stop offset=".559" style="stop-color:#000;stop-opacity:0"/><stop offset="1" style="stop-color:#000"/></linearGradient><polygon points="151.23 174.45 151.21 343.36 443.79 512.27 590.08 427.81" class="st5"/></g><linearGradient id="SVGID_7_" x1="78.091" x2="736.337" y1="554.498" y2="174.459" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#ccecff"/><stop offset="1" style="stop-color:#9feced"/></linearGradient><polygon points="297.51 765.64 151.23 681.18 590.08 427.81 151.23 174.45 297.5 90 882.61 427.82" class="st6"/></svg>
|
After Width: | Height: | Size: 2.6 KiB |
15
src/components/app.component.pug
Normal file
15
src/components/app.component.pug
Normal file
@ -0,0 +1,15 @@
|
||||
.sidebar
|
||||
img.logo(src='{{_logo}}')
|
||||
|
||||
div(ngbDropdown)
|
||||
button.btn.btn-secondary(ngbDropdownToggle) Cfg
|
||||
//) !{require('../icons/download-solid.svg')}
|
||||
div(ngbDropdownMenu)
|
||||
a(
|
||||
*ngFor='let config of configs',
|
||||
ngbDropdownItem,
|
||||
(click)='selectConfig(config)'
|
||||
) Config modified at {{config.modified_at}}
|
||||
|
||||
.terminal([hidden]='!showApp')
|
||||
iframe(#iframe)
|
34
src/components/app.component.scss
Normal file
34
src/components/app.component.scss
Normal file
@ -0,0 +1,34 @@
|
||||
:host {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 64px;
|
||||
flex: none;
|
||||
|
||||
.logo {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.terminal {
|
||||
flex: 1 1 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
50
src/components/app.component.ts
Normal file
50
src/components/app.component.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { AppConnectorService } from '../services/appConnector.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
templateUrl: './app.component.pug',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent {
|
||||
_logo = require('../assets/logo.svg')
|
||||
showApp = false
|
||||
configs: any[] = []
|
||||
@ViewChild('iframe') iframe: ElementRef
|
||||
|
||||
constructor (
|
||||
private appConnector: AppConnectorService,
|
||||
private http: HttpClient,
|
||||
) {
|
||||
window.addEventListener('message', event => {
|
||||
if (event.data === 'request-connector') {
|
||||
this.iframe.nativeElement.contentWindow['__connector__'] = this.appConnector
|
||||
this.iframe.nativeElement.contentWindow.postMessage('connector-ready', '*')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async ngAfterViewInit () {
|
||||
this.configs = await this.http.get('/api/1/configs').toPromise()
|
||||
this.selectConfig(this.configs[0])
|
||||
}
|
||||
|
||||
unloadApp () {
|
||||
this.showApp = false
|
||||
this.iframe.nativeElement.src = 'about:blank'
|
||||
}
|
||||
|
||||
loadApp () {
|
||||
this.iframe.nativeElement.src = '/terminal'
|
||||
this.showApp = true
|
||||
}
|
||||
|
||||
selectConfig (config: any) {
|
||||
this.appConnector.config = config
|
||||
this.unloadApp()
|
||||
setTimeout(() => {
|
||||
this.loadApp()
|
||||
})
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
base(href='dist/')
|
||||
meta(name='viewport', content='initial-scale=1, minimal-ui, shrink-to-fit=no')
|
||||
link(href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400", rel="stylesheet")
|
||||
script(src='index.js', defer)
|
||||
script(src='/build/index.js', defer)
|
||||
title Terminus
|
||||
body
|
||||
.terminal
|
||||
iframe(src='terminal.html')
|
||||
app
|
15
src/index.ts
Normal file
15
src/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import 'zone.js'
|
||||
import 'core-js/proposals/reflect-metadata'
|
||||
import 'core-js/features/array/flat'
|
||||
import 'rxjs'
|
||||
|
||||
import { enableProdMode } from '@angular/core'
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
|
||||
import './styles.scss'
|
||||
import { AppModule } from './app.module'
|
||||
|
||||
|
||||
|
||||
enableProdMode()
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
24
src/services/appConnector.service.ts
Normal file
24
src/services/appConnector.service.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Subject } from 'rxjs'
|
||||
import { debounceTime } from 'rxjs/operators'
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AppConnectorService {
|
||||
config: any
|
||||
private configUpdate = new Subject<string>()
|
||||
|
||||
constructor (private http: HttpClient) {
|
||||
this.configUpdate.pipe(debounceTime(1000)).subscribe(content => {
|
||||
this.http.patch(`/api/1/configs/${this.config.id}`, { content }).toPromise()
|
||||
})
|
||||
}
|
||||
|
||||
async loadConfig (): Promise<string> {
|
||||
return this.config.content
|
||||
}
|
||||
|
||||
async saveConfig (content: string): Promise<void> {
|
||||
this.configUpdate.next(content)
|
||||
}
|
||||
}
|
9
src/styles.scss
Normal file
9
src/styles.scss
Normal file
@ -0,0 +1,9 @@
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$border-radius-lg: 0;
|
||||
$btn-border-width: 3px;
|
||||
|
||||
body {
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
@import "node_modules/bootstrap/scss/bootstrap";
|
0
src/terminal-styles.scss
Normal file
0
src/terminal-styles.scss
Normal file
@ -2,7 +2,7 @@ doctype html
|
||||
html.terminus
|
||||
head
|
||||
meta(charset='UTF-8')
|
||||
script(src='/dist/terminal.js')
|
||||
script(src='/build/terminal.js')
|
||||
style#custom-css
|
||||
style.
|
||||
body { transition: 0.5s background; }
|
@ -15,6 +15,17 @@ Object.assign(window, {
|
||||
})
|
||||
|
||||
|
||||
import * as angularCoreModule from '@angular/core'
|
||||
import * as angularCompilerModule from '@angular/compiler'
|
||||
import * as angularCommonModule from '@angular/common'
|
||||
import * as angularFormsModule from '@angular/forms'
|
||||
import * as angularPlatformBrowserModule from '@angular/platform-browser'
|
||||
import * as angularPlatformBrowserAnimationsModule from '@angular/platform-browser/animations'
|
||||
import * as angularPlatformBrowserDynamicModule from '@angular/platform-browser-dynamic'
|
||||
import * as angularAnimationsModule from '@angular/animations'
|
||||
import * as ngBootstrapModule from '@ng-bootstrap/ng-bootstrap'
|
||||
import * as ngxToastrModule from 'ngx-toastr'
|
||||
|
||||
|
||||
import 'core-js/proposals/reflect-metadata'
|
||||
import '@fortawesome/fontawesome-free/css/solid.css'
|
||||
@ -22,7 +33,6 @@ import '@fortawesome/fontawesome-free/css/brands.css'
|
||||
import '@fortawesome/fontawesome-free/css/fontawesome.css'
|
||||
import 'source-code-pro/source-code-pro.css'
|
||||
import 'source-sans-pro/source-sans-pro.css'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { Duplex } from 'stream-browserify'
|
||||
import { Buffer } from 'buffer'
|
||||
|
||||
@ -88,21 +98,6 @@ async function start () {
|
||||
}
|
||||
}
|
||||
|
||||
let windowReadyCallback
|
||||
const configContent = `
|
||||
enableAnalytics: false
|
||||
enableWelcomeTab: false
|
||||
terminal:
|
||||
font: "Source Code Pro"
|
||||
autoOpen: true
|
||||
rightClick: menu
|
||||
copyOnSelect: false
|
||||
appearance:
|
||||
vibrancy: false
|
||||
pluginBlacklist: []
|
||||
`
|
||||
const config = yaml.load(configContent)
|
||||
|
||||
const mocks = {
|
||||
fs: {
|
||||
realpathSync: path => {
|
||||
@ -110,9 +105,6 @@ async function start () {
|
||||
return path
|
||||
},
|
||||
existsSync: path => {
|
||||
if (path === 'app-path/config.yaml') {
|
||||
return true
|
||||
}
|
||||
console.warn('mock existsSync', path)
|
||||
return false
|
||||
},
|
||||
@ -126,9 +118,6 @@ async function start () {
|
||||
},
|
||||
writeFileSync: () => null,
|
||||
readFileSync: (path) => {
|
||||
if (path === 'app-path/config.yaml') {
|
||||
return configContent
|
||||
}
|
||||
return ''
|
||||
},
|
||||
readFile: (path, enc, cb) => {
|
||||
@ -186,19 +175,13 @@ async function start () {
|
||||
},
|
||||
electron: {
|
||||
ipcRenderer: {
|
||||
on: () => null,
|
||||
on: (e, c) => {
|
||||
console.log('[ipc listen]', e)
|
||||
},
|
||||
once: (e, c) => {
|
||||
if (e === 'start') {
|
||||
windowReadyCallback = c
|
||||
}
|
||||
console.log('[ipc listen once]', e)
|
||||
},
|
||||
send: msg => {
|
||||
if (msg === 'ready') {
|
||||
windowReadyCallback(null, {
|
||||
config,
|
||||
executable: '---',
|
||||
})
|
||||
}
|
||||
console.log('[ipc]', msg)
|
||||
}
|
||||
},
|
||||
@ -277,7 +260,7 @@ async function start () {
|
||||
exists: path => mocks.fs.existsSync(path),
|
||||
existsSync: path => mocks.fs.existsSync(path),
|
||||
},
|
||||
constants: {},
|
||||
constants: require('constants-browserify'),
|
||||
'hterm-umdjs': {
|
||||
hterm: {
|
||||
PreferenceManager: class { set () {} },
|
||||
@ -307,16 +290,16 @@ async function start () {
|
||||
;(mocks.assert as any).notStrictEqual = () => true
|
||||
|
||||
let builtins = {
|
||||
'@angular/core': require('@angular/core'),
|
||||
'@angular/compiler': require('@angular/compiler'),
|
||||
'@angular/common': require('@angular/common'),
|
||||
'@angular/forms': require('@angular/forms'),
|
||||
'@angular/platform-browser': require('@angular/platform-browser'),
|
||||
'@angular/platform-browser/animations': require('@angular/platform-browser/animations'),
|
||||
'@angular/platform-browser-dynamic': require('@angular/platform-browser-dynamic'),
|
||||
'@angular/animations': require('@angular/animations'),
|
||||
'@ng-bootstrap/ng-bootstrap': require('@ng-bootstrap/ng-bootstrap'),
|
||||
'ngx-toastr': require('ngx-toastr'),
|
||||
'@angular/core': angularCoreModule,
|
||||
'@angular/compiler': angularCompilerModule,
|
||||
'@angular/common': angularCommonModule,
|
||||
'@angular/forms': angularFormsModule,
|
||||
'@angular/platform-browser': angularPlatformBrowserModule,
|
||||
'@angular/platform-browser/animations': angularPlatformBrowserAnimationsModule,
|
||||
'@angular/platform-browser-dynamic': angularPlatformBrowserDynamicModule,
|
||||
'@angular/animations': angularAnimationsModule,
|
||||
'@ng-bootstrap/ng-bootstrap': ngBootstrapModule,
|
||||
'ngx-toastr': ngxToastrModule,
|
||||
'deepmerge': require('deepmerge'),
|
||||
'rxjs': require('rxjs'),
|
||||
'rxjs/operators': require('rxjs/operators'),
|
||||
@ -339,18 +322,17 @@ async function start () {
|
||||
|
||||
window['require'].main = {
|
||||
paths: []
|
||||
}
|
||||
} as any
|
||||
|
||||
window['module'] = {
|
||||
paths: []
|
||||
}
|
||||
} as any
|
||||
|
||||
window['require'].resolve = path => null
|
||||
window['require'].resolve = (path => null) as any
|
||||
window['Buffer'] = mocks.buffer.Buffer
|
||||
window['__dirname'] = '__dirname'
|
||||
window['setImmediate'] = setTimeout
|
||||
window['setImmediate'] = setTimeout as any
|
||||
mocks.module['prototype'] = { require: window['require'] }
|
||||
window['terminusConfig'] = configContent
|
||||
|
||||
Buffer.prototype['latin1Slice'] = latin1Slice
|
||||
Buffer.prototype['utf8Slice'] = utf8Slice
|
||||
@ -364,7 +346,7 @@ async function start () {
|
||||
async function loadPlugin (name, file = 'index.js') {
|
||||
const url = `../app-dist/${name}/dist/${file}`
|
||||
const e = document.createElement('script')
|
||||
window['module'] = { exports: {} }
|
||||
window['module'] = { exports: {} } as any
|
||||
window['exports'] = window['module'].exports
|
||||
await new Promise(resolve => {
|
||||
e.onload = resolve
|
||||
@ -392,6 +374,17 @@ async function start () {
|
||||
await loadPlugin('app', 'preload.js')
|
||||
await loadPlugin('app', 'bundle-web.js')
|
||||
document.querySelector('app-root')['style'].display = 'flex'
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
window.addEventListener('message', event => {
|
||||
if (event.data === 'connector-ready') {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
window.parent.postMessage('request-connector', '*')
|
||||
})
|
||||
|
||||
const config = window['__connector__'].loadConfig()
|
||||
window['bootstrapTerminus'](pluginModules, { config })
|
||||
}
|
||||
|
27
styles.scss
27
styles.scss
@ -1,27 +0,0 @@
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$border-radius-lg: 0;
|
||||
$btn-border-width: 3px;
|
||||
|
||||
// @import "node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
|
||||
|
||||
.terminal {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
width: calc(100vw - 200px);
|
||||
height: calc(100vh - 200px);
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 100px black;
|
||||
}
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
20
terminal.d.ts
vendored
20
terminal.d.ts
vendored
@ -1,20 +0,0 @@
|
||||
/// <reference types="node" />
|
||||
import 'core-js/proposals/reflect-metadata';
|
||||
import '@fortawesome/fontawesome-free/css/solid.css';
|
||||
import '@fortawesome/fontawesome-free/css/brands.css';
|
||||
import '@fortawesome/fontawesome-free/css/fontawesome.css';
|
||||
import 'source-code-pro/source-code-pro.css';
|
||||
import 'source-sans-pro/source-sans-pro.css';
|
||||
import { Duplex } from 'stream-browserify';
|
||||
import './terminal-styles.scss';
|
||||
export declare class Socket extends Duplex {
|
||||
webSocket: WebSocket;
|
||||
initialBuffer: Buffer;
|
||||
constructor();
|
||||
connect(): void;
|
||||
setNoDelay(): void;
|
||||
setTimeout(): void;
|
||||
_read(size: number): void;
|
||||
_write(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void;
|
||||
_destroy(error: Error | null, callback: (error: Error | null) => void): void;
|
||||
}
|
19
terminus/app/api.py
Normal file
19
terminus/app/api.py
Normal file
@ -0,0 +1,19 @@
|
||||
# from rest_framework import fields
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
||||
from .models import Config
|
||||
|
||||
|
||||
class ConfigSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Config
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class ConfigViewSet(ModelViewSet):
|
||||
queryset = Config.objects.all()
|
||||
serializer_class = ConfigSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return Config.objects.filter(user=self.request.user)
|
@ -2,6 +2,7 @@ from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_save
|
||||
|
||||
|
||||
class Config(models.Model):
|
||||
@ -19,4 +20,7 @@ class User(AbstractUser):
|
||||
modified_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
# @receiver
|
||||
# @receiver(user_logged_in)
|
||||
# def post_login(sender, user, request, **kwargs):
|
||||
# if not user.active_config:
|
||||
# user.active_config = Config.objects.filter()
|
||||
|
@ -1,16 +1,19 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework import routers
|
||||
|
||||
from . import api
|
||||
from . import consumers
|
||||
from . import views
|
||||
|
||||
|
||||
router = routers.DefaultRouter(trailing_slash=False)
|
||||
# router.register('api/2/auth/saml', SAMLProviderViewSet)
|
||||
router.register('api/1/configs', api.ConfigViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.IndexView.as_view()),
|
||||
path('terminal', views.TerminalView.as_view()),
|
||||
path('app-dist/<path:path>', views.AppDistView.as_view()),
|
||||
path('dist/<path:path>', views.DistView.as_view()),
|
||||
path('build/<path:path>', views.BuildView.as_view()),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
||||
|
@ -7,7 +7,14 @@ from django.views import static
|
||||
|
||||
class IndexView(APIView):
|
||||
def get(self, request, format=None):
|
||||
return static.serve(request, 'terminal.html', document_root=str(settings.BASE_DIR / 'dist'))
|
||||
return static.serve(request, 'index.html', document_root=str(settings.BASE_DIR / 'build'))
|
||||
|
||||
|
||||
class TerminalView(APIView):
|
||||
def get(self, request, format=None):
|
||||
response = static.serve(request, 'terminal.html', document_root=str(settings.BASE_DIR / 'build'))
|
||||
response['X-Frame-Options'] = 'SAMEORIGIN'
|
||||
return response
|
||||
|
||||
|
||||
class AppDistView(APIView):
|
||||
@ -15,6 +22,6 @@ class AppDistView(APIView):
|
||||
return static.serve(request, path, document_root=str(settings.BASE_DIR / 'app-dist'))
|
||||
|
||||
|
||||
class DistView(APIView):
|
||||
class BuildView(APIView):
|
||||
def get(self, request, path=None, format=None):
|
||||
return static.serve(request, path, document_root=str(settings.BASE_DIR / 'dist'))
|
||||
return static.serve(request, path, document_root=str(settings.BASE_DIR / 'build'))
|
||||
|
@ -128,3 +128,8 @@ STATIC_URL = '/static/'
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
CSRF_USE_SESSIONS = False
|
||||
CSRF_COOKIE_HTTPONLY = False
|
||||
CSRF_COOKIE_NAME = 'XSRF-TOKEN'
|
||||
CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src/",
|
||||
"module": "esNext",
|
||||
"target": "es6",
|
||||
"moduleResolution": "node",
|
||||
@ -21,7 +22,10 @@
|
||||
"es5",
|
||||
"es6",
|
||||
"es7"
|
||||
]
|
||||
],
|
||||
"paths": {
|
||||
"*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["app-dist"]
|
||||
}
|
31
tsconfig.main.json
Normal file
31
tsconfig.main.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src/",
|
||||
"module": "esNext",
|
||||
"target": "es6",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"removeComments": false,
|
||||
"emitDeclarationOnly": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedLocals": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"declaration": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
"es6",
|
||||
"es7"
|
||||
],
|
||||
"paths": {
|
||||
"*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["app-dist"]
|
||||
}
|
@ -1,120 +1,4 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
|
||||
module.exports = {
|
||||
target: 'web',
|
||||
entry: {
|
||||
'index.ignore': 'file-loader?name=../index.html!pug-html-loader!' + path.resolve(__dirname, './index.pug'),
|
||||
'terminal.ignore': 'file-loader?name=terminal.html!pug-html-loader!' + path.resolve(__dirname, './terminal.pug'),
|
||||
index: path.resolve(__dirname, 'index.ts'),
|
||||
terminal: path.resolve(__dirname, 'terminal.ts'),
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
pathinfo: true,
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].bundle.js',
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
...[
|
||||
'../terminus/terminus-core/node_modules/',
|
||||
'../terminus/terminus-settings/node_modules/',
|
||||
'../terminus/terminus-terminal/node_modules/',
|
||||
'../terminus/node_modules',
|
||||
'../terminus/app/node_modules',
|
||||
'../terminus/app/assets/',
|
||||
].map(x => path.join(__dirname, x)),
|
||||
'node_modules/',
|
||||
],
|
||||
extensions: ['.ts', '.js'],
|
||||
fallback: {
|
||||
stream: require.resolve('stream-browserify'),
|
||||
assert: require.resolve('assert/'),
|
||||
constants: require.resolve('constants-browserify'),
|
||||
util: require.resolve('util/'),
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
'dns': 'commonjs dns',
|
||||
'tls': 'commonjs tls',
|
||||
'tty': 'commonjs tty',
|
||||
'crypto': 'commonjs crypto',
|
||||
'querystring': 'commonjs querystring',
|
||||
'https': 'commonjs https',
|
||||
'http': 'commonjs http',
|
||||
'url': 'commonjs url',
|
||||
'zlib': 'commonjs zlib',
|
||||
'../build/Release/cpufeatures.node': 'commonjs ../build/Release/cpufeatures.node',
|
||||
'./crypto/build/Release/sshcrypto.node': 'commonjs ./crypto/build/Release/sshcrypto.node',
|
||||
'terminus-core': 'commonjs terminus-core',
|
||||
'terminus-terminal': 'commonjs terminus-terminal',
|
||||
'terminus-settings': 'commonjs terminus-settings',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /terminus\/app\/dist/, use: ['script-loader'] },
|
||||
// { test: /dist\/index/, use: ['raw-loader'] },
|
||||
{
|
||||
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'fonts/[name].[ext]',
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.css$/, use: ['css-loader', 'sass-loader'] },
|
||||
{
|
||||
test: /\.(jpeg|png|svg)?$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const externals = [
|
||||
'@electron/remote',
|
||||
'any-promise',
|
||||
'child_process',
|
||||
'electron-promise-ipc',
|
||||
'electron',
|
||||
'fontmanager-redux',
|
||||
'fs',
|
||||
'keytar',
|
||||
'hterm-umdjs',
|
||||
'macos-native-processlist',
|
||||
'native-process-working-directory',
|
||||
'net',
|
||||
'os',
|
||||
'path',
|
||||
'readline',
|
||||
'serialport',
|
||||
'socksv5',
|
||||
'windows-native-registry',
|
||||
'windows-process-tree',
|
||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||
module.exports = [
|
||||
require('./webpack.main.config'),
|
||||
require('./webpack.terminal.config'),
|
||||
]
|
||||
|
||||
for (const k of externals) {
|
||||
module.exports.externals[k] = `commonjs ${k}`
|
||||
}
|
||||
|
67
webpack.main.config.js
Normal file
67
webpack.main.config.js
Normal file
@ -0,0 +1,67 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const { AngularWebpackPlugin } = require('@ngtools/webpack')
|
||||
|
||||
module.exports = {
|
||||
target: 'web',
|
||||
entry: {
|
||||
'index.ignore': 'file-loader?name=index.html!pug-html-loader!' + path.resolve(__dirname, './src/index.pug'),
|
||||
index: path.resolve(__dirname, 'src/index.ts'),
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.join(__dirname, 'build'),
|
||||
pathinfo: true,
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].bundle.js',
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
'src/',
|
||||
'node_modules/',
|
||||
],
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.[jt]sx?$/,
|
||||
loader: '@ngtools/webpack',
|
||||
},
|
||||
{ test: /terminus\/app\/dist/, use: ['script-loader'] },
|
||||
{
|
||||
test: /\.pug$/,
|
||||
use: ['apply-loader', 'pug-loader'],
|
||||
include: /component\.pug/
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ['@terminus-term/to-string-loader', 'css-loader', 'sass-loader'],
|
||||
include: /component\.scss/
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
exclude: /component\.scss/
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{ test: /\.css$/, use: ['css-loader', 'sass-loader'] },
|
||||
{
|
||||
test: /\.(jpeg|png|svg)?$/,
|
||||
type: 'asset/resource',
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new AngularWebpackPlugin({
|
||||
tsconfig: 'tsconfig.main.json',
|
||||
directTemplateLoading: false,
|
||||
}),
|
||||
],
|
||||
}
|
122
webpack.terminal.config.js
Normal file
122
webpack.terminal.config.js
Normal file
@ -0,0 +1,122 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
|
||||
module.exports = {
|
||||
name: 'web-container-terminal',
|
||||
target: 'web',
|
||||
entry: {
|
||||
'terminal.ignore': 'file-loader?name=terminal.html!pug-html-loader!' + path.resolve(__dirname, './src/terminal.pug'),
|
||||
terminal: path.resolve(__dirname, 'src/terminal.ts'),
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.join(__dirname, 'build'),
|
||||
pathinfo: true,
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].bundle.js',
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
...[
|
||||
'../terminus/terminus-core/node_modules/',
|
||||
'../terminus/terminus-settings/node_modules/',
|
||||
'../terminus/terminus-terminal/node_modules/',
|
||||
'../terminus/node_modules',
|
||||
'../terminus/app/node_modules',
|
||||
'../terminus/app/assets/',
|
||||
'src',
|
||||
].map(x => path.join(__dirname, x)),
|
||||
'node_modules/',
|
||||
],
|
||||
extensions: ['.ts', '.js'],
|
||||
fallback: {
|
||||
stream: require.resolve('stream-browserify'),
|
||||
assert: require.resolve('assert/'),
|
||||
constants: require.resolve('constants-browserify'),
|
||||
util: require.resolve('util/'),
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
'dns': 'commonjs dns',
|
||||
'tls': 'commonjs tls',
|
||||
'tty': 'commonjs tty',
|
||||
'crypto': 'commonjs crypto',
|
||||
'querystring': 'commonjs querystring',
|
||||
'https': 'commonjs https',
|
||||
'http': 'commonjs http',
|
||||
'url': 'commonjs url',
|
||||
'zlib': 'commonjs zlib',
|
||||
'../build/Release/cpufeatures.node': 'commonjs ../build/Release/cpufeatures.node',
|
||||
'./crypto/build/Release/sshcrypto.node': 'commonjs ./crypto/build/Release/sshcrypto.node',
|
||||
'terminus-core': 'commonjs terminus-core',
|
||||
'terminus-terminal': 'commonjs terminus-terminal',
|
||||
'terminus-settings': 'commonjs terminus-settings',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.container.json'),
|
||||
},
|
||||
},
|
||||
},
|
||||
// { test: /terminus\/app\/dist/, use: ['script-loader'] },
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'fonts/[name].[ext]',
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /\.css$/, use: ['css-loader', 'sass-loader'] },
|
||||
{
|
||||
test: /\.(jpeg|png|svg)?$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const externals = [
|
||||
'@electron/remote',
|
||||
'any-promise',
|
||||
'child_process',
|
||||
'electron-promise-ipc',
|
||||
'electron',
|
||||
'fontmanager-redux',
|
||||
'fs',
|
||||
'keytar',
|
||||
'hterm-umdjs',
|
||||
'macos-native-processlist',
|
||||
'native-process-working-directory',
|
||||
'net',
|
||||
'os',
|
||||
'path',
|
||||
'readline',
|
||||
'serialport',
|
||||
'socksv5',
|
||||
'windows-native-registry',
|
||||
'windows-process-tree',
|
||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||
]
|
||||
|
||||
for (const k of externals) {
|
||||
module.exports.externals[k] = `commonjs ${k}`
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user