mirror of
https://github.com/Textualize/textual-web.git
synced 2025-10-17 02:36:40 +03:00
signup
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "textual_web"
|
name = "textual_web"
|
||||||
version = "0.1.0"
|
version = "0.1.0pre0"
|
||||||
description = "Serve Textual apps"
|
description = "Serve Textual apps"
|
||||||
authors = ["Will McGugan <will@textualize.io>"]
|
authors = ["Will McGugan <will@textualize.io>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from rich.console import RenderableType
|
from rich.console import Console, RenderableType
|
||||||
|
from rich.panel import Panel
|
||||||
|
import xdg
|
||||||
|
|
||||||
from textual import on
|
from textual import on
|
||||||
from textual import work
|
from textual import work
|
||||||
@@ -13,8 +16,11 @@ from textual.containers import Vertical, Container
|
|||||||
from textual.renderables.bar import Bar
|
from textual.renderables.bar import Bar
|
||||||
from textual.reactive import reactive
|
from textual.reactive import reactive
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
from textual.widgets import Label, Input, Button, LoadingIndicator
|
from textual.widgets import Label, Input, Button, LoadingIndicator, RichLog
|
||||||
from textual.screen import Screen
|
from textual.screen import ModalScreen, Screen
|
||||||
|
|
||||||
|
|
||||||
|
from ..environment import Environment
|
||||||
|
|
||||||
|
|
||||||
class Form(Container):
|
class Form(Container):
|
||||||
@@ -28,7 +34,7 @@ class Form(Container):
|
|||||||
layout: grid;
|
layout: grid;
|
||||||
grid-size: 2;
|
grid-size: 2;
|
||||||
grid-columns: auto 50;
|
grid-columns: auto 50;
|
||||||
grid_rows: auto;
|
grid-rows: auto;
|
||||||
grid-gutter: 1;
|
grid-gutter: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +87,6 @@ class Form(Container):
|
|||||||
Form Input {
|
Form Input {
|
||||||
border: tall transparent;
|
border: tall transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -237,7 +240,7 @@ class SignupScreen(Screen):
|
|||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
"http://127.0.0.1:8080/api/signup/", data=data
|
f"{self.app.environment.api_url}signup/", data=data
|
||||||
)
|
)
|
||||||
result = response.json()
|
result = response.json()
|
||||||
|
|
||||||
@@ -250,25 +253,32 @@ class SignupScreen(Screen):
|
|||||||
finally:
|
finally:
|
||||||
self.disabled = False
|
self.disabled = False
|
||||||
|
|
||||||
self.notify("There are errors in the form. Please try again.")
|
try:
|
||||||
self.query_one(Form).add_class("-show-errors")
|
result = response.json()
|
||||||
|
except Exception:
|
||||||
|
self.notify(
|
||||||
|
"Server returned an invalid response. Please try again later.",
|
||||||
|
severity="error",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
for error_label in self.query(ErrorLabel):
|
for error_label in self.query(ErrorLabel):
|
||||||
error_label.update("")
|
error_label.update("")
|
||||||
error_label.remove_class("-show-error")
|
error_label.remove_class("-show-error")
|
||||||
|
|
||||||
for error in result:
|
result_type = result["type"]
|
||||||
if error["loc"]:
|
|
||||||
error_label = self.query_one(
|
if result_type == "success":
|
||||||
f"#{error['loc'][0]} ErrorLabel", ErrorLabel
|
self.dismiss(result)
|
||||||
)
|
elif result_type == "fail":
|
||||||
error_label.add_class("-show-error")
|
for field, errors in result.get("errors", {}).items():
|
||||||
error_label.update(error["ctx"].get("error", error["msg"]))
|
if field == "_":
|
||||||
|
for error in errors:
|
||||||
|
self.notify(error, severity="error")
|
||||||
else:
|
else:
|
||||||
self.notify(
|
error_label = self.query_one(f"#{field} ErrorLabel", ErrorLabel)
|
||||||
error["ctx"].get("error", error["msg"]), severity="error", timeout=5
|
error_label.add_class("-show-error")
|
||||||
)
|
error_label.update("\n".join(errors))
|
||||||
self.app.log(result)
|
|
||||||
|
|
||||||
@on(Input.Changed, "#password Input")
|
@on(Input.Changed, "#password Input")
|
||||||
def input_changed(self, event: Input.Changed):
|
def input_changed(self, event: Input.Changed):
|
||||||
@@ -295,10 +305,53 @@ class SignupScreen(Screen):
|
|||||||
class SignUpApp(App):
|
class SignUpApp(App):
|
||||||
CSS_PATH = "signup.tcss"
|
CSS_PATH = "signup.tcss"
|
||||||
|
|
||||||
|
def __init__(self, environment: Environment) -> None:
|
||||||
|
self.environment = environment
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
def on_ready(self) -> None:
|
def on_ready(self) -> None:
|
||||||
self.push_screen(SignupScreen())
|
self.push_screen(SignupScreen(), callback=self.exit)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def signup(cls, environment: Environment) -> None:
|
||||||
|
console = Console()
|
||||||
|
app = SignUpApp(environment)
|
||||||
|
result = app.run()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if result is None:
|
||||||
app = SignUpApp()
|
return
|
||||||
app.run()
|
|
||||||
|
console.print(
|
||||||
|
Panel.fit("[bold]You have signed up to textual-web!", border_style="green")
|
||||||
|
)
|
||||||
|
|
||||||
|
home_path = xdg.xdg_config_home()
|
||||||
|
config_path = home_path / "textual-web"
|
||||||
|
config_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
auth_path = config_path / "auth.json"
|
||||||
|
auth = {
|
||||||
|
"email": result["user"]["email"],
|
||||||
|
"auth": result["auth_token"]["key"],
|
||||||
|
}
|
||||||
|
auth_path.write_text(json.dumps(auth))
|
||||||
|
|
||||||
|
console.print(f" • Wrote auth to {str(auth_path)!r}")
|
||||||
|
api_key = result["api_key"]["key"]
|
||||||
|
console.print(f" • Your API key is {api_key!r}")
|
||||||
|
ganglion_path = Path("./ganglion.toml")
|
||||||
|
|
||||||
|
CONFIG = f"""\
|
||||||
|
[account]
|
||||||
|
api_key = "{api_key}"
|
||||||
|
"""
|
||||||
|
if ganglion_path.exists():
|
||||||
|
console.print(
|
||||||
|
f" • [red]Not writing to existing {str(ganglion_path)!r}, please update manually."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ganglion_path.write_text(CONFIG)
|
||||||
|
console.print(f" • [green]Wrote {str(ganglion_path)!r}")
|
||||||
|
|
||||||
|
console.print()
|
||||||
|
|
||||||
|
console.print("Run 'textual-web --config ganglion.toml' to get started.")
|
||||||
|
|||||||
@@ -70,11 +70,9 @@ def print_disclaimer() -> None:
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-t", "--terminal", is_flag=True, help="Publish a remote terminal on a random URL"
|
"-t", "--terminal", is_flag=True, help="Publish a remote terminal on a random URL"
|
||||||
)
|
)
|
||||||
|
@click.option("-s", "--signup", is_flag=True, help="Create a textual-web account")
|
||||||
def app(
|
def app(
|
||||||
config: str | None,
|
config: str | None, environment: str, terminal: bool, api_key: str, signup: bool
|
||||||
environment: str,
|
|
||||||
terminal: bool,
|
|
||||||
api_key: str,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Main entry point for the CLI.
|
"""Main entry point for the CLI.
|
||||||
|
|
||||||
@@ -84,12 +82,19 @@ def app(
|
|||||||
terminal: Enable a terminal.
|
terminal: Enable a terminal.
|
||||||
api_key: API key.
|
api_key: API key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_console = Console(stderr=True)
|
error_console = Console(stderr=True)
|
||||||
from .config import load_config, default_config
|
from .config import load_config, default_config
|
||||||
from .environment import get_environment
|
from .environment import get_environment
|
||||||
|
|
||||||
_environment = get_environment(environment)
|
_environment = get_environment(environment)
|
||||||
|
|
||||||
|
if signup:
|
||||||
|
from .apps.signup import SignUpApp
|
||||||
|
|
||||||
|
SignUpApp.signup(_environment)
|
||||||
|
return
|
||||||
|
|
||||||
VERSION = version("textual-web")
|
VERSION = version("textual-web")
|
||||||
|
|
||||||
print_disclaimer()
|
print_disclaimer()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ ENVIRONMENTS = {
|
|||||||
# ),
|
# ),
|
||||||
"local": Environment(
|
"local": Environment(
|
||||||
name="local",
|
name="local",
|
||||||
api_url="ws://127.0.0.1:8080/api",
|
api_url="ws://127.0.0.1:8080/api/",
|
||||||
url="ws://127.0.0.1:8080/app-service/",
|
url="ws://127.0.0.1:8080/app-service/",
|
||||||
),
|
),
|
||||||
"dev": Environment(
|
"dev": Environment(
|
||||||
|
|||||||
Reference in New Issue
Block a user