mirror of
https://github.com/Eugeny/tabby-web.git
synced 2025-06-09 05:59:53 +00:00
.
This commit is contained in:
parent
c9aa8aac18
commit
5b64d034c4
@ -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,
|
||||
|
@ -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].
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -88,3 +88,7 @@ a, button {
|
||||
lib-ngx-image-zoom {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
ngb-tooltip-window {
|
||||
z-index: 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user