blux-framework 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- blux_framework-0.1.0/PKG-INFO +100 -0
- blux_framework-0.1.0/README.md +90 -0
- blux_framework-0.1.0/pyproject.toml +33 -0
- blux_framework-0.1.0/src/blux/__init__.py +10 -0
- blux_framework-0.1.0/src/blux/__projeto_test/app/api/payments/appypay.py +24 -0
- blux_framework-0.1.0/src/blux/__projeto_test/app/api/produtos/index.py +18 -0
- blux_framework-0.1.0/src/blux/__projeto_test/app/assets/globals.css +47 -0
- blux_framework-0.1.0/src/blux/__projeto_test/app/pages/index.py +68 -0
- blux_framework-0.1.0/src/blux/__projeto_test/app/pages/sobre.py +16 -0
- blux_framework-0.1.0/src/blux/__projeto_test/box.config.py +0 -0
- blux_framework-0.1.0/src/blux/app.py +48 -0
- blux_framework-0.1.0/src/blux/cli.py +103 -0
- blux_framework-0.1.0/src/blux/core/api.py +33 -0
- blux_framework-0.1.0/src/blux/core/elements.py +264 -0
- blux_framework-0.1.0/src/blux/core/render.py +68 -0
- blux_framework-0.1.0/src/blux/core/routes.py +199 -0
- blux_framework-0.1.0/src/blux/core/state.py +26 -0
- blux_framework-0.1.0/src/blux/core/types.py +0 -0
- blux_framework-0.1.0/src/blux/utils.py +32 -0
- blux_framework-0.1.0/src/blux/web/static/css/base.css +17 -0
- blux_framework-0.1.0/src/blux/web/static/js/app.js +0 -0
- blux_framework-0.1.0/src/blux/web/static/js/htmx-ext-head.js +1 -0
- blux_framework-0.1.0/src/blux/web/static/js/htmx.js +1 -0
- blux_framework-0.1.0/src/blux/web/static/js/idiomorph-ext.min.js +1 -0
- blux_framework-0.1.0/src/blux/web/templates/_head.html +9 -0
- blux_framework-0.1.0/src/blux/web/templates/index.html +12 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: blux-framework
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Um framework full-stack declarativo
|
|
5
|
+
Author: Ricardo
|
|
6
|
+
Author-email: Ricardo <ricardokayoca@gmail.com>
|
|
7
|
+
Requires-Dist: fastapi[standard]>=0.141.1
|
|
8
|
+
Requires-Python: >=3.14
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# blux
|
|
12
|
+
blux é um framework full-stack declarativo feito em Python para criar interfaces web com renderização dinâmica, ações no backend e roteamento baseado em diretórios.
|
|
13
|
+
|
|
14
|
+
## Visão geral
|
|
15
|
+
|
|
16
|
+
- roteamento baseado em diretórios
|
|
17
|
+
- componentes para UI
|
|
18
|
+
- text
|
|
19
|
+
- view
|
|
20
|
+
- button
|
|
21
|
+
- input
|
|
22
|
+
- textarea
|
|
23
|
+
- image
|
|
24
|
+
- link
|
|
25
|
+
- table
|
|
26
|
+
- modal
|
|
27
|
+
- form
|
|
28
|
+
- atualização parcial do componente quando uma action é chamada
|
|
29
|
+
- actions: funções executadas no backend quando um evento ocorre
|
|
30
|
+
|
|
31
|
+
## Documentação
|
|
32
|
+
|
|
33
|
+
A documentação está em `docs/` e distribuída com MkDocs (Material).
|
|
34
|
+
|
|
35
|
+
### Rodar a versão local
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python -m pip install -e '.[docs]'
|
|
39
|
+
mkdocs serve
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Conteúdo principal
|
|
43
|
+
|
|
44
|
+
- [Início](docs/index.md)
|
|
45
|
+
- [Primeiros passos](docs/quickstart.md)
|
|
46
|
+
- [Conceitos](docs/concepts.md)
|
|
47
|
+
- [Componentes](docs/components.md)
|
|
48
|
+
- [Actions](docs/actions.md)
|
|
49
|
+
- [API](docs/api.md)
|
|
50
|
+
|
|
51
|
+
### Build da documentação
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
mkdocs build
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Status do projeto
|
|
58
|
+
|
|
59
|
+
- [x] atualizar componente sempre que uma action é chamada
|
|
60
|
+
- [x] actions: função que serão chamadas no back-end assim que um evento for chamado
|
|
61
|
+
- [ ] api: rotas publicas
|
|
62
|
+
- [ ] Middleware: deve executar antes da renderisação
|
|
63
|
+
- [ ] Autenticação
|
|
64
|
+
- [ ] Proteção contra CSRF
|
|
65
|
+
- [ ] State
|
|
66
|
+
|
|
67
|
+
## Estrutura principal
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
app/
|
|
71
|
+
pages/
|
|
72
|
+
src/
|
|
73
|
+
blux/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Exemplo rápido
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import blux
|
|
80
|
+
|
|
81
|
+
class HomePage(blux.Page):
|
|
82
|
+
title = "Home"
|
|
83
|
+
|
|
84
|
+
@blux.action
|
|
85
|
+
def salvar(self, request):
|
|
86
|
+
form = request.state.form
|
|
87
|
+
print(form.get("nome"))
|
|
88
|
+
|
|
89
|
+
def render(self, request):
|
|
90
|
+
return blux.Form(
|
|
91
|
+
action=self.salvar,
|
|
92
|
+
elements=[
|
|
93
|
+
blux.Input(name="nome", placeholder="Digite seu nome"),
|
|
94
|
+
blux.Button(content="Enviar", type="submit"),
|
|
95
|
+
],
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# blux
|
|
2
|
+
blux é um framework full-stack declarativo feito em Python para criar interfaces web com renderização dinâmica, ações no backend e roteamento baseado em diretórios.
|
|
3
|
+
|
|
4
|
+
## Visão geral
|
|
5
|
+
|
|
6
|
+
- roteamento baseado em diretórios
|
|
7
|
+
- componentes para UI
|
|
8
|
+
- text
|
|
9
|
+
- view
|
|
10
|
+
- button
|
|
11
|
+
- input
|
|
12
|
+
- textarea
|
|
13
|
+
- image
|
|
14
|
+
- link
|
|
15
|
+
- table
|
|
16
|
+
- modal
|
|
17
|
+
- form
|
|
18
|
+
- atualização parcial do componente quando uma action é chamada
|
|
19
|
+
- actions: funções executadas no backend quando um evento ocorre
|
|
20
|
+
|
|
21
|
+
## Documentação
|
|
22
|
+
|
|
23
|
+
A documentação está em `docs/` e distribuída com MkDocs (Material).
|
|
24
|
+
|
|
25
|
+
### Rodar a versão local
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m pip install -e '.[docs]'
|
|
29
|
+
mkdocs serve
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Conteúdo principal
|
|
33
|
+
|
|
34
|
+
- [Início](docs/index.md)
|
|
35
|
+
- [Primeiros passos](docs/quickstart.md)
|
|
36
|
+
- [Conceitos](docs/concepts.md)
|
|
37
|
+
- [Componentes](docs/components.md)
|
|
38
|
+
- [Actions](docs/actions.md)
|
|
39
|
+
- [API](docs/api.md)
|
|
40
|
+
|
|
41
|
+
### Build da documentação
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
mkdocs build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Status do projeto
|
|
48
|
+
|
|
49
|
+
- [x] atualizar componente sempre que uma action é chamada
|
|
50
|
+
- [x] actions: função que serão chamadas no back-end assim que um evento for chamado
|
|
51
|
+
- [ ] api: rotas publicas
|
|
52
|
+
- [ ] Middleware: deve executar antes da renderisação
|
|
53
|
+
- [ ] Autenticação
|
|
54
|
+
- [ ] Proteção contra CSRF
|
|
55
|
+
- [ ] State
|
|
56
|
+
|
|
57
|
+
## Estrutura principal
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
app/
|
|
61
|
+
pages/
|
|
62
|
+
src/
|
|
63
|
+
blux/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Exemplo rápido
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import blux
|
|
70
|
+
|
|
71
|
+
class HomePage(blux.Page):
|
|
72
|
+
title = "Home"
|
|
73
|
+
|
|
74
|
+
@blux.action
|
|
75
|
+
def salvar(self, request):
|
|
76
|
+
form = request.state.form
|
|
77
|
+
print(form.get("nome"))
|
|
78
|
+
|
|
79
|
+
def render(self, request):
|
|
80
|
+
return blux.Form(
|
|
81
|
+
action=self.salvar,
|
|
82
|
+
elements=[
|
|
83
|
+
blux.Input(name="nome", placeholder="Digite seu nome"),
|
|
84
|
+
blux.Button(content="Enviar", type="submit"),
|
|
85
|
+
],
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "blux-framework"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Um framework full-stack declarativo"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Ricardo", email = "ricardokayoca@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.14"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"fastapi[standard]>=0.141.1",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
blux = "blux.cli:main"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["uv_build>=0.11.29,<0.12.0"]
|
|
19
|
+
build-backend = "uv_build"
|
|
20
|
+
|
|
21
|
+
[tool.uv.build-backend]
|
|
22
|
+
module-name = "blux"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"mkdocs-material>=9.7.7",
|
|
27
|
+
"pymdown-extensions>=11.0.2",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[tool.uv.workspace]
|
|
31
|
+
members = [
|
|
32
|
+
"test_app",
|
|
33
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import blux
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
class Payment(BaseModel):
|
|
5
|
+
amount:float
|
|
6
|
+
client_name:str
|
|
7
|
+
client_email: str
|
|
8
|
+
|
|
9
|
+
@blux.api()
|
|
10
|
+
def get_payment(nome:str):
|
|
11
|
+
""" Criar um novo produto"""
|
|
12
|
+
|
|
13
|
+
return {"ok":"ok"}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@blux.api(method="POST")
|
|
17
|
+
def create_produtos(nome:str):
|
|
18
|
+
""" Criar um novo produto"""
|
|
19
|
+
|
|
20
|
+
return {"ok":"ok"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import blux
|
|
2
|
+
|
|
3
|
+
@blux.api()
|
|
4
|
+
def get_produtos(nome:str):
|
|
5
|
+
""" Criar um novo produto"""
|
|
6
|
+
|
|
7
|
+
return {"ok":"ok"}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@blux.api(method="POST")
|
|
11
|
+
def create_produtos(nome:str):
|
|
12
|
+
""" Criar um novo produto"""
|
|
13
|
+
|
|
14
|
+
return {"ok":"ok"}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
.content_app {
|
|
2
|
+
padding: 10px;
|
|
3
|
+
height: 100%;
|
|
4
|
+
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
align-items: center;
|
|
8
|
+
padding: 2rem;
|
|
9
|
+
text-align: center;
|
|
10
|
+
|
|
11
|
+
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.title {
|
|
16
|
+
font-weight: bold;
|
|
17
|
+
font-size: 2rem;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.text {
|
|
21
|
+
font-size: .8rem;
|
|
22
|
+
opacity: .7;
|
|
23
|
+
max-width: 70%;
|
|
24
|
+
margin: auto;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.content {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: 10px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.button_count {
|
|
34
|
+
background-color: #141414;
|
|
35
|
+
padding: 10px;
|
|
36
|
+
border: 0;
|
|
37
|
+
border-radius: 10px;
|
|
38
|
+
color: #d2d2d2;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.row2 {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: 10px;
|
|
46
|
+
justify-content: center;
|
|
47
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import blux
|
|
2
|
+
|
|
3
|
+
num = 0
|
|
4
|
+
|
|
5
|
+
class Index(blux.Page):
|
|
6
|
+
|
|
7
|
+
title = "index"
|
|
8
|
+
styles = ["globals.css"]
|
|
9
|
+
|
|
10
|
+
@blux.action
|
|
11
|
+
def contador(self, request:blux.Request):
|
|
12
|
+
global num
|
|
13
|
+
num += 1
|
|
14
|
+
|
|
15
|
+
def render(self, request:blux.Request):
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
blux.View(
|
|
19
|
+
state=self.state,
|
|
20
|
+
class_name="content_app",
|
|
21
|
+
elements=[
|
|
22
|
+
blux.View(
|
|
23
|
+
class_name="content",
|
|
24
|
+
elements=[
|
|
25
|
+
|
|
26
|
+
blux.Text(content="Bem vindo ao Box", class_name="title"),
|
|
27
|
+
blux.Text(
|
|
28
|
+
content="O framework pensado na produtividade de criar aplicações full-stack com apenas uma base de codigo",
|
|
29
|
+
class_name="text"
|
|
30
|
+
),
|
|
31
|
+
blux.View(
|
|
32
|
+
elements=[
|
|
33
|
+
blux.Button(
|
|
34
|
+
content=f"contador {num}",
|
|
35
|
+
on_click=self.contador,
|
|
36
|
+
class_name="button_count"
|
|
37
|
+
),
|
|
38
|
+
]
|
|
39
|
+
),
|
|
40
|
+
blux.View(
|
|
41
|
+
elements=[
|
|
42
|
+
blux.Link(
|
|
43
|
+
content="Develop",
|
|
44
|
+
href="http://ricardocayoca.onrender.com/",
|
|
45
|
+
target="_blank"
|
|
46
|
+
),
|
|
47
|
+
blux.Link(
|
|
48
|
+
content="Doc box",
|
|
49
|
+
href="/"
|
|
50
|
+
),
|
|
51
|
+
blux.Link(
|
|
52
|
+
content="Swager",
|
|
53
|
+
href="/docs",
|
|
54
|
+
target="_blank"
|
|
55
|
+
),
|
|
56
|
+
blux.Link(
|
|
57
|
+
content="API doc",
|
|
58
|
+
href="/redoc",
|
|
59
|
+
target="_blank"
|
|
60
|
+
)
|
|
61
|
+
],
|
|
62
|
+
class_name="row2"
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from fastapi import FastAPI
|
|
5
|
+
from fastapi.staticfiles import StaticFiles
|
|
6
|
+
from fastapi.templating import Jinja2Templates
|
|
7
|
+
|
|
8
|
+
from .core.routes import build_router
|
|
9
|
+
from .utils import install_form_middleware
|
|
10
|
+
|
|
11
|
+
APP_DIR = None
|
|
12
|
+
WEB_DIR = os.path.join(os.path.dirname(__file__), "web")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
template = Jinja2Templates(
|
|
16
|
+
directory=os.path.join(WEB_DIR, "templates")
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def create_app():
|
|
20
|
+
app = FastAPI()
|
|
21
|
+
|
|
22
|
+
install_form_middleware(app)
|
|
23
|
+
|
|
24
|
+
app.mount("/static", StaticFiles(
|
|
25
|
+
directory=os.path.join(WEB_DIR, "static")
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
for page in Path(os.getcwd()).rglob("**/app"):
|
|
30
|
+
if page.exists():
|
|
31
|
+
APP_DIR = page
|
|
32
|
+
break
|
|
33
|
+
|
|
34
|
+
if not APP_DIR: raise FileNotFoundError(
|
|
35
|
+
f"Diretório de páginas não encontrado: app\n"
|
|
36
|
+
f"Rode o comando a partir da raiz do projeto, ou passe --app-dir."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
app.mount("/assets", StaticFiles(
|
|
42
|
+
directory=APP_DIR.joinpath("assets")
|
|
43
|
+
))
|
|
44
|
+
|
|
45
|
+
for route in build_router(APP_DIR, template):
|
|
46
|
+
app.include_router(route, include_in_schema=True)
|
|
47
|
+
|
|
48
|
+
return app
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
import uvicorn
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(help="CLI do blux — sobe o servidor e escaneia as rotas de app/")
|
|
13
|
+
|
|
14
|
+
FACTORY_TARGET = "blux.app:create_app"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command()
|
|
18
|
+
def dev(
|
|
19
|
+
host: str = typer.Option("127.0.0.1", help="Endereço para escutar"),
|
|
20
|
+
port: int = typer.Option(8000, help="Porta para escutar"),
|
|
21
|
+
):
|
|
22
|
+
"""Sobe o servidor de desenvolvimento com reload automático."""
|
|
23
|
+
typer.echo(f"blux dev -> http://{host}:{port}")
|
|
24
|
+
uvicorn.run(FACTORY_TARGET, factory=True, host=host, port=port, reload=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.command()
|
|
28
|
+
def init(name:str=typer.Argument(".", help="Diretório")):
|
|
29
|
+
""" Cria um estrutura do projeto """
|
|
30
|
+
|
|
31
|
+
ROOT = Path(name)
|
|
32
|
+
|
|
33
|
+
if ROOT.exists():
|
|
34
|
+
typer.echo(f"O projeto '{ROOT}' Já existe")
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
origem = Path(os.path.dirname(__file__)).joinpath("__projeto_test")
|
|
38
|
+
print(origem)
|
|
39
|
+
|
|
40
|
+
for arquivo in origem.rglob("*"):
|
|
41
|
+
if arquivo.is_file():
|
|
42
|
+
relativo = arquivo.relative_to(origem)
|
|
43
|
+
destino_arquivo = ROOT / relativo
|
|
44
|
+
|
|
45
|
+
destino_arquivo.parent.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
shutil.copy2(arquivo, destino_arquivo)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
typer.echo(f"Projeto {ROOT} inicializado")
|
|
50
|
+
typer.echo(f"use: cd {ROOT}")
|
|
51
|
+
typer.echo("start develop server: blux dev")
|
|
52
|
+
typer.echo("cli help use: blux --help")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@app.command()
|
|
66
|
+
def start(
|
|
67
|
+
host: str = typer.Option("0.0.0.0", help="Endereço para escutar"),
|
|
68
|
+
port: int = typer.Option(8000, help="Porta para escutar"),
|
|
69
|
+
app_dir: str = typer.Option("app", "--app-dir", help="Diretório com as páginas"),
|
|
70
|
+
workers: int = typer.Option(1, help="Número de processos worker"),
|
|
71
|
+
):
|
|
72
|
+
"""Sobe o servidor em modo produção (sem reload)."""
|
|
73
|
+
os.environ["blux_APP_DIR"] = app_dir
|
|
74
|
+
typer.echo(f"backpay start -> http://{host}:{port} (páginas em ./{app_dir}, workers={workers})")
|
|
75
|
+
uvicorn.run(FACTORY_TARGET, factory=True, host=host, port=port, workers=workers)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@app.command()
|
|
79
|
+
def routes(
|
|
80
|
+
app_dir: str = typer.Option("app", "--app-dir", help="Diretório com as páginas"),
|
|
81
|
+
):
|
|
82
|
+
"""Lista as rotas descobertas em app/, sem subir o servidor."""
|
|
83
|
+
from pathlib import Path
|
|
84
|
+
|
|
85
|
+
from .core.routes import discover_pages
|
|
86
|
+
|
|
87
|
+
pages = discover_pages(Path(app_dir))
|
|
88
|
+
if not pages:
|
|
89
|
+
typer.echo(f"Nenhuma página encontrada em ./{app_dir}")
|
|
90
|
+
raise typer.Exit(code=1)
|
|
91
|
+
|
|
92
|
+
for page in pages:
|
|
93
|
+
typer.echo(f"GET {page.route_path}")
|
|
94
|
+
base = page.route_path.rstrip("/")
|
|
95
|
+
typer.echo(f"POST {base}/_action/{{component_id}}/{{action_name}}")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def main():
|
|
99
|
+
app()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
main()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from fastapi import (
|
|
3
|
+
APIRouter,
|
|
4
|
+
HTTPException,
|
|
5
|
+
Depends
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def api(
|
|
12
|
+
method:Literal["GET", "POST", "PUT"]="GET",
|
|
13
|
+
middeware:list=[],
|
|
14
|
+
title="",
|
|
15
|
+
):
|
|
16
|
+
|
|
17
|
+
def decorador(f:callable):
|
|
18
|
+
@wraps(f)
|
|
19
|
+
def wrapper(*args, **kwargs):
|
|
20
|
+
|
|
21
|
+
return f(*args, **kwargs)
|
|
22
|
+
wrapper._api = True
|
|
23
|
+
wrapper._method = method
|
|
24
|
+
wrapper._title = title
|
|
25
|
+
return wrapper
|
|
26
|
+
|
|
27
|
+
return decorador
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|