mirror of
https://github.com/Eugeny/tabby-web.git
synced 2026-08-16 22:36:02 +01:00
fixup
This commit is contained in:
22
README.md
Normal file
22
README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Using Docker images
|
||||
|
||||
Tabby Web consists of two Docker images - `backend` and `frontend`. See an example set up in `docker-compose.yml`
|
||||
|
||||
## Environment variables
|
||||
|
||||
### Frontend
|
||||
|
||||
* `BACKEND_URL`
|
||||
* `WEB_CONCURRENCY`
|
||||
|
||||
### Backend
|
||||
|
||||
* `DATABASE_URL` (required).
|
||||
* `FRONTEND_URL`
|
||||
* `APP_DIST_STORAGE`: a `file://`, `s3://`, or `gcs://` URL to store app distros in.
|
||||
* `SOCIAL_AUTH_*_KEY` & `SOCIAL_AUTH_*_SECRET`: social login credentials, supported providers are `GITHUB`, `GITLAB`, `MICROSOFT_GRAPH` and `GOOGLE_OAUTH2`.
|
||||
* `ENABLE_HOMEPAGE`: set to `False` to disable the homepage and always redirect to the app.
|
||||
|
||||
## Installing Tabby app versions
|
||||
|
||||
* `docker-compose run backend ./manage.py add_version 1.0.156-nightly.1`
|
||||
0
app-dist/.gitkeep
Normal file
0
app-dist/.gitkeep
Normal file
@@ -81,6 +81,7 @@ class AppVersionViewSet(ListModelMixin, GenericViewSet):
|
||||
return [
|
||||
self._get_version(x['name'])
|
||||
for x in fs.listdir(settings.APP_DIST_STORAGE)
|
||||
if x['type'] == 'directory'
|
||||
]
|
||||
|
||||
def _get_version(self, dir):
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import fsspec
|
||||
import os
|
||||
from fsspec.implementations.local import LocalFileSystem
|
||||
from django.conf import settings
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.http.response import FileResponse, HttpResponseNotFound, HttpResponseRedirect
|
||||
from django.views import static
|
||||
from rest_framework.views import APIView
|
||||
from urllib.parse import urlparse
|
||||
@@ -24,4 +26,9 @@ class AppDistView(APIView):
|
||||
def get(self, request, version=None, path=None, format=None):
|
||||
fs = fsspec.filesystem(urlparse(settings.APP_DIST_STORAGE).scheme)
|
||||
url = f'{settings.APP_DIST_STORAGE}/{version}/{path}'
|
||||
return HttpResponseRedirect(fs.url(url))
|
||||
if isinstance(fs, LocalFileSystem):
|
||||
if not fs.exists(url):
|
||||
return HttpResponseNotFound()
|
||||
return FileResponse(fs.open(url), filename=os.path.basename(url))
|
||||
else:
|
||||
return HttpResponseRedirect(fs.url(url))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.urls import path, include
|
||||
from django.views.static import serve
|
||||
from .app.urls import urlpatterns as app_urlpatterns
|
||||
@@ -8,7 +9,7 @@ urlpatterns = [
|
||||
path('', include(app_urlpatterns)),
|
||||
path('api/1/auth/social/', include('social_django.urls', namespace='social')),
|
||||
path('admin/', admin.site.urls),
|
||||
path(f'{settings.STATIC_URL.strip("/")}/<path:path>', serve, kwargs={
|
||||
'document_root': settings.STATIC_ROOT,
|
||||
}),
|
||||
]
|
||||
# path(f'{settings.STATIC_URL.strip("/")}/<path:path>', serve, kwargs={
|
||||
# 'document_root': settings.STATIC_ROOT,
|
||||
# }),
|
||||
] + staticfiles_urlpatterns(settings.STATIC_URL)
|
||||
|
||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
frontend:
|
||||
build: frontend
|
||||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
- PORT=80
|
||||
- BACKEND_URL=http://localhost:9091
|
||||
backend:
|
||||
build: backend
|
||||
ports:
|
||||
- 9091:80
|
||||
volumes:
|
||||
- ./app-dist:/app-dist
|
||||
environment:
|
||||
- DATABASE_URL
|
||||
- PORT=80
|
||||
- FRONTEND_URL=http://localhost:9090
|
||||
- ENABLE_HOMEPAGE=False
|
||||
- DEBUG=False
|
||||
- APP_DIST_STORAGE=file:///app-dist
|
||||
@@ -7,8 +7,6 @@ steps:
|
||||
- '${_DOCKER_TAG}'
|
||||
- '--cache-from'
|
||||
- '${_DOCKER_TAG}'
|
||||
- '--build-arg'
|
||||
- 'BACKEND_URL=${_BACKEND_URL}'
|
||||
- '.'
|
||||
|
||||
images: ['${_DOCKER_TAG}']
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<meta property="twitter:title" content="Tabby - a terminal for a more modern age">
|
||||
<meta property="twitter:description" content="Tabby is a free and open source SSH, local and Telnet terminal with everything you'll ever need.">
|
||||
<meta property="twitter:image" content="https://user-images.githubusercontent.com/161476/126016449-a053012a-e322-48ed-a2ab-3ed4f3281465.png">
|
||||
|
||||
<meta property="x-tabby-web-backend-url" content="{{backendURL}}">
|
||||
</head>
|
||||
<body>
|
||||
<app></app>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { enableProdMode } from '@angular/core'
|
||||
import { ngExpressEngine } from '@nguniversal/express-engine'
|
||||
|
||||
import * as express from 'express'
|
||||
|
||||
import { join } from 'path'
|
||||
|
||||
|
||||
@@ -42,7 +43,19 @@ function start () {
|
||||
}))
|
||||
|
||||
app.get(['/', '/app', '/login'], (req, res) => {
|
||||
res.render('index', { req })
|
||||
res.render(
|
||||
'index',
|
||||
{
|
||||
req,
|
||||
providers: [
|
||||
{ provide: 'BACKEND_URL', useValue: process.env.BACKEND_URL ?? '' },
|
||||
],
|
||||
},
|
||||
(err: Error, html: string) => {
|
||||
html = html.replace('{{backendURL}}', process.env.BACKEND_URL ?? '')
|
||||
res.status(err ? 500 : 200).send(html || err.message)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
app.get(['/terminal'], (req, res) => {
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
declare const BACKEND_URL: any
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CommonService {
|
||||
backendURL: string = BACKEND_URL
|
||||
backendURL: string
|
||||
|
||||
constructor () {
|
||||
constructor (@Inject('BACKEND_URL') @Optional() ssrBackendURL: string) {
|
||||
const tag = (document.querySelector('meta[property=x-tabby-web-backend-url]') as HTMLMetaElement)
|
||||
if (ssrBackendURL) {
|
||||
this.backendURL = ssrBackendURL
|
||||
tag.content = ssrBackendURL
|
||||
} else {
|
||||
if (tag.content && !tag.content.startsWith('{{')) {
|
||||
this.backendURL = tag.content
|
||||
} else {
|
||||
this.backendURL = ''
|
||||
}
|
||||
}
|
||||
|
||||
console.log(this.backendURL)
|
||||
if (this.backendURL.endsWith('/')) {
|
||||
this.backendURL = this.backendURL.slice(0, -1)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import './terminal-styles.scss'
|
||||
|
||||
async function start () {
|
||||
window['__filename'] = ''
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
window.addEventListener('message', event => {
|
||||
if (event.data === 'connector-ready') {
|
||||
|
||||
@@ -953,6 +953,11 @@ async-foreach@^0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
|
||||
integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
|
||||
|
||||
async@~3.2.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8"
|
||||
integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
@@ -2898,6 +2903,13 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
lru-cache@~5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
magic-string@^0.25.0:
|
||||
version "0.25.7"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
|
||||
@@ -3064,6 +3076,20 @@ ms@2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
mustache-express@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/mustache-express/-/mustache-express-1.3.1.tgz#b5144513ab79a503c87aa8cb16fe019d2f61d9f9"
|
||||
integrity sha512-RSSzrvM+CVAk9217dkWSNYyl6c2JnesNn6zaZ8+FvZSn8aLxY9l4kTnYqIoiE8GxdLyVQL2ak7XlMZS6t/l8YA==
|
||||
dependencies:
|
||||
async "~3.2.0"
|
||||
lru-cache "~5.1.1"
|
||||
mustache "^4.2.0"
|
||||
|
||||
mustache@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64"
|
||||
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
|
||||
|
||||
nan@^2.13.2:
|
||||
version "2.14.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
||||
@@ -4950,6 +4976,11 @@ y18n@^5.0.5:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
|
||||
Reference in New Issue
Block a user