This commit is contained in:
Eugene Pankov 2021-10-22 22:35:15 +02:00
parent c9aa8aac18
commit 5b64d034c4
No known key found for this signature in database
GPG Key ID: 5896FCBBDD1CF4F4
9 changed files with 110 additions and 49 deletions

View File

@ -1,5 +1,4 @@
import { NgModule } from '@angular/core'
import { NgbDropdownModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
import { BrowserModule } from '@angular/platform-browser'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { CommonModule } from '@angular/common'
@ -40,8 +39,6 @@ const ROUTES = [
BrowserAnimationsModule,
CommonModule,
FormsModule,
NgbDropdownModule,
NgbModalModule,
FontAwesomeModule,
ClipboardModule,
HttpClientModule,

View File

@ -1,14 +1,40 @@
.sidebar
img.logo(src='{{_logo}}')
button.btn.mt-auto((click)='openConfig()')
fa-icon([icon]='_configIcon', [fixedWidth]='true')
button.btn.mt-auto(
(click)='openConfig()',
placement='right',
ngbTooltip='Manage configs'
)
fa-icon([icon]='_configIcon', [fixedWidth]='true', size='lg')
button.btn((click)='openSettings()')
fa-icon([icon]='_settingsIcon', [fixedWidth]='true')
button.btn(
(click)='openSettings()',
*ngIf='loginService.user',
placement='right',
ngbTooltip='Settings'
)
fa-icon([icon]='_settingsIcon', [fixedWidth]='true', size='lg')
button.btn.mt-3((click)='logout()')
fa-icon([icon]='_logoutIcon', [fixedWidth]='true')
a.btn.mt-3(
href='/login',
*ngIf='!loginService.user',
placement='right',
ngbTooltip='Log in'
)
fa-icon([icon]='_loginIcon', [fixedWidth]='true', size='lg')
.terminal([hidden]='!showApp')
iframe(#iframe)
button.btn.mt-3(
(click)='logout()',
*ngIf='loginService.user',
placement='right',
ngbTooltip='Log out'
)
fa-icon([icon]='_logoutIcon', [fixedWidth]='true', size='lg')
.terminal
iframe(#iframe, [hidden]='!showApp')
.alert.alert-warning.d-flex.border-0.m-0(*ngIf='!loginService.user')
fa-icon.me-2([icon]='_saveIcon', [fixedWidth]='true')
div
div To save profiles and settings, #[a(href='/login') log in].

View File

@ -25,7 +25,7 @@
margin-bottom: 20px;
}
>button, >[ngbdropdown] > button {
>.btn {
width: 64px;
height: 64px;
background: transparent;
@ -34,6 +34,10 @@
&::after {
display: none;
}
&:hover {
color: white;
}
}
}
@ -41,19 +45,20 @@
flex: 1 1 0;
overflow: hidden;
position: relative;
}
display: flex;
flex-direction: column;
iframe {
> * {
flex: none;
}
> iframe {
background: $body-bg;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: none;
flex: 1 1 0;
}
}
.config-menu {
.header {
border-bottom: 1px solid black;

View File

@ -3,14 +3,13 @@ import { HttpClient } from '@angular/common/http'
import { Title } from '@angular/platform-browser'
import { AppConnectorService } from '../services/appConnector.service'
import { faCog, faFile, faPlus, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'
import { faCog, faFile, faPlus, faSave, faSignInAlt, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { SettingsModalComponent } from './settingsModal.component'
import { ConfigModalComponent } from './configModal.component'
import { ConfigService, LoginService } from 'src/common'
import { combineLatest } from 'rxjs'
import { Config, Version } from 'src/api'
import { Router } from '@angular/router'
@Component({
selector: 'main',
@ -20,9 +19,11 @@ import { Router } from '@angular/router'
export class MainComponent {
_logo = require('../../../assets/logo.svg')
_settingsIcon = faCog
_loginIcon = faSignInAlt
_logoutIcon = faSignOutAlt
_addIcon = faPlus
_configIcon = faFile
_saveIcon = faSave
showApp = false
@ -35,7 +36,6 @@ export class MainComponent {
public loginService: LoginService,
private ngbModal: NgbModal,
private config: ConfigService,
private router: Router,
) {
titleService.setTitle('Tabby')
window.addEventListener('message', this.connectorRequestHandler)
@ -50,10 +50,6 @@ export class MainComponent {
async ngAfterViewInit () {
await this.loginService.ready$.toPromise()
if (!this.loginService.user) {
this.router.navigate(['/login'])
return
}
combineLatest(
this.config.activeConfig$,
@ -63,7 +59,7 @@ export class MainComponent {
this.reloadApp(config, version)
}
})
this.config
await this.config.ready$.toPromise()
await this.config.selectDefaultConfig()
}
@ -80,10 +76,12 @@ export class MainComponent {
async loadApp (config, version) {
this.showApp = true
this.iframe.nativeElement.src = '/terminal'
if (this.loginService.user) {
await this.http.patch(`/api/1/configs/${config.id}`, {
last_used_with_version: version.version,
}).toPromise()
}
}
reloadApp (config: Config, version: Version) {
// TODO check config incompatibility

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core'
import { NgbDropdownModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
import { NgbDropdownModule, NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { CommonModule } from '@angular/common'
import { FormsModule } from '@angular/forms'
import { RouterModule } from '@angular/router'
@ -31,6 +31,7 @@ const ROUTES = [
FormsModule,
NgbDropdownModule,
NgbModalModule,
NgbTooltipModule,
ClipboardModule,
FontAwesomeModule,
RouterModule.forChild(ROUTES),

View File

@ -39,7 +39,7 @@ export class SocketProxy {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async connect (options: any): Promise<void> {
if (!this.loginService.user.is_pro && this.appConnector.sockets.length > this.appConnector.connectionLimit && !window.sessionStorage['upgrade-skip-active']) {
if (!this.loginService.user?.is_pro && this.appConnector.sockets.length > this.appConnector.connectionLimit && !window.sessionStorage['upgrade-skip-active']) {
let skipped = false
try {
skipped = await this.zone.run(() => this.ngbModal.open(UpgradeModalComponent)).result
@ -51,8 +51,8 @@ export class SocketProxy {
}
this.options = options
this.url = this.loginService.user.custom_connection_gateway
this.authToken = this.loginService.user.custom_connection_gateway_token
this.url = this.loginService.user?.custom_connection_gateway
this.authToken = this.loginService.user?.custom_connection_gateway_token
if (!this.url) {
try {
const gateway = await this.appConnector.chooseConnectionGateway()
@ -151,11 +151,14 @@ export class AppConnectorService {
private http: HttpClient,
private commonService: CommonService,
private zone: NgZone,
private loginService: LoginService,
) {
this.configUpdate.pipe(debounceTime(1000)).subscribe(async content => {
if (this.loginService.user) {
const result = await this.http.patch(`/api/1/configs/${this.config.id}`, { content }).toPromise()
Object.assign(this.config, result)
}
})
}

View File

@ -30,14 +30,29 @@ export class ConfigService {
}
async updateUser () {
if (!this.loginService.user) {
return
}
await this.http.put('/api/1/user', this.user).toPromise()
}
async createNewConfig (): Promise<Config> {
const config = await this.http.post('/api/1/configs', {
const configData = {
content: '{}',
last_used_with_version: this._activeVersion?.version ?? this.getLatestStableVersion().version,
}).toPromise()
}
if (!this.loginService.user) {
const config = {
id: Date.now(),
name: `Temporary config at ${new Date()}`,
created_at: new Date(),
modified_at: new Date(),
...configData,
}
this.configs.push(config)
return config
}
const config = await this.http.post('/api/1/configs', configData).toPromise()
this.configs.push(config)
return config
}
@ -47,8 +62,11 @@ export class ConfigService {
}
async duplicateActiveConfig () {
const copy = {...this._activeConfig, pk: undefined}
this.configs.push(await this.http.post('/api/1/configs', copy).toPromise())
let copy = {...this._activeConfig, pk: undefined, id: undefined}
if (this.loginService.user) {
copy = await this.http.post('/api/1/configs', copy).toPromise()
}
this.configs.push(copy)
}
async selectVersion (version: Version) {
@ -66,23 +84,29 @@ export class ConfigService {
this._activeConfig = config
this.activeConfig$.next(config)
this.selectVersion(matchingVersion)
if (this.loginService.user) {
this.loginService.user.active_config = config.id
await this.loginService.updateUser()
}
}
async selectDefaultConfig () {
await this.ready$.toPromise()
await this.loginService.ready$.toPromise()
this.selectConfig(this.configs.find(c => c.id === this.loginService.user.active_config) ?? this.configs[0])
this.selectConfig(this.configs.find(c => c.id === this.loginService.user?.active_config) ?? this.configs[0])
}
async deleteConfig (config: Config) {
if (this.loginService.user) {
await this.http.delete(`/api/1/configs/${config.id}`).toPromise()
}
this.configs = this.configs.filter(x => x.id !== config.id)
}
private async init () {
if (this.loginService.user) {
this.configs = await this.http.get('/api/1/configs').toPromise()
}
this.versions = await this.http.get('/api/1/versions').toPromise()
this.versions.sort((a, b) => -semverCompare(a.version, b.version))

View File

@ -6,7 +6,7 @@ import { User } from '../../api'
@Injectable({ providedIn: 'root' })
export class LoginService {
user: User
user: User | null
ready$ = new AsyncSubject<void>()
constructor (private http: HttpClient) {
@ -14,6 +14,9 @@ export class LoginService {
}
async updateUser () {
if (!this.user) {
return
}
await this.http.put('/api/1/user', this.user).toPromise()
}

View File

@ -88,3 +88,7 @@ a, button {
lib-ngx-image-zoom {
display: flex;
}
ngb-tooltip-window {
z-index: 1;
}