mirror of
https://github.com/Eugeny/tabby-web.git
synced 2025-06-09 14:09:57 +00:00
wip
This commit is contained in:
parent
df108d9071
commit
6bd5aff8b7
18
src/api.ts
18
src/api.ts
@ -1,3 +1,8 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { Resolve } from '@angular/router'
|
||||||
|
import { Observable } from 'rxjs'
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
active_config: number
|
active_config: number
|
||||||
active_version: string
|
active_version: string
|
||||||
@ -17,3 +22,16 @@ export interface Config {
|
|||||||
export interface Version {
|
export interface Version {
|
||||||
version: string
|
version: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InstanceInfo {
|
||||||
|
login_enabled: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class InstanceInfoResolver implements Resolve<Observable<InstanceInfo>> {
|
||||||
|
constructor (private http: HttpClient) { }
|
||||||
|
|
||||||
|
resolve(): Observable<InstanceInfo> {
|
||||||
|
return this.http.get('/api/1/instance-info').toPromise()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,11 +13,30 @@ import { ConfigModalComponent } from './components/configModal.component'
|
|||||||
import { SettingsModalComponent } from './components/settingsModal.component'
|
import { SettingsModalComponent } from './components/settingsModal.component'
|
||||||
import { HomeComponent } from './components/home.component'
|
import { HomeComponent } from './components/home.component'
|
||||||
import { LoginComponent } from './components/login.component'
|
import { LoginComponent } from './components/login.component'
|
||||||
|
import { InstanceInfoResolver } from './api'
|
||||||
|
|
||||||
const ROUTES = [
|
const ROUTES = [
|
||||||
{ path: '', component: HomeComponent },
|
{
|
||||||
{ path: 'app', component: MainComponent },
|
path: '',
|
||||||
{ path: 'login', component: LoginComponent },
|
component: HomeComponent,
|
||||||
|
resolve: {
|
||||||
|
instanceInfo: InstanceInfoResolver,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'app',
|
||||||
|
component: MainComponent,
|
||||||
|
resolve: {
|
||||||
|
instanceInfo: InstanceInfoResolver,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'login',
|
||||||
|
component: LoginComponent,
|
||||||
|
resolve: {
|
||||||
|
instanceInfo: InstanceInfoResolver,
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
BIN
src/assets/screenshots/win.png
Normal file
BIN
src/assets/screenshots/win.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 585 KiB |
@ -5,7 +5,10 @@
|
|||||||
a.btn.btn-primary([href]='releaseURL', target='_blank')
|
a.btn.btn-primary([href]='releaseURL', target='_blank')
|
||||||
fa-icon([icon]='_downloadIcon', [fixedWidth]='true')
|
fa-icon([icon]='_downloadIcon', [fixedWidth]='true')
|
||||||
span Download
|
span Download
|
||||||
a.btn.btn-secondary(routerLink='/login')
|
a.btn.btn-secondary([href]='donationURL', target='_blank')
|
||||||
|
fa-icon([icon]='_donateIcon', [fixedWidth]='true')
|
||||||
|
span Donate
|
||||||
|
a.btn.btn-secondary(routerLink='/login', *ngIf='instanceInfo.login_enabled')
|
||||||
fa-icon([icon]='_loginIcon', [fixedWidth]='true')
|
fa-icon([icon]='_loginIcon', [fixedWidth]='true')
|
||||||
span Login
|
span Login
|
||||||
|
|
||||||
@ -84,7 +87,7 @@
|
|||||||
.col
|
.col
|
||||||
img.screenshot([src]='screenshots.ssh')
|
img.screenshot([src]='screenshots.ssh')
|
||||||
.col
|
.col
|
||||||
h1 SSH
|
h1 SSH Client
|
||||||
ul
|
ul
|
||||||
li SSH2 client with a connection manager
|
li SSH2 client with a connection manager
|
||||||
li #[strong SFTP and Zmodem] file transfers
|
li #[strong SFTP and Zmodem] file transfers
|
||||||
@ -94,3 +97,47 @@
|
|||||||
li Login scripts
|
li Login scripts
|
||||||
li Optional built-in #[strong password manager] with a master passphrase
|
li Optional built-in #[strong password manager] with a master passphrase
|
||||||
li #[strong Proxy command] support
|
li #[strong Proxy command] support
|
||||||
|
|
||||||
|
.section.section-b
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
h1 Windows, but nice
|
||||||
|
ul
|
||||||
|
li Support for #[strong different shells] in the same window
|
||||||
|
li Better tab completion #[strong cmd.exe] thanks to Clink.
|
||||||
|
li Explorer menu integration
|
||||||
|
li Optional #[strong portable mode]
|
||||||
|
li Current directory detection that works
|
||||||
|
.col
|
||||||
|
img.screenshot([src]='screenshots.win')
|
||||||
|
|
||||||
|
.section.section-a
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
img.screenshot([src]='screenshots.serial')
|
||||||
|
.col
|
||||||
|
h1 Serial Terminal
|
||||||
|
ul
|
||||||
|
li Multiple #[strong connection profiles]
|
||||||
|
li Newline conversion
|
||||||
|
li Text, #[strong readline] and #[strong byte-by-byte] input modes
|
||||||
|
li Text and #[strong hexdump] output modes
|
||||||
|
li Zmodem
|
||||||
|
li Non-standard baud rates
|
||||||
|
|
||||||
|
.section.section-a
|
||||||
|
.container
|
||||||
|
h1 And just too much stuff to mention here:
|
||||||
|
ul
|
||||||
|
li Themes #[strong customizable with CSS]
|
||||||
|
li Extensible via #[strong plugins] (in JS)
|
||||||
|
li A bunch of color schemes already included
|
||||||
|
li #[strong Font ligatures] and font fallback
|
||||||
|
li #[strong Clickable URLs], IPs and paths
|
||||||
|
li #[strong WinSCP] integration
|
||||||
|
li Shell #[strong profiles]
|
||||||
|
li Simultaneous #[strong multi-pane input]
|
||||||
|
li Optional PuTTY style #[strong right-click paste] and #[strong copy on select]
|
||||||
|
li macOS vibrancy and Win 10 fluent background support
|
||||||
|
@ -52,7 +52,7 @@ iframe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quotes {
|
.quotes {
|
||||||
margin: 30px 0;
|
margin: 50px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -79,7 +79,7 @@ strong {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
padding: 30px 0;
|
padding: 50px 0;
|
||||||
|
|
||||||
.screenshot {
|
.screenshot {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import * as semverGT from 'semver/functions/gt'
|
import * as semverGT from 'semver/functions/gt'
|
||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Component, ElementRef, ViewChild } from '@angular/core'
|
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||||
import { Version } from '../api'
|
import { InstanceInfo, Version } from '../api'
|
||||||
import { faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons'
|
import { faCoffee, faDownload, faSignInAlt } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||||
|
import { ActivatedRoute } from '@angular/router'
|
||||||
|
|
||||||
class DemoConnector {
|
class DemoConnector {
|
||||||
constructor (targetWindow: Window, private version: Version) {
|
constructor (targetWindow: Window, private version: Version) {
|
||||||
@ -47,18 +48,30 @@ export class HomeComponent {
|
|||||||
connector: DemoConnector
|
connector: DemoConnector
|
||||||
githubURL = 'https://github.com/Eugeny/terminus'
|
githubURL = 'https://github.com/Eugeny/terminus'
|
||||||
releaseURL = `${this.githubURL}/releases/latest`
|
releaseURL = `${this.githubURL}/releases/latest`
|
||||||
|
donationURL = 'https://ko-fi.com/eugeny'
|
||||||
|
|
||||||
_logo = require('../assets/logo.svg')
|
_logo = require('../assets/logo.svg')
|
||||||
_downloadIcon = faDownload
|
_downloadIcon = faDownload
|
||||||
_loginIcon = faSignInAlt
|
_loginIcon = faSignInAlt
|
||||||
_githubIcon = faGithub
|
_githubIcon = faGithub
|
||||||
|
_donateIcon = faCoffee
|
||||||
|
|
||||||
screenshots = {
|
screenshots = {
|
||||||
window: require('../assets/screenshots/window.png'),
|
window: require('../assets/screenshots/window.png'),
|
||||||
tabs: require('../assets/screenshots/tabs.png'),
|
tabs: require('../assets/screenshots/tabs.png'),
|
||||||
ssh: require('../assets/screenshots/ssh.png'),
|
ssh: require('../assets/screenshots/ssh.png'),
|
||||||
|
serial: require('../assets/screenshots/serial.png'),
|
||||||
|
win: require('../assets/screenshots/win.png'),
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (private http: HttpClient) {
|
instanceInfo: InstanceInfo
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private http: HttpClient,
|
||||||
|
route: ActivatedRoute,
|
||||||
|
) {
|
||||||
window.addEventListener('message', this.connectorRequestHandler)
|
window.addEventListener('message', this.connectorRequestHandler)
|
||||||
|
this.instanceInfo = route.snapshot.data.instanceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
connectorRequestHandler = event => {
|
connectorRequestHandler = event => {
|
||||||
|
@ -9,7 +9,7 @@ from rest_framework.response import Response
|
|||||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer, Serializer
|
||||||
from rest_framework_dataclasses.serializers import DataclassSerializer
|
from rest_framework_dataclasses.serializers import DataclassSerializer
|
||||||
|
|
||||||
from .models import Config, User
|
from .models import Config, User
|
||||||
@ -89,3 +89,17 @@ class LogoutView(APIView):
|
|||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
logout(request)
|
logout(request)
|
||||||
return Response(None)
|
return Response(None)
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceInfoSerializer(Serializer):
|
||||||
|
login_enabled = fields.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceInfoViewSet(RetrieveModelMixin, GenericViewSet):
|
||||||
|
queryset = '' # type: ignore
|
||||||
|
serializer_class = InstanceInfoSerializer
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
return {
|
||||||
|
'login_enabled': settings.ENABLE_LOGIN,
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ router.register('api/1/versions', api.AppVersionViewSet, basename='app-versions'
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('api/1/auth/logout', api.LogoutView.as_view()),
|
path('api/1/auth/logout', api.LogoutView.as_view()),
|
||||||
path('api/1/user', api.UserViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
|
path('api/1/user', api.UserViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
|
||||||
|
path('api/1/instance-info', api.InstanceInfoViewSet.as_view({'get': 'retrieve'})),
|
||||||
|
|
||||||
re_path('^(|login|app)$', views.IndexView.as_view()),
|
re_path('^(|login|app)$', views.IndexView.as_view()),
|
||||||
|
|
||||||
|
@ -157,6 +157,7 @@ for key in [
|
|||||||
'GITHUB_SPONSORS_USER',
|
'GITHUB_SPONSORS_USER',
|
||||||
'GITHUB_SPONSORS_MIN_PAYMENT',
|
'GITHUB_SPONSORS_MIN_PAYMENT',
|
||||||
'GITHUB_TOKEN',
|
'GITHUB_TOKEN',
|
||||||
|
'ENABLE_LOGIN',
|
||||||
]:
|
]:
|
||||||
globals()[key] = os.getenv(key)
|
globals()[key] = os.getenv(key)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user